Fade In / Fade Out Effect

Topics related to the API, programming discussions & questions, coding tips, bugs, etc. should go here.
Post Reply
User avatar
pragma
Posts: 175
Joined: Sat Sep 20, 2008 2:16 am
Location: Washington, DC

Fade In / Fade Out Effect

Post by pragma »

Here's something I cooked up, thanks to Uze trying to help out another coder in another thread*.

If you manipulate the Port C Data Direction Register, you can set the pins to become input rather than output pins. This allows you to effectively mask whatever color information the blitter is writing to the video port.

I've tested this technique on my Fuzebox with great results, so your mileage may vary. Note that this does not work in the v1.08 emulator.

Code: Select all

// values to write to Port C for fade effects.
// 0 = no write (set pin to input)
// 1 = can write
unsigned char fader[9]={
           // BB GGG RRR
    0x00,  // 00 000 000
    0x80,  // 10 000 000
    0x84,  // 10 000 100
    0xA4,  // 10 100 100
    0xB4,  // 10 110 100
    0xB6,  // 10 110 110
    0xBE,  // 10 111 110
    0xBF,  // 10 111 111
    0xFF,  // 11 111 111
};

int main(){
    //TODO: RENDER YOUR SCREEN HERE IN ANY VIDEO MODE

    // demonstration loop
    int i;
    int delay;
    while(1){
        WaitVsync(1); 
        
        // fade out
        for(i=8; i>=0; i--){
            WaitVsync(1);
            DDRC = fader[i];
            for(delay=0; delay<5; delay++){
                WaitVsync(1); 
            }
        }
        // fade in
        for(i=0; i<9; i++){
            WaitVsync(1); 
            DDRC = fader[i];
           // do nothing for five frames
            for(delay=0; delay<5; delay++){ 
                WaitVsync(1); 
            }
        }
    }
    return 0;
}
This example will fade your screen in and out, advancing the effect every five frames. Notice how the real work is done by a single byte write to DDRC per frame. Enjoy.

Sadly, I don't know of a way to do the opposite, and force the pins to be output high (1), no matter what is written to the port. That would allow for a whiteout at virtually the same cost.

(* viewtopic.php?f=3&t=164&st=0&sk=t&sd=a&start=30)
havok1919
Posts: 474
Joined: Thu Aug 28, 2008 9:44 pm
Location: Vancouver, WA
Contact:

Re: Fade In / Fade Out Effect

Post by havok1919 »

pragma wrote:Here's something I cooked up, thanks to Uze trying to help out another coder in another thread*.
Hey, cool! Great idea!

-Clay
DavidEtherton
Posts: 252
Joined: Tue Dec 02, 2008 12:38 am
Location: Carlsbad, California (USA)

Re: Fade In / Fade Out Effect

Post by DavidEtherton »

This would be a one line change in the emulator. In the spot where we access PORTC, just & it with DDRC.

-Dave
User avatar
uze6666
Site Admin
Posts: 4801
Joined: Tue Aug 12, 2008 9:13 pm
Location: Montreal, Canada
Contact:

Re: Fade In / Fade Out Effect

Post by uze6666 »

Wow...great idea! I was looking on how to do a fadeout function for a while. I will certainly add this to the kernel.

Thanks!

Uze
tim1724
Posts: 30
Joined: Mon Dec 08, 2008 8:38 pm

Re: Fade In / Fade Out Effect

Post by tim1724 »

The emulator fix is very easy. (I've tried it and it works great.)

Just change this:

Code: Select all

        else if (addr == ports::PORTC)
        {
                pixel = palette[value];
        }
to this:

Code: Select all

        else if (addr == ports::PORTC)
        {
                pixel = palette[value&DDRC];
        }

But I think this is a better fade:

Code: Select all

unsigned char fader[8]={
           // BB GGG RRR
    0x00,  // 00 000 000
    0x09,  // 00 001 001
    0x52,  // 01 010 010
    0x5B,  // 01 011 011
    0xA4,  // 10 100 100
    0xAD,  // 10 101 101
    0xF6,  // 11 110 110
    0xFF,  // 11 111 111
};
It ramps up each color channel linearly. (Note that there are only 8 values in this array, so the constants in the for loops need to be adjusted as well.)

The previously posted array didn't increment each color channel at the same time, and it wasn't linear. (There's nothing wrong with that, of course, and you can get some really cool color effects by using different values.. for example, you could fade out the blue & green channels to turn everything red when a character takes damage or something.)
Last edited by tim1724 on Fri Jan 30, 2009 9:13 pm, edited 1 time in total.
tim1724
Posts: 30
Joined: Mon Dec 08, 2008 8:38 pm

Re: Fade In / Fade Out Effect

Post by tim1724 »

And in case anyone out there is lazy and doesn't want to write up a test program himself, here's "tutorial.c" with the fade (my version) added.

Code: Select all

#include <stdbool.h>
#include <avr/io.h>
#include <stdlib.h>
#include <avr/pgmspace.h>
#include "kernel/uzebox.h"

#include "data/fonts.pic.inc"

const char strHello[] PROGMEM ="HELLO WORLD FROM THE UZEBOX!";

// values to write to Port C for fade effects.
// 0 = no write (set pin to input)
// 1 = can write
#define FADER_STEPS 8
unsigned char fader[FADER_STEPS]={
           // BB GGG RRR
    0x00,  // 00 000 000
    0x09,  // 00 001 001
    0x52,  // 01 010 010
    0x5B,  // 01 011 011
    0xA4,  // 10 100 100
    0xAD,  // 10 101 101
    0xF6,  // 11 110 110
    0xFF,  // 11 111 111
};

int main(){

   SetFontTable(fonts);
   ClearVram();
   Print(8,12,strHello);

    int i;
    int delay;
    while(1){
        WaitVsync(1); 
        
        // fade out
        for(i=FADER_STEPS-1; i>=0; i--){
            WaitVsync(1);
            DDRC = fader[i];
            for(delay=0; delay<5; delay++){
                WaitVsync(1); 
            }
        }
        // fade in
        for(i=0; i<FADER_STEPS; i++){
            WaitVsync(1); 
            DDRC = fader[i];
           // do nothing for five frames
            for(delay=0; delay<5; delay++){ 
                WaitVsync(1); 
            }
        }
    }
    return 0;
}
Attachments
fade.hex
hello world with fade effect
(43.5 KiB) Downloaded 351 times
User avatar
pragma
Posts: 175
Joined: Sat Sep 20, 2008 2:16 am
Location: Washington, DC

Re: Fade In / Fade Out Effect

Post by pragma »

tim1724 wrote:The previously posted array didn't increment each color channel at the same time, and it wasn't linear. (There's nothing wrong with that, of course, and you can get some really cool color effects by using different values..
Hey, that's what the forum is for, right? I'll have to try your fader set out since I've noticed that the behavior of my original take isn't quite right.

Thanks for posting the demo program too.
tim1724
Posts: 30
Joined: Mon Dec 08, 2008 8:38 pm

Re: Fade In / Fade Out Effect

Post by tim1724 »

ugh, my fade only works on whites (or colors close to white)

definitely not right for a color image. (testing on the megatris gets really ugly :-)

pragma's was closer to the right idea... mine is pretty dumb (except for monochrome, where it works great. :-)
tim1724
Posts: 30
Joined: Mon Dec 08, 2008 8:38 pm

Re: Fade In / Fade Out Effect

Post by tim1724 »

I've done quite a bit of experimenting, and it looks like it's hard to come up with a single fader table which works well in a variety of cases. I think it's best to customize it based on the circumstances.

There are a few competing factors to consider, and it's impossible in general to balance them all completely:
  • smoothness of gradation between steps (brightness should change at uniform rate)
  • color balance (whether the 3 color channels fade evenly)
  • noise (does any ugly visual noise appear at any step in the fade)
the last one is the hardest to deal with. When you're at the dark end of the fade, you want to be using only the least significant bits of each color channel. For example, one might be tempted to use 0x49 (which is 01 001 001, in blue green red order) but this tends to end up causing a fair amount of visual noise, due to the least significant bit in each color channel being essentially random for many types of images. (This ends up causing my original table to produce absolute garbage when used with the Megatris title screen, my second test. My original choice of tutorial.c had been a horrible testbed, due to it being black and white.)

pragma's fade values avoid noise by dropping the low-order bits first, and using only the most significant bits at the lowest brightness levels. The problem there is that it has a pretty sharp drop-off between the lowest brightness and full black. It's definitely weighted towards the bright end. (But maybe that's not so bad on a real TV .. I've only been testing stuff in the emulator. On a real TV it might be that pragma's values end up working best. I'm going to have to do some real TV tests this weekend.)

I think a certain amount of trial and error is needed to get something that looks good, and it's going to be different in different games. Here's one which I think works well on the Megatris title screen:

Code: Select all

#define FADER_STEPS 12
unsigned char fader[FADER_STEPS]={
           // BB GGG RRR
    0x00,  // 00 000 000
    0x40,  // 01 000 000
    0x88,  // 10 001 000
    0x91,  // 10 010 001
    0xD2,  // 11 010 010
    0xE4,  // 11 100 100
    0xAD,  // 10 101 101
    0xB5,  // 10 110 101
    0xB6,  // 10 110 110
    0xBE,  // 10 111 110
    0xBF,  // 10 111 111
    0xFF,  // 11 111 111
};
This one tries to balance the three factors I listed above, but it gives up a bit of color balance in order to avoid noise, while allowing for a fairly smooth change in brightness (with no big drop off at the low end). You'll see that it is weighted heavily towards blue in the darker end, and switches to more yellow at the brighter end. Also, the brightness of the blue channel ends up jumping around in an odd way to try to balance out the overall brightness while trying to avoid noise in the red and green channels. Noise in the blue channel is harder to see, so I think it's more important to avoid noise in the red and green channels and use blue to control the overall brightness, without worrying too much about artifacts in the blue.

If you're displaying mostly white or just pure blue (0xC0 == 11 000 000), green (0x38 == 00 111 000), and red (0x07 == 00 000 111), then my initial fade table works well. But if you're using any other colors, it looks really bad. Something like the 12 step table above works better for complex images. (And you should test pragma's values too, as they are very good for avoiding noise.) But I think the exact sequence of values to use will vary greatly between different games. There's no one-size-fits-all solution, as far as I can tell.

And of course you'll need to use custom values for special effects. Want to flash the screen red when the player is low on health, or a nuclear reactor is going to blow, or it's red alert on the Enterprise? Pretty easy. :-)

hmm.. it would be fun to set DDRC on a per-scanline basis. That's something to think about...

I've spent too much time on this today.. I'm moving on to something else. (like playing with my fuzebox on the new 46" LCD that I got this week.)
Post Reply