Programming AmigaOS in C

9. Animation

Bobs or Blitter Objects

Bobs are used for animation on the Amiga, the main advantage over Sprites is that you can have a lot more of them and can be of any size. Bobs are controlled by the blitter which can move large graphics areas around very fast.
To define a bob you need to specify data using layers, each layer can have 2 colours, the colours are defined by the current palette. You can also specify plane pick to select which colours the bob uses.

To use bobs, you need to include the following header files:
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <intuition/intuition.h>
#include <graphics/gels.h>

Here is a sample bob setup using two alternate images (see Bob.c from the Rom Kernel Manual's Lib Examples or RKMCompanion disk):

#define GEL_SIZE 4 /* number of lines in the bob */
/* Bob data - two sets that are alternated between. Note that this */
/* data is at the resolution of the screen. */
/* data is 2 planes by 2 words by GEL_SIZE lines */
__chip WORD bob_data1[2 * 2 * GEL_SIZE] =
{
      /* plane 1 */
      0xffff, 0x0003, 0xfff0, 0x0003, 0xfff0, 0x0003, 0xffff, 0x0003,
      /* plane 2 */
      0x3fff, 0xfffc, 0x3ff0, 0x0ffc, 0x3ff0, 0x0ffc, 0x3fff, 0xfffc
};
/* data is 2 planes by 2 words by GEL_SIZE lines */
__chip WORD bob_data2[2 * 2 * GEL_SIZE] =
{
      /* plane 1 */
      0xc000, 0xffff, 0xc000, 0x0fff, 0xc000, 0x0fff, 0xc000, 0xffff,
      /* plane 2 */
      0x3fff, 0xfffc, 0x3ff0, 0x0ffc, 0x3ff0, 0x0ffc, 0x3fff, 0xfffc
};
NEWBOB myNewBob = /* Data for the new bob structure defined in animtools.h    */
{ /* Initial image, WORD width, line height */
      bob_data2, 2, GEL_SIZE,             /* Image depth, plane pick, plane    on off, VSprite flags */
      2, 3, 0, SAVEBACK | OVERLAY,        /* dbuf (0=false), raster depth,    x,y position, hit mask, */
      0, 2, 160, 100, 0,0,                /* me mask */
};
 

If your compiler does not support the '__chip' modifier used in SAS/C or other old compilers, then you need to allocate chip ram and copy the data from the bob_data to the allocated ram (see below).
In the myNewBob structure, replace bob_data2 with bob_data2_ptr instead. This only applies to classic Amiga systems such as A500, A1200 that has Chip RAM and using the custom chipset.
If the system does not use the custom chips and uses an RTG card, then you can instead use MEMF_SHARED type memory for graphics.

/* Allocate chip  memory for Bob data */
 WORD  bob_data2_ptr = AllocVec( 2*2*GEL_SIZE, MEMF_CHIP);
 WORD  bob_data1_ptr = AllocVec( 2*2*GEL_SIZE, MEMF_CHIP);
/* Copy data from  bob_data1 and 2 to bob_data1_ptr1 and 2 */
   copymem(bob_data1,  bob_data1_ptr,  2*2*GEL_SIZE);
   copymem(bob_data2,  bob_data2_ptr,  2*2*GEL_SIZE);

This is the structure for the Window to place the Bob into, it is a 400 x 150 window placed on the Workbench screen:

struct NewWindow myNewWindow =
   { /* information for the new window */
   80, 20, 400, 150, -1, -1, CLOSEWINDOW | INTUITICKS,
   ACTIVATE | WINDOWCLOSE | WINDOWDEPTH | RMBTRAP,
   NULL, NULL, "Bob", NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN
   };
 

Now draw the bob on the window with the bobDrawGList() function. rport is a pointer to to the rastport ie the Window's bitmap
structuture and vport is a portion of the physical display to be viewed, you can have multiple viewports on one display seperated by
a least one blank line.

Functions:
void SortGList(struct RastPort *rp)
void DrawGList(struct RastPort *rp, struct ViewPort *vp)
void WaitTOF(void)

/* Draw the Bobs into the RastPort. */
   VOID bobDrawGList(struct RastPort *rport, struct ViewPort *vport)
   {
       /* This function sorts the gel list by its x,y co-ords, required before DrawGList */ 
       SortGList(rport);
       /* This function draws all the gels including bobs and vsprites */ 
       DrawGList(rport, vport); 
       /* If the GelsList includes true VSprites, MrgCop() and LoadView() here */
       WaitTOF() ; /* Wait for next top of frame refresh interval before continuing */ 
   }

For AmigaOS 4, prefix SortGList, DrawGList and WaitTOF with 'IGraphics->'.

The next bit of code does the actual display and starts animation of Bobs. You need a Bob structure to store the bob information.
The most useful functions are:

Functions:
void AddBob(struct Bob *bob, struct RaspPort *rp) - Add a bob to the current gel list.
void RemBob(struct Bob *bob) - Remove bob from the current gel list.
void RemIBob(struct Bob *bob, struct RaspPort *rp, struct ViewPort *) - Remove bob from the current gel list and current viewport.
void InitMasks(struct VSprite *vs) - Initialises BorderLine and CollMask of a VSprite or bob.

VOID do_Bob(struct Window *win)
   {
      struct Bob *myBob;
      struct GelsInfo *my_ginfo;
   if (NULL == (my_ginfo = setupGelSys(win->RPort, 0x03)))
         return_code = RETURN_WARN;
      else
     {
      /* Create the Bob using makeBob() from Animtools.c to allocate    memory and fill in the required information for Bob structure
           to create the Bob object */
       if (NULL == (myBob = makeBob(&myNewBob)))
             return_code = RETURN_WARN;
       else
       {
            /* Add the bob to the window's rastport ready for display */
            AddBob(myBob, win->RPort);
            /* Display the gels (bobs) in the given window and viewport */
            bobDrawGList(win->RPort, ViewPortAddress(win));
            /* do animation in this function */
            process_window(win, myBob);
           /* When done, remove bob from system */
           RemBob(myBob);
           /* Alternatively, use RemIBob(myBob, win->RPort, ViewPortAddress(win)); */
           /* Update the display to remove it from the screen */
           bobDrawGList(win->RPort, ViewPortAddress(win));
          /* Free up any memory uses by bob  */ 
           freeBob(myBob, myNewBob.nb_RasDepth);
       }
        cleanupGelSys(my_ginfo,win->RPort);
      }
   }
 

Animtools.c code can be found in the RKM_Manuals, Lib_examples in the NDK or from the RKMCompanion on Aminet. It will contain the definitions for setupGelSys, makeBob, bobDrawGList, process_window, FreeBob, cleanupGelSys.
For AmigaOS 4, prefix the functions AddBob and RemBob (or RemIBob) with 'IGraphics->'. Prefix ViewPortAddress with 'IIntuition->'.

Finally the code that does the animation which in this case moves the Bob depending on mouse movement using the values
of the MouseX and MouseY values with a sight offset and changing the X and Y values of the bob object. It will also change
the bob's image by changing the ImageData value to different images defined earlier.

VOID process_window(struct Window *win, struct Bob *myBob)
{
   struct IntuiMessage *msg;
/* FOREVER is equivalent to an empty for() loop that never ends */
   FOREVER {
     /* Wait for a signal bit to be returned from the window */
     Wait(1L << win->UserPort->mp_SigBit);
     /* If a message is received from window then process it */
     while (NULL != (msg = (struct IntuiMessage *)GetMsg(win->UserPort)))
     {
       /* only CLOSEWINDOW and INTUITICKS are active */
       if (msg->Class == CLOSEWINDOW)
      {
          /* If the CloseWindows gadget is pressed, then reply and exit this function */
           ReplyMsg((struct Message *)msg);
           return;
       }
      /* Must be INTUITICKS: change x and y values on the fly. Note:
      ** do not have to add window offset, Bob is relative to the
      ** window (sprite relative to screen).
      */
      myBob->BobVSprite->X = msg->MouseX + 20;
      myBob->BobVSprite->Y = msg->MouseY + 1;
      ReplyMsg((struct Message *)msg);
     }
     /* after getting a message, change image data on the fly */
      myBob->BobVSprite->ImageData = (myBob->BobVSprite->ImageData == bob_data1) ? bob_data2 :    bob_data1;
     InitMasks(myBob->BobVSprite);      /* set up masks for new image */
     bobDrawGList(win->RPort, ViewPortAddress(win));
    }
   }
 

For AmigaOS 4, prefix Wait and ReplyMsg with 'IExec->'. Prefix InitMasks and ViewPortAddress with 'IGraphics->'.
See animtools.c code for definition for bobDrawGList function.

Next Page