GameSource/pixiZAM - direct blitter/pixiZAM.c

#include "PixiZAM.h"
 
 
OSErr LoadPixiFromCIcon(pixiZAM *pz, short resID)
/*
    Load the icons into a GWorld, then copy from the GWorld
    to the pixiZAM.
    
    Need to:  Either read the icon data directly from the iconHandle (GetResource)
                or fix the crappy GWOrld extra rowLong problem for real.
                
*/
{
    CIconHandle cicn;               // the icon we are loading
    GWorldPtr   image;              // the image of the icon
    GWorldPtr   mask;               // the mask that defines it
    long        imageSize;          // number of bytes for the image
    char        *pixBaseAddr;       // base address of pixmap in GWORld
    OSErr       err = noErr;        // 
    char        *maskFixer;         // used to make sure the mask is correct
    Rect        alignedBounds;      // rect stretched to be long aligned
    short       realRowBytes;       // this will one day be the real rowBytes, no padding
    short       needDump = 0;       // bit flags set here to manage memory
 
    enum    {   kDumpCicn = 1,          // if any of these flags are set
                kDumpImageGWorld = 2,   // the object they represent will
                kDumpMaskGWorld = 4,    // be disposed of at the end of the function
                kDumpImageZAM = 8       // in the case of an error, if any of the
            };                          // pixiZAM has been allocated, it will be dumped
    
    /*
        first load in the color icon
    */
    cicn = GetCIcon(resID);
    if(!cicn) {
        err = ResError();
        ErrMsgCode("\pErrror  GetCIcon",err);
    }
    
    /* now create a GWorld from it, and set the bit to dump it. */
    if(err == noErr) {
        needDump |= kDumpCicn;
        err = CreateGWorldFromCIcon(&image, cicn);
        if(err != noErr) {
            ErrMsgCode("\pError creating GWorld for image",err);
        }
    }
    
    /* if that was cool, we do the same thing for the mask */
    if(err == noErr) {
        needDump |= kDumpImageGWorld;
        err = CreateGWorldFromCIconMask(&mask, cicn);
        if(err != noErr) {
            ErrMsgCode("\pError creating GWorld",err);
        }
    }
    
    /* we now do not need the icon anymore */
    if( (needDump & kDumpCicn) != 0)
        DisposCIcon(cicn);
    
    /* Calculate the needed memory for the pixiZAM image, and get it */
    if(err == noErr) {
        needDump |= kDumpMaskGWorld;
 
        //realRowBytes = (image->portRect.right - image->portRect.left);        
        realRowBytes = 0x7FFF & (**image->portPixMap).rowBytes;     
        alignedBounds = image->portRect;
        LongAlignRect(&alignedBounds);
 
        imageSize = (alignedBounds.bottom 
                    - alignedBounds.top)
                    * realRowBytes;
 
        if (imageSize & 3)  {
            imageSize &= ~3;
            imageSize += 4;
        }
 
        pz->image = (long*)NewPtrClear(imageSize);
        if(!pz->image) {
            err = MemError();
            ErrMsgCode("\pError allocating pz->image",err);
        }
    }
    
    /* get the same amount of memory for the mask */
    if(err == noErr) {
        pz->mask = (long*)NewPtrClear(imageSize);
        if(!pz->mask) {
            err = MemError();
            ErrMsgCode("\pError allocating pz->mask",err);
            needDump |= kDumpImageZAM;
        }
    }
    
    /* now load the GWorlds into the pixiZAM buffers */
    
    if(err == noErr) {
        
        LockPixels(image);
        pixBaseAddr = GetPixBaseAddr(GetGWorldPixMap(image));
        BlockMove(pixBaseAddr, pz->image, imageSize);
        UnlockPixels(image);
        
        LockPixels(mask);
        pixBaseAddr = GetPixBaseAddr(GetGWorldPixMap(mask));        
        BlockMove(pixBaseAddr, pz->mask, imageSize);
        UnlockPixels(mask);
        
        /* this makes any byte of the mask that has on pixels */
        /* all the way turned on, just to make sure the mask color */
        /* indexes are correct */
        maskFixer = (char*)pz->mask;
        while(imageSize--) {
            if(*maskFixer)  
                *maskFixer = 0xFF;
            *maskFixer++;
        }
 
        /* initialize the rest of the pixiZAM structure */
        pz->bounds = image->portRect;
        pz->height = image->portRect.bottom - image->portRect.top;
        pz->rowLongs = (realRowBytes/ 4);
    }
    
    /* check the bits in needDump, and clean up what we allocated */
    
    if(needDump & kDumpImageGWorld)
        DisposeGWorld(image);
        
    if(needDump & kDumpMaskGWorld)
        DisposeGWorld(mask);
 
    if( needDump & kDumpImageZAM)
        DisposePtr(image);              // only if allocated and an error occured
 
    return err;
}
 
void PixelMover(pixiZAM *srcPixi, PixMapHandle destMap, Rect *destRect)
/*
    This is a non-masked straight copy.
    
    The entire source is copied to the topLeft of the destination rectangle
    
    Assumes:  The destination's color table matches the pixiZAMs
              The pixiZAM is 8 bits deep, and so is the destination
*/
{
    register long *dst;
    register long *src;
    register long *mask;
    register long numRowsToCopy;
    register long rowLongsOffset;
    register long stripRowBytes;
             char mmuMode;
 
    stripRowBytes = (0x7FFF & (**destMap).rowBytes);
    
    src = srcPixi->image;
    mask = srcPixi->mask;
 
    LongAlignRect(destRect);
    
    dst = (long *)(GetPixBaseAddr(destMap) + (stripRowBytes * destRect->top) + destRect->left);
    
    mmuMode = true32b;
    SwapMMUMode(&mmuMode);
    
    numRowsToCopy = srcPixi->height;
    rowLongsOffset = (stripRowBytes/4) - srcPixi->rowLongs;
    
    while(numRowsToCopy--) {
 
        switch(srcPixi->rowLongs) {
            #include "pmSplat.gen"
        }
        dst += rowLongsOffset;
    }
    
    SwapMMUMode(&mmuMode);
}
 
void MaskedPixelMover(pixiZAM *srcPixi, PixMapHandle destMap, Rect *destRect)
/*
    This is a masked copy.
    
    The entire source is copied to the topLeft of the destination rectangle
    
    Assumes:  The destination's color table matches the pixiZAMs
              The pixiZAM is 8 bits deep, and so is the destination
              Also assumes that clipping won't be needed, so don't tell this
              to do anything stupid, cause it will.
              
    NeedTo:   Correct problems in the pixiZam loaded because the images contain
              an extra longword at the end of each row, inherited from the GWorld.
    
    Also NeedTo:  Write one that take a source and destination rectangle
*/
{
    register long *dst;
    register long *src;
    register long *mask;
    register long numRowsToCopy;
    register long rowLongsOffset;
    register long stripRowBytes;
             char mmuMode;
 
    stripRowBytes = (0x7FFF & (**destMap).rowBytes);
    
    src = srcPixi->image;
    mask = srcPixi->mask;
    
    LongAlignRect(destRect);
    
    dst = (long *)(GetPixBaseAddr(destMap) + (stripRowBytes * destRect->top) + destRect->left);
    
    mmuMode = true32b;
    SwapMMUMode(&mmuMode);
    
    numRowsToCopy = srcPixi->height;
    rowLongsOffset = (stripRowBytes/4) - srcPixi->rowLongs;
        
    while(numRowsToCopy--) {
        switch(srcPixi->rowLongs) {
            #include "pmSplatMask.gen"
        }
        dst += rowLongsOffset;
    }
    
    SwapMMUMode(&mmuMode);
}