
  \ ***********************************************************
  \
  \        SIMPLE HARDWARE SPRITE FROM IFF IMAGERY DEMO
  \
  \ ***********************************************************
  \
  \ This code demonstrates how to create a simple HeliOS single
  \ playfield display and generate a simple hardware sprite from
  \ imagery stored as an IFF ILBM file.
  \
  \ One IFF file is loaded and displayed as the screen backdrop,
  \ and another is loaded and used for the hardware sprite imagery.
  \
  \ The hardware sprite is moved around the screen using the mouse.
  \
  \ Press <Space> to quit when finished.
  \
  \ ***********************************************************


  \ ***********************************************************
  \ Re-initialise HeliOS dictionary to standard CORE vocabulary
  \ ***********************************************************

  \ This should always be used at the start of any program which
  \ is to be repeatedly recompiled.

  FORGET **CORE**

  \ *************************
  \ Load include symbol files
  \ *************************
  \
  \ These "include files" are pre-compiled (for speed) versions of the
  \ Amiga includes and the Helios system includes.
  \
  \ Uncomment the lines below for standalone compilation, but otherwise
  \ it is better to set these include files from the Helios Forth menus

  AMIGAINCLUDE Helios:Amiga_Include
  USERINCLUDE  Helios:Helios_Include

  \ ****************************************
  \ Create display imagery file name strings
  \ ****************************************

  \ These files are ordinary IFF's (and may be "PowerPacked" if required)
  \
  \ The pictures here will be loaded into each of the display BitMaps.
  \

  $CONSTANTL Slice1Pic $Helios:Source/Data/Pic2$

  \ **************************************
  \ Create display configuration constants
  \ **************************************
  \
  \ Collect all "display-specific" parameters here and generate "named"
  \ constants which make references easier than using numeric values.
  \
  \ Collecting these together here makes it easier to adjust things at any
  \ time without having to search source code to replace values individually.
  \


  256                      CONSTANT DisplayHeight      \ Full PAL display
  320                      CONSTANT DisplayWidth       \ Lores display
  44                       CONSTANT DisplayTopLine     \ Display start

  DisplayWidth             CONSTANT Slice1Width        \ Lores width
  DisplayWidth 32 +        CONSTANT Slice1RasterWidth  \ Raster=screenwidth
  DisplayHeight            CONSTANT Slice1Height       \ Slice height
  DisplayHeight 32 +       CONSTANT Slice1RasterHeight \ Slice Raster=Displayheight
  0                        CONSTANT Slice1Mode         \ Lores
  3                        CONSTANT Slice1Planes       \ Slice bitplanes

  \ The calculation below takes the number of bitplanes and calculates
  \ how many colours this represents.
  \
  \ One bitplane gives two colours.
  \
  \ Each additional bitplane multiplies the number of colours by two.
  \
  \ Performing a single LSL operation on any number multipies by 2, so we
  \ have a quick method of multiplying by two for our colour calculation.
  \
  \ In this case, we need "2 to the power 3", which is 2*2*2=8.
  \
  \ e.g.                              2*2*2
  \                                   ^ ^ ^
  \                                   Total number of planes = 3
  \
  \
  \ So, we take the first value two
  \
  \ e.g.                              2*2*2
  \                                   ^
  \                                  Initial start value of 2
  \
  \ and we now need to multiply it by two "the_number_of_planes minus_one"
  \ more times.
  \
  \ e.g.                              2*2*2
  \                                     ^ ^
  \                                     Total planes minus one
  \
  \
  \ So, Number of colours = 2 operated on by LSL NumberOfPlanes-1 times.
  \

  2 Slice1Planes 1- LSL    CONSTANT Slice1Colours      \ A-slice colours

  \ ***********************
  \ Error handling routines
  \ ***********************

  \ This error handler allows all errors to be routed via a comprehensive
  \ sequential closedown routine, which is associated with the HeliOS
  \ system error handler word ERROR".
  \
  \ When ERROR" senses an error, it prints an associated error message
  \ delimited by '"' characters, and then closes everything down using the
  \ routine CLOSEDOWN below which you have supplied.
  \
  \ This simplifies errors checks to the use of a single word, ERROR", which
  \ displays a text message and closes eveything down.
  \

  0 VARIABLE (CLOSEDOWN)

  : ?CLOSEDOWNERROR

  IF
    CR
    CR
    TYPE
    CR
    CR
    ." Press <Space> to quit!"
    CR
    CR
    WAITSPACE
    (CLOSEDOWN) @EXECUTE
    QUIT
  ELSE
    DDROP
  THEN
  ;

  LATESTCFA VARIABLE ERROR1

  \ ****************************************
  \ Create display pointer storage variables
  \ ****************************************

  \ Here we create a set of "pointers", initially set to a "null" value.
  \
  \ These "pointers" are set up as "long addresses" when various components
  \ of the display system are allocated and initialised.
  \
  \ Note that initially these are all set to zero, and we clear them back
  \ to zero when we de-allocate the associated resource.
  \
  \ These DPOINTERs are all initially set to "null" by using 'D0'.
  \
  \ When we allocate memory or Amiga system resources in the program at
  \ run-time, these pointers are updated to contain the 32-bit address
  \ of the newly allocated resource.
  \
  \ Subsequently the symbolic DPOINTER name can be used in your code to
  \ represent the associated address.

  D0 DPOINTER Display1             \ Main Display structure pointer
  D0 DPOINTER Slice1               \ Slice 1 Slice structure pointer

  D0 DPOINTER Slice1_ColorMap      \ Slice 1 ColourMap structure pointer

  D0 DPOINTER Slice1_RasInfo       \ Slice 1 RasInfo structure pointer

  D0 DPOINTER Slice1_BMap          \ Slice 1 BitMap structure pointer

  D0 DPOINTER Slice1_SliceControl  \ Slice 1 SliceControl structure pointer

  \ *************
  \ Colour tables
  \ *************

  \ Each colour entry requies 2 bytes of storage space

  CREATEL Slice1_ColorTable        \ Create longword pointer to table
  Slice1Colours 2* 0 ALLOTFILL     \ Allocate Slice1 colours * 2 bytes

  \ ***********************************
  \ Create Display and Slice structures
  \ ***********************************

  \ This routine simply makes blank structures, which then need to be
  \ initialised later (in the CREATE_DISPLAY routine).

  : CREATE_DSLICES

  DS_SIZEOF MAKESTRUCTURE Display1 MAKEPOINTER  \ Main "Display" structure

  SL_SIZEOF MAKESTRUCTURE Slice1   MAKEPOINTER  \ Display "Slice" structure
  ;

  : FREE_DSLICES

  Slice1    DDUP FREEMEMORY   CLEARPOINTER
  Display1  DDUP FREEMEMORY   CLEARPOINTER
  ;

  \ ******************************
  \ Create RasInfo structures etc.
  \ ******************************

  : CREATE_RASINFO

  \ First allocate and initialise complete RasInfo structures.
  \
  \ This routine automatically allocates all BitMaps etc.
  \

  Slice1RasterWidth Slice1RasterHeight Slice1Planes  OPENRASINFO
  DFLAG0= ERROR" Fail: RasInfo1"
  Slice1_RasInfo MAKEPOINTER

  \ Set invisible area "sprite margins" for slice RasInfo

  16              Slice1_RasInfo         ri_RxOffset    INDEX!L
  16              Slice1_RasInfo         ri_RyOffset    INDEX!L

  \ Store BitMap pointer - often useful for later reference

  Slice1_RasInfo  ri_BitMap INDEXD@L Slice1_BMap MAKEPOINTER
  ;

  : FREE_RASINFO

  Slice1_RasInfo   DDUP CLOSERASINFO   CLEARPOINTER
  ;

  \ ********************************
  \ Create Display/Slice Copperlists
  \ ********************************

  \ This function builds the main display copperlist by:
  \
  \ 1. Initialising the Slice data structure
  \ 2. Calling MAKECOPSTRIP for the slice, to build a copperlist
  \ 3. Calling MAKEDISPLAY to build the master Display copperlist
  \

  : CREATE_DISPLAY

  \ First initialise main display structures

  Slice1                           Display1  DS_Slice     INDEXD!L

  Slice1Width                      Slice1    SL_DWidth    INDEX!L
  Slice1Height                     Slice1    SL_DHeight   INDEX!L
  DisplayTopLine                   Slice1    SL_DyOffset  INDEX!L
  Slice1_RasInfo                   Slice1    SL_RasInfo   INDEXD!L
  Slice1_ColorMap                  Slice1    SL_ColorMap  INDEXD!L
  Slice1Mode                       Slice1    SL_Modes     INDEX!L

  \ Generate copper list information for each of the display slices

  Slice1 MAKECOPSTRIP
  D0= ERROR" Fail: Slice1CopStrip"

  \ Make display

  Display1 MAKEDISPLAY
  D0= ERROR" Fail: Display1"
  ;

  : FREE_DISPLAY

  Display1                 FREEDISPLAY
  Slice1                   FREECOPSTRIP
  ;

  \ ********************************************************
  \ Create SliceControl structures for double buffered slice
  \ ********************************************************

  \ SliceControl structures are used to control any slices which perform
  \ mapping or scrolling functions, or which require double or triple
  \ playfield buffering.
  \
  \ In this case we have one slice which does not scroll, is not mapped,
  \ but IS double buffered.
  \

  : CREATE_SLICECONTROL

  \ Make SliceControl for double buffered bitmap display

  Slice1  0 0 MAKESLICECONTROL
  DFLAG0= ERROR" Fail: SliceControl1"
  Slice1_SliceControl MAKEPOINTER

  \ Install slice controls into HeliOS display control system

  Slice1_SliceControl  INSTALLSLICECONTROL
  ;

  : FREE_SLICECONTROL

  CLEARSLICECONTROLS
  Slice1_SliceControl  CLOSESLICECONTROL
  ;

  \ These routines load an IFF picture into supplied BitMap, and correctly
  \ initialises the supplied ColorTable.
  \
  \ The ColorTable is then used to create an initialised ColorMap structure.
  \

  : CREATE_IMAGERY

  Slice1_BMap
  Slice1_ColorTable
  Slice1Pic
  10 2 DOSLIB                        \ Call to internal HeliOS library
  10 <> ERROR" Fail: Slice1Pic"

  Slice1_ColorTable  Slice1Colours MAKECOLORMAP  \ Allocate ColourMap
  DFLAG0= ERROR" Fail: Slice1ColorMap"
  Slice1_ColorMap MAKEPOINTER
  ;

  : FREE_IMAGERY

  Slice1_ColorMap  DDUP FREECOLORMAP  CLEARPOINTER
  ;

  \ ***********************************
  \ Create hardware sprite colour table
  \ ***********************************

  \ This colour table simply specifies a few arbitrary colours which we
  \ will then set into colour registers 16 to 31

  CREATEL MySpriteColourTable

  HEX

  0000 ,  \ Colour 16
  0FFF ,  \ Colour 17
  0AA0 ,  \ Colour 18
  000F ,  \ Colour 19
  0000 ,  \ Colour 20
  000F ,  \ Colour 21
  00F0 ,  \ Colour 22
  0F00 ,  \ Colour 23
  0000 ,  \ Colour 24
  0004 ,  \ Colour 25
  0040 ,  \ Colour 26
  0400 ,  \ Colour 27
  0000 ,  \ Colour 28
  0008 ,  \ Colour 29
  0080 ,  \ Colour 30
  0800 ,  \ Colour 31

  DECIMAL

  \ ************************
  \ Allocate a pointer store
  \ ************************

  D0 DPOINTER  MyHSpriteData

  CREATEL MYFILE $ HeliOS:Source/Data/4ColourHSTestBrush$

  \ MAKEHSPRITE  ( - - - HSpriteData(l) or null for failure )

  : MAKEHSPRITE

  MYFILE  2 3 DOSLIB
  2 =
  IF
    1 1  DOVER  5 5 9 9 MAKEHSPRITEBLOCK_BMAP
    DSWAP CLOSEBMAP
  ELSE
    D0
  THEN
  ;

  \ **********************
  \ Set up hardware sprite
  \ **********************

  \ First we set sprite colours 16 to 31
  \ Then we create a hardware sprite definition block
  \ Then we install the hardware sprite

  : SetupHSprite

  Slice1 MySpriteColourTable 16 16 SETSLICECOLOURS

  MAKEHSPRITE
  DFLAG
  IF
    MyHSpriteData MAKEPOINTER
    MyHSpriteData 1 HSPRITE_INSTALL
    0
  ELSE
    DDROP
    1
  THEN
  ;

  \ **************************
  \ Close down hardware sprite
  \ **************************

  \ First we remove the hardware sprite
  \ Then we de-allocate the sprite definition

  : FREE_HSPRITE

  MyHSpriteData HSPRITE_REMOVE

  MyHSpriteData  DDUP FREEHSPRITEBLOCK  CLEARPOINTER
  ;

  \ ********************************
  \ Display and move hardware sprite
  \ ********************************

  \ Switch on mouse position reporting
  \ Switch off the HeliOS mouse pointer image
  \ Repeatedly set the sprite to the current mouse pointer position

  : TestHSprite

  1 REPORTMOUSE
  0 HELIOSMPOINTER

  BEGIN
    0 MOUSEX MOUSEY 0 MyHSpriteData HSPRITE_PLACE
    ?TERMINAL 32 =
  UNTIL
  ;


  \ *********************
  \ Close down everything
  \ *********************

  : CLOSEDOWN

  FREE_HSPRITE
  FREE_SLICECONTROL
  FREE_DISPLAY
  FREE_IMAGERY
  FREE_RASINFO
  FREE_DSLICES
  RESETERROR"
  ;

  LATESTCFA (CLOSEDOWN) !

  : TestDisplay          \ Start of program

  SCRCLR

  CR
  ."        **********************************************************"
  CR 6 FPENSET
  ."               SIMPLE HARDWARE SPRITE FROM IFF IMAGERY DEMO"
  CR 1 FPENSET
  ."        **********************************************************"
  CR
  CR
  ."        This code demonstrates how to set up a simple HeliOS display"
  CR
  ."        and create a simple hardware sprite from bitmapped imagery."
  CR
  CR
  ."        One IFF file is loaded as a backdrop picture, and another IFF"
  CR
  ."        file is loaded and used for the hardware sprite imagery."
  CR
  CR
  ."        The hardware sprite can then be moved around using the mouse."
  CR
  CR
  ."        Press <Space> to quit demo."
  CR
  CR
  ."        **********************************************************"
  CR 6 FPENSET
  ."                  Press <Space> or <L-Mouse> to see Demo          "
  CR 1 FPENSET
  ."        **********************************************************"
  CR

  WAITSPACE

  SCRCLR

  ERROR1 SETERROR"       \ Redirect system errors to our routine ERROR1

  CREATE_DSLICES
  CREATE_RASINFO
  CREATE_IMAGERY
  CREATE_DISPLAY
  CREATE_SLICECONTROL

  SetupHSPrite ERROR" Failed to open HSprite!"

  HeliOS_On

  1 FrameRate !L

  Display1 SHOWDISPLAY

  TestHSprite

  HeliOS_Off

  0 REPORTMOUSE

  CLOSEDOWN
  ;

  TestDisplay
