Fade question

I am new to game programming and graphics programming. I have a question regarding fading in and out of a screen. I have looked throught the archives and done a site search to find some info on gamma fading. However, I cannot get it to work for me. I am in 8bit mode and am wanting to fade out to black. Using SDL_SetGamma does not seem to work. Any clues?
Thanks, Jason

In 8 bit mode the easiest way to do it is to write the color palette in
a loop. Each time you write the palette modify the color values so they
are closer and closer to black. Use a timer to control the time used for
the fade. This will do a true fade to black. You do have to be careful
with the arithmetic on the palette items to avoid negative values and to
make sure that all the colors reach black at the same time, else you get
a weird ghosting effect as the bright colors fade out after the dark
colors. Of course, you might like that effect.

The result is the screen is black and all the palette entries are
0x000000. This lets you paint what ever you want on the screen and then
when you load a palette with your colors they appear on the screen
instantly. We used this technique a lot in the old DOS/VGA days.

Another way to do it is to write black over the buffer starting at the
first pixel and picking the next pixel using something like:
(pixel + 7) mod buffer_size
(But, obviously not exactly like that.) So that after you have reached
the end of the buffer 7 times the whole buffer is black. The effect is
rather nice if done quickly enough. You want to pick a number that is
relatively prime to the width of the buffer so that you don’t get
vertical stripes, but rather a psuedo random pattern of pixels that is
guarantedd to cover the entire buffer.

	Bob Pendleton

Jason Brunson wrote:> I am new to game programming and graphics programming. I have a

question regarding fading in and out of a screen. I have looked
throught the archives and done a site search to find some info on gamma
fading. However, I cannot get it to work for me. I am in 8bit mode and
am wanting to fade out to black. Using SDL_SetGamma does not seem to
work. Any clues?
Thanks, Jason


±-----------------------------------------+

  • Bob Pendleton, an experienced C/C++/Java +
  • UNIX/Linux programmer, researcher, and +
  • system architect, is seeking full time, +
  • consulting, or contract employment. +
  • Resume: http://www.jump.net/~bobp +
  • Email: @Bob_Pendleton +
    ±-----------------------------------------+

| In 8 bit mode the easiest way to do it is to write the color palette in
| a loop. Each time you write the palette modify the color values so they

How would you do that in 16bit mode?

Would you need to:

  • lock the surface
  • For each pixel
    ** Alter the RGB for it
  • unlock the surface
  • blitOn Tue, Jun 25, 2002 at 09:40:59AM -0500, Bob Pendleton wrote:


I will not call my teacher ‘Hot Cakes’

PGP Fingerprint [6AD6 865A BF6E 76BB 1FC2 E4C4 DEEA 7D08 D511 E149]
PGP Public key [www.piku.org.uk/public-key.asc] - Home [www.piku.org.uk]

If you’re in a true 8 bit (palettized) mode, just fade the palette instead, like we did in the old days. :slight_smile:

//David

.---------------------------------------
| David Olofson
| Programmer

david.olofson at reologica.se
Address:
REOLOGICA Instruments AB
Scheelev?gen 30
223 63 LUND
Sweden
---------------------------------------
Phone: 046-12 77 60
Fax: 046-12 50 57
Mobil:
E-mail: david.olofson at reologica.se
WWW: http://www.reologica.se

`-----> We Make Rheology RealOn Mon, 24/06/2002 21:51:25 , Jason Brunson wrote:

I am new to game programming and graphics programming. I have a question regarding fading in and out of a screen. I have looked throught the archives and done a site search to find some info on gamma fading. However, I cannot get it to work for me. I am in 8bit mode and am wanting to fade out to black. Using SDL_SetGamma does not seem to work. Any clues?

James wrote:

| In 8 bit mode the easiest way to do it is to write the color palette in
| a loop. Each time you write the palette modify the color values so they

How would you do that in 16bit mode?

Would you need to:

  • lock the surface
  • For each pixel
    ** Alter the RGB for it
  • unlock the surface
  • blit

That is what you would have to do when you don’t have access to the
gamma table. In component color modes (RGB modes) you can use the same
trick I described for 8 bit palette mode by changing the gamma table
instead of the color palette.

An 8 bit mode is called a palettized mode because each 8 bit value picks
1 of 256 colors to be displayed on the screen. In the 15 bit and higher
modes we don’t have a palette because the palette gets rather large,
starting a 32768 entries for a 15 bit mode and going up to 16,777,216
entries for 24 bit mode. (The largest palette I ever saw was 4096
entries for a 12 bit mode on some old SGI workstations.) Instead, each
part of the color, the red bits, the green bits, the blue bits, are used
to pick a new red, green, or blue value out of a gamma table. The gamma
table has a column for each color component, and it is normally used to
mask the nonliniear response of the display. But, you can use it to map,
for example, all blue values of 0xff or to 0x00, by writing 0xff or 0x00
to each entry in the blue gamma ramp (the columns of the game table are
usually called “gamma ramps.”)

If you can’t get to either the palette or the gamma table you have to
mess with the pixels themselves. The fastest methods involve just over
writing pixels. Reading, modifying, and rewriting pixels is usually
pretty slow. In OpenGL and other accelerated 3D APIs you can get some
interesting fades using fog.

	Bob Pendleton> On Tue, Jun 25, 2002 at 09:40:59AM -0500, Bob Pendleton wrote:


±-----------------------------------------+

  • Bob Pendleton, an experienced C/C++/Java +
  • UNIX/Linux programmer, researcher, and +
  • system architect, is seeking full time, +
  • consulting, or contract employment. +
  • Resume: http://www.jump.net/~bobp +
  • Email: @Bob_Pendleton +
    ±-----------------------------------------+

[…]

Another way to do it is to write black over the buffer starting at the
first pixel and picking the next pixel using something like:
(pixel + 7) mod buffer_size
(But, obviously not exactly like that.) So that after you have reached
the end of the buffer 7 times the whole buffer is black. The effect is
rather nice if done quickly enough. You want to pick a number that is
relatively prime to the width of the buffer so that you don’t get
vertical stripes, but rather a psuedo random pattern of pixels that is
guarantedd to cover the entire buffer.

Just an idea; working with lines covering the whole width of the screen is very simple and fast in SDL. Just use SDL_FillRect() with a rectangly height of 1 to quickly “set” the color of whatever line you like to whatever color you like.

If you’ve seen the background “1D plasma” effect in the audio benchmarking screen of Kobo Deluxe (hit F9 in a debug build), that’s how it’s done.

Filling every N’th line with block pixels that way would be very fast, and I guess it could look pretty neat.

Oh, and then there’s the “nibble” effects used in Kobo Deluxe. :slight_smile: (In much more prominent positions; you’ll actually see them in a release build.)

Note however, that these “iterative transformation” effects don’t mix well with double buffering. You can use them with double buffering by always applying every change twice - but that may break if you happen to be on a target that implements double buffering through back->front blitting instead of h/w pageflipping.

The Kobo Deluxe nibble effect has this problem with OpenGL, as there doesn’t seem to be a way of telling which kind of double buffering the driver is using. The only reliable ways I can see of doing it is avoiding all brushes with alpha channels (those are the ones that cause trouble if applied twice), or doing the whole effect in a procedural texture. (Needless to say, I haven’t spent much time trying to solve this, as it’s hardly critical, and doesn’t even look too bad when it “fails”.)

//David

.---------------------------------------
| David Olofson
| Programmer

david.olofson at reologica.se
Address:
REOLOGICA Instruments AB
Scheelev?gen 30
223 63 LUND
Sweden
---------------------------------------
Phone: 046-12 77 60
Fax: 046-12 50 57
Mobil:
E-mail: david.olofson at reologica.se
WWW: http://www.reologica.se

`-----> We Make Rheology RealOn Tue, 25/06/2002 09:40:59 , Bob Pendleton wrote:

| In 8 bit mode the easiest way to do it is to write the color palette in
| a loop. Each time you write the palette modify the color values so they

How would you do that in 16bit mode?

You either don’t, or you prepare to do some serious optimizing of s/w “filtering” code.

Would you need to:

  • lock the surface
  • For each pixel
    ** Alter the RGB for it
  • unlock the surface
  • blit

No. Unless you’re using single buffering + shadow surface (ie SDL “fake” double buffering, which you can either enforce, or get whether you like it or not on targets without h/w screen surface support), this will be slower than you could possibly imagine.

Do it on your own s/w surface (which should be of the display format, of course), and then blit the result to the screen, and pray that there is h/w accelleration for such blits.

As to the code, there are some shortcuts that can yield rather nice results at a reasonable cost.

For example, try saturating subtraction instead of multiplication. (Used to be popular in the Amiga and Atari ST days, and most people couldn’t tell the difference anyway. :slight_smile: Obviously, saturation will require conditionals unless you use some SIMD extension (or an integer/fixed point DSP), but there are shortcuts for that as well.

You might get away with shifting the 5:6:5 bit fields around, so you have at least one bit of headroom above each field. Then you combine and test one of the bits above each field, and check for 1’s. Whenever you get a 1 anywhere, you’ll know you had a wrap, and needs to do the saturation tests. Preventing all zero pixel pairs (process two pixels at a time…) from being processed at all is probably a good idea. (You could do that without conditionals in the main path by constructing a “skip table”, but that’s probably a bad idea unless all data fits in the cache.)

//David

.---------------------------------------
| David Olofson
| Programmer

david.olofson at reologica.se
Address:
REOLOGICA Instruments AB
Scheelev?gen 30
223 63 LUND
Sweden
---------------------------------------
Phone: 046-12 77 60
Fax: 046-12 50 57
Mobil:
E-mail: david.olofson at reologica.se
WWW: http://www.reologica.se

`-----> We Make Rheology RealOn Tue, 25/06/2002 16:25:56 , James wrote:

On Tue, Jun 25, 2002 at 09:40:59AM -0500, Bob Pendleton wrote:

David Olofson wrote:

Oh, and then there’s the “nibble” effects used in Kobo Deluxe. :slight_smile: (In much more prominent positions; you’ll actually see them in a release build.)

Note however, that these “iterative transformation” effects don’t mix well with double buffering. You can use them with double buffering by always applying every change twice - but that may break if you happen to be on a target that implements double buffering through back->front blitting instead of h/w pageflipping.

The Kobo Deluxe nibble effect has this problem with OpenGL, as there doesn’t seem to be a way of telling which kind of double buffering the driver is using. The only reliable ways I can see of doing it is avoiding all brushes with alpha channels (those are the ones that cause trouble if applied twice), or doing the whole effect in a procedural texture. (Needless to say, I haven’t spent much time trying to solve this, as it’s hardly critical, and doesn’t even look too bad when it “fails”.)

//David

Yeah, one of the fun things in game/graphic programming is that some of
your worst mistakes can look really good. One time I fired up a game I
was working and just as I realized that I had totally messed up the
projection matrix I heard the creative director, who just happened to be
walking by my door, yell “WOW! what a khol effect! Can I use that in the
game?”

Back on topic, you can fade a double buffered system just fine if you
follow the rules of double buffering, you have to redraw the back buffer
for each frame, and then fade it the appropriate number of steps, and
then swap it. Otherwise, the difference in semantics between a blitted
and a swapped implementation will kill you no matter what you are doing.
The nice thing about double buffered systems is that you can keep
animating as you fade out.

	Bob Pendleton

P.S.

The word “khol” is normally spelled as “cool” but for a creative
director to pronounce it as “cool” would have been distinctly un-cool.
Took me 6 months to learn how to pronounce it correctly and now my kids
laugh at me every time I say it…> On Tue, 25/06/2002 09:40:59 , Bob Pendleton wrote:

.---------------------------------------
| David Olofson
| Programmer

david.olofson at reologica.se
Address:
REOLOGICA Instruments AB
Scheelev?gen 30
223 63 LUND
Sweden
---------------------------------------
Phone: 046-12 77 60
Fax: 046-12 50 57
Mobil:
E-mail: david.olofson at reologica.se
WWW: http://www.reologica.se

`-----> We Make Rheology Real


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl


±-----------------------------------------+

  • Bob Pendleton, an experienced C/C++/Java +
  • UNIX/Linux programmer, researcher, and +
  • system architect, is seeking full time, +
  • consulting, or contract employment. +
  • Resume: http://www.jump.net/~bobp +
  • Email: @Bob_Pendleton +
    ±-----------------------------------------+

[…]

Back on topic, you can fade a double buffered system just fine if you
follow the rules of double buffering, you have to redraw the back buffer
for each frame, and then fade it the appropriate number of steps, and
then swap it. Otherwise, the difference in semantics between a blitted
and a swapped implementation will kill you no matter what you are doing.

Yeah… Problem is that the very reason that I’m using this
"iterative" effect is speed. Anything looks better than “fading” at 5 fps, IMHO.

The nice thing about double buffered systems is that you can keep
animating as you fade out.

Yeah - but then you need the power to both animate and fade fullscreen at the same time.

That is, you need accelerated OpenGL. :slight_smile:

(All right, there is 320x240…)

//David

.---------------------------------------
| David Olofson
| Programmer

david.olofson at reologica.se
Address:
REOLOGICA Instruments AB
Scheelev?gen 30
223 63 LUND
Sweden
---------------------------------------
Phone: 046-12 77 60
Fax: 046-12 50 57
Mobil:
E-mail: david.olofson at reologica.se
WWW: http://www.reologica.se

`-----> We Make Rheology RealOn Tue, 25/06/2002 13:42:44 , Bob Pendleton wrote:

SDL_SetGamma is not always supported, as far as I know.

The usual approach is to slowly interpolate the palette to black. This
is obviously only possible in paletted modes (8 bit should be
fine). Pretty simple, but you might get interesting results if SDL is
emulating an 8 bit mode on a 16 or 32 bit display (don’t know, haven’t
tried).

-JohnOn Mon, Jun 24, 2002 at 09:51:25PM -0500, Jason Brunson wrote:

I am new to game programming and graphics programming. I have a question regarding fading in and out of a screen. I have looked throught the archives and done a site search to find some info on gamma fading. However, I cannot get it to work for me. I am in 8bit mode and am wanting to fade out to black. Using SDL_SetGamma does not seem to work. Any clues?
Thanks, Jason


John R. Hall - KG4RUO - Stranded in the Sol System
Student, Georgia Tech; Author, Programming Linux Games

— Jason Brunson wrote:

I am new to game programming and graphics
programming. I have a question regarding fading in
and out of a screen. I have looked throught the
archives and done a site search to find some info on
gamma fading. However, I cannot get it to work for
me. I am in 8bit mode and am wanting to fade out to
black. Using SDL_SetGamma does not seem to work.
Any clues?

Hmm… Let’s see if I can dust off my SDL skills from
the mothballs:

Perhaps something like:

Note… I have tested it (at least in 16 bit mode)…
and it seems to work… (I
t does have a memory leak if you exit without doing an
un-faded draw…

Hope that helps,

Enjoy,

-Loren

/* Global pointer /
/
Initialize this to the screen surface /
SDL_Surface
pGlobalDestSurface;
/* Initialize this to the screen surface’s palette /
SDL_Palette
pGlobalPalette;
float GlobalFadeRate = 0.0f;

/* Put this right before SDL_Flip /
static SDL_Surface
pScreenSurface=pGlobalDestSurface;
static SDL_Surface* pFadeSurface=NULL;
static SDL_Palette* pUnFadedPalette=NULL;
static SDL_Palette* pFadedPalette=NULL;
static SDL_Rect TempRect;
static Uint8 CurrentFadeAmount = 255;
static Uint32 LastFadeTime = 0;

if (GlobalFadeRate != 0.0f)
{
Uint32 CurrentTime = SDL_GetTicks();
int FadeDelta=(GlobalFadeRate*
(CurrentTime-LastFadeTime)255.0f)
/1000.0f;
LastFadeTime = CurrentTime;
if( FadeDelta > 255 - CurrentFadeAmount)
{
CurrentFadeAmount = 255;
GlobalFadeRate = 0.0f;
}
else if ( (0-FadeDelta) > CurrentFadeAmount)
{
CurrentFadeAmount = 0;
GlobalFadeRate = 0.0f;
}
else
{
CurrentFadeAmount += FadeDelta;
}
}
else
{
LastFadeTime = SDL_GetTicks();
if (
(CurrentFadeAmount == 0) &&
(LastFadeTime + 2000 < SDL_GetTicks())
)
{
assert(!“Someone should probably turn the fade
back up”);
}
}
}
if(pScreenSurface->format->palette)
{
if(pUnFadedPalette && (CurrentFadeAmount == 255))
{
SDL_SetPalette(
pScreenSurface,
0,
pUnFadedPalette->colors,
0,
pUnFadedPalette->ncolors);
pGlobalPalette = pScreenSurface->format->palette;
free((void )(pUnFadedPalette->colors));
pUnFadedPalette->colors = NULL;
free((void )(pUnFadedPalette));
pUnFadedPalette = NULL;
free((void )(pFadedPalette->colors));
pFadedPalette->colors = NULL;
free((void )(pFadedPalette));
pFadedPalette = NULL;
}
else if(!pUnFadedPalette && (CurrentFadeAmount<255))
{
assert(pScreenSurface->format->palette);
pUnFadedPalette =
(SDL_Palette
)malloc(sizeof(SDL_Palette));
memcpy(
(void
)pUnFadedPalette,
(void
)pScreenSurface->format->palette,
sizeof(SDL_Palette));
pUnFadedPalette->colors = NULL;
pUnFadedPalette->colors =
(SDL_Color
)calloc(
pUnFadedPalette->ncolors,
sizeof(SDL_Color));
memcpy(
(void
)pUnFadedPalette->colors,
(void*)pScreenSurface->format->palette->colors,
(pUnFadedPalette->ncolors)sizeof(SDL_Color));
pGlobalPalette = pUnFadedPalette;
pFadedPalette =
(SDL_Palette
)malloc(sizeof(SDL_Palette));
memcpy(
(void*)pFadedPalette,
(void*)pScreenSurface->format->palette,
sizeof(SDL_Palette));
pFadedPalette->colors = NULL;
pFadedPalette->colors =
(SDL_Color*)calloc(
pFadedPalette->ncolors,
sizeof(SDL_Color));
memcpy(
(void*)pFadedPalette->colors,
0x00,
(pUnFadedPalette->ncolors)sizeof(SDL_Color));
}
if(pUnFadedPalette)
{
uint index = 0;
for(
index=0;
index < pUnFadedPalette->ncolors;
index++
)
{
pFadedPalette->colors[index].r =
(((int)pUnFadedPalette->colors[index].r)
* CurrentFadeAmount)/255;
pFadedPalette->colors[index].g =
(((int)pUnFadedPalette->colors[index].g)
* CurrentFadeAmount)/255;
pFadedPalette->colors[index].b =
(((int)pUnFadedPalette->colors[index].b)
* CurrentFadeAmount)/255;
}
SDL_SetPalette(
pScreenSurface,
0,
pFadedPalette->colors,
0,
pFadedPalette->ncolors);
}
}
else
{
if(pFadeSurface && (CurrentFadeAmount == 255))
{
SDL_GetClipRect(pFadeSurface, &TempRect);
SDL_SetAlpha(pFadeSurface, 0, 255);
SDL_BlitSurface(pFadeSurface, NULL,
pScreenSurface, NULL);
SDL_SetClipRect(pScreenSurface, &TempRect);
pGlobalDestSurface = pScreenSurface;
SDL_FreeSurface(pFadeSurface);
pFadeSurface=NULL;
}
else if(!pFadeSurface && (CurrentFadeAmount < 255))
{
SDL_GetClipRect(pScreenSurface, &TempRect);
SDL_SetClipRect(pScreenSurface, NULL);
pFadeSurface = SDL_CreateRGBSurface(
SDL_SRCALPHA,
pScreenSurface->w,
pScreenSurface->h,
pScreenSurface->format->BitsPerPixel,
pScreenSurface->format->Rmask,
pScreenSurface->format->Gmask,
pScreenSurface->format->Bmask,
0x00000000 /
Amask */ );
SDL_BlitSurface( pScreenSurface, NULL,
pFadeSurface, NULL);
SDL_SetClipRect(pFadeSurface, &TempRect);
pGlobalDestSurface = pFadeSurface;
}
if(pFadeSurface)
{
SDL_FillRect(pScreenSurface, NULL, 0x00000000);
if(CurrentFadeAmount > 0)
{
SDL_SetAlpha(pFadeSurface, SDL_SRCALPHA,
CurrentFadeAmount);
SDL_BlitSurface(pFadeSurface, NULL,
pScreenSurface, NULL);
SDL_SetAlpha(pFadeSurface, 0, 255);
}
}
SDL_UpdateRect(pScreenSurface, 0, 0, 0, 0);
}__________________________________________________
Do You Yahoo!?
Yahoo! - Official partner of 2002 FIFA World Cup