menu
  home
  contact
  guestbook

downloads
  demos/intros
  wolfenstein 3d
  miscellaneous
  bundeswehr

docs
  unrolling loops
  c2p part I (st)
  c2p part II (st)
  avoiding c2p (st)
  interlacing (st)
  fat mapping
  3d pipeline
  portal rendering
  8bpp color mixing
  fixedpoint math
  blitter (mst/ste)
  sample replay (st)
  blitter gouraud (falc)
  blitter fading (falc)
  arbitrary mapping
  frustrum clipping etc.

sourcecode
  mc68000 math lib
  32 bytes sin-gen
  24 bit tga-viewer
  blitter example
  lz77 packer
  lz78 packer
  protracker replayer
 
realtime truecolor fading using the blitter

in contrast to working in indexed colormodes fading truecolor screens is a mere challange for a standard falcon with its 16bit wide data bus. this clearly corresponds to the fact that you can't control the colors' brightness by changing a small color lookup table (sic) per vbl interrupt but you rather must process the complete screen per pixel, which is why this task isn't basically something to be performed in realtime or even ontop of another effect.
however, two realtime methods exist, one of which i've been told that it does not work on vga screens and also only working due to a bug in ataris videl chip, so it doesn't suit my needs (you can read about it nontheless here ).
the second uses a large table which has shaded scales for each of the possible 65536 colors, but since you can't fade to abitrary colors using a single table and because each table eats 128kbytes i don't like this method, either - even worse, it can't be keyframed so it just depends on your falcon's speed how fast it will fade all the way.

desperately trying to finish our beams demo i came up with the idea of abusing the blitter once again. this time for the fading task since it outperforms the cpu when it comes to bit and shifting operations and i have finally come up with a solution. here it goes, it is quite straightforward imo:
people tend to forget that the blitter actually does have an indexed addressing mode which is a bit limited though, since only the small range of 16 halfetone registers can be addressed. this can be achieved by setting the _LineNum register's smudge flag (bit 5, $ffff8a3c.w). operating in 'smuge mode' a source words' four LSBs will be interpreted to access a corresponding halftone word only in case you forgot.

it's plain to see that

 f(n) = shade/(n*a)

can directly be expressed as series of:

 f(n) = f(n-1)-a , f(0) = shade

i assume you're already slowly guessing how this taps into my method. a screen can be faded by iteratively substracting/adding a (constant) number to each pixel (of course you mustn't forget to catch overflows seperately for each channel).
using the blitter you can perform a single iteration in 3 passes (one per red, green and blue), shifting the source data by accordingly setting up the skew-register. and don't forget to adapt the endmasks either - and there comes one drawback, you can't have more than 4 bits accuracy per channel due to the halftone ram's limitations.
you might wonder how this should be keyframed also as the core isn't any diffrent from the table method mentioned above (i.e. an iterative process)...well this is simple. see, the halftone ram is quite small (just as the CLUT in an indexed color mode), so you can change the halftone registers in between based on a synced keyframing counter, so now this is decoupled from machine speed.
notice that you can have very flexible and non linear fadings and you can select single color channels because those are seperated and so forth.
using large screen resolutions generally isn't recommended though, because the blitter speed is limited as well (16bit bus, source and destination must be located in st-ram...) but you can skip pixels and or rows per iteration and with the blitter you get this for free as opposed to the cpu.
'nuff said, here comes my source:


BlitterFade move.l  #$20000,d0        ; Initialize blitter
            move.l  d0,$ffff8a20.w    ; Source X|Y-Increment
            move.l  d0,$ffff8a2e.w    ; Dest X|Y-Increment

            move.w  #$103,$ffff8a3a.w ; HOP (halftone only), LOP (source only)


            move.w  .scale(pc),d0
            move.w  .keyframe(pc),d1  ; Keyframing delta (increment during timer interrupt)
            clr.w   .keyframe

            sub.w   d1,d0             ; Fade out
            bmi.s   .break            ; Reached minimum brightness?

            move.w  d0,.scale
            lsr.w   #2,d0             ; Scale down the timer

            movem.l .halftone(pc,d0.w*2),d0-d7 ; Load halftone ram
            movem.l d0-d7,$ffff8a00.w

            lea.l   .rgb(pc),a0

            moveq.l #3-1,d3           ; 3 passes

.passes     move.l  source(pc),$ffff8a24.w ; *Source
            move.l  dest(pc),$ffff8a32.w   ; *Dest

            movem.w (a0)+,d0-d2       ; Endmasks
            movem.w d0-d2,$ffff8a28.w

            move.l  #(x_res+1)<<16|y_res,$ffff8a36.w ; XCount|YCount

            move.w  (a0)+,$ffff8a3c.w ; Start blitter
            dbra    d3,.passes        ; Fade r, g, b seperately

.break      rts


.halftone   dcb.w 16,$0000            ; Linear Fading table
scale       set  0
       rept 16
            dc.w scale
scale       set  scale+%0001000010000010
       endr
            dcb.w 16,$ffff            ; Overflow range (all white)


.rgb        dc.w $f800,$f800,$f800    ; Endmasks (r,g,b)
            dc.w %1110000000001100    ; Smudge=true, FXSR=false, NFSR=false, skew
            dc.w $07e0,$07e0,$07e0
            dc.w %1110000000000111
            dc.w $001f,$001f,$001f
            dc.w %1110000000000001


.scale      dc.w 16<<2 ; Current brightness



- 2005 ray//.tscc. -