User Tools

Site Tools


palette_20animation

Palette animation

by Alex Farlie and Richard Russell, July 2012

On 'hardware paletted' displays (i.e. those with 256 colours - 8 bits-per-pixel - or fewer) palette animation is possible. For example by changing the contents of the colour palette everything displayed in blue might be changed to be red, without actually needing to re-plot any graphics. Also, effects such as flashing colours can be achieved by dynamically changing the contents of the palette (this is how the BBC Micro achieves its flashing colours).

However all modern PC displays have a colour depth of greater than 8 bits-per-pixel, and therefore do not have a hardware colour palette. Superficially, therefore, they do not support palette animation, other than by using the compatibility mode provided by Windows (right-click on a shortcut, select Properties… Compatibility… Display settings… Run in 256 colors). This method has a number of disadvantages, not least that the entire display - not just a single window - must be switched to 256 colours.

Fortunately it is possible to provide a limited emulation of a hardware palette with the assistance of the Windows API. This article describes the steps which are necessary to achieve this.

Firstly the 'memory bitmap' used to hold the output from BBC BASIC for Windows must be changed from the usual 24 or 32 bits-per-pixel format to a suitable reduced colour depth (in this instance 4 bit-per-pixel). The procedure PROCpalleted shown below achieves this:

        DEF PROCpaletted
        LOCAL bits%, hbm%, oldbm%, bmih{}
        DIM bmih{Size%, Width%, Height%, Planes{l&,h&}, BitCount{l&,h&}, \
        \        Compression%, SizeImage%, XPelsPerMeter%, YPelsPerMeter%, \
        \        ClrUsed%, ClrImportant%}
        bmih.Size% = DIM(bmih{})
        bmih.Width% = @vdu%!208
        bmih.Height% = @vdu%!212
        bmih.Planes.l& = 1
        bmih.BitCount.l& = 4
        SYS "CreateDIBSection", @memhdc%, bmih{}, 0, ^bits%, 0, 0 TO hbm%
        IF hbm% = 0 ERROR 100, "Couldn't create DIBSection"
        SYS "SelectObject", @memhdc%, hbm% TO oldbm%
        SYS "DeleteObject", oldbm%
        PROCanimate
        ENDPROC

@vdu%!208 and @vdu%!212 are system variables containing the current width and height of the output window (client area) respectively. The third parameter of the call to CreateDIBSection is set to zero (DIB_RGB_COLORS) because the colour table will contain RGB colour values. Note that the colour table is not directly specified as it will be created dynamically later.

The bitmap is then selected into the device context used by BBC Basic for Windows, and the previous bitmap deleted. Finally PROCanimate is called to initialise the colour table from the contents of the palette.

Having changed the bitmap to 4bpp the contents of the palette may be changed in the usual way, for example using the VDU 19 command. However in order to animate the palette every change must be followed by another call to PROCanimate, which copies the logical palette into the colour table (involving swapping the red and blue colour values!) and then forces a display refresh:

        DEF PROCanimate
        LOCAL C%, pal%()
        DIM pal%(15)
        SYS "GetPaletteEntries", @hpal%, 0, 16, ^pal%(0)
        pal%() AND= &E0F0F0
        FOR C% = 0 TO 15 : SWAP ?^pal%(C%), ?(2+^pal%(C%)) : NEXT
        SYS "SetDIBColorTable", @memhdc%, 0, 16, ^pal%(0)
        SYS "InvalidateRect", @hwnd%, 0, 0
        ENDPROC

Having set up the two routines to emulate palette animation, the following code demonstrates how to achieve an effect similar to the flashing colours on the BBC micro.

First a screen mode is selected, and the palletised version of it created:

        MODE 8
        PROCpaletted

Now some text and graphics, including the 'flashing' colour numbers 8 to 15, are drawn:

        COLOUR 11
        COLOUR 128+12
        PRINT TAB(19,5) " Flashing colours demo by Richard Russell "
 
        VDU 5
        FOR col% = 0 TO 15
          GCOL col%
          RECTANGLE FILL col%*80,440,80,160
          MOVE col%*80+30,420
          GCOL 7
          PRINT ;col%;
        NEXT
 
        GCOL 1
        GCOL 128+8
        MOVE 968,180
        PRINT STRING$(41, CHR$127) " This has a flashing graphics background "

The code now enters a loop to animate the 'flashing' colours:

        REPEAT
          FOR C% = 8 TO 15
            VDU 19,C%,C%-8,0,0,0
          NEXT
          PROCanimate
          WAIT 40
          FOR C% = 8 TO 15
            VDU 19,C%,15-C%,0,0,0
          NEXT
          PROCanimate
          WAIT 40
        UNTIL FALSE
        END

Logical colours 8 to 15 are first defined as physical colours 0 to 7 respectively, followed by a 400 millisecond delay. Then colours 8 to 15 are defined as physical colours 7 to 0 respectively (i.e. the order is reversed) and another 400 millisecond delay initiated. This is repeated indefinitely in order to cause the colours to flash.

It should be noted that whilst in this example the 'default' behaviour of the BBC Micro colours is demonstrated, other uses of palette animation can be emulated by adding a call to PROCanimate following every VDU 19 command. For example the RISC OS style VDU 19,l,17,r,g,b and VDU 19,l,18,r,g,b behaviour can be simulated.

The full example is:

        MODE 8
        PROCpaletted
 
        COLOUR 11
        COLOUR 128+12
        PRINT TAB(19,5) " Flashing colours demo by Richard Russell "
 
        VDU 5
        FOR col% = 0 TO 15
          GCOL col%
          RECTANGLE FILL col%*80,440,80,160
          MOVE col%*80+30,420
          GCOL 7
          PRINT ;col%;
        NEXT
 
        GCOL 1
        GCOL 128+8
        MOVE 968,180
        PRINT STRING$(41, CHR$127) " This has a flashing graphics background "
 
        REPEAT
          FOR C% = 8 TO 15
            VDU 19,C%,C%-8,0,0,0
          NEXT
          PROCanimate
          WAIT 40
          FOR C% = 8 TO 15
            VDU 19,C%,15-C%,0,0,0
          NEXT
          PROCanimate
          WAIT 40
        UNTIL FALSE
        END
 
        DEF PROCanimate
        LOCAL C%, pal%()
        DIM pal%(15)
        SYS "GetPaletteEntries", @hpal%, 0, 16, ^pal%(0)
        pal%() AND= &E0F0F0
        FOR C% = 0 TO 15 : SWAP ?^pal%(C%), ?(2+^pal%(C%)) : NEXT
        SYS "SetDIBColorTable", @memhdc%, 0, 16, ^pal%(0)
        SYS "InvalidateRect", @hwnd%, 0, 0
        ENDPROC
 
        DEF PROCpaletted
        LOCAL bits%, hbm%, oldbm%, bmih{}
        DIM bmih{Size%, Width%, Height%, Planes{l&,h&}, BitCount{l&,h&}, \
        \        Compression%, SizeImage%, XPelsPerMeter%, YPelsPerMeter%, \
        \        ClrUsed%, ClrImportant%}
        bmih.Size% = DIM(bmih{})
        bmih.Width% = @vdu%!208
        bmih.Height% = @vdu%!212
        bmih.Planes.l& = 1
        bmih.BitCount.l& = 4
        SYS "CreateDIBSection", @memhdc%, bmih{}, 0, ^bits%, 0, 0 TO hbm%
        IF hbm% = 0 ERROR 100, "Couldn't create DIBSection"
        SYS "SelectObject", @memhdc%, hbm% TO oldbm%
        SYS "DeleteObject", oldbm%
        PROCanimate
        ENDPROC
This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information
palette_20animation.txt · Last modified: 2018/04/13 15:51 by richardrussell