Copyright (c) Hyperion Entertainment and contributors.

Virtual Sprites

From AmigaOS Documentation Wiki
Revision as of 20:58, 27 May 2013 by Steven Solie (talk | contribs) (Created page with "== Using Virtual Sprites == This section describes how to set up the VSprite structure so that it represents a true VSprite. True VSprites are managed by the GELs system whic...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Using Virtual Sprites

This section describes how to set up the VSprite structure so that it represents a true VSprite. True VSprites are managed by the GELs system which converts them to Simple Sprites and displays them. (Later sections describe how a VSprite structure can be set up for Bobs and AnimComps.)

Before the system is told of a VSprite's existence, space for the VSprite data structure must be allocated and initialized to "correctly" represent a VSprite. Since the system does no validity checking on the VSprite structure, the result of using a bogus structure is usually a fireworks display, followed by a system failure.

The system software provides a way to detect collisions between VSprites and other on-screen objects. There is also a method of extending the VSprite structure to incorporate user defined variables. These subjects are applicable to all GELs and are explained later in "Collisions and GEL Structure Extensions".

Specification of VSprite Structure

The VSprite structure is defined in the include file <graphics/gels.h> as follows:

/* VSprite structure definition */
struct VSprite {
    struct VSprite *NextVSprite;
    struct VSprite *PrevVSprite;
    struct VSprite *DrawPath;
    struct VSprite *ClearPath;
    WORD            OldY, OldX;
    WORD            Flags;
    WORD            Y, X;
    WORD            Height;
    WORD            Width;
    WORD            Depth;
    WORD            MeMask;
    WORD            HitMask;
    WORD           *ImageData;
    WORD           *BorderLine;
    WORD           *CollMask;
    WORD           *SprColors;
    struct Bob     *VSBob;
    BYTE            PlanePick;
    BYTE            PlaneOnOff;
    VUserStuff      VUserExt;
    };

There are two primary ways to allocate and fill in space for VSprite data. They can be statically declared, or a memory allocation function can be called and they can be filled in programmatically. The declaration to statically set up a VSprite structure is listed below.

/* VSprite static data definition.
** must set the following for TRUE VSprites:
**    VSPRITE flag.
**    Width to 1.
**    Depth to 2.
**    VSBob to NULL.
*/
struct VSprite myVSprite =
    {
    NULL, NULL, NULL, NULL, 0, 0, VSPRITE, 0, 0, 5, 1, 2, 0, 0,
    &myImage, 0, 0, &mySpriteColors, NULL, 0x3, 0, 0
    };

This static allocation gives the required VSprite structure, but does not allocate or set up collision masks for the VSprite. Note that the VSprite structure itself does not need to reside in Chip memory.

Refer to the makeVSprite() and freeVSprite() functions in the animtools.c listing at the end of the chapter for an example of dynamically allocating, initializing and freeing a VSprite structure.

Reserved VSprite Members

These VSprite structure members are reserved for system use (do not write to them):

NextVSprite and PrevVSprite
These are used as links in the GelsInfo list.
DrawPath and ClearPath
These are used for Bobs, not true VSprites.
OldY and OldX
Previous position holder, the system uses these for double buffered Bobs, but application programs can read them too.

The values can be set like this:

myVSprite.NextVSprite = NULL;
myVSprite.PrevVSprite = NULL;
myVSprite.DrawPath  = NULL;
myVSprite.ClearPath = NULL;
myVSprite.OldY = 0;
myVSprite.OldX = 0;

Using VSprite Flags

The Flags member of the VSprite structure is both read and written by the system. Some bits are used by the application to inform the system; others are used by the system to indicate things to the application.

The only Flags bits that are used by true VSprites are:

VSPRITE
This may be set to indicate to the system that it should treat the structure as a true VSprite, not part of a Bob. This affects the interpretation of the data layout and the use of various system variables.
VSOVERFLOW
The system sets this bit in the true VSprites that it is unable to display. This happens when there are too many in the same scan line, and the system has run out of Simple Sprites to assign. It indicates that this VSprite has not been displayed. If no sprites are reserved, this means that more than eight sprites touch one scan line. This bit will not be set for Bobs and should not be changed by the application.
GELGONE
If the system has set GELGONE bit in the Flags member, then the GEL associated with this VSprite is not on the display at all, it is entirely outside the GEL boundaries. This area is defined by the GelsInfo members topmost, bottommost, leftmost and rightmost (see the <graphics/rastport.h> include file).

On the basis of that information, the application may decide that the object need no longer be part of the GEL list and may decide to remove it to speed up the consideration of other objects. Use RemVSprite() (or RemBob(), if it's a Bob) to do this. This bit should not be changed by the application.

The VSprite.Flags value should be initialized like this for a VSprite GEL:

myVSprite.Flags = VSPRITE;

VSprite Position

To control the position of a VSprite, the x and y variables in the VSprite structure are used. These specify where the upper left corner of the VSprite will be, relative to the upper left corner of the playfield area it appears over. So if VSprites are used under Intuition and within a screen, they will be positioned relative to the upper left-hand corner of the screen.

In a 320x200 screen, a y value of 0 puts the VSprite at the top of that display, a y value of (200 - VSprite height) puts the VSprite at the bottom. And an x value of 0 puts the VSprite at the left edge of that display, while an x value of (320 - VSprite width) puts the VSprite at the far right. Values of less than (0,0) or greater than (320, 200) may be used to move the VSprite partially or entirely off the screen, if desired.

See Graphics Primitives for more information on display coordinates and display size. See the "Amiga Hardware Reference Manual" for more information on hardware sprites.

Position VSprites Properly
It is important that the starting position of true VSprites is not less than -20 in the y direction, which is the start of the active display area for sprites. Also, if they are moved too far to the left, true VSprites may not have enough DMA time to be displayed.

The x, y values may be set like this to put the VSprite in the upper-left:

myVSprite.Y = 0;
myVSprite.X = 0;

VSprite Image Size

A true VSprite is always one word (16 pixels) wide and may be any number of lines high. It can be made to appear thinner by making some pixels transparent. Like Simple Sprites, VSprite pixels are always the size of a pixel in low-resolution mode (320x200); regardless of the resolution the display is set to. To specify how many lines make up the VSprite image, the VSprite structure member, Height, is used.

VSprites always have a Depth of two, allowing for three colors. The values may be set like this:

myVSprite.Width  = 1;      /* ALWAYS 1 for true VSprites. */
myVSprite.Height = 5;      /* The example height. */
myVSprite.Depth  = 2;      /* ALWAYS 2 for true VSprites. */

VSprites and Collision Detection

Some members of the VSprite data structure are used for special purposes such as collision detection, user extensions or for system extensions (such as Bobs and AnimComps). For most applications these fields are set to zero:

myVSprite.HitMask    = 0;  /* These are all used for collision detection */
myVSprite.MeMask     = 0;
myVSprite.BorderLine = 0;
myVSprite.CollMask   = 0;

myVSprite.VUserExt = 0;    /* Only use this for user extensions to VSprite */

myVSprite.VSBob = NULL;    /* Only Bobs and AnimComps need this */

The special uses of this fields are explained further in the sections that follow.

VSprite Image Data

The ImageData pointer of the VSprite structure must be initialized with the address of the first word of the image data array. The image data array must be in Chip memory. It takes two sequential 16-bit words to define each line of a VSprite. This means that the data area containing the VSprite image is always "Heightx2" (10 in the example case) words long.

A VSprite image is defined just like a real hardware sprite. The combination of bits in corresponding locations in the two data words that define each line select the color for that pixel. The first of the pair of words supplies the low-order bit of the color selector for that pixel; the second word supplies the high-order bit.

These binary values select colors as follows:

00 selects "transparent"
01 selects the first of three VSprite colors
10 selects the second VSprite color
11 selects the third VSprite color

In those areas where the combination of bits yields a value of 0, the VSprite is transparent. This means that the playfield, and all Bobs and AnimComps, and any VSprite whose priority is lower than this VSprite will all show through in transparent sections. For example:

(&VSprite->ImageData)      1010 0000 0000 0000
(&VSprite->ImageData + 1)  0110 0000 0000 0000

Reading from top to bottom, left to right, the combinations of these two sequential data words form the binary values of 01, 10, 11, and then all 00s. This VSprite's first pixel will be color 1, the next color 2, the third color 3. The rest will be transparent, making this VSprite appear to be three pixels wide. Thus, a three-color image, with some transparent areas, can be formed from a data set like the following sample:

Address    Binary Data            VSprite Image Data
-------    -----------            ------------------
mem        1111 1111 1111 1111    Defines top line
mem + 1    1111 1111 1111 1111    3333 3333 3333 3333

mem + 2    0011 1100 0011 1100    Defines second line
mem + 3    0011 0000 0000 1100    0033 1100 0011 3300

mem + 4    0000 1100 0011 0000    Defines third line
mem + 5    0000 1111 1111 0000    0000 3322 2233 0000

mem + 6    0000 0010 0100 0000    Defines fourth line
mem + 7    0000 0011 1100 0000    0000 0032 2300 0000

mem + 8    0000 0001 1000 0000    Defines fifth line
mem + 9    0000 0001 1000 0000    0000 0003 3000 0000

The VSprite.Height for this sample image is 5.

Specifying the Colors of a VSprite

The system software provides a great deal of versatility in the choice of colors for Virtual Sprites. Each VSprite has "its own set" of three colors, pointed to by SprColors, which the system jams into the display's Copper list as needed.

SprColors points to the first of three 16-bit values. The first value represents the color used for the VSprite bits that select color 1, the second value is color 2, and the third value is color 3. When the system assigns a hardware sprite to carry the VSprite's image, it jams these color values into the Copper list (the intermediate Copper list, "not" the color table), so that the View's colors will be correct for this VSprite at the time the VSprite is displayed. It doesn't jam the original palette's colors back after the VSprite is done. If there is another VSprite later, that VSprite's colors will get jammed; if there is not another VSprite, the colors will remain the same until the next ViewPort's colors get loaded.

If the SprColors pointer is set to NULL, that VSprite does not generate a color-change instruction stream for the Copper. Instead, the VSprite appears drawn in whatever color set that the hardware sprite happens to have in it already.

Since the registers are initially loaded with the colors from the ViewPort's ColorMap, if all VSprites have NULL SprColors, they will appear in the ViewPort's colors.

To continue our example, a set of colors can be declared and the VSprite colors set with the following statements:

WORD mySpriteColors[] = { 0x0000, 0x00f0, 0x0f00 }; /* Declare colors statically */

myVSprite.SprColors = mySpriteColors;               /* Assign colors to VSprite */

Adding and Removing VSprites

Once a true VSprite has been set up and initialized, the obvious next step is to give it to the system by adding it to the GEL list. The VSprite may then be manipulated as needed. Before the program ends, the VSprite should be removed from the GELs list by calling RemVSprite().

A typical calling sequence could be performed like so:

struct VSprite  myVSprite = {0};
struct RastPort myRastPort = {0};

AddVSprite(&myVSprite, &myRastPort);

/* Manipulate the VSprite as needed here */

RemVSprite(&myVSprite);

The &myVSprite argument is a fully initialized VSprite structure and &myRastPort is the RastPort with which this VSprite is to be associated. Note that you will probably not like the results if you try to RemVSprite() a VSprite that has not been added to the system with AddVSprite(). See the SDK for additional information on these functions.

Changing VSprites

Once the VSprite has been added to the GELs list and is in the display, some of its characteristics can be changed dynamically by:

  • Changing y, x to a new VSprite position
  • Changing ImageData to point to a new VSprite image
  • Changing SprColors to point to a new VSprite color set

Study the next two sections to find out how to reserve hardware Sprites for use outside the VSprite system and how to assign the VSprites.

Getting the VSprite List in Order

When the system has displayed the last line of a VSprite, it is able to reassign the hardware sprite to another VSprite located at a lower position on the screen. The system allocates hardware sprites in the order in which it encounters the VSprites in the list. Therefore, the list of VSprites must be sorted before the system can assign the use of the hardware Sprites correctly.

The function SortGList() must be used to get the GELs in the correct order before the system is asked to display them. This sorting step is essential! It should be done before calling DrawGList(), whenever a GEL has changed position. This function is called as follows:

struct RastPort myRastPort = {0};

SortGList(&myRastPort);

The only argument is a pointer to the RastPort structure containing the GelsInfo.

Displaying the VSprites

The next few sections explain how to display the VSprites. The following system functions are used:

DrawGList()
Draws the VSprites into the current RastPort.
MrgCop()
Installs the VSprites into the display.
LoadView()
Asks the system to display the new View.
WaitTOF()
Synchronizes the functions with the display.

Drawing the Graphics Elements

The system function called DrawGList() looks through the list of GELS and prepares the necessary Copper instructions and memory areas to display the data. This function is called as follows:

struct RastPort myRastPort = {0};
struct ViewPort myViewPort = {0};

DrawGList(&myRastPort, &myViewPort);

The myRastPort argument specifies the RastPort containing the GelsInfo list with the VSprites that you want to display. The &myViewPort argument is a pointer to the ViewPort for which the VSprites will be created.

Merging VSprite Instructions

Once DrawGList() has prepared the necessary instructions and memory areas to display the data, the VSprites are installed into the display with MrgCop(). (DrawGList() does not actually draw the VSprites, it only prepares the Copper instructions.)

struct View *view;

MrgCop(view);

The view is a pointer to the View structure whose Copper instructions are to be merged.

Loading the New View

Now that the display instructions include the definition of the VSprites, the system can display this newly configured View with the LoadView() function:

struct View *view;

LoadView(view);

Again, view is a pointer to the View that contains the the new Copper instruction list (if you are using GELs in an Intuition Screen, do not call LoadView().)

The Copper instruction lists are double-buffered, so this instruction does not actually take effect until the next display field occurs. This avoids the possibility of some function trying to update the Copper instruction list while the Copper is trying to use it to create the display.

Synchronizing with the Display

To synchronize application functions with the display, call the system function WaitTOF().

WaitTOF() holds your task until the vertical-blanking interval (blank area at the top of the screen) has begun. At that time, the system has retrieved the current Copper instruction list and is ready to allow generation of a new list.

WaitTOF();

WaitTOF() takes no arguments and returns no values. It simply suspends your task until the video beam is at the top of field.