LoadAnim()
loads an animation, as shown in the code fragment in the example below, which is part of the Initialize()
function. Example 1: Loading an animation.
if ( ( gExplosionAnim = LoadAnim("jsdata/art/boom.anim",
MEMTYPE_CEL )) == 0)
{
PRT(("Can't load the explosion animation\n"));
goto DONE;
}
UnifyAnimation(gExplosionAnim);
gExplosionCCB = GetAnimCel(gExplosionAnim, 0);
LAST_CEL(gExplosionCCB);
LoadAnim()
expects the name of an animation file in 3DO file format, a buffer, and a pointer to an ANIM
structure that is filled by LoadAnim()
. The ANIM
structure has as one of its fields a pointer to an array of AnimFrame
structures. Together, the two structures contain all the information you need to manipulate the animation.
Example 2: The AnimFrame and ANIM structures.
typedef struct tag_AnimFrame
{
CCB *af_CCB; /*Pointer to CCB for this frame*/
char *af_PLUT; /*Pointer to PLUT for this frame*/
char *af_pix; /*Pointer to pixels for this frame*/
int32 reserved;
} AnimFrame;
typedef struct tag_ANIM
{
long num_Frames; /*max number of PDATs or CCBs in file*/
frac16 cur_Frame; /*allow fract values for smooth speed*/
long num_Alloced_Frames;
AnimFrame *pentries;
} ANIM;
Playing the Animation
In the simplest case, you can loop through calls to GetAnimCel()
to play the animation. GetAnimCel()
takes an ANIM
structure created by LoadAnim()
and a frame increment as arguments. It returns a pointer to the CCB of the next cel in an animation sequence and adds frameIncrement to the current frame counter within the ANIM. It does not draw the cel.
The example below shows a code fragment from the TargetAction()
function in jsanimation.c which retrieves and draws the animation. The FRAME_INCREMENT macro is defined at the beginning of the program.
Example 3: Retrieving and drawing an animation.
The actual switching of buffers is done by the
/*
Animate the UFO: If it's still exploding, play the explosion's next frame,
otherwise display the UFO (after a nominal post-explosion delay).
*/
{
if (gBoomCount)
{
gBoomCount--;
if (gBoomCount)
{
GetAnimCel(gExplosionAnim, FRAME_INCREMENT);
DrawCels(gScreenContext->sc_BitmapItems
[gScreenContext->sc_curScreen], gExplosionCCB);
}
else
{
gExplosionAnim->cur_Frame = 0; /* Reset animation to first frame */
gPostBoomDelay = gExplosionAnim->num_Frames * 5;
/* Wait awhile before showing the target */
}
}
else
{
if (gPostBoomDelay)
gPostBoomDelay--;
if (!gPostBoomDelay)
DrawCels(gScreenContext->sc_BitmapItems
[gScreenContext->sc_curScreen], aTarget);
}
}
main()
function, which also displays the image, handles control pad input-discussed in "Getting User Input"-and handles the drawing of the UFO and explosion.
Example 4: Buffer switching and screen display.
while ( HandleControlPad() >= 0 )
{
/* Draw the background image */
DrawImage(gScreenContext->sc_Screens [gScreenContext->
sc_curScreen], gBackgroundImage, gScreenContext);
/* Handle the drawing of the UFO cel and the explosion */
TargetAction(gUFO_CCB);
/*
Display the current screen.
DisplayScreen waits for the next vertical blank, then
tells the display hardware to use the specified screen
as the display buffer. The hardware continues showing
this buffer on the TV every frame until another call
to DisplayScreen specifies a different buffer.
*/
DisplayScreen(gScreenContext->sc_Screens[gScreenContext->
sc_curScreen], 0);
/* Toggle the current screen */
gScreenContext->sc_curScreen = 1 - gScreenContext->
sc_curScreen;
}