GameSource/SpriteFrameSet.c

#include "ZAMProtos.h"
 
 
void InitFrameSetInfo(frameSetPtr fsp, short frameCount)
/* initialize the frame set header */
/* this is the stuff that is block moved around when a sprite frame set is shared */
/* not a good way to do it. */
{
    fsp->finfo.frameCount = frameCount;
    fsp->finfo.frameIndex = 0;
    fsp->finfo.curImage = &fsp->flist[0];
    fsp->finfo.prevImage = fsp->finfo.curImage;
    fsp->finfo.dimension.h = RECT_WD(fsp->flist[0].image->portRect);
    fsp->finfo.dimension.v = RECT_HT(fsp->flist[0].image->portRect);
    fsp->finfo.center.h = fsp->finfo.dimension.h / 2;
    fsp->finfo.center.v = fsp->finfo.dimension.v / 2;
}
 
 
void SetSpriteCurrentFrame(spritePtr theSprite, short frameNum)
/*
    Force the sprite to change frame. This also remembers the current frame
    so that erasing happens correctly later.
*/
{
    theSprite->frameList->finfo.frameIndex = frameNum;
    theSprite->frameList->finfo.prevImage = theSprite->frameList->finfo.curImage;
    theSprite->frameList->finfo.curImage = &theSprite->frameList->flist[frameNum];
}
 
OSErr CopyFrameSet(frameSetPtr srcFrameSet, frameSetPtr *destFrameSet)
/*
    This should be called duplicate or clone because it allocates
    the destination frame set for you and copies the source to it.
*/
{
    frameSetPtr fsp;
    long        fsSize;
    OSErr       err = noErr;
    
    
    fsSize = sizeof(frameInfo) + (sizeof(frameCell) * srcFrameSet->finfo.frameCount);
    
    /* create a new frame set block -- this is the destination frame set */
    fsp = (frameSetPtr)NewPtrClear(fsSize);
    if(fsp == nil) {
        err = MemError();
        ErrMsgCode("\pError allocating SpriteFrameSet",err);
    }
    
    if(err == noErr) {
        BlockMove(srcFrameSet, fsp, fsSize);
    }
    
    *destFrameSet = fsp;
    
    return err;
}
 
OSErr CreateEmptyFrameSet(frameSetPtr *dstFrameSet, short numFrames)
/*
    This creates a frame set with no actual content.  
    Content can be copied later with SetSpriteFrameSet, which is the nasty block move
    culprit.
*/
{
    frameSetPtr fsp;
    long        fsSize;
    OSErr       err = noErr;
 
    fsSize = sizeof(frameInfo) + (sizeof(frameCell) * numFrames);
    
    /* create a new frame set block -- this is the destination frame set */
    fsp = (frameSetPtr)NewPtrClear(fsSize);
    if(fsp == nil) {
        err = MemError();
        ErrMsgCode("\pError allocating SpriteFrameSet",err);
    }
 
    if(err == noErr) {
        fsp->finfo.frameCount = numFrames;
        fsp->finfo.frameIndex = 0;
        fsp->finfo.curImage = nil;
        fsp->finfo.prevImage = nil;
    }
 
    *dstFrameSet = fsp;
    
    return err;
}
 
void SetSpriteFrameSet( spritePtr theSprite, frameSetPtr srcFrameSet)
/*
    Change the frame set of a sprite from whatever it was to the new one.
    
    Note that this has one severe limiation, in that you can only go to another
    frame set that has the same number of frames.   This function could be changed
    to check for a difference in size and deal with it, but it is actually pretty
    weak as it is already, and a completely different scheme would work better.
    A frame set reference perhaps or something like that.
*/
{
    long            fsSize;
    frameCellPtr    prevFrameSet;
    
    fsSize = GetPtrSize(srcFrameSet);
    /* save the previous frame set for erasing the old image */
    prevFrameSet = theSprite->frameList->finfo.curImage;
 
    /* copy the new frame set over the first one, and set it to the start */
    BlockMove(srcFrameSet, theSprite->frameList, fsSize);
    InitFrameSetInfo(theSprite->frameList, srcFrameSet->finfo.frameCount);
 
    /* if there was a previous frame set, then restore it */
    if(prevFrameSet != nil)
        theSprite->frameList->finfo.prevImage = prevFrameSet;
}
 
OSErr CreateColorIconFrameSet(frameSetPtr *newFrameSet, short startID, short numFrames)
/*
    Create a frame set from color icons starting with CICN resource id startID for the numFrames.
*/
{
    short           index;
    frameSetPtr     fsp;
    frameCellPtr    fcp;
    short           err = noErr;
    CIconHandle     cicn;
    
    /* create a new frame set block */
    fsp = (frameSetPtr)NewPtrClear(sizeof(frameInfo) + (sizeof(frameCell) * numFrames));
    if(fsp == nil) {
        err = MemError();
        ErrMsgCode("\pError allocating SpriteFrameSet",err);
    }
    if(err == noErr) {
        /* load the frames into the GWorld list */
        for(index = 0; (index < numFrames) && (err == noErr); index ++) {
            fcp = &fsp->flist[index];
            cicn = GetCIcon(startID + index);
            if(cicn == nil) {
                err = ResError();
                ErrMsgCode("\pcicn resource not loaded in CreateColorIconFrameSet",err);
            } else {
                err = CreateGWorldFromCIcon(&fcp->image, cicn);
                if(err != noErr) {
                    ErrMsgCode("\pCreateColorIconFrameSet: CreateGWorldFromCIcon failed.",err);
                }
                if(err == noErr) {  
                    err = CreateRegionFromCIconMask(&fcp->mask, cicn);
                    if(err != noErr) {
                        ErrMsgCode("\pCreateRegionFromCIconMask failed.",err);
                    } else {
                        /* save off the topleft of the region so we can move */
                        /* it with the sprite */
                        fcp->maskLoc.v = (**fcp->mask).rgnBBox.top;
                        fcp->maskLoc.h = (**fcp->mask).rgnBBox.left;
                    }
                }
                DisposeCIcon(cicn);
            }
        }
        /* have all the frames, so set up the frame header information */
        InitFrameSetInfo(fsp, numFrames);
    }
    
    *newFrameSet = fsp;
 
    if(err != noErr) {
        /* crappy for now but hey */
        ErrMsgCode("\pIt would be unwise to proceed.!!!",err);
        ExitToShell();
    }
    
    return err;
 
}
 
 
OSErr CreatePICTIconFrameSet(frameSetPtr *newFrameSet, short startID, short numFrames)
/*
    Does the same thing, only the image is loaded from a picture while
    the mask is loaded from a cicn.  The reason for this is that I originally was only using
    cicns, but, then I discovered a lovely program called DeBabelizer 
    ( by Equilibrium Technologies, in Sausalito, CA), which will take a whole bunch of art work
    from just about anywhere and create a common palette for it, and even re-map the pictures to the
    new palette.  So I did that with all the artwork in ZAM, but did not want to take it from the PICTs
    back to CICN.  Too bad Debabelizer cannot process CICNS directly.
    So this is a hacky way around it, and I'm sorry to say it takes up more room on disk.
*/
{
    short           index;
    frameSetPtr     fsp;
    frameCellPtr    fcp;
    short           err = noErr;
    CIconHandle     cicn;
    PicHandle       pict;
    
    /* create a new frame set block */
    fsp = (frameSetPtr)NewPtrClear(sizeof(frameInfo) + (sizeof(frameCell) * numFrames));
    if(fsp == nil) {
        err = MemError();
        ErrMsgCode("\pError allocating SpriteFrameSet",err);
    }
    if(err == noErr) {
        /* load the frames into the GWorld list */
        for(index = 0; (index < numFrames) && (err == noErr); index ++) {
            fcp = &fsp->flist[index];
            cicn = GetCIcon(startID + index);
            if(cicn == nil) {
                err = ResError();
                ErrMsgCode("\pcicn resource not loaded in CreateColorIconFrameSet",err);
            } else {
                pict = GetPicture(startID + index);
                if(pict == nil) {
                    err = ResError();
                    ErrMsgCode("\pPICT resource not loaded in CreateColorIconFrameSet",err);
                } else {
                    err = CreateGWorldFromPict(&fcp->image, pict);
                    if(err != noErr) {
                        ErrMsgCode("\pCreateColorIconFrameSet: CreateGWorldFromPict failed.",err);
                    }
                    if(err == noErr) {  
                        err = CreateRegionFromCIconMask(&fcp->mask, cicn);
                        if(err != noErr) {
                            ErrMsgCode("\pCreateRegionFromCIconMask failed.",err);
                        } else {
                            /* save off the topleft of the region so we can move */
                            /* it with the sprite */
                            fcp->maskLoc.v = (**fcp->mask).rgnBBox.top;
                            fcp->maskLoc.h = (**fcp->mask).rgnBBox.left;
                        }
                    }
                    ReleaseResource(pict);
                }
                DisposeCIcon(cicn);
            }
        }
        /* have all the frames, so set up the frame header information */
        InitFrameSetInfo(fsp, numFrames);
    }
    
    *newFrameSet = fsp;
 
    if(err != noErr) {
        /* crappy for now but hey */
        ErrMsgCode("\pIt would be unwise to proceed.!!!",err);
        ExitToShell();
    }
    
    return err;
 
}
 
short GetNextSpriteFrameIndex(spritePtr spr)
{
    short   frameNum;
 
    frameNum = spr->frameList->finfo.frameIndex + 1;
 
    if(frameNum >= spr->frameList->finfo.frameCount) {
        frameNum    = 0;
    }
    
    return frameNum;
}
 
 
void AttachCTableToFrameSet(frameSetPtr frameSet, CTabHandle srcCtable, short ctSeed)
/*
    Change the color table of a frame set, and set the seed.  I had mixed results using this.
*/
{
    CTabHandle      ctab;
    frameCellPtr    prevFrameSet;
    short           i;
    PixMapHandle    pmH;
    
    
    ctab = srcCtable;
 
    for(i = 0; i < frameSet->finfo.frameCount; i++) {
        pmH = GetGWorldPixMap(frameSet->flist[i].image);        // get pixmap
        DisposeHandle((**pmH).pmTable);
        HandToHand(&ctab);                                      // duplicate it
        (**pmH).pmTable = ctab;                                 // stuff it in
        (**(**pmH).pmTable).ctSeed = ctSeed;                    // change the seed
    } 
    
}
 
 
void SetFrameSetCTSeed(frameSetPtr frameSet, short newSeed)
{
    short           i;
    PixMapHandle    pmH;
 
    for(i = 0; i < frameSet->finfo.frameCount; i++) {
        pmH = GetGWorldPixMap(frameSet->flist[i].image);        // get pixmap
        (**(**pmH).pmTable).ctSeed = newSeed;                   // change the seed
    } 
}
 
void SetSpriteXXFrameSet( spritePtr theSprite, frameSetPtr srcFrameSet)
/*
    Guess this is old dead code no longer used.
*/
{
    long            fsSize;
    frameCellPtr    prevFrameSet;
    
    fsSize = GetPtrSize(srcFrameSet);
    /* save the previous frame set for erasing the old image */
    prevFrameSet = theSprite->frameList->finfo.curImage;
 
    /* copy the new frame set over the first one, and set it to the start */
    BlockMove(srcFrameSet, theSprite->frameList, fsSize);
    InitFrameSetInfo(theSprite->frameList, srcFrameSet->finfo.frameCount);
 
    /* if there was a previous frame set, then restore it */
    theSprite->frameList->finfo.prevImage = prevFrameSet;
}