SPRITE.C

/*========================================================================== 
*
* Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
* Copyright (C) 1994-1995 ATI Technologies Inc. All Rights Reserved.
*
* File:sprite.c
* Content:sprite manipulation functions
*
***************************************************************************/
#include "foxbear.h"

/*
* CreateSprite
*/
HSPRITE *CreateSprite (
USHORT bitmapCount,
LONG x,
LONG y,
USHORT width,
USHORT height,
USHORT xmax,
USHORT ymax,
SHORT as,
BOOL active )
{
HSPRITE *hSprite;
USHORT i;

hSprite = MemAlloc( sizeof (HSPRITE) );
if( hSprite == NULL )
{
ErrorMessage( "hSprite in CreateSprite" );
}

hSprite->hSBM = CMemAlloc( bitmapCount, sizeof (HSPRITE_BM) );
if( hSprite->hSBM == NULL )
{
MemFree( hSprite );
ErrorMessage( "hSprite->hSBM in CreateSprite" );
}

hSprite->active = active;
hSprite->bitmapCount = bitmapCount;
hSprite->x = x;
hSprite->y = y;
hSprite->width = width;
hSprite->height = height;
hSprite->xv = 0;
hSprite->yv = 0;
hSprite->xa = 0;
hSprite->ya = 0;
hSprite->xmax = xmax;
hSprite->ymax = ymax;
hSprite->absSwitch = as;
hSprite->relSwitch = 0;
hSprite->switchType = HOR;
hSprite->switchForward = TRUE;
hSprite->switchDone = FALSE;

for( i = 0; i < bitmapCount; ++i )
{
hSprite->hSBM[i].hBM = NULL;
}

return hSprite;

} /* CreateSprite */

/*
* BitBltSprite
*/
BOOL BitBltSprite (
HSPRITE *hSprite,
GFX_HBM hBM,
ACTION action,
DIRECTION direction,
SHORT x,
SHORT y,
USHORT w,
USHORT h )
{
USHORT count;

if( hSprite == NULL )
{
ErrorMessage( "hSprite in BitBltSprite" );
}

if( hBM == NULL )
{
ErrorMessage( "hBM in BitBltSprite" );
}

if( (x >= hSprite->width) || (y >= hSprite->height) )
{
ErrorMessage( "x or y in BitBltSprite" );
}

count = 0;
while( hSprite->hSBM[count].hBM != NULL )
{
count++;
if( count >= hSprite->bitmapCount )
{
ErrorMessage( "Bitmap overflow in BitBltSprite" );
}
}

hSprite->hSBM[count].hBM = hBM;
hSprite->hSBM[count].action = action;
hSprite->hSBM[count].direction = direction;
hSprite->hSBM[count].x = x;
hSprite->hSBM[count].y = y;
hSprite->hSBM[count].width = w;
hSprite->hSBM[count].height = h;

return TRUE;

} /* BitBltSprite */

/*
* SetSpriteAction
*/
BOOL SetSpriteAction ( HSPRITE *hSprite, ACTION action, DIRECTION direction )
{
USHORT c;

c = 0;

if( direction == SAME )
{
direction = hSprite->currentDirection;
}

while( (hSprite->hSBM[c].action != action) || (hSprite->hSBM[c].direction != direction) )
{
++c;
}

hSprite->currentAction = action;
hSprite->currentDirection = direction;
hSprite->currentBitmap = c;
hSprite->relSwitch = 0;

return TRUE;

} /* SetSpriteAction */

/*
* ChangeSpriteDirection
*/
BOOL ChangeSpriteDirection( HSPRITE *hSprite )
{
DIRECTION direction;

if( hSprite->currentDirection == RIGHT )
{
direction = LEFT;
}
else
{
direction = RIGHT;
}

SetSpriteAction( hSprite, hSprite->currentAction, direction );

return TRUE;

} /* ChangeSpriteDirection */

/*
* GetSpriteAction
*/
ACTION GetSpriteAction( HSPRITE *hSprite )
{
return hSprite->currentAction;

} /* GetSpriteAction */


/*
* GetSpriteDirection
*/
DIRECTION GetSpriteDirection( HSPRITE *hSprite )
{
return hSprite->currentDirection;

} /* GetSpriteDirection */

/*
* SetSpriteActive
*/
BOOL SetSpriteActive( HSPRITE *hSprite, BOOL active )
{
hSprite->active = active;

if( active == FALSE )
{
hSprite->xv = 0;
hSprite->yv = 0;
hSprite->xa = 0;
hSprite->ya = 0;
}

return TRUE;

} /* SetSpriteActive */

/*
* GetSpriteActive
*/
BOOL GetSpriteActive( HSPRITE *hSprite )
{
return hSprite->active;

} /* GetSpriteActive */

/*
* SetSpriteVelX
*/
BOOL SetSpriteVelX( HSPRITE *hSprite, LONG xv, POSITION position )
{
if( hSprite->active == FALSE )
{
return FALSE;
}

if( position == P_ABSOLUTE )
{
hSprite->xv = xv;
}
else if( position == P_RELATIVE )
{
hSprite->xv += xv;
}

return TRUE;

} /* SetSpriteVelX */

/*
* GetSpriteVelX
*/
LONG GetSpriteVelX( HSPRITE *hSprite )
{
return hSprite->xv;

} /* GetSpriteVelX */

/*
* SetSpriteVelY
*/
BOOL SetSpriteVelY( HSPRITE *hSprite, LONG yv, POSITION position )
{
if( hSprite->active == FALSE )
{
return FALSE;
}

if( position == P_ABSOLUTE )
{
hSprite->yv = yv;
}
else if( position == P_RELATIVE )
{
hSprite->yv += yv;
}

return TRUE;

} /* SetSpriteVelY */

/*
* GetSpriteVelY
*/
LONG GetSpriteVelY( HSPRITE *hSprite )
{
return hSprite->yv;

} /* GetSpriteVelY */

/*
* SetSpriteAccX
*/
BOOL SetSpriteAccX ( HSPRITE *hSprite, LONG xa, POSITION position )
{
if( position == P_ABSOLUTE )
{
hSprite->xa = xa;
}
else if( position == P_RELATIVE )
{
hSprite->xa += xa;
}
return TRUE;

} /* SetSpriteAccX */

/*
* GetSpriteAccX
*/
LONG GetSpriteAccX( HSPRITE *hSprite )
{
return hSprite->xa;

} /* GetSpriteAccX */

/*
* SetSpriteAccY
*/
BOOL SetSpriteAccY ( HSPRITE *hSprite, LONG ya, POSITION position )
{
if( position == P_ABSOLUTE )
{
hSprite->ya = ya;
}
else if( position == P_RELATIVE )
{
hSprite->ya += ya;
}
return TRUE;

} /* SetSpriteAccY */

/*
* GetSpriteAccY
*/
LONG GetSpriteAccY( HSPRITE *hSprite )
{
return hSprite->ya;

} /* GetSpriteAccY */

/*
* SetSpriteX
*/
BOOL SetSpriteX( HSPRITE *hSprite, LONG x, POSITION position )
{
if( hSprite->active == FALSE )
{
return FALSE;
}

if( position == P_AUTOMATIC )
{
hSprite->xv += hSprite->xa;
hSprite->x += hSprite->xv;
}
else if( position == P_ABSOLUTE )
{
hSprite->x = x;
}
else if( position == P_RELATIVE )
{
hSprite->x += x;
}

if( hSprite->x < 0 )
{
hSprite->x += hSprite->xmax << 16;
}
else if( hSprite->x >= hSprite->xmax << 16 )
{
hSprite->x -= hSprite->xmax << 16;
}
return TRUE;

} /* SetSpriteX */

/*
* GetSpriteX
*/
LONG GetSpriteX( HSPRITE *hSprite )
{
return hSprite->x;

} /* GetSpriteX */

/*
* SetSpriteY
*/
BOOL SetSpriteY ( HSPRITE *hSprite, LONG y, POSITION position )
{
if( hSprite->active == FALSE )
{
return FALSE;
}

if( position == P_AUTOMATIC )
{
hSprite->yv += hSprite->ya;
hSprite->y += hSprite->yv;
}
else if( position == P_ABSOLUTE )
{
hSprite->y = y;
}
else if( position == P_RELATIVE )
{
hSprite->y += y;
}

if( hSprite->y < 0 )
{
hSprite->y += hSprite->ymax << 16;
}
else if( hSprite->y >= hSprite->ymax << 16 )
{
hSprite->y -= hSprite->ymax << 16;
}

return TRUE;

} /* SetSpriteY */

/*
* GetSpriteY
*/
LONG GetSpriteY( HSPRITE *hSprite )
{
return hSprite->y;

} /* GetSpriteY */

/*
* SetSpriteSwitch
*/
BOOL SetSpriteSwitch ( HSPRITE *hSprite, LONG absSwitch, POSITION position )
{
if( position == P_ABSOLUTE )
{
hSprite->absSwitch = absSwitch;
}
else if( position == P_RELATIVE )
{
hSprite->absSwitch += absSwitch;
}
return TRUE;

} /* SetSpriteSwitch */


/*
* IncrementSpriteSwitch
*/
BOOL IncrementSpriteSwitch ( HSPRITE *hSprite, LONG n )
{
hSprite->relSwitch += n;
return TRUE;

} /* IncrementSpriteSwitch */

/*
* SetSpriteSwitchType
*/
BOOL SetSpriteSwitchType( HSPRITE *hSprite, SWITCHING switchType )
{
hSprite->switchType = switchType;
hSprite->relSwitch = 0;
return TRUE;

} /* SetSpriteSwitchType */


/*
* GetSpriteSwitchType
*/
SWITCHING GetSpriteSwitchType ( HSPRITE *hSprite )
{
return hSprite->switchType;

} /* GetSpriteSwitchType */

/*
* SetSpriteSwitchForward
*/
BOOL SetSpriteSwitchForward( HSPRITE *hSprite, BOOL switchForward )
{
hSprite->switchForward = switchForward;

return TRUE;

} /* SetSpriteSwitchForward */

/*
* GetSpriteSwitchForward
*/
BOOL GetSpriteSwitchForward( HSPRITE *hSprite )
{
return hSprite->switchForward;

} /* GetSpriteSwitchForward */

/*
* SetSpriteSwitchDone
*/
BOOL SetSpriteSwitchDone( HSPRITE *hSprite, BOOL switchDone )
{
hSprite->switchDone = switchDone;
return TRUE;

} /* SetSpriteSwitchDone */


/*
* GetSpriteSwitchDone
*/
BOOL GetSpriteSwitchDone( HSPRITE *hSprite )
{
return hSprite->switchDone;

} /* GetSpriteSwitchDone */

/*
* SetSpriteBitmap
*/
BOOL SetSpriteBitmap ( HSPRITE *hSprite, USHORT currentBitmap )
{
USHORT c;

c = 0;
while( (hSprite->currentAction != hSprite->hSBM[c].action) ||
(hSprite->currentDirection != hSprite->hSBM[c].direction) )
{
++c;
}
hSprite->currentBitmap = c + currentBitmap;
return TRUE;

} /* SetSpriteBitmap */

/*
* GetSpriteBitmap
*/
USHORT GetSpriteBitmap( HSPRITE *hSprite )
{
USHORT count;

count = 0;
while( (hSprite->currentAction != hSprite->hSBM[count].action) ||
(hSprite->currentDirection != hSprite->hSBM[count].direction) )
{
++count;
}
return hSprite->currentBitmap - count;

} /* GetSpriteBitmap */

/*
* advanceSpriteBitmap
*/
static BOOL advanceSpriteBitmap( HSPRITE *hSprite )
{
SHORTc;
SHORTn;
ACTIONcurAct;
ACTIONact;
DIRECTIONcurDir;
DIRECTIONdir;

curAct = hSprite->currentAction;
curDir = hSprite->currentDirection;

//
// See if we're cycling forward or backward though the images.
//
if( hSprite->switchForward ) // Are we cycling forward?
{
c = hSprite->currentBitmap + 1;

// Does the next image exceed the number of images we have?
if( c >= hSprite->bitmapCount )
{
// if the next image is past the end of the list,
// we need to set it to the start of the series.
SetSpriteBitmap( hSprite, 0 );
c = hSprite->currentBitmap;
}
else
{
act = hSprite->hSBM[c].action;
dir = hSprite->hSBM[c].direction;

// By examining the action and direction fields we can tell
// if we've past the current series of images and entered
// another series.
if( (curAct != act) || (curDir != dir) )
{
SetSpriteBitmap( hSprite, 0 );
}
else // We're still in the series, use the next image.
{
hSprite->currentBitmap = c;
}
}
}
else //cycling backwards
{
c = hSprite->currentBitmap - 1;

if( c < 0 ) // Is the next image past the beginning of the list?
{
n = 0;

// Find the last bitmap in the series
while( (n <= hSprite->bitmapCount) &&
(curAct == hSprite->hSBM[n].action) &&
(curDir == hSprite->hSBM[n].direction) )
{
++n;
}

hSprite->currentBitmap = n - 1;
}

else
{
act = hSprite->hSBM[c].action;
dir = hSprite->hSBM[c].direction;
// Is the next image past the of the series
if( (curAct != act) || (curDir != dir) )
{
n = c + 1;
while( (n <= hSprite->bitmapCount) &&
(curAct == hSprite->hSBM[n].action) &&
(curDir == hSprite->hSBM[n].direction) )
{
++n;
}

hSprite->currentBitmap = n - 1;
}
else // The next image is fine, use it.
{
hSprite->currentBitmap = c;
}
}
}
return TRUE;

} /* advanceSpriteBitmap */

/*
* DisplaySprite
*/
BOOL DisplaySprite ( GFX_HBM hBuffer, HSPRITE *hSprite, LONG xPlane )
{
USHORTcount;
SHORTleft;
SHORTright;
SHORTshortx;
SHORTshorty;
SHORTplanex;
POINT src;
RECT dst;

if( hSprite->active == FALSE )
{
return FALSE;
}

count = hSprite->currentBitmap;
shortx = (SHORT) (hSprite->x >> 16);
shorty = (SHORT) (hSprite->y >> 16);
planex = (SHORT) (xPlane >> 16);
src.x = 0;
src.y = 0;

if( shortx < planex - C_SCREEN_W )
{
shortx += hSprite->xmax;
}
else if( shortx >= planex + C_SCREEN_W )
{
shortx -= hSprite->xmax;
}

left = shortx - planex;

if( hSprite->currentDirection == RIGHT )
{
left += hSprite->hSBM[count].x;
}
else
{
left += hSprite->width - hSprite->hSBM[count].x - hSprite->hSBM[count].width;
}

right = left + hSprite->hSBM[count].width;

if( left > C_SCREEN_W )
{
left = C_SCREEN_W;
}
else if( left < 0 )
{
src.x = -left;
left = 0;
}

if( right > C_SCREEN_W )
{
right = C_SCREEN_W;
}
else if( right < 0 )
{
right = 0;
}

dst.left = left;
dst.right = right;
dst.top = shorty + hSprite->hSBM[count].y;
dst.bottom = dst.top + hSprite->hSBM[count].height;

gfxBlt(&dst,hSprite->hSBM[count].hBM,&src);

if( hSprite->switchType == HOR )
{
hSprite->relSwitch += abs(hSprite->xv);

if( hSprite->relSwitch >= hSprite->absSwitch )
{
hSprite->relSwitch = 0;
advanceSpriteBitmap( hSprite );
}
}
else if( hSprite->switchType == VER )
{
hSprite->relSwitch += abs(hSprite->yv);

if( hSprite->relSwitch >= hSprite->absSwitch )
{
hSprite->relSwitch = 0;
advanceSpriteBitmap( hSprite );

if( GetSpriteBitmap( hSprite ) == 0 )
{
SetSpriteSwitchDone( hSprite, TRUE );
}
}
}
else if( hSprite->switchType == TIME )
{
hSprite->relSwitch += C_UNIT;

if( hSprite->relSwitch >= hSprite->absSwitch )
{
hSprite->relSwitch = 0;
advanceSpriteBitmap( hSprite );

if( GetSpriteBitmap( hSprite ) == 0 )
{
SetSpriteSwitchDone( hSprite, TRUE );
}
}
}

return TRUE;

} /* DisplaySprite */

/*
* DestroySprite
*/
BOOL DestroySprite ( HSPRITE *hSprite )
{
USHORT i;

if( hSprite == NULL )
{
ErrorMessage( "hSprite in DestroySprite" );
}

if( hSprite->hSBM == NULL )
{
ErrorMessage( "hSprite->hSBM in DestroySprite" );
}

for( i = 0; i < hSprite->bitmapCount; ++i )
{
if( !gfxDestroyBitmap( hSprite->hSBM[i].hBM ) )
{
ErrorMessage( "gfxDestroyBitmap (hBM) in DestroySprite" );
}
}

MemFree( hSprite->hSBM );
MemFree( hSprite );

return TRUE;

} /* DestroySprite */