@database CadOS display management
@node main "CadOS.display functions"
TABLE OF CONTENTS

@{" CadOS.display/TakeoverScreen " link TakeoverScreen}
@{" CadOS.display/RestoreScreen " link RestoreScreen}
@{" CadOS.display/WriteDispRegs " link WriteDispRegs}
@{" CadOS.display/WriteClxCon " link WriteClxCon}
@{" CadOS.display/GenerateScroll " link GenerateScroll}
@{" CadOS.display/MakeScreen " link MakeScreen}
@{" CadOS.display/MakeCopper " link MakeCopper}
@{" CadOS.display/AllocBitmap " link AllocBitmap}
@{" CadOS.display/DisplayIFF " link DisplayIFF}
@{" CadOS.display/UnpackILBM " link UnpackILBM}
@{" CadOS.display/MakeCprBpl " link MakeCprBpl}
@{" CadOS.display/FindChunk " link FindChunk}
@{" CadOS.display/SetColour " link SetColour}
@{" CadOS.display/SetColoursRGB " link SetColoursRGB}
@{" CadOS.display/SetColourRGB " link SetColourRGB}
@{" CadOS.display/FadeColoursRGB " link FadeColoursRGB}

@endnode

@node TakeoverScreen
CadOS.display/TakeoverScreen                   CadOS.display/TakeoverScreen

  NAME
    TakeoverScreen()

  SYNOPSIS
    void TakeoverScreen()

  DESCRIPTION
    This function correctly takes over the screen display of the Amiga, but
    does not inhibit multitasking, or Intuition rendering, you just can't
    see it. Before it takes the screen, it sets the Workbench sprites to
    normal 15Khz ones. It flushes the Intuition View and sets the default
    copper (set with the setcop macro) to run, which it will if copper DMA
    is not disabled by CadOS.system/Disable() or such. The colours will be
    set from a colour-cache, which is filled by RestoreScreen. Only the
    hardware registers FMODE, COP1LC and COPJMP1 will automatically be set,
    all others are left at their current settings.

  INPUTS
    none

  RESULT
    none - CadOS takes control of the display

  NOTE
    In the future, the Workbench screen may also be closed here.

  SEE ALSO
    @{" RestoreScreen " link RestoreScreen}, @{" CadOS.system/Disable " link CadOS_system/Disable},
    @{" setcop macro " link CadOS_macros.guide/setcop}

@endnode

@node RestoreScreen
CadOS.display/RestoreScreen                     CadOS.display/RestoreScreen

  NAME
    RestoreScreen()

  SYNOPSIS
    void RestoreScreen()

  DESCRIPTION
    This function correctly restores the screen display to the one provided
    by AmigaOS, it resets the Workbench sprites to their correct settings.
    All coppers you are running will be stopped, several hardware settings
    such as colour registers and screen registers will be disrupted by
    AmigaOS. Also, the hardware registers FMODE, COP1LC, COP2LC, COPJMP1
    and COPJMP2 will forcibly be set to their AmigaOS settings.

  INPUTS
    none

  RESULT
    none - CadOS restores the normal AmigaOS display

  NOTE
    In the future, the Workbench screen may also be reopened here.

  SEE ALSO
    @{" TakeoverScreen " link TakeoverScreen}, @{" CadOS.system/Enable " link CadOS_system/Enable},

@endnode

@node WriteDispRegs
CadOS.display/WriteDispRegs                     CadOS.display/WriteDispRegs

  NAME
    WriteDispRegs()

  SYNOPSIS
    void WriteDispRegs()

  DESCRIPTION
    CadOS holds a set of buffers of the 5 bplcon registers, which anyone
    can set to the current values in a copperlist or such, so that when the
    processor writes these registers to adjust particular bits, it does not
    majorly disrupt the screen image. An example of this is SetColour(),
    which needs to change bits 15,14,13 and 9 of bplcon3, but will not
    disrupt bit 5, BRDRBLNK, which, if it did, would cause the screen
    border to flicker between black, and color00.
    Anyone can write to the buffers, they are word-sized, ordered
    sequentially, and are called _bplcon0, _bplcon1, _bplcon2, _bplcon3
    and _bplcon4.

  INPUTS
    none

  RESULT
    none - CadOS writes the bplconX buffers to hardware

  NOTE
    MakeCopper currently writes to the bplcon0 and bplcon3 buffers.

  SEE ALSO
    @{" MakeCopper " link MakeCopper}, @{" SetColour " link SetColour}
@endnode

@node WriteClxCon
CadOS.display/WriteClxCon                         CadOS.display/WriteClxCon

  NAME
    WriteClxCon()

  SYNOPSIS
    void WriteClxCon(enables, matches, ORsprites)
                       D0       D1         D2

  DESCRIPTION
    The AGA chipset introduced a CLXCON2 register, to use the 2 new
    bitplanes. This function allows you to write to it and the old
    register at once.

  INPUTS
    enables     - ENBPx bitplanes to enable for testing (8 bits)
    matches     - MVBPx match bits against bitplanes (8 bits)
    ORsprites   - ENSPx sprites to enable for testing (4 bits)

  RESULT
    none - CLXCON and CLXCON2 are written

  SEE ALSO
    The hardware documentation
@endnode

@node GenerateScroll
CadOS.display/GenerateScroll                   CadOS.display/GenerateScroll

  NAME
    GenerateScroll()

  SYNOPSIS
    bplcon1=GenerateScroll(scroll1, scroll2)
      D0                      D1       D2

  DESCRIPTION
    Will correctly calculate a 1/4 pixel scroll value for both playfields
    and return a value that you can write to the AGA BPLCON1 register.

  INPUTS
    scroll1     - playfield 1 scroll value (0-255)
    scroll2     - playfield 2 scroll value (0-255)

  RESULT
    bplcon1     - correct value for BPLCON1 register

  SEE ALSO
    The hardware documentation
@endnode

@node MakeScreen
CadOS.display/MakeScreen                           CadOS.display/MakeScreen

  NAME
   MakeScreen()

  SYNOPSIS
    *copper, *bitmap, bytesrow, bytesplane=MakeScreen(width, height,
       A0       A1       D0         D1                  D0     D1
                                            planes, left, top, cmds, flags)
                                              D2     D3   D4    D5    D6

  DESCRIPTION
    This is the highest-level routine in CadOS. It takes a set of screen
    parameters, allocates the required bitmap with AllocBitmap, and also
    creates a copperlist to go with it using MakeCopper. The real magic is
    in MakeCopper, but the inputs required for it are quite scarey, this is
    a much more programmer-friendly approach. It's main drawbacks are that
    you cannot allocate a large bitmap _and_ make the copperlist display
    only a partial fragment of that bitmap. If you ask for a bitmap over
    368 pixels wide, MakeScreen will automatically switch on the MSF_HIRES
    flag, and if you ask for a bitmap of over 344 pixels in height,
    MSF_LACE will be set. You cannot allocate a bitmap of over 736 pixels
    wide or 688 pixels tall, or over over 8 bitplanes. The width of your
    bitmap will be rounded up to the nearest 16, 32 or 64 bit boundary,
    dependant on what fetchmode you are using, so do not assume if you
    allocate a specific size of screen you will get one, always refer to
    the bytesrow result. For example, if you asked for a bitmap of width
    160 in a 4x fetchmode situ, you would actually get a 192 pixel wide
    bitmap. If either the copper or bitmap allocation fails, the copper
    result returned will be 0. If the copper result returned is non-zero,
    bitmap will be non-zero, but the opposite is not true. Do not check
    the bitmap result, check the copper result. See the autodocs of
    AllocBitmap and MakeCopper for more information.

  INPUTS
    width       - the displayed and actual width of the screen (in pixels)
    height      - the displayed and actual width of the screen (in pixels)
    planes      - the number of bitplanes (1-8)
    left        - the left-edge hardware coordinate (96-432)
    top         - the top-edge hardware coordinate (20-312)
    cmds        - the number of extra copper commands to make space for in
                  the copperlist (1 command = 4 bytes)
    flags       - any or none of these flags ORed together:
                  MSF_HIRES       - hires screen (see MakeCopper)
                  MSF_LACE        - interlaced screen (see MC)
                  MSF_HAM         - set the HAM bit in BPLCON0 (see MC)
                  MSF_INTERLEAVED - interleaved bitmaps (see AllocBitmap)
                  MSF_WIDEDISPLAY - use a max-sized display window (see MC)
                  MSF_NOBORDER    - use BRDRBLNK bit in BPLCON3 (see MC)

  RESULT
    copper      - A copperlist created by MakeCopper or 0 if it failed
    bitmap      - A bitmap allocated by AllocBitmap, or 0 if it failed
    bytesplane  - The bytesplane value returned by AllocBitmap
    bytesrow    - The bytesrow value returned by AllocBitmap

  BUGS
    See the bugs of MakeCopper and AllocBitmap. However, unlike
    AllocBitmap, MakeScreen will not allow creation of a screen with more
    than 8 bitplanes.

  SEE ALSO
    @{" AllocBitmap " link AllocBitmap}, @{" MakeCopper " link MakeCopper}
@endnode

@node MakeCopper
CadOS.display/MakeCopper                           CadOS.display/MakeCopper

  NAME
    MakeCopper()

  SYNOPSIS
    *copper=MakeCopper(wh, p, lt, br, bp, cmds, flags, modulo, bitmap)
                       D0  D1 D2  D3  D4   D5    D6      D7      A0

  DESCRIPTION
    MakeCopper is a shockingly complex routine that will allocate and
    fill in a copperlist to allow display of a bitmap, according to the
    large set of parameters passed to it. The space allocation formula,
    currently over-generous for safety, is 200+(cmds*4), this is doubled
    in the case of an interlaced screen which requires two copperlists.
    Interlaced copperlists from MakeCopper are self-perpetuating, ie the
    single allocation returned from MakeCopper contains 2 seperate
    copperlists in laced mode, a LOF list then SHF list, both of whose last
    instruction before COPEND is to write the address of the opposite
    copperlist to COP1LC. The two interlaced copperlists are the same,
    except the bitplane modulos have bytesrow added to them in both
    copperlists and the SHF's bitplane pointers have bytesrow added to
    them. The cmds space you request will be available in both copperlists,
    the suggested method for finding them is:

	;a0=interlaced copperlist returned from MakeCopper
	;a1 becomes ptr to 1st copperspace, a2 is 2nd copperspace ptr
.first	cmp.l	#$1fe0000,(a0)+
	bne.s	.first
	move.l	a0,a1
	subq	#4,a1
.mid	cmp.l	#$1fe0000,(a0)+
	beq.s	.mid
.second	cmp.l	#$1fe0000,(a0)+
	bne.s	.second
	move.l	a0,a2
	subq	#4,a2

    Remember that the cmds space in interlace only works on one field in
    each case, so the first copperlist should contain data for the even
    scanlines only, and the second should contain data for the odd
    scanlines only.

    The positions of certain instructions in the copperlist are not
    guaranteed, so find out where it is by searching down it, rather than
    assuming where a value is, otherwise you'll be in for a big surprise
    when you change your call to MakeScreen a little and it blows up.

  INPUTS
    wh          - The width and height of the display. The width is stored
                  as a word in the upper half of D0, the height is stored
                  in the bottom half. Use MOVE.W #width,D0 / SWAP D0 /
                  MOVE.W #height,D0 . Unlike MakeScreen, the values passed
                  are not properly range-checked.
    p           - The number of bitplanes (1-8)
    lt          - The left and top edge of the display. Left is stored as a
                  word in the upper half of D0, Top is stored in the bottom
                  half. Use MOVE.W #left,D2 / SWAP D0 / MOVE.W #top,D0 .
                  These values are not properly range-checked.
    br          - The bytesrow value, see AllocBitmap for more details.
    bp          - The bytesplane value, see AllocBitmap for more details.
    cmds        - The amount of copper-commands you want MakeCopper to
                  leave space for, between the turning on of the display
                  and the turning off of the display. Each copper-command
                  is initialised to $01FE0000 (move 0 to NOOP) for safety.
    flags       - See the section below
    modulo      - This is the value for the bitplane modulos. Neccesary if
                  you have interleaved bitmaps, or something like that.
    bitmap      - A pointer to an area of memory that will be displayed by
                  this copper.

  RESULT
    copper      - A pointer to an initialised copperlist, ready to be
                  displayed. Use of the "setcop" macro is advised. If the
                  memory for the copperlist couldn't be allocated, 0 is
                  returned.

  FLAGS
    These flags are defined BITDEF style. You can use the MSF_<flag> as an
    actual value to OR with other flags or 0 to set that flag, or you can
    bset the MSB_<flag> value. MSB_INTERLEAVED=3 and MSF_INTERLEAVED=1<<3

	Flag		Usage
	------------	--------------------------------------------
	HIRES      	Display is in hires, ie HIRES bit in BPLCON0 is set
			and width of display is halved.
	LACE       	Interlaced display is set up, see above for more
			details of interlaced copperlists. Note that you
			should use the "lofsync" macro before setting your
			copperlist if you want to be sure of getting the
			right lines matching.
	HAM        	set the HAM bit in BPLCON0, must be either 6 or 8
			bitplanes, else you'll get funny results
	WIDEDISPLAY	Use the widest possible display window, instead of
			making the display window the area of the display
			itself. Useful if you want to move the screen
			around without getting clipped
	STATICREGS 	All the 'one-time' registers, such as BPLCON0 and
			BPL1MOD, can be set once and, if left undisturbed,
			do not need to be set again, therefore if you set
			this flag they will not be written into the
			copperlist, thus shortening it's execution time and
			therefore DMA load. Instead, they are set by the
			MakeCopper call immediately, corrupting the current
			values, if there are any. !BEWARE! If something
			changes any of these values after the MakeCopper
			call, there is no way to get them back!
	NOBORDER   	AGA has a sexy bit, BRDRBLNK in BPLCON3. Setting
			this flag makes the area outside the display area
			TOTALLY JET BLACK, instead of COLOR00 as usual.
			It's even darker than colour 000, if I turn up the
			brightness to full! Well cool!

  BUGS
    None of the parameters you pass are checked to be reasonable or
    correct, so if nothing or crap displays from this copper, check your
    input values to MakeCopper (or whatever calls MakeCopper)
    Also, if you're using the "lofsync" macro, note that it can potentially
    exit ANYWHERE down the long frame, so do vsync / lofsync / setcop
    rather than just lofsync / setcop.

  SEE ALSO
    @{" MakeScreen " link MakeScreen}, @{" AllocBitmap " link AllocBitmap}
@endnode

@node AllocBitmap
CadOS.display/AllocBitmap                         CadOS.display/AllocBitmap

  NAME
    AllocBitmap()

  SYNOPSIS
    *bitmap, bytesrow, bytesplane, modulo=AllocBitmap(width, height,
       A0       D0         D1        D2                 D0     D1
                                                      planes, interleave)
                                                        D2       D3

  DESCRIPTION
    This routine performs a very simple function - it allocates a block
    of memory, and performs some simple but very important calculations.
    The block of memory allocated is a contiguous block, large enough
    to hold a set of N bitplanes, sized (width/8)*height bytes long.
    N=planes, so the allocation is (width/8)*height*planes. Next, it
    calculates bytesrow, bytesplane and modulo. Now bytesrow is a value
    that, if you add it to the address of row 0 of the bitmap, you get
    the address of row 1. It certainly does not mean that row 0 is that
    many bytes long, just bitmap+(bytesrow*N)=row N of the bitmap.
    Bytesplane is like bytesrow, if you add it to the bitmap pointer you
    get the address of the next bitplane. Many functions in CadOS will
    happily work like this, and it means that to these functions, bitmaps
    that are "interleaved" are the same as "contiguous" bitmaps. These
    "contiguous" bitmaps are the old classic form of Amiga graphics. In
    a bitmap with N rows, it goes plane0row0, plane0row1, plane0row2 ...
    plane0rowN-1, plane1,row0 ... Every row in one bitplane occurs, then
    every row in the next, and so on. This can be annoying, as sometimes
    you want to "blit" objects, and to do it this way, you must blit once
    for every bitplane as the data is so far apart. In "interleaved"
    bitmaps, it goes plane0row0, plane1row0 ... planeN-1row0, plane1,row0
    ... every bitplane is on per row, so the bitplanes are much nearer.
    All that is needed to do this magical trickery is to change the
    bitplane modulos, so that at the end of each row on the display,
    instead of changing the bitplane pointer by 0, you change it to skip
    past all the other bitplanes, which is still very near. So, you get
    the best of both worlds. An interleaved bitmap is exactly the same
    size as a contiguous bitmap, but you can not assume with an
    interleaved bitmap that the width is bytesrow*8 and the height is
    bytesplane/bytesrow : you must know that seperately. The returned
    modulo value is best put straight into a copperlist and forgotton.

  INPUTS
    width       - width of desired bitmap (in pixels, 16-65535)
                  this value is rounded up to the nearest 16 pixels
    height      - height of desired bitmap (in pixels, 1-65536)
    planes      - amount of bitplanes in the bitmap
    interleave  - 0 if you want a "contiguous" bitmap, 1 if you want an
                  "interleaved" bitmap

  RESULT
    bitmap      - pointer to enough memory to hold the bitmap, or 0 if
                  one couldn't be allocated
    bytesrow    - see discussion above
    bytesplane  - see discussion above. Treat this as a longword, because
                  in a large contiguous bitmap, bytesplane can go over
                  65536 bytes.
    modulo      - 16 bit modulo value

  BUGS
    Unlike MakeScreen, your input is NOT checked for validity, so if this
    function returns 0 all the time, check your input.

  SEE ALSO
    @{" CadOS.memory/AllocMem " link CadOS_memory.guide/AllocMem}, @{" MakeScreen " link MakeScreen}
@endnode

@node DisplayIFF
CadOS.display/DisplayIFF                           CadOS.display/DisplayIFF

  NAME
    DisplayIFF()

  SYNOPSIS
    *copper,*bitmap,bytesrow,bytesplane=DisplayIFF(*iff,left,top,cmds,flags)
       A0      A1      D0        D1                 A0   D0   D1  D2   D3

  DESCRIPTION
    This is a simple covering routine, that basically extracts information
    from an IFF ILBM to make a call to MakeScreen, then with that unpacks
    the bitmap with UnpackILBM. It returns the same as MakeScreen.

  INPUTS
    iff         - pointer to an IFF ILBM file, loaded in memory
    left        - left edge of the display (see MakeScreen)
    top         - top edge of the display (see MakeScreen)
    cmds        - extra copper commands (see MakeScreen)
    flags       - MakeScreen flags. MSF_HIRES, MSF_LACE and MSF_HAME may
                  be overridden by the IFF's CAMG chunk

  RESULT
    copper      - See MakeScreen
    bitmap      - See MakeScreen
    bytesrow    - See MakeScreen
    bytesplane  - See MakeScreen

  SEE ALSO
    @{" MakeScreen " link MakeScreen}, @{" UnpackILBM " link UnpackILBM}
@endnode

@node UnpackILBM
CadOS.display/UnpackILBM                           CadOS.display/UnpackILBM

  NAME
    UnpackILBM()

  SYNOPSIS
    void UnpackILBM(bytesrow, bytesplane, rows, iff, bitmap)
                       D0         D1       D2    A0    A1
  DESCRIPTION
    Unpacks an IFF ILBM into a bitmap, it knowns the IFF compression
    types 0 and 1. That's all, and it's quite safe.

  INPUTS
    bytesrow    - the bytesrow value for the bitmap, see AllocBitmap
    bytesplane  - the bytesplane value for the bitmap, see AllocBitmap
    rows        - the amount rows are in the bitmap, see AllocBitmap
    iff         - a pointer to an IFF file, pointing at the head ("FORM"),
                  NOT the body ("BODY") !
    bitmap      - the bitmap to write into

  RESULT
    none - bitmap is filled with the ILBM data

  BUGS
    If the physical width of your bitmap is less than the width of the
    ILBM data being unpacked, you will kill (ilbmwidth-bmpwidth) bytes
    at the end of the bitmap. *DON'T DO THAT THEN*
    If you have less bitplanes in the bitmap than are defined in the
    ILBM then you are an idiot, and deserve to have a huge wad of
    unallocated memory trashed (tsk!)
    You *should* be allocating the bitmap based on the data in the ILBM's
    BMHD.

  SEE ALSO
    @{" DisplayIFF " link DisplayIFF}
@endnode

@node MakeCprBpl
CadOS.display/MakeCprBpl                           CadOS.display/MakeCprBpl

  NAME
    MakeCprBpl()

  SYNOPSIS
    *newcopper=MakeCprBpl(planes, bytesplane, *copper, *bitmap)
        A0                  D0        D1         A0       A1

  DESCRIPTION
    Writes data to memory pointed at by the copper parameter, this data
    is instructions that the copper can read to set the bitplane pointers
    to the bitmap pointer, also a parameter. Also, it needs the number of
    bitplanes, and the bytes to add to the bitplane pointer to get the
    next bitplane. The value that it returns is the original copper
    parameter, plus (8*planes) The upshot of all this is that you can
    call this to write your BPLxPT pointers into your copperlist.

  INPUTS
    planes      - number of bitplanes to write
    bytesplane  - the bytesplane value. See AllocBitmap
    copper      - address to write copper data to
    bitmap      - the bitmap to have the BPLxPTs pointing at

  RESULT
    newcopper   - new address right after where copper data was written

  NOTE
    This is used by MakeCopper.

  SEE ALSO
    @{" AllocBitmap " link AllocBitmap}, @{" MakeCopper " link MakeCopper}
@endnode

@node FindChunk
CadOS.display/FindChunk                             CadOS.display/FindChunk

  NAME
    FindChunk()

  SYNOPSIS
    *chunk, size=FindChunk(chunktype, *iff)
       A0    D0                D0      A0

  DESCRIPTION
    This finds an IFF chunk inside an IFF FORM. It is very fast, it
    only looks at the actual chunkheaders and skips actual data.
    Simply point at a loaded IFF file, set the chunk type using a 32-bit
    identifier, eg #"CMAP" or such, so you don't get a pointer to a string,
    but a 32-bit number with 4 ascii digits in it. If the chunk you ask for
    is not found, 0 is returned in both result parameters.

  INPUTS
    chunktype   - a 32-bit "chunk descriptor", such as "CRNG" or "VHDR"
    iff         - pointer to the start of an IFF file in memory

  RESULT
    chunk       - a pointer to the data of the first occurance of the 
                  chunk asked for, or 0 if the chunk was not found
    size        - the size of the chunk, in bytes, or 0 if the chunk was
                  not found

  BUGS
    Only works on VALID IFF files! It's safe to call on any kind of data,
    though. An annoying fact is that it won't find 2nd or 3rd occurances
    of the same named chunk, so DPaint's "CRNG" sections are hard to get
    all of.

  NOTE
    Used by DisplayIFF and UnpackILBM

  SEE ALSO
    @{" DisplayIFF " link DisplayIFF}, @{" UnpackILBM " link UnpackILBM}
@endnode

@node SetColour
CadOS.display/SetColour                             CadOS.display/SetColour

  NAME
    SetColour()

  SYNOPSIS
    void SetColour(pen, colour)
                    D0    D1
  DESCRIPTION
    Sets a pen to the colour specified, supplied as a long 24-bit value,
    in hex we say $00RRGGBB, this means (red, 0-255)<<16 +
    (green, 0-255)<<8 + (blue, 0-255). White is $00FFFFFF, grey is
    $007F7F7F, red is $00FF0000, blue is $000000FF, etc...

  INPUTS
    pen         - The pen to set (0-255)
    colour      - A 24-bit long, as described above.

  RESULT
    none - colour is set

  BUGS
    ENSURE YOU DO NOT HAVE THE RDRAM FLAG IN BPLCON2 SET!

  SEE ALSO
    @{" SetColourRGB " link SetColourRGB}
@endnode

@node SetColourRGB
CadOS.display/SetColourRGB                       CadOS.display/SetColourRGB

  NAME
    SetColourRGB()

  SYNOPSIS
    void SetColourRGB(pen, red, green, blue)
                       D0   D1    D2    D3
  DESCRIPTION
    Sets a pen to the colour specified, supplied as its red, green and
    blue components.

  INPUTS
    pen         - The pen to set (0-255)
    red         - the amount of red in the colour (0-255)
    green       - the amount of green in the colour (0-255)
    blue        - the amount of blue in the colour (0-255)

  RESULT
    none - colour is set

  BUGS
    ENSURE YOU DO NOT HAVE THE RDRAM FLAG IN BPLCON2 SET!

  SEE ALSO
    @{" SetColoursRGB " link SetColoursRGB}, @{" SetColour " link SetColour}
@endnode

@node SetColoursRGB
CadOS.display/SetColoursRGB                     CadOS.display/SetColoursRGB

  NAME
    SetColoursRGB()

  SYNOPSIS
    void SetColoursRGB(start, number, *colours)
                         D0     D1       A0

  DESCRIPTION
    This function sets a multiple amount of colours at once, starting
    from the pen specified by parameter "start", and finishing at pen
    start+number. If start+number goes beyond 255, it will be wrapped
    round to 0 again, which can be played with to get easy colour-
    cycling of 256 colours. The format of the data pointed to by
    "colours" is in the style of an IFF CMAP; one byte red, one byte
    green and one byte blue, then repeat for each colour. In fact,
    you can actually provide an IFF CMAP as input, with start=0 and
    number= the size of the CMAP chunk divided by 3. You can also
    generate a range of colours with the "colfade" macro. This routine
    uses the SetColourRGB routine to do it's dirty work.

  INPUTS
    start        - the pen number to start from
    number       - the number of colours to change
    colours      - a pointer to a CMAP-style array of colours

  RESULT
    none - the colours are set

  SEE ALSO
    @{" SetColourRGB " link SetColourRGB}
@endnode

@node FadeColoursRGB
CadOS.display/FadeColoursRGB                   CadOS.display/FadeColoursRGB

  NAME
    FadeColoursRGB()

  SYNOPSIS
    void FadeColoursRGB(start, number, method, steps, *src, *dest, *back)
                          D0     D1      D2      D3    A0     A1     A2
  DESCRIPTION
    This routine works on what I call a "colourset", defined by the
    "start" and "number" parameters, see SetColoursRGB for more details
    about how they work. It has four "methods", which are:

	Method	Output
	------	---------------------------------
	  1	fade from src colour to dest colour
	  2	fade from src colour to dest colourset
	  3	fade from src colourset to dest colour
	  4	fade from src colourset to dest colourset

    Based on this, the parameters "src" and "dest" either refer to a
    colour, which is a 24-bit colour in the way that SetColour (not
    SetColourRGB) specifies as $00RRGGBB, or a colourset, which is a
    pointer to a set of colours defined in the way SetColoursRGB specifies.
    Now we have described how the fading is defined, I'm sure you will
    realise if we did this fade without pausing, it would be over in less
    than 1 frame, so we generally wait for a vertical blank to pass, each
    iteration. Because I can't say how you will be counting this wait, I
    ask you to provide a call-back routine that is called each iteration of
    the routine, at it's simplest just use a vsync / rts as shown in the
    example below. Finally, we say 'how many iterations?', and that is
    defined by the parameter "steps", so if you put 500 as the steps, and
    a single vsync is the callback, it will take 10 seconds to fade! Any
    value can be steps, but for speed I suggest values <= 256. Values for
    steps less than 1 are not done. Finally, to do this routine needs a
    small amount of memory, so it may fail if memory is not available.
    If no memory is available, the dest colour/colourset will be
    put in anyway.

  INPUTS
    start        - the pen number to start from
    number       - the number of colours to fade through
    method       - the method to use for fading (see above table)
    src          - EITHER a pointer to a CMAP-style array, or a $00RRGGBB
                   24-bit colour value. This is the source colour/colourset
    dest         - EITHER a pointer to a CMAP-style array, or a $00RRGGBB
                   24-bit colour value. This is the dest colour/colourset
    back         - pointer to a routine

  RESULT
    none - the colourset is faded

  BUGS
    If it dies during this call, make sure that your callback routine is
    working. All registers are preserved for the call, so don't worry
    about that. Remember to leave the stack alone! :-) Also, the size of
    the array(s) provided for src/dest must be as big as the "number"
    parameter*3, else it will go off the end of the arrays.

  EXAMPLE
	; fade in an IFF. A0 points to the FORM itself, we assume that
	; DisplayIFF has been called on it, setcop has been issued and
	; the raster and copper DMA are on.
	move.l	#"CMAP",d0
	bsr.s	_FindChunk	; returns A0=chunk or 0, D0=size of chunk
	tst.l	d0
	beq.s	.fin
	move.w	d0,d1
	divu.w	#3,d1
	moveq	#0,d0
	moveq	#2,d2
	moveq	#127,d0
	move.l	a0,a1
	move	#$000000,a0
	lea	.vs(pc),a2
	jsr	_FadeColoursRGB
	bra.s	.fin
.vs	vsync
	rts
.fin	.......

  SEE ALSO
    @{" SetColoursRGB " link SetColoursRGB}, @{" SetColour " link SetColour}
@endnode

