Source/Sprite.c

//¥ ------------------------------------------------------------------------------------------  ¥
//¥
//¥ Copyright © 1996 Apple Computer, Inc., All Rights Reserved
//¥
//¥
//¥     You may incorporate this sample code into your applications without
//¥     restriction, though the sample code has been provided "AS IS" and the
//¥     responsibility for its operation is 100% yours.  However, what you are
//¥     not permitted to do is to redistribute the source as "DSC Sample Code"
//¥     after having made changes. If you're going to re-distribute the source,
//¥     we require that you make it clear in the source that the code was
//¥     descended from Apple Sample Code, but that you've made changes.
//¥
//¥     Authors:
//¥         Chris De Salvo
//¥
//¥ ------------------------------------------------------------------------------------------  ¥
 
//¥ ------------------------------  Includes
 
#include <Resources.h>
 
#include "Blitter.h"
#include "ErrorHandler.h"
#include "MemoryHandler.h"
#include "Sprite.h"
 
//¥ ------------------------------  Private Definitions
 
#define kSpriteResType              'SPRT'
 
//¥ ------------------------------  Private Types
//¥ ------------------------------  Private Variables
//¥ ------------------------------  Private Functions
 
static void NewFramesFromPtr(SpritePtr theSprite, Ptr theData, UInt32 numFrames);
 
//¥ ------------------------------  Public Variables
//¥ --------------------    SpriteLoad
 
SpritePtr
SpriteLoad(SInt16 resNum)
{
SpritePtr   theSprite;
Handle      theHandle;
UInt16      numFrames;
Ptr         index;
 
    theHandle = GetResource(kSpriteResType, resNum);
    if (! theHandle)
        return (nil);
 
    theSprite = (SpritePtr) NewPtrClear(sizeof (Sprite));
    if (! theSprite)
        return (nil);
        
    HLockHi(theHandle);
    index = *theHandle;
    
    numFrames = *((UInt16 *) index);
    index += 2;
 
    theSprite->frames = (FramePtr *) NewTaggedPtrClear(numFrames * sizeof (FramePtr), 'FPTR', resNum);
    if (! theSprite->frames)
    {
        HUnlock(theHandle);
        return (nil);
    }
    
    theSprite->numFrames = numFrames;
 
    NewFramesFromPtr(theSprite, index, numFrames);
    DisposeHandleZ(&theHandle);
    
    return (theSprite);
}
 
//¥ --------------------    NewFramesFromPtr
 
static void
NewFramesFromPtr(SpritePtr theSprite, Ptr theData, UInt32 numFrames)
{
int     i;
UInt16  h, w;
SInt16  hotX, hotY;
 
    for (i = 0; i < numFrames; i++)
    {
        w = * ((UInt16 *) theData);
        theData += 2;
        
        h = * ((UInt16 *) theData);
        theData += 2;
        
        hotX = * ((SInt16 *) theData);
        theData += 2;
        
        hotY = * ((SInt16 *) theData);
        theData += 2;
 
        theSprite->frames[i] = (FramePtr) NewTaggedPtrClear(sizeof (Frame), 'FRAM', 1);
        if (! theSprite->frames[i])
            FatalError("Could not allocate sprite frame.");
        
        theSprite->frames[i]->width = w;
        theSprite->frames[i]->height = h;
        theSprite->frames[i]->hotX = hotX;
        theSprite->frames[i]->hotY = hotY;
        
        theSprite->frames[i]->image = (UInt8 *) NewTaggedPtrClear(w * h, 'IMAG', i);
        if (! theSprite->frames[i]->image)
            FatalError("Could not allocate sprite frame bits.");
            
        BlockMoveData(theData, theSprite->frames[i]->image, w * h);
        
        theData += w * h;
    }
}
 
//¥ --------------------    SpriteDraw
 
Rect
SpriteDraw(SpritePtr theSprite, UInt32 frameNum, CGrafPtr dest, SInt32 x, SInt32 y)
{
FramePtr    theFrame;
Rect        blitRect;
Rect        emptyRect = { 0, 0, 0, 0 };
UInt32      h = 0, v = 0;
 
    theFrame = theSprite->frames[frameNum];
 
    //¥ Set up a rectangle inside the image area that is clipped to the edges of the window
    blitRect.left = blitRect.top = 0;
    blitRect.right = theFrame->width;
    blitRect.bottom = theFrame->height;
 
    x -= theFrame->hotX;
    y -= theFrame->hotY;
    
    OffsetRect(&blitRect, x, y);
    
    if (blitRect.left < 0)
        h = -blitRect.left;
 
    if (blitRect.left > dest->portRect.right)
        return (emptyRect);
        
    if (blitRect.top < 0)
        v = -blitRect.top;
 
    if (blitRect.top > dest->portRect.bottom)
        return (emptyRect);
        
    if (blitRect.right > dest->portRect.right)
        blitRect.right = dest->portRect.right;
 
    if (blitRect.right < 0)
        return (emptyRect);
        
    if (blitRect.bottom > dest->portRect.bottom)
        blitRect.bottom = dest->portRect.bottom;
 
    if (blitRect.bottom < 0)
        return (emptyRect);
 
    OffsetRect(&blitRect, -blitRect.left, -blitRect.top);
    blitRect.left += h;
    blitRect.top += v;
 
    //¥ Blit the clipped area to the screen
    TransBitBlit(theFrame->image + (blitRect.top * theFrame->width) + blitRect.left, dest,
        blitRect.right - blitRect.left, blitRect.bottom - blitRect.top, theFrame->width,
        x + h, y + v);
 
    OffsetRect(&blitRect, x, y);
    
    return (blitRect);
}
 
//¥ --------------------    SpriteDispose
 
void
SpriteDispose(SpritePtr *theSprite)
{
UInt32  i;
 
    if (! *theSprite)
        return;
 
    for (i = 0; i < (*theSprite)->numFrames; i++)
    {
        DisposeTaggedPtrZ((Ptr *) &(*theSprite)->frames[i]->image);
        DisposeTaggedPtrZ((Ptr *) &(*theSprite)->frames[i]);
    }
 
    DisposeTaggedPtrZ((Ptr *) &(*theSprite)->frames);
    DisposeTaggedPtrZ((Ptr *) theSprite);
}
 
//¥ --------------------    SpriteHeight
 
UInt16
SpriteHeight(SpritePtr whichSprite, UInt16 whichFrame)
{
    if (whichFrame > (whichSprite->numFrames - 1))
        return (0);
        
    return (whichSprite->frames[whichFrame]->height);
}
 
//¥ --------------------    SpriteWidth
 
UInt16
SpriteWidth(SpritePtr whichSprite, UInt16 whichFrame)
{
    if (whichFrame > (whichSprite->numFrames - 1))
        return (0);
        
    return (whichSprite->frames[whichFrame]->width);
}
 
//¥ --------------------    IntersectRects
 
Boolean
IntersectRects(const RectPtr a, const RectPtr b)
{
    if (b->right < a->left)
        return (false);
        
    if (b->left > a->right)
        return (false);
        
    if (b->top > a->bottom)
        return (false);
        
    if (b->bottom < a->top)
        return (false);
        
    return (true);
}