(c)  Copyright 1989 Commodore-Amiga, Inc.   All rights reserved.
The information contained herein is subject to change without notice, and 
is provided "as is" without warranty of any kind, either expressed or implied.  
The entire risk as to the use of this information is assumed by the user.


                      Creating Sprites in C
                    from the Intuition Pointer

                          by Adam Levin 


The Amiga's sprite hardware makes it easy to display and move sprites. 
The hardest part of using Amiga sprites is creating the sprite image
itself using C statements.  Getting the sprite to look exactly as you want 
by manipulating hexadecimal numbers to alter pixels is tedious and error-prone.
What is needed is a sprite editor that will create the C code automatically.
You can use the Preferences pointer-editor and the p2sprite program listed
below to do the job.


A Sprite Editor
---------------

The Amiga comes with its own sprite editor built-in though you may not be 
aware of it.  The small red arrow used as the Intuition pointer is a sprite.
So the Preferences pointer-editor is actually a sprite editor.  All that we 
need is a way to convert the sprite shape and color data into C statements.

The p2sprite ("pointer to sprite") program will read the current Preferences 
pointer image from your Amiga's memory and automatically create the data 
arrays needed to use an identical-looking sprite in a 'C' program.  If you 
have a Preferences information file, which Preferences saves as
"devs:system-configuration", p2sprite can extract the pointer data from the 
file instead.

To create the C code for a sprite follow these steps.  First, in Preferences,
edit the pointer and its colors to your liking.  The transparent background 
color of the pointer will also be transparent for your C sprite.  When
you're done select "OK" to exit.

Next select either "Save" or "Use" from the main Preferences screen.  If you 
select "Save", all the Preferences information will be written out to the 
file "devs:system-configuration".  You may want to save a copy of your
original system-configuration file before doing this so that you can easily
restore it later.  Use "copy devs:system-configuration to devs:temp-config"
to save it, and "copy devs:temp-config to devs:system-configuration" to 
restore it later.

To convert the sprite that you see on the screen to C statements just type
"p2sprite".  P2sprite will get the pointer data from the active Preferences
setting and display it on the standard output device as C code.  To save it 
to a file type "p2sprite >outfile".

To have p2sprite get the pointer data from the Preferences information file, 
type "p2sprite filename" where "filename" is the name of the file, in this
case, "devs:system-configuration".  The equivalent C code will be displayed
on the standard output device.  To save the pointer as a file of C statements,
use "p2sprite >outfile filename".


Sprite Data in C
----------------

Using the sprite data in your C  program is simple.  First, insert the sprite
file into your source code with your editor.  P2sprite creates two arrays of 
USHORT data, one for the sprite colors and one for the sprite shape.  Next,
add code to your program to make sure the sprite data appears in chip memory.
You can use the TypeOfMem() routine to do this.  If the sprite data is not 
in chip RAM, then use AllocMem() to get some chip RAM and use CopyMem() to
copy the sprite data into it.  Second, initialize a SimpleSprite structure 
with the GetSprite() routine.  Finally, call ChangeSprite() with the sprite 
array as the spriteImage.  Here is a code fragment:

=========  LAUREN, CODE STARTS HERE!=================

      USHORT sprite[] =...  /* def'n of sprite[] from p2sprite.  */

      struct ViewPort *viewport;
      struct SimpleSprite *simplesprite;

          /*  Get address of viewport from screen and 
              initialize simplesprite with GetSprite().  */
 
      ChangeSprite(viewport, simplesprite, sprite);

========== LAUREN, CODE ENDS HERE! ===================

Data created by p2sprite can be used for both hardware and virtual sprites.
Note however that the set-up described here pertains to hardware sprites.  
Also note that sprites edited with the pointer-editor are limited to a 
height of 16 pixels.  There is no such limit in the Amiga hardware; an 
Amiga sprite can be abitrarily tall.


Making a Tall Sprite
--------------------

To make a sprite taller than 16 pixels, create the sprite in sections with
the pointer editor and then join together the resulting C data to define the 
full sprite.  To join two or more sprites together, strip off the first two 
words from each sprite definition except for the first sprite.  The first two 
words in a sprite definition are position control data. 

Next strip off the last two words from each sprite definition except for the 
last sprite.  The last two words in a sprite definition are "reserved data."
For example, the two small sprite definitions shown below could be joined
as follows: 

============ LAUREN, EXAMPLE STARTS HERE! ==================

   USHORT spriteA[] =         and          USHORT spriteB[] =
   {                                       {
     0x0000, 0x0000,                         0x0000, 0x0000,
     0x0000, 0xfc00,                         0xa0c0, 0x0c0a,
     0x7c00, 0xfe00,                         0xbb00, 0xbb00,
     0xaa00, 0xaa00,                         0x0000, 0x0000
     0x0000, 0x0000                        };
    };



could be joined like this -

   USHORT spriteAB[] =
   {                          
     0x0000, 0x0000,      /* Make sure commas appear between each word  */
     0x0000, 0xfc00,      /* but not before the first or after the last */ 
     0x7c00, 0xfe00,
     0xaa00, 0xaa00,
     0xa0c0, 0x0c0a,
     0xbb00, 0xbb00,
     0x0000, 0x0000
   };

================= LAUREN, EXAMPLE ENDS HERE! =================

In addition to the image definition for the pointer, your application must
handle the colors as well.  Here is a routine to set the colors of a sprite, 
given a color array such as the one returned by p2sprite:

========== LAUREN, CODE STARTS HERE =====================

   /*  setSpriteColors
       Sets a sprite's color-registers in the ViewPort's ColorTable.
   */

   BOOL setSpriteColors(viewPort, spriteNum, colors)
   struct ViewPort *viewPort;
   int spriteNum;    /*  0 <= spriteNum <= 7  */

   USHORT *colors;   /*  As returned by p2sprite.  */

   {
   int index;
   ULONG colorRegister;
   /*  Each pair of sprites share a set of four consecutive color registers
       (e.g. Sprites 0 & 1 share 16, 17, 18 and 19).  The color in the first
       of these registers will always be transparent for sprites.
       The array "spriteSecondColor[]" holds the value of the second
       register for each set of four.
   */
   static ULONG spriteSecondColor[] = { 17L, 21L, 25L, 29L };

     if (spriteNum >= 0 && spriteNum <= 7)
     {
        colorRegister = spriteSecondColor[spriteNum >> 1];

        for (index=0; index<3; index++)
            SetRGB4(viewPort, colorRegister + (long)index,
                (long)(0x0f00 & colors[index]) >> 8,
                (long)(0x00f0 & colors[index]) >> 4,
                (long)(0x000f & colors[index]));  

        return(TRUE);
     }
     else
        return(FALSE);
   }

============== LAUREN, CODE ENDS HERE!===========================

Using p2sprite and the Preferences pointer-editor, you will be able to create 
sprites more quickly for your applications.  The method described above is 
designed to work with V1.3 of the Amiga operating system.  Future revisions 
of the OS may change the layout of Preferences information, so use caution
with versions of the operating system beyond V1.3.



============== LAUREN, MAIN LISTING STARTS HERE===========================

/*  p2sprite
    Creates a 'C' code sprite definition for the current Intuition pointer.
    If a filename is given, extracts the pointer information
    from that (system-configuration format) file.
    Adam Levin   Commodore-Amiga
    Manx: Compile with "cc p2sprite.c +L"; Link with "ln p2sprite.o -lc32"
*/

#include <exec/types.h>
#include <libraries/dos.h>
#include <intuition/preferences.h>
#include <stdio.h>

#define INTUIT_LIB "intuition.library"
struct IntuitionBase *IntuitionBase;


/*   A buffer is needed to receive a partial copy of the Preferences
     information.  A structure is defined which contains the same definitions
     as the Preferences structure, up to the last needed item: color19.
*/
struct Bit_O_Prefs
{
    BYTE FontHeight;
    UBYTE PrinterPort;
    USHORT BaudRate;
    struct timeval KeyRptSpeed;
    struct timeval KeyRptDelay;
    struct timeval DoubleClick;
    USHORT PointerMatrix[POINTERSIZE];
    BYTE XOffset;
    BYTE YOffset;
    USHORT color17;
    USHORT color18;
    USHORT color19;
} bit_o_prefs;


main(argc, argv)
int argc;
char *argv[];
{
int p;
long actual;
struct FileHandle *fileHandle;
void printf(), puts(), fprintf(), fputs(), GetPrefs();

    /*  Run only from CLI.  */
    if (argc == 0)
        return(RETURN_WARN);
    else
    {
        /*  Usage  */
        if (argc > 2 || (argc == 2 && argv[1][0] == '?'))
        {
            fprintf(stderr, "\nUsage: %s [filename]\n", argv[0]);
            fputs("Creates a 'C' code sprite definition for the\n", stderr);
            fputs("current Intuition pointer.  If a filename is\n", stderr);
            fputs("given, extracts the pointer information from\n", stderr);
            fputs("that (system-configuration format) file.\n\n", stderr);
            exit(RETURN_WARN);
        }

        if (argc == 2)
        /*  A filename was given; extract the information from the file. */
        {
            if ((fileHandle = Open(argv[1], MODE_OLDFILE)) == NULL)
            {
                fprintf(stderr, "%s: Unable to read from \"%s\".\n",
                    argv[0], argv[1]);
                exit(RETURN_ERROR);
            }

            /*  Read as much of the (system-configuration format) file
                as will fit in the Bit_O_Prefs structure.
            */
            actual = Read(fileHandle, &bit_o_prefs,
                sizeof(struct Bit_O_Prefs));
            Close(fileHandle);

            /*  Read error.  */
            if (actual != sizeof(struct Bit_O_Prefs))
            {
                    fprintf(stderr, "%s: Error reading from \"%s\".\n",
                        argv[0], argv[1]);
                    fputs("It must be of the format created by\n", stderr);
                    fputs("\"Save\"-ing from Preferences.\n", stderr);
                exit(RETURN_FAIL);
            }
        }
        else
        /*  Get pointer information from active Preferences.  */
        {
            /* Open Intuition */
            IntuitionBase = (struct IntuitionBase *)
                OpenLibrary(INTUIT_LIB, LIBRARY_VERSION);
            if (IntuitionBase == NULL)
            {
                fprintf(stderr, "%s: Unable to open \"%s\".\n",
                    argv[0], INTUIT_LIB);
                exit(RETURN_FAIL);
            }

            /*  Copy as much of the Preferences structure as will
                fit in the Bit_O_Prefs structure.
            */
            GetPrefs(&bit_o_prefs, sizeof(struct Bit_O_Prefs));

            CloseLibrary(IntuitionBase);
        }

        /*  Print the information to stdout.  */
        puts("/*  Sprite color data:  */\n");
        puts("USHORT colors[] =\n{\n");
        printf("    0x%04x,\n", bit_o_prefs.color17);
        printf("    0x%04x,\n", bit_o_prefs.color18);
        printf("    0x%04x\n};\n\n", bit_o_prefs.color19);

        puts("/*  Sprite shape data:  */\n");
        puts("USHORT sprite[] =\n{\n");
        for (p=0; p<POINTERSIZE; p+=2)
            printf("     0x%04x, 0x%04x%s",
                bit_o_prefs.PointerMatrix[p], bit_o_prefs.PointerMatrix[p+1],
                    (p < POINTERSIZE-2) ? ",\n" : "\n};\n");
    }
    return(RETURN_OK);
}



