Blitting through an Intermediary

I am using one png file (with alpha) to hold several images belonging to a
sprite.
I have a sprite class which I would like to have a function returning a
surface corresponding to a given request.
My attempt at this has been calling SDL_CreateRGBSurface(?) with the default
options as presented in the documentation.
I then blit to this surface and return it. On the upper level now I blit
this temporary surface to the screen.
The result is simple: nothing appears.
If I set the amask to 0 I get a black box, but any other value (including
default 0x000000ff) seems does nothing.
Every SDL command I call returns success.

Some relevant code:

image = IMG_Load_RW( SDL_RWFromFile( imageFile, “rb” ), 1 );
?
temp = SDL_CreateRGBSurface(SDL_HWSURFACE, 40,80,32,rmask,gmask,bmask,amask);
?
src.w = 40;
src.h = 80;
src.x = 40i;
src.y = 80
j;
dst.x = 0;
dst.y = 0;
SDL_BlitSurface( image, &src, temp, &dst );
?
(passed up)
?
dst.x = 2;
dst.y = 2;
SDL_BlitSurface( temp, NULL, target, &dst );

Where ?target? is the screen.
Other blits going from File -> Surface -> Display work with alpha.
(As oppose to this File -> Surface -> Surface -> Display)

I?ve removed all my error checking and obviously quite a bit of other code,
but this is everything involving SDL calls.
The sprite is currently 40x80 pixels,and the png file holds 3x3 images.

Thanks.

[…alpha & intermediate surface…]

I’m doing that in Fixed Rate Pig (http://olofson.net/examples.html),
in order to avoid some clipping overhead when using RLE acceleration.
The basic procedure is as follows:

1. Load the image. (Let's call it tmp.)

2. Disable alpha blending;
	SDL_SetAlpha(tmp, 0, 0);

3. For each target surface (tmp2), create an RGBA
   surface:
	tmp2 = SDL_CreateRGBSurface(SDL_SWSURFACE,
			sw, sh, 32,
			0xff000000, 0x00ff0000,
			0x0000ff00, 0x000000ff);

3b. Disable alpha blending for the target surface:
	SDL_SetAlpha(tmp2, 0, 0);

3c. Blit the area(s) you want as usual:
	SDL_BlitSurface(tmp, &rect, tmp2, NULL);

3d. Enable alpha blending for the target surface:
	SDL_SetAlpha(tmp2, SDL_SRCALPHA | SDL_RLEACCEL,
			SDL_ALPHA_OPAQUE);

3e. (For performance) convert the surface to a suitable
    format for blitting to the screen:
	sprite = SDL_DisplayFormatAlpha(tmp2);

And of course, don’t forget to SDL_FreeSurface() the temporary
surfaces. (Note that SDL_DisplayFormat*() creates a new surface
without freeing the original surface.)

//David Olofson - Programmer, Composer, Open Source Advocate

.- Audiality -----------------------------------------------.
| Free/Open Source audio engine for games and multimedia. |
| MIDI, modular synthesis, real time effects, scripting,… |
`-----------------------------------> http://audiality.org -’
http://olofson.nethttp://www.reologica.se —On Monday 26 April 2004 14.20, Brian wrote:

According to the SDL docs, blitting a surface with an alpha channel to another
surface with an alpha channel doesn’t alter the alpha channel of the
destination surface. So, even after the blitting is done, the destination
surface will still have its old alpha channel. That’s why what you’re trying
to do doesn’t work.

I honestly have no idea why the destination alpha channel doesn’t get modified
along with the destination color channels. Can Sam or anybody else please
explain the reason?

-Sean Ridenour> I am using one png file (with alpha) to hold several images belonging to a

sprite.
I have a sprite class which I would like to have a function returning a
surface corresponding to a given request.
My attempt at this has been calling SDL_CreateRGBSurface(?) with the
default options as presented in the documentation.
I then blit to this surface and return it. On the upper level now I blit
this temporary surface to the screen.
The result is simple: nothing appears.
If I set the amask to 0 I get a black box, but any other value (including
default 0x000000ff) seems does nothing.
Every SDL command I call returns success.

Some relevant code:

image = IMG_Load_RW( SDL_RWFromFile( imageFile, “rb” ), 1 );
?
temp = SDL_CreateRGBSurface(SDL_HWSURFACE,
40,80,32,rmask,gmask,bmask,amask); ?
src.w = 40;
src.h = 80;
src.x = 40i;
src.y = 80
j;
dst.x = 0;
dst.y = 0;
SDL_BlitSurface( image, &src, temp, &dst );
?
(passed up)
?
dst.x = 2;
dst.y = 2;
SDL_BlitSurface( temp, NULL, target, &dst );

Where ?target? is the screen.
Other blits going from File -> Surface -> Display work with alpha.
(As oppose to this File -> Surface -> Surface -> Display)

I?ve removed all my error checking and obviously quite a bit of other code,
but this is everything involving SDL calls.
The sprite is currently 40x80 pixels,and the png file holds 3x3 images.

Thanks.

David Olofson <david olofson.net> writes:

[…alpha & intermediate surface…]

  1. Load the image. (Let’s call it tmp.)
  2. Disable alpha blending;
  3. For each target surface (tmp2), create an RGBA
    surface:
    3b. Disable alpha blending for the target surface:
    3c. Blit the area(s) you want as usual:
    3d. Enable alpha blending for the target surface:
    3e. (For performance) convert the surface to a suitable
    format for blitting to the screen:
    //David Olofson - Programmer, Composer, Open Source Advocate

Thanks man, this worked great at first.
I’m running in windowed mode for working with issues (much easier to
navigate) but I expect to have the program work in full screen most of
the time. What you mentioned works perfectly for windowed mode, but if
I start the program up in full screen the blit to screen is a black box.

Any suggestions? Thanks!

Brian <bjc9019 rit.edu> writes:

I start the program up in full screen the blit to screen is a black box.

Sorry, the blit to the screen isn’t a black box. The alpha channel becomes
solid black instead of see-through. Does something additional need to be set on
the primary viewing surface?

That’s odd… No, there shouldn’t be any special requirements. The
display surface would normally be some sort of RGB surface no matter
what, so it should Just Work™.

However, note that doing alpha blending directly to the screen in
"normal" fullscreen mode (ie SDL_FULLSCREEN | SDL_DOUBLEBUF) is
usually very, very slow, since you end up doing a lot of reading from
VRAM. (Blending requires both reading and writing of the target
surface.)

You could have a look at Fixed Rate Pig:

http://olofson.net/examples.html

where I (among other things) demonstrate a way of avoiding that
problem while still making use of page flipped double buffering with
retrace sync where available. (That is, though Pig uses alpha for all
sprites, it’ll never do it into a VRAM display buffer, even on
DirectDraw and other targets that support h/w page flipping.)

Anyway, it would be interesting to see if what you’re seeing is a
problem with your code or with SDL. What you’re trying to do - though
it may run slowly on most systems - should work, especially
considering that your code works in windowed mode…

//David Olofson - Programmer, Composer, Open Source Advocate

.- Audiality -----------------------------------------------.
| Free/Open Source audio engine for games and multimedia. |
| MIDI, modular synthesis, real time effects, scripting,… |
`-----------------------------------> http://audiality.org -’
http://olofson.nethttp://www.reologica.se —On Tuesday 27 April 2004 05.13, Brian wrote:

Brian <bjc9019 rit.edu> writes:

I start the program up in full screen the blit to screen is a
black box.

Sorry, the blit to the screen isn’t a black box. The alpha channel
becomes solid black instead of see-through. Does something
additional need to be set on the primary viewing surface?

David Olofson <david olofson.net> writes:

That’s odd… No, there shouldn’t be any special requirements. The
display surface would normally be some sort of RGB surface no matter
what, so it should Just Work™.

However, note that doing alpha blending directly to the screen in
"normal" fullscreen mode (ie SDL_FULLSCREEN | SDL_DOUBLEBUF) is
usually very, very slow, since you end up doing a lot of reading from
VRAM. (Blending requires both reading and writing of the target
surface.)

You could have a look at Fixed Rate Pig:

http://olofson.net/examples.html

where I (among other things) demonstrate a way of avoiding that
problem while still making use of page flipped double buffering with
retrace sync where available. (That is, though Pig uses alpha for all
sprites, it’ll never do it into a VRAM display buffer, even on
DirectDraw and other targets that support h/w page flipping.)

Anyway, it would be interesting to see if what you’re seeing is a
problem with your code or with SDL. What you’re trying to do - though
it may run slowly on most systems - should work, especially
considering that your code works in windowed mode…

You’ve referenced your pig example a couple times and it is indeed a good
example to look at-- but for an example it really lacks commenting. I was able
to figure out what you were doing, but it did take me a while.
I tried duplicating your process of apparently blttitng everything onto a buffer
then blitting that buffer onto the screen. The thing is with what I’m currently
working on there can be no update rectangles. It’ll either be everything or
nothing (tile-based scrolling background). Taking that into account my
framerate actually fell by half. I’ll try again when I’m on a different kind of
scene where I’d have update rectangles.
As for the transparent blitting problem I have confirmed it. Exactly the same
code except the full screen flag yields different results. Now I do have a
crappy system to work with here (Geforce2Go), and I’ve tried alternating the
surfaces between HW and SW but it doesn’t seem to make a difference.

Thanks again for your help. I’m keeping your code for reference!

[…]

You’ve referenced your pig example a couple times and it is indeed
a good example to look at-- but for an example it really lacks
commenting.

Yeah. The idea was to write a tutorial or something around it, but I
hardly had enough spare time to hack the code… So, I was in a great
hurry - and no comments are better than incorrect and confusing
comments. :wink:

Note that there’s a separate text file that describes the dirtyrect
manager, in case you’ve been scratching your head over that code.

I was able to figure out what you were doing, but it
did take me a while. I tried duplicating your process of apparently
blttitng everything onto a buffer then blitting that buffer onto
the screen. The thing is with what I’m currently working on there
can be no update rectangles. It’ll either be everything or nothing
(tile-based scrolling background).

Then you’re lucky, at least in some respects. The algorithm Pig uses
is overkill, and in fact just a waste of cycles, if you have to
repaint the whole screen every frame anyway.

What you do is very simple:

forever
{
	Blit into a shadow buffer;
	Blit the shadow buffer to the display surface;
	Flip the display surface;
}

Now, if you want to avoid extra copying on targets that don’t support
h/w display surfaces, just eliminate this part too, and blit directly
to the display surface instead. If the display surface is not a h/w
surface, it’s already a s/w shadow surface, so there’s no point in
adding another one.

Taking that into account my
framerate actually fell by half.

Yeah, that’s the bad news… :-/

That’s why there is glSDL - although that doesn’t really solve the
problem, but allows users with accelerated OpenGL to avoid it.

I’ll try again when I’m on a
different kind of scene where I’d have update rectangles.
As for the transparent blitting problem I have confirmed it.
Exactly the same code except the full screen flag yields different
results. Now I do have a crappy system to work with here
(Geforce2Go), and I’ve tried alternating the surfaces between HW
and SW but it doesn’t seem to make a difference.

Remember that SDL_SWSURFACE == 0, and SDL_DOUBLEBUF pulls in
SDL_HWSURFACE automatically… That is, you have to remove
SDL_DOUBLEBUF to get a s/w surface. (Except when the system can’t
give you a h/w surface, obviously.)

Either way, it could be the pixel format… The shadow surface may get
the same pixel format as the actual display buffer, unless you
specifically ask for something else. Does the display bpp have any
effect on the alpha blending, with and/or without a h/w surface?

Thanks again for your help. I’m keeping your code for reference!

No problem.

BTW, could you be more specific about what parts of the code are hard
to understand? That would help improve the documentation for the next
release. :slight_smile:

//David Olofson - Programmer, Composer, Open Source Advocate

.- Audiality -----------------------------------------------.
| Free/Open Source audio engine for games and multimedia. |
| MIDI, modular synthesis, real time effects, scripting,… |
`-----------------------------------> http://audiality.org -’
http://olofson.nethttp://www.reologica.se —On Wednesday 28 April 2004 14.09, Brian wrote: