MoofEncoder/GridEncode.cp

/*
    File:       GridEncode.cp
 
    Contains:   This is just a very simple encoder that shows how to build GRID and TILE resources.
                The TILE resource is a set of 32x32x1 byte tiles.  This encoder takes a picture and
                dices it into 32x32 tiles, which it writes out to output file.  It then builds a
                standard grid, repeating the original picture as a pattern across the grid.
    
                Eventually, it would be nice to make a program that lets someone graphically edit
                the available list of tiles and the actual GRID resource, much like any number
                of map editors out for various games.
 
    Written by: Timothy Carroll 
 
    Copyright:  Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source 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 source
                code, but that you've made changes.
 
    Change History (most recent first):
                7/1/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                2/24/97     Timothy Carroll Now explicitly include main.h
                8/15/96     Timothy Carroll Initial Release
                
 
*/
 
#include <Resources.h>
#include "Main.h"
#include "GridEncode.h"
#include "GridTilesFormat.h"
#include "Error Macros.h"
 
 
OSStatus GridTileEncode (short inputFileResNum, short outputFileResNum)
{
    OSStatus        theErr;
    short           saveResNum;
    
    // Used to compile the tile resource
    PicHandle       tilePict = NULL;
    GWorldPtr       tileWorld = NULL;
    PixMapHandle    tilePix = NULL;
    
    CGrafPtr        savePort;
    GDHandle        saveDevice;
    
    Rect            pictRect;
 
    long            width, height, numTiles;
    long            tileRowBytes;
    Ptr             tileBaseAddress;
    
    long            x, y, loop;
    
    Ptr             destPtr, srcPtr;
    CellGridType    *gridPtr;
    CellGridType    currentValue;
    
    // Our output handles
    Handle          tile = NULL;
    Handle          grid = NULL;
    
    // Whether or not we've written it out as a resource
    Boolean         tileIsResource = false, gridIsResource = false;
        
    saveResNum = CurResFile();
 
    UseResFile (inputFileResNum);
 
 
    // First thing is to copy the color table resource to the output.
    theErr = CopyResource (inputFileResNum, outputFileResNum,'clut', kAppColorTableResID);
    FAIL_OSERR (theErr, "\pFailed to copy the color table to the destination file")
 
    // Load the color table and the graphic we want to dice into pieces
    gAppColorTable = GetCTable( kAppColorTableResID );
    FAIL_NIL (gAppColorTable, "\pFailed to load the color table")
    
    tilePict = (PicHandle) Get1Resource ('PICT', kPICTInputResID);
    theErr = ResError();
    FAIL_OSERR (theErr, "\pFailed to load the pict")
    FAIL_NIL (tilePict, "\pFailed to load the pict")
 
 
    
    // Create a GWorld and draw our PICT into it.
    
    pictRect = (**tilePict).picFrame;
    
    pictRect.right -= pictRect.left;
    pictRect.left = 0;
    pictRect.bottom -= pictRect.top;
    pictRect.top = 0;
    
    theErr = NewGWorld(&tileWorld, kPreferredDepth, &pictRect, gAppColorTable, NULL, keepLocal);
    FAIL_OSERR (theErr, "\pCouldn't allocate GWorld for encoding")
    FAIL_NIL (tileWorld, "\pCouldn't allocate GWorld for encoding")
    
    tilePix  = GetGWorldPixMap(tileWorld);
    FAIL_NIL (tilePix, "\pCouldn't get the GWorld's PixMap")
    FAIL_FALSE ( LockPixels(tilePix), "\pCouldn't lock GWorld PixMap")
    
    GetGWorld (&savePort, &saveDevice);
    SetGWorld (tileWorld, NULL);
    
    EraseRect (&pictRect);
    DrawPicture (tilePict, &pictRect);
    
    SetGWorld (savePort, saveDevice);
 
    // We're done with the picture, release it
    ReleaseResource ((Handle) tilePict);
    tilePict = NULL;
 
    // Time to build the tile resource.  We're going to dice it into as many
    // 32x32 tiles as we can.  Any partial data to the bottom or the right will
    // be ignored -- we only build complete tiles.
    
    width = pictRect.right / 32;
    height = pictRect.bottom / 32;
    numTiles = width * height + 1;  // Our first tile is always an all black tile, for the "borders"
    
    tile = NewHandleClear (sizeof (TileCollectionResHeader) + numTiles*kTileSize);
    theErr = MemError();
    FAIL_OSERR (theErr, "\p Failed to create the tile resource file")
    FAIL_NIL (tile, "\p Failed to create the tile resource file")
 
    // Fill in the tile header.
    (**((TileCollectionResHeader **) tile)).version = 0;
    (**((TileCollectionResHeader **) tile)).depth = kPreferredDepth;
    (**((TileCollectionResHeader **) tile)).flags = 0;
    (**((TileCollectionResHeader **) tile)).numTiles = numTiles;
    
    tileBaseAddress = ( Ptr) GetPixBaseAddr( tilePix );
    tileRowBytes = ( **tilePix ).rowBytes & 0x3fff;
    
    destPtr = (*tile) + sizeof (TileCollectionResHeader);
    
    // First tile, we just fill with black
    for (loop = 0; loop < 32; loop++)
    {
        ((UInt32 *) destPtr)[0] = 0xFFFFFFFF;
        ((UInt32 *) destPtr)[1] = 0xFFFFFFFF;
        ((UInt32 *) destPtr)[2] = 0xFFFFFFFF;
        ((UInt32 *) destPtr)[3] = 0xFFFFFFFF;
        ((UInt32 *) destPtr)[4] = 0xFFFFFFFF;
        ((UInt32 *) destPtr)[5] = 0xFFFFFFFF;
        ((UInt32 *) destPtr)[6] = 0xFFFFFFFF;
        ((UInt32 *) destPtr)[7] = 0xFFFFFFFF;
        destPtr += 32;
    }
 
    // Iterate over each tile and copy 1K of data to the destination
    for (x = 0; x < width; x++)
    {
        for (y = 0; y < height; y++)
        {
            srcPtr = tileBaseAddress + 32*y*tileRowBytes + 32*x;
            for (loop = 0; loop < 32; loop++)
            {
                register UInt32 temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8;
                temp1 = ((UInt32 *) srcPtr)[0];
                temp2 = ((UInt32 *) srcPtr)[1];
                temp3 = ((UInt32 *) srcPtr)[2];
                temp4 = ((UInt32 *) srcPtr)[3];
                temp5 = ((UInt32 *) srcPtr)[4];
                temp6 = ((UInt32 *) srcPtr)[5];
                temp7 = ((UInt32 *) srcPtr)[6];
                temp8 = ((UInt32 *) srcPtr)[7];
                ((UInt32 *) destPtr)[0] = temp1;
                ((UInt32 *) destPtr)[1] = temp2;
                ((UInt32 *) destPtr)[2] = temp3;
                ((UInt32 *) destPtr)[3] = temp4;
                ((UInt32 *) destPtr)[4] = temp5;
                ((UInt32 *) destPtr)[5] = temp6;
                ((UInt32 *) destPtr)[6] = temp7;
                ((UInt32 *) destPtr)[7] = temp8;
                srcPtr += tileRowBytes;
                destPtr += 32;
            }
        }
    }
    
    // Tile resource is done.  Dispose of the GWorld
    DisposeGWorld ( tileWorld);
    tileWorld = NULL;
    
    
    // Time to create the GRID resource
    grid = NewHandle (sizeof (TileGridResHeader) + 
                            sizeof (CellGridType)*kGridWidth*kGridHeight);
    theErr = MemError();
    FAIL_OSERR (theErr, "\p Failed to allocate memory for GRID resource")
    FAIL_NIL (grid, "\p Failed to allocate memory for GRID resource")
    
    // Fill in the header
    (**((TileGridResHeader **) grid)).version = 0;
    (**((TileGridResHeader **) grid)).flags = 0;
    (**((TileGridResHeader **) grid)).tileResID = kOutputResID;
    (**((TileGridResHeader **) grid)).width = kGridWidth;
    (**((TileGridResHeader **) grid)).height = kGridHeight;
    (**((TileGridResHeader **) grid)).defaultTile = 0;  // our black tile
    
    // Point to the start of the grid data.
    gridPtr = (CellGridType * ) ((Ptr)(*grid) + sizeof (TileGridResHeader));
    
    // Fill in each tile
    for (x = 0; x < kGridWidth; x++)
    {
        for (y = 0; y < kGridWidth; y++)
        {
            currentValue = (y % height)*height + (x % width) +1;
            *gridPtr = currentValue;
            gridPtr++;
        }
    }
 
    // Write the resources out to the output file.
    UseResFile (outputFileResNum);
    
    AddResource( tile, TileCollectionResType, kOutputResID, "\p" );
    theErr = ResError();
    FAIL_OSERR (theErr, "\pFailed to add the TILE resource to the file")
    tileIsResource = true;  
    
    WriteResource( tile );
    theErr = ResError();
    FAIL_OSERR (theErr, "\pFailed to write the TILE resource to the file")
    
    ReleaseResource( tile );
    tile = NULL;
 
    AddResource( grid, TileGridResType, kOutputResID, "\p" );
    theErr = ResError();
    FAIL_OSERR (theErr, "\pFailed to add the GRID resource to the file")
    gridIsResource = true;
    
    WriteResource( grid );
    FAIL_OSERR (theErr, "\pFailed to write the GRID resource to the file")
    theErr = ResError();
    
    ReleaseResource( grid );
    grid = NULL;
 
        
    // Build the grid resource;
    
    goto cleanup;
    
    error:
    if (theErr == noErr)
        theErr = paramErr;
        
    cleanup:
    
    UseResFile (saveResNum);
    
    if (tilePict != NULL)
        ReleaseResource ((Handle) tilePict);
        
    if (tileWorld != NULL)
        DisposeGWorld (tileWorld);
        
    if (gAppColorTable != NULL)
        DisposeCTable (gAppColorTable);     
    gAppColorTable = NULL;
    
    if (tile)
        if (tileIsResource)
            ReleaseResource (tile);
        else
            DisposeHandle (tile); 
            
    if (grid)
        if (gridIsResource)
            ReleaseResource (grid);
        else
            DisposeHandle (grid);
    return theErr;
}