home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1999 Spring / macformat-077.iso / Shareware Plus / Development / SpriteWorld 2.2 / SpriteWorld files / Sources / Tiling.c < prev   
Encoding:
Text File  |  1999-02-12  |  85.6 KB  |  2,918 lines  |  [TEXT/CWIE]

  1. ///--------------------------------------------------------------------------------------
  2. //    Tiling.c
  3. //
  4. //    By Vern Jensen. SWLoadTile routines by Karl Bunker.
  5. //    
  6. //    Created: 11/15/95
  7. //
  8. //    Description:    Routines to use tiling with SpriteWorld
  9. ///--------------------------------------------------------------------------------------
  10.  
  11.  
  12. #ifndef __QUICKDRAW__
  13. #include <QuickDraw.h>
  14. #endif
  15.  
  16. #ifndef __MEMORY__
  17. #include <Memory.h>
  18. #endif
  19.  
  20. #ifndef __SPRITEWORLD__
  21. #include "SpriteWorld.h"
  22. #endif
  23.  
  24. #ifndef __SPRITEFRAME__
  25. #include "SpriteFrame.h"
  26. #endif
  27.  
  28. #ifndef __SPRITEWORLDUTILS__
  29. #include "SpriteWorldUtils.h"
  30. #endif
  31.  
  32. #ifndef __TILING__
  33. #include "Tiling.h"
  34. #endif
  35.  
  36. #ifndef __BLITPIXIE__
  37. #include "BlitPixie.h"
  38. #endif
  39.  
  40.  
  41.  
  42. ///--------------------------------------------------------------------------------------
  43. //    SWInitTiling
  44. ///--------------------------------------------------------------------------------------
  45.  
  46. SW_FUNC OSErr SWInitTiling(
  47.     SpriteWorldPtr    spriteWorldP,
  48.     short             tileHeight,
  49.     short            tileWidth,
  50.     short            maxNumTiles)
  51. {
  52.     OSErr     err = noErr;
  53.     Size    arraySize;
  54.     short    tileIndex;
  55.     
  56.     SW_ASSERT(spriteWorldP != NULL);
  57.     
  58.     if (spriteWorldP->tilingIsInitialized)
  59.     {
  60.         err = kTilingAlreadyInitialized;
  61.     }
  62.     
  63.     
  64.     if (err == noErr)
  65.     {
  66.         spriteWorldP->tilingIsOn = true;
  67.         spriteWorldP->tilingIsInitialized = true;
  68.         spriteWorldP->lastActiveTileLayer = 0;
  69.         spriteWorldP->maxNumTiles = maxNumTiles;
  70.         spriteWorldP->tileHeight = tileHeight;
  71.         spriteWorldP->tileWidth = tileWidth;
  72.     }
  73.     
  74.     
  75.     if (err == noErr)
  76.     {
  77.             // Create both tiling cache and changedTiles array of rects
  78.         err = SWInitTilingCache(spriteWorldP);
  79.     }
  80.     
  81.     
  82.     if (err == noErr)
  83.     {
  84.             // Allocate memory for tileFrameArray
  85.         arraySize = (Size)maxNumTiles * sizeof(FramePtr);
  86.         spriteWorldP->tileFrameArray = (FramePtr *)NewPtrClear(arraySize);
  87.         err = MemError();
  88.     }
  89.     
  90.     
  91.     if (err == noErr)
  92.     {
  93.             // Allocate memory for curTileImage array
  94.         arraySize = (Size)maxNumTiles * sizeof(short);
  95.         spriteWorldP->curTileImage = (short *)NewPtr(arraySize);
  96.         err = MemError();
  97.         
  98.         if (err == noErr)
  99.         {
  100.                 // Set up values in curTileImage array
  101.             for (tileIndex = 0; tileIndex < maxNumTiles; tileIndex++)
  102.                 spriteWorldP->curTileImage[tileIndex] = tileIndex;
  103.         }
  104.     }
  105.     
  106.     
  107.     if (err == noErr)
  108.     {
  109.             // Allocate memory for tileLayerArray
  110.         arraySize = (Size)kNumTileLayers * sizeof(TileMapStructPtr);
  111.         spriteWorldP->tileLayerArray = (TileMapStructPtr *)NewPtrClear(arraySize);
  112.         err = MemError();
  113.     }
  114.     
  115.     
  116.     SWSetStickyIfError(err);
  117.     return err;
  118. }
  119.  
  120.  
  121. ///--------------------------------------------------------------------------------------
  122. //    SWExitTiling
  123. ///--------------------------------------------------------------------------------------
  124.  
  125. SW_FUNC void SWExitTiling(
  126.     SpriteWorldPtr    spriteWorldP)
  127. {
  128.     short    tileIndex;
  129.     
  130.     SW_ASSERT(spriteWorldP != NULL);
  131.     
  132.         // Was tiling ever initialized?
  133.     if (spriteWorldP->tilingIsInitialized)
  134.     {
  135.         tileIndex = spriteWorldP->maxNumTiles;
  136.         while (tileIndex--)
  137.         {
  138.             SWDisposeTile(spriteWorldP, tileIndex);
  139.         }
  140.         
  141.         DisposePtr((Ptr)spriteWorldP->tileFrameArray);
  142.         DisposePtr((Ptr)spriteWorldP->curTileImage);
  143.         DisposePtr((Ptr)spriteWorldP->tileLayerArray);
  144.         DisposePtr((Ptr)spriteWorldP->changedTiles);
  145.         spriteWorldP->changedTiles = NULL;
  146.         
  147.         DisposePtr((Ptr)spriteWorldP->tilingCache[0]);    // Dispose the data
  148.         DisposePtr((Ptr)spriteWorldP->tilingCache);        // Dispose the array of pointers
  149.         spriteWorldP->tilingCache = NULL;
  150.         
  151.                 
  152.         spriteWorldP->tilingIsInitialized = false;
  153.         spriteWorldP->tilingIsOn = false;
  154.     }
  155. }
  156.  
  157.  
  158. ///--------------------------------------------------------------------------------------
  159. //    SWInitTilingCache - an internal function; called by SWInitTiling and SWChangeTileSize.
  160. //    Creates both the tiling cache and the changedTiles array of rects.
  161. ///--------------------------------------------------------------------------------------
  162.  
  163. SW_FUNC OSErr SWInitTilingCache(
  164.     SpriteWorldPtr    spriteWorldP)
  165. {
  166.     short    row, col, numTilingCacheCols, numTilingCacheRows, *tilingCacheData;
  167.     Size    arraySize;
  168.     OSErr    err = noErr;
  169.     
  170.         // Dispose the old tilingCache if necessary
  171.     if (spriteWorldP->tilingCache != NULL)
  172.     {
  173.         DisposePtr((Ptr)spriteWorldP->tilingCache[0]);    // Dispose the data
  174.         DisposePtr((Ptr)spriteWorldP->tilingCache);        // Dispose the array of pointers
  175.     }
  176.     
  177.         // Dispose the old changeTiles array of rects if necessary
  178.     if (spriteWorldP->changedTiles != NULL)
  179.     {
  180.         DisposePtr((Ptr)spriteWorldP->changedTiles);
  181.     }
  182.     
  183.     numTilingCacheRows = spriteWorldP->backRect.bottom / spriteWorldP->tileHeight;
  184.     numTilingCacheCols = spriteWorldP->backRect.right / spriteWorldP->tileWidth;
  185.     spriteWorldP->numTilingCacheRows = numTilingCacheRows;
  186.     spriteWorldP->numTilingCacheCols = numTilingCacheCols;
  187.     
  188.  
  189.         // Allocate memory for changedTiles array of rects
  190.     spriteWorldP->changedTilesArraySize = (numTilingCacheRows+1) * (numTilingCacheCols+1);
  191.     arraySize = (Size)(numTilingCacheRows+1) * (numTilingCacheCols+1) * sizeof(Rect);
  192.     spriteWorldP->changedTiles = (Rect *)NewPtr(arraySize);
  193.     err = MemError();
  194.     
  195.     
  196.     if (err == noErr)
  197.     {
  198.             // Allocate the array of pointers for the tiling Cache
  199.         arraySize = (Size)numTilingCacheRows * sizeof(short*);
  200.         spriteWorldP->tilingCache = (short **)NewPtr(arraySize);
  201.         err = MemError();
  202.         
  203.         if (err == noErr)
  204.         {
  205.                 // Allocate memory for the actual data of the tiling Cache
  206.             arraySize = (Size)numTilingCacheRows * numTilingCacheCols * sizeof(short);
  207.             tilingCacheData = (short *)NewPtr(arraySize);
  208.             err = MemError();
  209.             
  210.                 // If there was an error, dispose what we already created earlier
  211.             if (err != noErr)
  212.                 DisposePtr((Ptr)spriteWorldP->tilingCache);
  213.         }
  214.         
  215.         if (err == noErr)
  216.         {
  217.                 // Point each element of the tilingCache array to each row of the data
  218.             for (row = 0; row < numTilingCacheRows; row++)
  219.                 spriteWorldP->tilingCache[row] = &tilingCacheData[(long)row * numTilingCacheCols];
  220.  
  221.                 // Set all elements to -1 (indicating that each tile needs to be drawn)
  222.             for (row = 0; row < numTilingCacheRows; row++)
  223.                 for (col = 0; col < numTilingCacheCols; col++)
  224.                     spriteWorldP->tilingCache[row][col] = -1;
  225.         }
  226.     }
  227.     
  228.     if (err)
  229.     {
  230.         spriteWorldP->tilingCache = NULL;
  231.         spriteWorldP->changedTiles = NULL;
  232.     }
  233.     
  234.     return err;
  235. }
  236.  
  237.  
  238. ///--------------------------------------------------------------------------------------
  239. //    SWCreateTileMap
  240. ///--------------------------------------------------------------------------------------
  241.  
  242. SW_FUNC OSErr SWCreateTileMap(
  243.     TileMapStructPtr    *tileMapStructPP,
  244.     short                 numTileMapRows,
  245.     short                numTileMapCols)
  246. {
  247.     TileMapStructPtr    tileMapStructP;
  248.     Size                arraySize;
  249.     OSErr                err = noErr;
  250.     
  251.     
  252.         // Allocate memory for the TileMapStruct
  253.     tileMapStructP = (TileMapStructPtr)NewPtrClear(sizeof(TileMapStruct));
  254.     err = MemError();
  255.     
  256.     if (err == noErr)
  257.     {
  258.         tileMapStructP->numRows = numTileMapRows;
  259.         tileMapStructP->numCols = numTileMapCols;
  260.         
  261.             // Allocate the array of pointers that point to the data of the TileMap
  262.         arraySize = (Size)numTileMapRows * sizeof(short*);
  263.         tileMapStructP->arrayOfPointersH = NewHandle(arraySize);
  264.         err = MemError();
  265.     }
  266.     
  267.     if (err == noErr)
  268.     {
  269.             // Allocate memory for the actual data of the TileMap
  270.         arraySize = ((Size)numTileMapRows * numTileMapCols + 2) * sizeof(short);
  271.         tileMapStructP->tileMapDataH = NewHandleClear(arraySize);
  272.         err = MemError();
  273.     }
  274.     
  275.     if (err == noErr)
  276.     {
  277.         SWLockTileMap(tileMapStructP);
  278.     }
  279.     
  280.     
  281.     if (err != noErr)
  282.     {
  283.             // Dispose what we created
  284.         if (tileMapStructP != NULL)
  285.         {
  286.             DisposeHandle((Handle)tileMapStructP->arrayOfPointersH);
  287.             DisposeHandle((Handle)tileMapStructP->tileMapDataH);
  288.             DisposePtr((Ptr)tileMapStructP);
  289.             tileMapStructP = NULL;
  290.         }
  291.     }
  292.  
  293.         // Return a pointer to the TileMapStruct in the tileMapStructPP variable
  294.     *tileMapStructPP = tileMapStructP;
  295.     
  296.     SWSetStickyIfError(err);
  297.     return err;
  298. }
  299.  
  300.  
  301. ///--------------------------------------------------------------------------------------
  302. //    SWDisposeTileMap
  303. ///--------------------------------------------------------------------------------------
  304.  
  305. SW_FUNC void SWDisposeTileMap(
  306.     TileMapStructPtr    *tileMapStructPP)
  307. {
  308.     TileMapStructPtr    myTileMapStructP = *tileMapStructPP;
  309.     
  310.     if (myTileMapStructP != NULL)
  311.     {
  312.         DisposeHandle((Handle)myTileMapStructP->arrayOfPointersH);
  313.         DisposeHandle((Handle)myTileMapStructP->tileMapDataH);
  314.         DisposePtr((Ptr)myTileMapStructP);
  315.         *tileMapStructPP = NULL;
  316.     }
  317. }
  318.  
  319.  
  320. ///--------------------------------------------------------------------------------------
  321. //    SWLockTileMap
  322. ///--------------------------------------------------------------------------------------
  323.  
  324. SW_FUNC void SWLockTileMap(
  325.     TileMapStructPtr    tileMapStructP)
  326. {
  327.     short        **arrayOfPointers;
  328.     short        *tileMapDataP;
  329.     short        row;
  330.     
  331.     SW_ASSERT(tileMapStructP != NULL);
  332.     
  333.     HLockHi(tileMapStructP->arrayOfPointersH);
  334.     HLockHi(tileMapStructP->tileMapDataH);
  335.     
  336.     tileMapDataP = (short*)*tileMapStructP->tileMapDataH;
  337.     arrayOfPointers = (short**)*tileMapStructP->arrayOfPointersH;
  338.  
  339.         // Point each element of the array of pointers to each row of the data
  340.     for (row = 0; row < tileMapStructP->numRows; row++)
  341.     {
  342.         arrayOfPointers[row] = &tileMapDataP[(long)row * tileMapStructP->numCols + 2];
  343.     }
  344.     
  345.     tileMapStructP->tileMap = arrayOfPointers;
  346.     tileMapStructP->isLocked = true;
  347. }
  348.  
  349.  
  350. ///--------------------------------------------------------------------------------------
  351. //    SWUnlockTileMap
  352. ///--------------------------------------------------------------------------------------
  353.  
  354. SW_FUNC void SWUnlockTileMap(
  355.     TileMapStructPtr    tileMapStructP)
  356. {
  357.     SW_ASSERT(tileMapStructP != NULL);
  358.     
  359.     HUnlock(tileMapStructP->arrayOfPointersH);
  360.     HUnlock(tileMapStructP->tileMapDataH);
  361.     tileMapStructP->tileMap = NULL;
  362.     tileMapStructP->isLocked = false;
  363. }
  364.  
  365.  
  366. ///--------------------------------------------------------------------------------------
  367. //    SWInstallTileMap
  368. ///--------------------------------------------------------------------------------------
  369.  
  370. SW_FUNC void SWInstallTileMap(
  371.     SpriteWorldPtr        spriteWorldP,
  372.     TileMapStructPtr    tileMapStructP,
  373.     short                tileLayer)
  374. {
  375.     short    curLayer;
  376.     
  377.     SW_ASSERT(spriteWorldP != NULL);
  378.     SW_ASSERT(tileLayer < kNumTileLayers);
  379.     
  380.         // Install the TileMap
  381.     spriteWorldP->tileLayerArray[tileLayer] = tileMapStructP;
  382.     spriteWorldP->lastActiveTileLayer = 0;
  383.     
  384.         // Find the last active tile layer
  385.     for (curLayer = 0; curLayer < kNumTileLayers; curLayer++)
  386.     {
  387.         if (spriteWorldP->tileLayerArray[curLayer] != NULL)
  388.             spriteWorldP->lastActiveTileLayer = curLayer;
  389.     }
  390.     
  391.         // Set the appropriate tileRectDrawProc
  392.     if (spriteWorldP->lastActiveTileLayer == 0)
  393.     {
  394.         spriteWorldP->tileRectDrawProc = SWDrawTilesInRect;
  395.     }
  396.     else
  397.     {
  398.         spriteWorldP->tileRectDrawProc = SWDrawTileLayersInRect;
  399.     }
  400. }
  401.  
  402.  
  403. ///--------------------------------------------------------------------------------------
  404. //    SWLoadTileMap
  405. ///--------------------------------------------------------------------------------------
  406.  
  407. SW_FUNC OSErr SWLoadTileMap(
  408.     TileMapStructPtr    *tileMapStructPP,
  409.     short                 resourceID)
  410. {
  411.     TileMapStructPtr    tileMapStructP;
  412.     short                *tileMapData;
  413.     Size                arraySize;
  414.     OSErr                err = noErr;
  415.     
  416.     
  417.         // Allocate memory for the TileMapStruct
  418.     tileMapStructP = (TileMapStructPtr)NewPtrClear(sizeof(TileMapStruct));
  419.     err = MemError();
  420.     
  421.     if (err == noErr)
  422.     {    
  423.             // Load the resource
  424.         tileMapStructP->tileMapDataH = Get1Resource('TMAP', resourceID);
  425.         
  426.         if (tileMapStructP->tileMapDataH == NULL)
  427.             err = ResError() ? ResError() : resNotFound;
  428.     }
  429.     
  430.     if (err == noErr)
  431.     {
  432.         DetachResource((Handle)tileMapStructP->tileMapDataH);
  433.         
  434.         tileMapData = (short*)*tileMapStructP->tileMapDataH;
  435.         tileMapStructP->numRows = tileMapData[0];
  436.         tileMapStructP->numCols = tileMapData[1];
  437.         
  438.             // Allocate the array of pointers that point to the data of the TileMap
  439.         arraySize = (Size)tileMapStructP->numRows * sizeof(short*);
  440.         tileMapStructP->arrayOfPointersH = NewHandle(arraySize);
  441.         err = MemError();
  442.     }
  443.     
  444.     if (err == noErr)
  445.     {
  446.         SWLockTileMap(tileMapStructP);
  447.     }
  448.     
  449.     
  450.     if (err != noErr)
  451.     {
  452.             // Dispose what we created
  453.         if (tileMapStructP != NULL)
  454.         {
  455.             DisposeHandle((Handle)tileMapStructP->arrayOfPointersH);
  456.             DisposeHandle((Handle)tileMapStructP->tileMapDataH);
  457.             DisposePtr((Ptr)tileMapStructP);
  458.             tileMapStructP = NULL;
  459.         }
  460.     }
  461.     
  462.         // Return a pointer to the TileMapStruct in the tileMapStructPP variable
  463.     *tileMapStructPP = tileMapStructP;
  464.     
  465.     SWSetStickyIfError(err);
  466.     return err;
  467. }
  468.  
  469.  
  470. ///--------------------------------------------------------------------------------------
  471. //    SWSaveTileMap
  472. ///--------------------------------------------------------------------------------------
  473.  
  474. SW_FUNC OSErr SWSaveTileMap(
  475.     TileMapStructPtr    tileMapStructP,
  476.     short                 destResID)
  477. {
  478.     short        tempResID;
  479.     short        *tileMapData;
  480.     Handle        tempTileMapH;
  481.     OSErr        err = noErr;
  482.     
  483.         // Make sure there is a tileMap to save
  484.     if (tileMapStructP == NULL)
  485.         err = kNullTileMapErr;
  486.  
  487.     if (err == noErr)
  488.     {
  489.             // Save numRows & numCols in the first two elements of the tileMapData
  490.         tileMapData = (short*)*tileMapStructP->tileMapDataH;
  491.         tileMapData[0] = tileMapStructP->numRows;
  492.         tileMapData[1] = tileMapStructP->numCols;
  493.         
  494.             // Add the TMAP resource, assigning it a temporary, unused ID
  495.         tempResID = Unique1ID('TMAP');
  496.         AddResource(tileMapStructP->tileMapDataH, 'TMAP', tempResID, "\p");
  497.         err = ResError();
  498.         
  499.             // This call may fix a sporadic problem I've had occasionally that occurs when
  500.             // opening one level, then opening another one, making it larger, saving it, and
  501.             // re-opening it, all without quitting. Unfortunately, I couldn't reproduce it to 
  502.             // test this fix.
  503.         if (err == noErr)
  504.             WriteResource(tileMapStructP->tileMapDataH);
  505.     }
  506.     
  507.     if (err == noErr)
  508.     {
  509.         do        // Remove any old TMAP resources with destResID
  510.         {
  511.             SetResLoad(false);
  512.             tempTileMapH = Get1Resource('TMAP', destResID);
  513.             SetResLoad(true);
  514.             
  515.             if (tempTileMapH != NULL)
  516.             {
  517.                 RemoveResource(tempTileMapH);
  518.                 
  519.                     // This could happen if the resource is protected
  520.                 err = ResError();
  521.                 SW_ASSERT(ResError() == noErr);
  522.             }
  523.             else if (ResError() != resNotFound && ResError() != noErr)
  524.             {
  525.                 // This could happen if Get1Resource didn't have a free master
  526.                 // pointer and there isn't enough memory to allocate a new block
  527.                 err = ResError();
  528.             }
  529.         } while (tempTileMapH != NULL);
  530.         
  531.         
  532.             // Change the resource ID to the proper one
  533.         SetResInfo(tileMapStructP->tileMapDataH, destResID, "\p");
  534.         
  535.             // Update file, writing new resource and deleting old one in one step.
  536.         UpdateResFile( CurResFile() );
  537.         DetachResource(tileMapStructP->tileMapDataH);
  538.     }
  539.                 
  540.     
  541.     SWSetStickyIfError(err);
  542.     return err;
  543. }
  544.  
  545.  
  546. ///--------------------------------------------------------------------------------------
  547. //    SWResizeTileMap
  548. ///--------------------------------------------------------------------------------------
  549.  
  550. SW_FUNC OSErr SWResizeTileMap(
  551.     TileMapStructPtr    oldTileMapStructP,
  552.     short                 numNewTileMapRows,
  553.     short                numNewTileMapCols)
  554. {
  555.     TileMapStruct        tempTileMapStruct;
  556.     TileMapStructPtr    newTileMapStructP;
  557.     short                row, numRowsToCopy, numColsToCopy;
  558.     Size                arraySize;
  559.     OSErr                err = noErr;
  560.         
  561.     SW_ASSERT(numNewTileMapRows > 0 && numNewTileMapCols > 0);
  562.     
  563.     if (oldTileMapStructP == NULL)
  564.         err = kNullTileMapErr;
  565.     
  566.     
  567.     if (err == noErr)
  568.     {
  569.             // Don't do anything if the TileMap is already the requested size.
  570.         if (oldTileMapStructP->numRows == numNewTileMapRows && 
  571.             oldTileMapStructP->numCols == numNewTileMapCols)
  572.         {
  573.             return noErr;
  574.         }
  575.         
  576.             // Create the new TileMap
  577.         err = SWCreateTileMap(&newTileMapStructP, numNewTileMapRows, numNewTileMapCols);
  578.     }
  579.     
  580.     if (err == noErr)
  581.     {
  582.         if (oldTileMapStructP->isLocked == false)
  583.             SWLockTileMap(oldTileMapStructP);
  584.         
  585.         numRowsToCopy = SW_MIN(oldTileMapStructP->numRows, numNewTileMapRows);
  586.         numColsToCopy = SW_MIN(oldTileMapStructP->numCols, numNewTileMapCols);
  587.         
  588.             // Copy the data from the old TileMap to the new TileMap
  589.         arraySize = (Size)numColsToCopy * sizeof(short);
  590.         for (row = 0; row < numRowsToCopy; row++)
  591.         {
  592.             BlockMoveData(&oldTileMapStructP->tileMap[row][0],
  593.                 &newTileMapStructP->tileMap[row][0], arraySize);
  594.         }
  595.         
  596.             // Swap contents of the new and old TileMapStructs
  597.         tempTileMapStruct = *oldTileMapStructP;
  598.         *oldTileMapStructP = *newTileMapStructP;
  599.         *newTileMapStructP = tempTileMapStruct;
  600.         
  601.             // Dispose the newTileMapStruct, which now contains the old TileMap
  602.         SWDisposeTileMap(&newTileMapStructP);
  603.     }
  604.     
  605.     
  606.     SWSetStickyIfError(err);
  607.     return err;
  608. }
  609.  
  610.  
  611. ///--------------------------------------------------------------------------------------
  612. //    SWLoadTileFromCicnResource
  613. ///--------------------------------------------------------------------------------------
  614.  
  615. SW_FUNC OSErr SWLoadTileFromCicnResource(
  616.     SpriteWorldPtr    spriteWorldP, 
  617.     short            tileID,
  618.     short            cicnID, 
  619.     MaskType        maskType)
  620. {
  621.     OSErr             err;
  622.     GWorldPtr         saveGWorld;
  623.     GDHandle         saveGDH;
  624.     FramePtr         newFrameP;
  625.     CIconHandle     cIconH;
  626.     Rect            frameRect;
  627.     Boolean            maskIsSolid = false;
  628.     
  629.     SW_ASSERT(spriteWorldP != NULL);
  630.     
  631.     err = noErr;
  632.     newFrameP = NULL;
  633.  
  634.     if ( !spriteWorldP->tilingIsInitialized )
  635.     {
  636.         err = kTilingNotInitialized;
  637.     }
  638.     else if ( tileID < 0 || tileID >= spriteWorldP->maxNumTiles)
  639.     {
  640.         err = kOutOfRangeErr;
  641.     }
  642.     
  643.     if (maskType == kSolidMask)
  644.     {
  645.         maskIsSolid = true;
  646.         maskType = kNoMask;
  647.     }
  648.     
  649.     if ( err == noErr )
  650.     {    
  651.         err = SWCreateFrameFromCicnResource(spriteWorldP, &newFrameP, cicnID, maskType);
  652.         
  653.         if ( err == noErr )
  654.         {    
  655.             newFrameP->tileMaskIsSolid = maskIsSolid;
  656.             
  657.                 // "Fix" the size if the CICN is larger than the tiles are
  658.             if (newFrameP->frameRect.right > spriteWorldP->tileWidth)
  659.                 newFrameP->frameRect.right = spriteWorldP->tileWidth;
  660.             if (newFrameP->frameRect.bottom > spriteWorldP->tileHeight)
  661.                 newFrameP->frameRect.bottom = spriteWorldP->tileHeight;
  662.             
  663.             cIconH = GetCIcon( cicnID );
  664.  
  665.             if (cIconH != NULL)
  666.             {
  667.                 GetGWorld(&saveGWorld, &saveGDH);
  668.                 
  669.                 HLock((Handle)cIconH);
  670.                 frameRect = ((**cIconH).iconPMap.bounds);
  671.                 (**cIconH).iconPMap.baseAddr = *(**cIconH).iconData;
  672.                 (**cIconH).iconBMap.baseAddr = (Ptr)&((**cIconH).iconMaskData ) +
  673.                     ((**cIconH).iconMask.rowBytes * (frameRect.bottom-frameRect.top));    
  674.                                 
  675.                 (void)LockPixels( GetGWorldPixMap( newFrameP->framePort ) );
  676.                 SetGWorld( newFrameP->framePort, NULL );
  677.                 if ( spriteWorldP->pixelDepth > 1 )
  678.                 {
  679.                     CopyBits( (BitMap*)(&((**cIconH).iconPMap)),
  680.                         (BitMap*)*GetGWorldPixMap( newFrameP->framePort ), 
  681.                         &frameRect, &newFrameP->frameRect, srcCopy, nil);
  682.                 }
  683.                 else
  684.                 {
  685.                     CopyBits( (BitMap*)(&((**cIconH).iconBMap)),
  686.                         (BitMap*)*GetGWorldPixMap( newFrameP->framePort ), 
  687.                         &frameRect,
  688.                         &newFrameP->frameRect, srcCopy, nil);
  689.                 }
  690.                 UnlockPixels( GetGWorldPixMap( newFrameP->framePort ) );
  691.                 DisposeCIcon( cIconH );
  692.                 SetGWorld( saveGWorld, saveGDH );
  693.             }
  694.             else
  695.             {
  696.                 err = MemError();
  697.             }
  698.         }
  699.         
  700.         if ( err == noErr )
  701.         {
  702.                 // Are we replacing an old tile?
  703.             if (spriteWorldP->tileFrameArray[tileID] != NULL)
  704.             {
  705.                 SWDisposeTile( spriteWorldP, tileID );
  706.             }
  707.             spriteWorldP->tileFrameArray[tileID] = newFrameP;
  708.             newFrameP->useCount++;
  709.         }
  710.     }
  711.     
  712.     if ( err != noErr && newFrameP != NULL )
  713.     {
  714.         SWDisposeFrame(&newFrameP);
  715.     }
  716.     
  717.     SWSetStickyIfError(err);
  718.     return err;
  719. }
  720.  
  721.  
  722. ///--------------------------------------------------------------------------------------
  723. //    SWLoadTilesFromPictResource
  724. ///--------------------------------------------------------------------------------------
  725.  
  726. SW_FUNC OSErr SWLoadTilesFromPictResource(
  727.     SpriteWorldPtr    spriteWorldP, 
  728.     short            startTileID,
  729.     short            endTileID, 
  730.     short            pictResID, 
  731.     short            maskResID,
  732.     MaskType        maskType,
  733.     short            horizBorderWidth,
  734.     short            vertBorderHeight)
  735. {
  736.     OSErr             err;
  737.     short            tileIndex;
  738.     FramePtr         newFrameP;
  739.     GWorldPtr        tempPictGWorldP,
  740.                     tempMaskGWorldP,
  741.                     tempTempMaskGWorldP,
  742.                     currentGWorld;
  743.     GDHandle        currentGDH;
  744.     Rect            currentTileRect;
  745.     short            horizOffset,
  746.                     vertOffset;
  747.     Boolean            allTilesDone,
  748.                     maskIsSolid = false;
  749.     
  750.     SW_ASSERT(spriteWorldP != NULL);
  751.     
  752.     err = noErr;
  753.     newFrameP = NULL;
  754.     tempPictGWorldP = NULL;
  755.     tempMaskGWorldP = NULL;
  756.     tempTempMaskGWorldP = NULL;
  757.     
  758.     if ( !spriteWorldP->tilingIsInitialized )
  759.     {
  760.         err = kTilingNotInitialized;
  761.     }
  762.     else if ( startTileID < 0 || endTileID >= spriteWorldP->maxNumTiles)
  763.     {
  764.         err = kOutOfRangeErr;
  765.     }
  766.     
  767.     if (maskType == kSolidMask)
  768.     {
  769.         maskIsSolid = true;
  770.         maskType = kNoMask;
  771.     }
  772.     
  773.     if ( err == noErr )
  774.     {    
  775.         err = SWCreateGWorldFromPictResource( spriteWorldP, &tempPictGWorldP, pictResID );
  776.         
  777.         if ( err == noErr && maskType != kNoMask )
  778.             err = SWCreateGWorldFromPictResource( spriteWorldP, &tempMaskGWorldP, maskResID );
  779.         
  780.         if (err == noErr)
  781.         {
  782.             if ( pictResID == maskResID && tempMaskGWorldP != NULL )
  783.             {
  784.                 err = SWBlackenGWorld( tempMaskGWorldP );
  785.             }
  786.         }
  787.         
  788.         if ( err == noErr )
  789.         {
  790.             err = SWCreateFrameFromGWorldAndRectStart( &tempTempMaskGWorldP, 
  791.                     spriteWorldP->tileWidth, spriteWorldP->tileHeight, maskType );
  792.         }
  793.     
  794.         if ( err == noErr )
  795.         {
  796.             SetRect( ¤tTileRect, 0,  0, 
  797.                 spriteWorldP->tileWidth, spriteWorldP->tileHeight );
  798.             tileIndex = startTileID;
  799.             horizOffset = spriteWorldP->tileWidth + horizBorderWidth;
  800.             vertOffset = spriteWorldP->tileHeight + vertBorderHeight;
  801.             
  802.             allTilesDone = false;
  803.             while( !allTilesDone && err == noErr )
  804.             {
  805.                 err = SWCreateFrameFromGWorldAndRectPartial( &newFrameP, tempPictGWorldP, 
  806.                         tempMaskGWorldP, tempTempMaskGWorldP, ¤tTileRect, maskType);
  807.                 
  808.                 if ( newFrameP != NULL && err == noErr )
  809.                 {
  810.                     newFrameP->tileMaskIsSolid = maskIsSolid;
  811.                     
  812.                         // Are we replacing an old tile?
  813.                     if (spriteWorldP->tileFrameArray[tileIndex] != NULL)
  814.                     {
  815.                         SWDisposeTile( spriteWorldP, tileIndex );
  816.                     }
  817.                     spriteWorldP->tileFrameArray[tileIndex] = newFrameP;
  818.                     newFrameP->useCount++;
  819.                     
  820.                     tileIndex++;
  821.                     if (tileIndex > endTileID )
  822.                     {
  823.                         allTilesDone = true;
  824.                     }
  825.                     else
  826.                     {
  827.                         if (tileIndex >= spriteWorldP->maxNumTiles)
  828.                         {
  829.                             err = kOutOfRangeErr;
  830.                         }
  831.                         currentTileRect.left += horizOffset;
  832.                         currentTileRect.right += horizOffset;
  833.                         if ( currentTileRect.right > tempPictGWorldP->portRect.right )
  834.                         {
  835.                             currentTileRect.left = 0;
  836.                             currentTileRect.right = spriteWorldP->tileWidth;
  837.                             currentTileRect.top += vertOffset;
  838.                             currentTileRect.bottom += vertOffset;
  839.                             if ( currentTileRect.bottom > tempPictGWorldP->portRect.bottom )
  840.                             {
  841.                                 err = kOutOfRangeErr;
  842.                             }
  843.                         }
  844.                     }
  845.                 }
  846.             }
  847.             
  848.             if (err == noErr)
  849.             {
  850.                     // make a pixel mask
  851.                 if ((maskType & kPixelMask) != 0)
  852.                 {
  853.                     if (spriteWorldP->pixelDepth <= 8)
  854.                     {
  855.                         GetGWorld( ¤tGWorld, ¤tGDH );
  856.                         (void)LockPixels( GetGWorldPixMap(tempMaskGWorldP) );
  857.                         SetGWorld(tempMaskGWorldP, nil);
  858.                         InvertRect(&tempMaskGWorldP->portRect);
  859.                         SetGWorld( currentGWorld, currentGDH );
  860.                         UnlockPixels( GetGWorldPixMap(tempMaskGWorldP) );
  861.                     }
  862.                 }
  863.                 else if (tempMaskGWorldP != NULL)
  864.                 {
  865.                         // If no pixel Mask wanted, dispose
  866.                         // of the GWorld we used to make region
  867.                     DisposeGWorld( tempMaskGWorldP );
  868.                 }
  869.             }
  870.         }
  871.         SWCreateFrameFromGWorldAndRectFinish( tempTempMaskGWorldP );
  872.     }
  873.     
  874.     SWSetStickyIfError(err);
  875.     return err;
  876. }
  877.  
  878.  
  879. ///--------------------------------------------------------------------------------------
  880. //    SWDisposeTile
  881. ///--------------------------------------------------------------------------------------
  882.  
  883. SW_FUNC void SWDisposeTile(
  884.     SpriteWorldPtr    spriteWorldP,
  885.     short            tileID)
  886. {
  887.     short        tileIndex;
  888.     Boolean        gWorldStillInUse;
  889.     
  890.     SW_ASSERT(spriteWorldP != NULL);
  891.     SW_ASSERT(spriteWorldP->tilingIsInitialized);
  892.     
  893.         // see if any other tile is using this tile's GWorld
  894.     gWorldStillInUse = false;
  895.     tileIndex = spriteWorldP->maxNumTiles;
  896.     while ( tileIndex-- )
  897.     {
  898.         if ( tileIndex != tileID )
  899.         {
  900.             if ( spriteWorldP->tileFrameArray[tileIndex] != NULL &&
  901.                 ((spriteWorldP->tileFrameArray[tileIndex])->framePort == 
  902.                 (spriteWorldP->tileFrameArray[tileID])->framePort) )
  903.             {
  904.                 gWorldStillInUse = true;
  905.             }
  906.         }
  907.     }
  908.         // set flag that tells SWDisposeFrame whether to dispose of GWorld
  909.     (spriteWorldP->tileFrameArray[tileID])->sharesGWorld = gWorldStillInUse;
  910.     
  911.     (void)SWDisposeFrame( &spriteWorldP->tileFrameArray[tileID] );
  912.     spriteWorldP->tileFrameArray[tileID] = NULL;
  913. }
  914.  
  915.  
  916. ///--------------------------------------------------------------------------------------
  917. //    SWLockTiles
  918. ///--------------------------------------------------------------------------------------
  919.  
  920. SW_FUNC void SWLockTiles(
  921.     SpriteWorldPtr    spriteWorldP)
  922. {
  923.     short        tileIndex;
  924.     
  925.     SW_ASSERT(spriteWorldP != NULL);
  926.     
  927.         // Tiling might not be initialized if this was called from SWLockSpriteWorld
  928.     if (spriteWorldP->tilingIsInitialized)    
  929.     {
  930.         for (tileIndex = 0; tileIndex < spriteWorldP->maxNumTiles; tileIndex++)
  931.         {
  932.             if (spriteWorldP->tileFrameArray[tileIndex] != NULL)
  933.                 SWLockFrame(spriteWorldP->tileFrameArray[tileIndex]);
  934.         }
  935.     }
  936. }
  937.  
  938.  
  939. ///--------------------------------------------------------------------------------------
  940. //    SWUnlockTiles
  941. ///--------------------------------------------------------------------------------------
  942.  
  943. SW_FUNC void SWUnlockTiles(
  944.     SpriteWorldPtr    spriteWorldP)
  945. {
  946.     short        tileIndex;
  947.     
  948.     SW_ASSERT(spriteWorldP != NULL);
  949.     
  950.         // Tiling might not be initialized if this was called from SWLockSpriteWorld
  951.     if (spriteWorldP->tilingIsInitialized)    
  952.     {
  953.         for (tileIndex = 0; tileIndex < spriteWorldP->maxNumTiles; tileIndex++)
  954.         {
  955.             if (spriteWorldP->tileFrameArray[tileIndex] != NULL)
  956.                 SWUnlockFrame(spriteWorldP->tileFrameArray[tileIndex]);
  957.         }
  958.     }
  959. }
  960.  
  961.  
  962. ///--------------------------------------------------------------------------------------
  963. //    SWCreateExtraBackFrame
  964. ///--------------------------------------------------------------------------------------
  965.  
  966. SW_FUNC OSErr SWCreateExtraBackFrame(
  967.     SpriteWorldPtr    spriteWorldP,
  968.     Rect            *frameRect)
  969. {
  970.     OSErr    err = noErr;
  971.     
  972.     SW_ASSERT(spriteWorldP != NULL);
  973.     SW_ASSERT(frameRect->right > frameRect->left && frameRect->bottom > frameRect->top);
  974.     
  975.     if (spriteWorldP->extraBackFrameP != NULL)
  976.     {
  977.         SWDisposeFrame(&spriteWorldP->extraBackFrameP);
  978.     }
  979.     
  980.         // Make sure rect starts at 0,0
  981.     OffsetRect(frameRect, -frameRect->left, -frameRect->top);
  982.     
  983.     err = SWCreateFrame(spriteWorldP->mainSWGDH, &spriteWorldP->extraBackFrameP, 
  984.             frameRect, spriteWorldP->pixelDepth);
  985.     
  986.     return err;
  987. }
  988.  
  989.  
  990. ///--------------------------------------------------------------------------------------
  991. //    SWDisposeExtraBackFrame
  992. ///--------------------------------------------------------------------------------------
  993.  
  994. SW_FUNC void SWDisposeExtraBackFrame(
  995.     SpriteWorldPtr    spriteWorldP)
  996. {
  997.     SW_ASSERT(spriteWorldP != NULL);
  998.     SWDisposeFrame(&spriteWorldP->extraBackFrameP);
  999.     spriteWorldP->extraBackFrameP = NULL;
  1000. }
  1001.  
  1002.  
  1003. ///--------------------------------------------------------------------------------------
  1004. //    SWSetPortToExtraBackFrame
  1005. ///--------------------------------------------------------------------------------------
  1006.  
  1007. SW_FUNC OSErr SWSetPortToExtraBackFrame(
  1008.     SpriteWorldPtr    spriteWorldP)
  1009. {
  1010.     OSErr    err = noErr;
  1011.     
  1012.     SW_ASSERT(spriteWorldP != NULL);
  1013.     
  1014.     if ( spriteWorldP->extraBackFrameP == NULL )
  1015.         err = kNilFrameErr;
  1016.     else if ( spriteWorldP->extraBackFrameP->isFrameLocked == false)
  1017.         err = kNotLockedErr;
  1018.     
  1019.     if (err == noErr)
  1020.         SetGWorld(spriteWorldP->extraBackFrameP->framePort, nil);
  1021.     
  1022.     SWSetStickyIfError( err );
  1023.     return err;
  1024. }
  1025.  
  1026.  
  1027. ///--------------------------------------------------------------------------------------
  1028. //    SWSetTilingOn
  1029. ///--------------------------------------------------------------------------------------
  1030.  
  1031. SW_FUNC void SWSetTilingOn(
  1032.     SpriteWorldPtr    spriteWorldP,
  1033.     Boolean            tilingIsOn)
  1034. {
  1035.     SW_ASSERT(spriteWorldP != NULL);
  1036.     spriteWorldP->tilingIsOn = tilingIsOn;
  1037. }
  1038.  
  1039.  
  1040. ///--------------------------------------------------------------------------------------
  1041. //    SWChangeTileSize
  1042. ///--------------------------------------------------------------------------------------
  1043.  
  1044. SW_FUNC OSErr SWChangeTileSize(
  1045.     SpriteWorldPtr    spriteWorldP,
  1046.     short             tileHeight,
  1047.     short            tileWidth)
  1048. {
  1049.     OSErr    err;
  1050.     
  1051.     SW_ASSERT(spriteWorldP != NULL);
  1052.     
  1053.     spriteWorldP->tileHeight = tileHeight;
  1054.     spriteWorldP->tileWidth = tileWidth;
  1055.     
  1056.         // Dispose and rebuild the tiling cache, based on the new tile width & height
  1057.     err = SWInitTilingCache(spriteWorldP);
  1058.     
  1059.     return err;
  1060. }
  1061.  
  1062.  
  1063. ///--------------------------------------------------------------------------------------
  1064. //    SWSetSpriteLayerUnderTileLayer
  1065. ///--------------------------------------------------------------------------------------
  1066.  
  1067. SW_FUNC void SWSetSpriteLayerUnderTileLayer(
  1068.     SpriteLayerPtr    spriteLayerP,
  1069.     short            tileLayer)
  1070. {
  1071.     SW_ASSERT(spriteLayerP != NULL);
  1072.     spriteLayerP->tileLayer = tileLayer;
  1073. }
  1074.  
  1075.  
  1076. ///--------------------------------------------------------------------------------------
  1077. //    SWSetTileMaskDrawProc
  1078. ///--------------------------------------------------------------------------------------
  1079.  
  1080. SW_FUNC OSErr SWSetTileMaskDrawProc(
  1081.     SpriteWorldPtr    spriteWorldP,
  1082.     DrawProcPtr        drawProc)
  1083. {
  1084.     OSErr    err = noErr;
  1085.     
  1086.     SW_ASSERT(spriteWorldP != NULL);
  1087.     
  1088.     if (drawProc == BlitPixie8BitPartialMaskDrawProc ||
  1089.         drawProc == BP8BitInterlacedPartialMaskDrawProc)
  1090.     {
  1091.         err = kBadParameterErr;
  1092.     }
  1093.     else if (spriteWorldP->pixelDepth != 8)
  1094.     {
  1095.         if (drawProc == BlitPixie8BitMaskDrawProc || drawProc == BP8BitInterlacedMaskDrawProc)
  1096.         {
  1097.             err = kWrongDepthErr;
  1098.         }
  1099.     }
  1100.  
  1101.     if ( err == noErr )
  1102.     {
  1103.         spriteWorldP->tileMaskDrawProc = drawProc;
  1104.     }
  1105.     
  1106.     SWSetStickyIfError( err );
  1107.     return err;
  1108. }
  1109.  
  1110.  
  1111. ///--------------------------------------------------------------------------------------
  1112. //    SWSetPartialMaskDrawProc
  1113. ///--------------------------------------------------------------------------------------
  1114.  
  1115. SW_FUNC OSErr SWSetPartialMaskDrawProc(
  1116.     SpriteWorldPtr    spriteWorldP,
  1117.     DrawProcPtr        drawProc)
  1118. {
  1119.     OSErr    err = noErr;
  1120.     
  1121.     SW_ASSERT(spriteWorldP != NULL);
  1122.     
  1123.     if (spriteWorldP->pixelDepth != 8)
  1124.     {
  1125.         if (drawProc == BlitPixie8BitPartialMaskDrawProc || 
  1126.             drawProc == BP8BitInterlacedPartialMaskDrawProc)
  1127.         {
  1128.             err = kWrongDepthErr;
  1129.         }
  1130.     }
  1131.  
  1132.     if ( err == noErr )
  1133.     {
  1134.         spriteWorldP->partialMaskDrawProc = drawProc;
  1135.     }
  1136.     
  1137.     SWSetStickyIfError( err );
  1138.     return err;
  1139. }
  1140.  
  1141.  
  1142. ///--------------------------------------------------------------------------------------
  1143. //    SWSetTileChangeProc
  1144. ///--------------------------------------------------------------------------------------
  1145.  
  1146. SW_FUNC void SWSetTileChangeProc(
  1147.     SpriteWorldPtr        spriteWorldP,
  1148.     TileChangeProcPtr    tileChangeProc)
  1149. {
  1150.     SW_ASSERT(spriteWorldP != NULL);
  1151.     spriteWorldP->tileChangeProc = tileChangeProc;
  1152. }
  1153.  
  1154.  
  1155. #pragma mark -
  1156. ///--------------------------------------------------------------------------------------
  1157. //    SWDrawTilesInBackground
  1158. ///--------------------------------------------------------------------------------------
  1159.  
  1160. SW_FUNC OSErr SWDrawTilesInBackground(
  1161.     SpriteWorldPtr    spriteWorldP)
  1162. {
  1163.     GWorldPtr        holdGWorld;
  1164.     GDHandle        holdGDH;
  1165.     OSErr            err = noErr;
  1166.     
  1167.     SW_ASSERT(spriteWorldP != NULL);
  1168.     
  1169.     GetGWorld( &holdGWorld, &holdGDH );
  1170.     
  1171.     if ( !spriteWorldP->tilingIsInitialized )
  1172.         err = kTilingNotInitialized;
  1173.     
  1174.     if (err == noErr)
  1175.     {
  1176.         (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &spriteWorldP->visScrollRect, true);
  1177.     }
  1178.     
  1179.     SetGWorld( holdGWorld, holdGDH );
  1180.     
  1181.     SWSetStickyIfError(err);
  1182.     return err;
  1183. }
  1184.  
  1185.  
  1186. ///--------------------------------------------------------------------------------------
  1187. //    SWDrawTile - sets value in tileMap and draws tile if visible in visScrollRect.
  1188. //    The main core of this function is very similar to the inner loop of 
  1189. //    SWTileDrawLayersInRect, except that this calls SWAddChangedRect, has code to set the
  1190. //    tiling cache, and makes sure the tile is visible on screen before drawing it.
  1191. //    Oh, and SWDrawTile *sets* the tileID in the tileMap, instead of getting it. :-)
  1192. ///--------------------------------------------------------------------------------------
  1193.  
  1194. SW_FUNC void SWDrawTile(
  1195.     SpriteWorldPtr    spriteWorldP,
  1196.     short            dstTileLayer,
  1197.     short            tileRow,
  1198.     short            tileCol,
  1199.     short            tileID)
  1200. {
  1201.     short        row, col, offscreenTileRow, offscreenTileCol, tileLayer;
  1202.     Rect*        visScrollRectP = &spriteWorldP->visScrollRect;
  1203.     Rect*        backRectP = &spriteWorldP->backRect;
  1204.     short        tileHeight = spriteWorldP->tileHeight;
  1205.     short        tileWidth = spriteWorldP->tileWidth;
  1206.     Rect        srcRect, dstRect;
  1207.     FramePtr    tileFrameP;
  1208.     Boolean        tileClipped, tileHasMask;
  1209.     
  1210.         // We must have a TileMap installed in the dstTileLayer to draw in it!
  1211.     if (spriteWorldP->tileLayerArray[dstTileLayer] == NULL)
  1212.         return;
  1213.     
  1214.         // Check SpriteWorldRec
  1215.     SW_ASSERT(spriteWorldP != NULL);
  1216.     SW_ASSERT(spriteWorldP->tilingIsInitialized);
  1217.     SW_ASSERT(spriteWorldP->tileMaskDrawProc != NULL);
  1218.     SW_ASSERT(spriteWorldP->offscreenDrawProc != NULL);
  1219.     SW_ASSERT(spriteWorldP->backFrameP->isFrameLocked);
  1220.     SW_ASSERT(spriteWorldP->workFrameP->isFrameLocked);
  1221.     SW_ASSERT(spriteWorldP->tileLayerArray[dstTileLayer] != NULL);
  1222.     SW_ASSERT(spriteWorldP->tileLayerArray[dstTileLayer]->isLocked);
  1223.     
  1224.         // Check parameters
  1225.     SW_ASSERT(dstTileLayer <= spriteWorldP->lastActiveTileLayer);
  1226.     SW_ASSERT(tileRow < spriteWorldP->tileLayerArray[dstTileLayer]->numRows);
  1227.     SW_ASSERT(tileCol < spriteWorldP->tileLayerArray[dstTileLayer]->numCols);
  1228.     SW_ASSERT(tileID < spriteWorldP->maxNumTiles);
  1229.     
  1230.     SetGWorld(spriteWorldP->backFrameP->framePort, nil);
  1231.     
  1232.         // Note: we can not return if the tileID is what is already in the TileMap, 
  1233.         // since tile animation would then not work.
  1234.     
  1235.     
  1236.         // Store the new tileID in the TileMap of the dstTileLayer
  1237.     spriteWorldP->tileLayerArray[dstTileLayer]->tileMap[tileRow][tileCol] = tileID;
  1238.     
  1239.     row = tileRow * tileHeight;
  1240.     col = tileCol * tileWidth;
  1241.             
  1242.     dstRect.bottom = row + tileHeight;
  1243.     dstRect.right = col + tileWidth;
  1244.         
  1245.         // Clip tile dstRect with visScrollRect //
  1246.     tileClipped = false;
  1247.     if (row < visScrollRectP->top)
  1248.     {
  1249.         dstRect.top = visScrollRectP->top;
  1250.         tileClipped = true;
  1251.     }
  1252.     else
  1253.         dstRect.top = row;
  1254.     
  1255.     if (col < visScrollRectP->left)
  1256.     {
  1257.         dstRect.left = visScrollRectP->left;
  1258.         tileClipped = true;
  1259.     }
  1260.     else
  1261.         dstRect.left = col;
  1262.     
  1263.     if (dstRect.bottom > visScrollRectP->bottom)
  1264.     {
  1265.         dstRect.bottom = visScrollRectP->bottom;
  1266.         tileClipped = true;
  1267.     }
  1268.     
  1269.     if (dstRect.right > visScrollRectP->right)
  1270.     {
  1271.         dstRect.right = visScrollRectP->right;
  1272.         tileClipped = true;
  1273.     }
  1274.     
  1275.  
  1276.         // Draw tile if visible on screen (in visScrollRect)
  1277.     if (dstRect.left < dstRect.right && dstRect.top < dstRect.bottom)
  1278.     {
  1279.             // Save rect as having been changed
  1280.         SWAddChangedRect(spriteWorldP, &dstRect);
  1281.         
  1282.             // Now get the tileID of this row and col in tileLayer 0
  1283.         if (spriteWorldP->tileLayerArray[0] == NULL)
  1284.             tileID = -1;
  1285.         else
  1286.             tileID = spriteWorldP->tileLayerArray[0]->tileMap[tileRow][tileCol];
  1287.             
  1288.             // Now we redraw all tiles in this location
  1289.         if (tileID >= 0)
  1290.         {
  1291.             tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  1292.             SW_ASSERT(tileFrameP != NULL);
  1293.             SW_ASSERT(tileFrameP->isFrameLocked);
  1294.             
  1295.                 // Determine whether the tile has a mask with background showing through
  1296.             tileHasMask = (tileFrameP->maskPort != NULL || tileFrameP->maskRgn != NULL);
  1297.         }
  1298.         else
  1299.             tileHasMask = false;
  1300.         
  1301.             // Copy a piece from the extraBackFrameP only if there is no tile, or the
  1302.             // tile has a mask with background showing through the unmasked part.
  1303.         if ( (tileID == -1 || tileHasMask) && spriteWorldP->extraBackFrameP != NULL)
  1304.         {
  1305.                 // There is no tile in this spot, or there is a masked tile and
  1306.                 // there is an extraBackFrameP, so copy a piece from extraBackFrameP
  1307.                 // Note: the function below wraps the dstRect for us, and leaves it 
  1308.                 // that way when it returns, so we don't have to wrap it ourselves.
  1309.             SWWrapRectFromExtraBackFrame(spriteWorldP, &dstRect);
  1310.         }
  1311.         else
  1312.         {
  1313.                 // Make the tile's dest rect local to the offscreen area
  1314.             dstRect.top -= spriteWorldP->vertScrollRectOffset;
  1315.             dstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  1316.             dstRect.left -= spriteWorldP->horizScrollRectOffset;
  1317.             dstRect.right -= spriteWorldP->horizScrollRectOffset;
  1318.             
  1319.                 // Wrap tile to top or bottom of offscreen area
  1320.             if (dstRect.bottom > backRectP->bottom)
  1321.             {
  1322.                 dstRect.top -= backRectP->bottom;
  1323.                 dstRect.bottom -= backRectP->bottom;
  1324.             }
  1325.             else if (dstRect.top < backRectP->top)
  1326.             {
  1327.                 dstRect.top += backRectP->bottom;
  1328.                 dstRect.bottom += backRectP->bottom;
  1329.             }
  1330.             
  1331.                 // Wrap tile to left or right side of offscreen area
  1332.             if (dstRect.right > backRectP->right)
  1333.             {
  1334.                 dstRect.left -= backRectP->right;
  1335.                 dstRect.right -= backRectP->right;
  1336.             }
  1337.             else if (dstRect.left < backRectP->left)
  1338.             {
  1339.                 dstRect.left += backRectP->right;
  1340.                 dstRect.right += backRectP->right;
  1341.             }
  1342.         }
  1343.  
  1344.  
  1345.         if (tileID >= 0)
  1346.         {    
  1347.             srcRect = tileFrameP->frameRect;
  1348.             
  1349.                 // Clip new srcRect
  1350.             if (row < visScrollRectP->top)
  1351.                 srcRect.top += visScrollRectP->top - row;
  1352.             if (col < visScrollRectP->left)
  1353.                 srcRect.left += visScrollRectP->left - col;
  1354.             if (row + tileHeight > visScrollRectP->bottom)
  1355.                 srcRect.bottom -= row + tileHeight - visScrollRectP->bottom;
  1356.             if (col + tileWidth > visScrollRectP->right)
  1357.                 srcRect.right -= col + tileWidth - visScrollRectP->right;
  1358.  
  1359.             if (tileHasMask && spriteWorldP->extraBackFrameP != NULL)
  1360.             {
  1361.                     // The tile has a mask, with background showing through
  1362.                 (*spriteWorldP->tileMaskDrawProc)(tileFrameP, 
  1363.                         spriteWorldP->backFrameP, &srcRect, &dstRect);
  1364.             }
  1365.             else
  1366.             {
  1367.                     // The entire tile should be drawn
  1368.                 (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  1369.                         spriteWorldP->backFrameP, &srcRect, &dstRect);
  1370.             }
  1371.         }
  1372.         
  1373.         
  1374.             // Draw tiles in higher layers
  1375.         for (tileLayer = 1; tileLayer <= spriteWorldP->lastActiveTileLayer; tileLayer++)
  1376.         {
  1377.             if (spriteWorldP->tileLayerArray[tileLayer] == NULL)
  1378.                 continue;
  1379.             
  1380.             SW_ASSERT(tileRow < spriteWorldP->tileLayerArray[tileLayer]->numRows);
  1381.             SW_ASSERT(tileCol < spriteWorldP->tileLayerArray[tileLayer]->numCols);
  1382.             
  1383.             tileID = spriteWorldP->tileLayerArray[tileLayer]->tileMap[tileRow][tileCol];
  1384.             if (tileID < 0)
  1385.                 continue;
  1386.             
  1387.             SW_ASSERT(tileID < spriteWorldP->maxNumTiles);
  1388.             
  1389.             tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  1390.             SW_ASSERT(tileFrameP != NULL);
  1391.             SW_ASSERT(tileFrameP->isFrameLocked);
  1392.             
  1393.             srcRect = tileFrameP->frameRect;
  1394.             
  1395.                 // Clip new srcRect
  1396.             if (row < visScrollRectP->top)
  1397.                 srcRect.top += visScrollRectP->top - row;
  1398.             if (col < visScrollRectP->left)
  1399.                 srcRect.left += visScrollRectP->left - col;
  1400.             if (row + tileHeight > visScrollRectP->bottom)
  1401.                 srcRect.bottom -= row + tileHeight - visScrollRectP->bottom;
  1402.             if (col + tileWidth > visScrollRectP->right)
  1403.                 srcRect.right -= col + tileWidth - visScrollRectP->right;
  1404.             
  1405.                 // Draw the tile
  1406.             if (tileFrameP->maskPort == NULL && tileFrameP->maskRgn == NULL)
  1407.             {
  1408.                     // Tile has no mask
  1409.                 (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  1410.                         spriteWorldP->backFrameP, &srcRect, &dstRect);
  1411.             }
  1412.             else
  1413.             {
  1414.                     // Tile has a mask
  1415.                 (*spriteWorldP->tileMaskDrawProc)(tileFrameP, 
  1416.                         spriteWorldP->backFrameP, &srcRect, &dstRect);
  1417.             }
  1418.         }
  1419.             
  1420.             // Copy tiles from back area to work area
  1421.         SetGWorld(spriteWorldP->workFrameP->framePort, nil);
  1422.         (*spriteWorldP->offscreenDrawProc)(spriteWorldP->backFrameP, 
  1423.                 spriteWorldP->workFrameP, &dstRect, &dstRect);
  1424.         
  1425.             // Update tiling cache info only if only one tile layer is used
  1426.         if (spriteWorldP->lastActiveTileLayer == 0)
  1427.         {
  1428.             offscreenTileRow = dstRect.top / spriteWorldP->tileHeight;
  1429.             offscreenTileCol = dstRect.left / spriteWorldP->tileWidth;
  1430.             
  1431.                 // Set new tile value in tilingCache
  1432.             if (tileClipped || tileID < 0)
  1433.             {
  1434.                 spriteWorldP->tilingCache[offscreenTileRow][offscreenTileCol] = -1;
  1435.             }
  1436.             else
  1437.             {
  1438.                 spriteWorldP->tilingCache[offscreenTileRow][offscreenTileCol] = 
  1439.                     spriteWorldP->curTileImage[tileID];
  1440.             }
  1441.         }
  1442.     }
  1443. }
  1444.  
  1445.  
  1446. ///--------------------------------------------------------------------------------------
  1447. //    SWDrawTilesInRect - draw only one layer of tiles in updateRect of backFrame. Note:
  1448. //    The only reason we use this instead of SWDrawTilesLayersInRect is because with this,
  1449. //    we can use the tiling cache.
  1450. ///--------------------------------------------------------------------------------------
  1451.  
  1452. SW_FUNC void SWDrawTilesInRect(
  1453.     SpriteWorldPtr    spriteWorldP,
  1454.     Rect*            updateRectP,
  1455.     Boolean            optimizingOn)
  1456. {
  1457.     short        row, col, tileRow, tileCol, tileID;
  1458.     short        startRow, startCol, stopRow, stopCol;
  1459.     short        offscreenTileRow, offscreenTileCol;
  1460.     Rect        srcRect, dstRect;
  1461.     FramePtr    tileFrameP;
  1462.     Boolean        tileClipped, tileHasMask;
  1463.     Rect*        visScrollRectP = &spriteWorldP->visScrollRect;
  1464.     Rect*        backRectP = &spriteWorldP->backRect;
  1465.     Rect        updateRect = *updateRectP;
  1466.     short        tileWidth = spriteWorldP->tileWidth;
  1467.     short        tileHeight = spriteWorldP->tileHeight;
  1468.     
  1469.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  1470.     SW_ASSERT(spriteWorldP->tileMaskDrawProc != NULL);
  1471.     SW_ASSERT(spriteWorldP->offscreenDrawProc != NULL);
  1472.     SW_ASSERT(spriteWorldP->backFrameP->isFrameLocked);
  1473.     
  1474.     SW_ASSERT(spriteWorldP->tileLayerArray[0] != NULL);
  1475.     SW_ASSERT(spriteWorldP->tileLayerArray[0]->isLocked);
  1476.     
  1477.     SetGWorld(spriteWorldP->backFrameP->framePort, nil);
  1478.     
  1479.         // Convert pixel row and col into tile row and col
  1480.     startRow = updateRect.top / tileHeight;
  1481.     startCol = updateRect.left / tileWidth;
  1482.     stopRow = (updateRect.bottom-1) / tileHeight;
  1483.     stopCol = (updateRect.right-1) / tileWidth;
  1484.  
  1485.  
  1486.     row = startRow * tileHeight;
  1487.     for (tileRow = startRow; tileRow <= stopRow; tileRow++, row += tileHeight)
  1488.     {
  1489.         col = startCol * tileWidth;
  1490.         for (tileCol = startCol; tileCol <= stopCol; tileCol++, col += tileWidth)
  1491.         {
  1492.             if (spriteWorldP->tileLayerArray[0] != NULL)
  1493.             {
  1494.                 SW_ASSERT(tileRow < spriteWorldP->tileLayerArray[0]->numRows);
  1495.                 SW_ASSERT(tileCol < spriteWorldP->tileLayerArray[0]->numCols);
  1496.             }
  1497.                     
  1498.             dstRect.bottom = row + tileHeight;
  1499.             dstRect.right = col + tileWidth;
  1500.             
  1501.                 // Is tile completely visible on screen?
  1502.             if (row >= visScrollRectP->top && col >= visScrollRectP->left &&
  1503.                 dstRect.bottom <= visScrollRectP->bottom && 
  1504.                 dstRect.right <= visScrollRectP->right)
  1505.             {
  1506.                 tileClipped = false;
  1507.             }
  1508.             else
  1509.             {
  1510.                 tileClipped = true;
  1511.             }
  1512.                 
  1513.                 // Clip tile dstRect with updateRect //
  1514.             if (row < updateRect.top)
  1515.                 dstRect.top = updateRect.top;
  1516.             else
  1517.                 dstRect.top = row;
  1518.             
  1519.             if (col < updateRect.left)
  1520.                 dstRect.left = updateRect.left;
  1521.             else
  1522.                 dstRect.left = col;
  1523.             
  1524.             if (dstRect.bottom > updateRect.bottom)
  1525.                 dstRect.bottom = updateRect.bottom;
  1526.             
  1527.             if (dstRect.right > updateRect.right)
  1528.                 dstRect.right = updateRect.right;
  1529.     
  1530.             if (spriteWorldP->tileLayerArray[0] == NULL)
  1531.                 tileID = -1;
  1532.             else
  1533.                 tileID = spriteWorldP->tileLayerArray[0]->tileMap[tileRow][tileCol];
  1534.             
  1535.             SW_ASSERT(tileID < spriteWorldP->maxNumTiles);
  1536.                 
  1537.             if (tileID >= 0)
  1538.             {
  1539.                 tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  1540.                 SW_ASSERT(tileFrameP != NULL);
  1541.                 SW_ASSERT(tileFrameP->isFrameLocked);
  1542.                 
  1543.                     // Determine whether the tile has a mask with background showing through
  1544.                 tileHasMask = (tileFrameP->maskPort != NULL || tileFrameP->maskRgn != NULL);
  1545.             }
  1546.             else
  1547.                 tileHasMask = false;
  1548.             
  1549.                 // Copy a piece from the extraBackFrameP only if there is no tile, or the
  1550.                 // tile has a mask with background showing through the unmasked part.
  1551.             if ( (tileID == -1 || tileHasMask) && spriteWorldP->extraBackFrameP != NULL)
  1552.             {
  1553.                     // There is no tile in this spot, or there is a masked tile and
  1554.                     // there is an extraBackFrameP, so copy a piece from extraBackFrameP
  1555.                     // Note: the function below wraps the dstRect for us, and leaves it 
  1556.                     // that way when it returns, so we don't have to wrap it ourselves.
  1557.                 SWWrapRectFromExtraBackFrame(spriteWorldP, &dstRect);
  1558.             }
  1559.             else
  1560.             {
  1561.                     // Make the tile's dest rect local to the offscreen area
  1562.                 dstRect.top -= spriteWorldP->vertScrollRectOffset;
  1563.                 dstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  1564.                 dstRect.left -= spriteWorldP->horizScrollRectOffset;
  1565.                 dstRect.right -= spriteWorldP->horizScrollRectOffset;
  1566.                 
  1567.                     // Wrap tile to top or bottom of offscreen area
  1568.                 if (dstRect.bottom > backRectP->bottom)
  1569.                 {
  1570.                     dstRect.top -= backRectP->bottom;
  1571.                     dstRect.bottom -= backRectP->bottom;
  1572.                 }
  1573.                 else if (dstRect.top < backRectP->top)
  1574.                 {
  1575.                     dstRect.top += backRectP->bottom;
  1576.                     dstRect.bottom += backRectP->bottom;
  1577.                 }
  1578.                 
  1579.                     // Wrap tile to left or right side of offscreen area
  1580.                 if (dstRect.right > backRectP->right)
  1581.                 {
  1582.                     dstRect.left -= backRectP->right;
  1583.                     dstRect.right -= backRectP->right;
  1584.                 }
  1585.                 else if (dstRect.left < backRectP->left)
  1586.                 {
  1587.                     dstRect.left += backRectP->right;
  1588.                     dstRect.right += backRectP->right;
  1589.                 }
  1590.             }
  1591.  
  1592.  
  1593.             offscreenTileRow = dstRect.top / tileHeight;
  1594.             offscreenTileCol = dstRect.left / tileWidth;
  1595.  
  1596.             if (tileID >= 0)
  1597.             {    
  1598.                 srcRect = tileFrameP->frameRect;
  1599.                 
  1600.                     // Clip new srcRect
  1601.                 if (row < updateRect.top)
  1602.                     srcRect.top += updateRect.top - row;
  1603.                 if (col < updateRect.left)
  1604.                     srcRect.left += updateRect.left - col;
  1605.                 if (row + tileHeight > updateRect.bottom)
  1606.                     srcRect.bottom -= row + tileHeight - updateRect.bottom;
  1607.                 if (col + tileWidth > updateRect.right)
  1608.                     srcRect.right -= col + tileWidth - updateRect.right;
  1609.  
  1610.                 if (tileHasMask && spriteWorldP->extraBackFrameP != NULL)
  1611.                 {
  1612.                         // The tile has a mask, with background showing through
  1613.                     (*spriteWorldP->tileMaskDrawProc)(tileFrameP, 
  1614.                             spriteWorldP->backFrameP, &srcRect, &dstRect);
  1615.                     
  1616.                         // Since the background is showing here, set this cache spot to -1
  1617.                     spriteWorldP->tilingCache[offscreenTileRow][offscreenTileCol] = -1;
  1618.                 }
  1619.                 else
  1620.                 {
  1621.                         // Save time by not drawing tile if already the same
  1622.                     if (spriteWorldP->tilingCache[offscreenTileRow][offscreenTileCol] != 
  1623.                         spriteWorldP->curTileImage[tileID] || !optimizingOn)
  1624.                     {    
  1625.                             // The entire tile should be drawn
  1626.                         (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  1627.                                 spriteWorldP->backFrameP, &srcRect, &dstRect);
  1628.                         
  1629.                             // Set new tile value in tilingCache
  1630.                         if (tileClipped)
  1631.                         {
  1632.                             spriteWorldP->tilingCache[offscreenTileRow][offscreenTileCol] = -1;
  1633.                         }
  1634.                         else
  1635.                         {
  1636.                             spriteWorldP->tilingCache[offscreenTileRow][offscreenTileCol] = 
  1637.                                 spriteWorldP->curTileImage[tileID];
  1638.                         }
  1639.                     }
  1640.                 }
  1641.             }
  1642.             else
  1643.             {
  1644.                     // Since no tile is here, this spot in the tiling Cache should be set to -1
  1645.                 spriteWorldP->tilingCache[offscreenTileRow][offscreenTileCol] = -1;
  1646.                 
  1647.                     // Cause assertion failure if tileID is -1 and there is no extraBackFrameP
  1648.                 SW_ASSERT(spriteWorldP->extraBackFrameP != NULL);
  1649.             }
  1650.         }
  1651.     }
  1652. }
  1653.  
  1654.  
  1655. ///--------------------------------------------------------------------------------------
  1656. //    SWDrawTileLayersInRect - draws all tile layers in updateRect of backFrame
  1657. ///--------------------------------------------------------------------------------------
  1658.  
  1659. SW_FUNC void SWDrawTileLayersInRect(
  1660.     SpriteWorldPtr    spriteWorldP,
  1661.     Rect*            updateRectP,
  1662.     Boolean            optimizingOn)
  1663. {
  1664.     #pragma        unused(optimizingOn)    // This is used in our sister function, SWDrawTilesInRect
  1665.     short        row, col, tileRow, tileCol, tileID;
  1666.     short        startRow, startCol, stopRow, stopCol;
  1667.     short        tileLayer, startPixelCol;
  1668.     Rect        srcRect, dstRect;
  1669.     FramePtr    tileFrameP;
  1670.     Rect*        visScrollRectP = &spriteWorldP->visScrollRect;
  1671.     Rect*        backRectP = &spriteWorldP->backRect;
  1672.     Rect        updateRect = *updateRectP;
  1673.     short        tileWidth = spriteWorldP->tileWidth;
  1674.     short        tileHeight = spriteWorldP->tileHeight;
  1675.     Boolean        tileHasMask;
  1676.     
  1677.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  1678.     SW_ASSERT(spriteWorldP->tileMaskDrawProc != NULL);
  1679.     SW_ASSERT(spriteWorldP->offscreenDrawProc != NULL);
  1680.     SW_ASSERT(spriteWorldP->backFrameP->isFrameLocked);
  1681.     
  1682.     SetGWorld(spriteWorldP->backFrameP->framePort, nil);
  1683.     
  1684.         // Convert pixel row and col into tile row and col
  1685.     startRow = updateRect.top / tileHeight;
  1686.     startCol = updateRect.left / tileWidth;
  1687.     stopRow = (updateRect.bottom-1) / tileHeight;
  1688.     stopCol = (updateRect.right-1) / tileWidth;
  1689.     
  1690.     startPixelCol = startCol * tileWidth;
  1691.     
  1692.     row = startRow * tileHeight;
  1693.     for (tileRow = startRow; tileRow <= stopRow; tileRow++, row += tileHeight)
  1694.     {
  1695.         col = startPixelCol;
  1696.         for (tileCol = startCol; tileCol <= stopCol; tileCol++, col += tileWidth)
  1697.         {
  1698.             if (spriteWorldP->tileLayerArray[0] != NULL)
  1699.             {
  1700.                 SW_ASSERT(spriteWorldP->tileLayerArray[0]->isLocked);
  1701.                 SW_ASSERT(tileRow < spriteWorldP->tileLayerArray[0]->numRows);
  1702.                 SW_ASSERT(tileCol < spriteWorldP->tileLayerArray[0]->numCols);
  1703.             }
  1704.             
  1705.             dstRect.bottom = row + tileHeight;
  1706.             dstRect.right = col + tileWidth;
  1707.                 
  1708.                 // Clip tile dstRect with updateRect //
  1709.             if (row < updateRect.top)
  1710.                 dstRect.top = updateRect.top;
  1711.             else
  1712.                 dstRect.top = row;
  1713.             
  1714.             if (col < updateRect.left)
  1715.                 dstRect.left = updateRect.left;
  1716.             else
  1717.                 dstRect.left = col;
  1718.             
  1719.             if (dstRect.bottom > updateRect.bottom)
  1720.                 dstRect.bottom = updateRect.bottom;
  1721.             
  1722.             if (dstRect.right > updateRect.right)
  1723.                 dstRect.right = updateRect.right;
  1724.             
  1725.             if (spriteWorldP->tileLayerArray[0] == NULL)
  1726.                 tileID = -1;
  1727.             else
  1728.                 tileID = spriteWorldP->tileLayerArray[0]->tileMap[tileRow][tileCol];
  1729.             
  1730.             SW_ASSERT(tileID < spriteWorldP->maxNumTiles);
  1731.                 
  1732.             if (tileID >= 0)
  1733.             {
  1734.                 tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  1735.                 SW_ASSERT(tileFrameP != NULL);
  1736.                 SW_ASSERT(tileFrameP->isFrameLocked);
  1737.                 
  1738.                     // Determine whether the tile has a mask with background showing through
  1739.                 tileHasMask = (tileFrameP->maskPort != NULL || tileFrameP->maskRgn != NULL);
  1740.             }
  1741.             else
  1742.                 tileHasMask = false;
  1743.             
  1744.                 // Copy a piece from the extraBackFrameP only if there is no tile, or the
  1745.                 // tile has a mask with background showing through the unmasked part.
  1746.             if ( (tileID == -1 || tileHasMask) && spriteWorldP->extraBackFrameP != NULL)
  1747.             {
  1748.                     // There is no tile in this spot, or there is a masked tile and
  1749.                     // there is an extraBackFrameP, so copy a piece from extraBackFrameP
  1750.                     // Note: the function below wraps the dstRect for us, and leaves it 
  1751.                     // that way when it returns, so we don't have to wrap it ourselves.
  1752.                 SWWrapRectFromExtraBackFrame(spriteWorldP, &dstRect);
  1753.             }
  1754.             else
  1755.             {
  1756.                     // Make the tile's dest rect local to the offscreen area
  1757.                 dstRect.top -= spriteWorldP->vertScrollRectOffset;
  1758.                 dstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  1759.                 dstRect.left -= spriteWorldP->horizScrollRectOffset;
  1760.                 dstRect.right -= spriteWorldP->horizScrollRectOffset;
  1761.                 
  1762.                     // Wrap tile to top or bottom of offscreen area
  1763.                 if (dstRect.bottom > backRectP->bottom)
  1764.                 {
  1765.                     dstRect.top -= backRectP->bottom;
  1766.                     dstRect.bottom -= backRectP->bottom;
  1767.                 }
  1768.                 else if (dstRect.top < backRectP->top)
  1769.                 {
  1770.                     dstRect.top += backRectP->bottom;
  1771.                     dstRect.bottom += backRectP->bottom;
  1772.                 }
  1773.                 
  1774.                     // Wrap tile to left or right side of offscreen area
  1775.                 if (dstRect.right > backRectP->right)
  1776.                 {
  1777.                     dstRect.left -= backRectP->right;
  1778.                     dstRect.right -= backRectP->right;
  1779.                 }
  1780.                 else if (dstRect.left < backRectP->left)
  1781.                 {
  1782.                     dstRect.left += backRectP->right;
  1783.                     dstRect.right += backRectP->right;
  1784.                 }
  1785.             }
  1786.  
  1787.  
  1788.             if (tileID >= 0)
  1789.             {    
  1790.                 srcRect = tileFrameP->frameRect;
  1791.                 
  1792.                     // Clip new srcRect
  1793.                 if (row < updateRect.top)
  1794.                     srcRect.top += updateRect.top - row;
  1795.                 if (col < updateRect.left)
  1796.                     srcRect.left += updateRect.left - col;
  1797.                 if (row + tileHeight > updateRect.bottom)
  1798.                     srcRect.bottom -= row + tileHeight - updateRect.bottom;
  1799.                 if (col + tileWidth > updateRect.right)
  1800.                     srcRect.right -= col + tileWidth - updateRect.right;
  1801.  
  1802.                 if (tileHasMask && spriteWorldP->extraBackFrameP != NULL)
  1803.                 {
  1804.                         // The tile has a mask, with background showing through
  1805.                     (*spriteWorldP->tileMaskDrawProc)(tileFrameP, 
  1806.                             spriteWorldP->backFrameP, &srcRect, &dstRect);
  1807.                 }
  1808.                 else
  1809.                 {
  1810.                         // The entire tile should be drawn
  1811.                     (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  1812.                             spriteWorldP->backFrameP, &srcRect, &dstRect);
  1813.                 }
  1814.             }
  1815.             
  1816.             
  1817.                 // Draw tiles in higher layers
  1818.             for (tileLayer = 1; tileLayer <= spriteWorldP->lastActiveTileLayer; tileLayer++)
  1819.             {
  1820.                 if (spriteWorldP->tileLayerArray[tileLayer] == NULL)
  1821.                     continue;
  1822.                 
  1823.                 SW_ASSERT(spriteWorldP->tileLayerArray[tileLayer]->isLocked);
  1824.                 SW_ASSERT(tileRow < spriteWorldP->tileLayerArray[tileLayer]->numRows);
  1825.                 SW_ASSERT(tileCol < spriteWorldP->tileLayerArray[tileLayer]->numCols);
  1826.                 
  1827.                 tileID = spriteWorldP->tileLayerArray[tileLayer]->tileMap[tileRow][tileCol];
  1828.                 if (tileID < 0)
  1829.                     continue;
  1830.                 
  1831.                 SW_ASSERT(tileID < spriteWorldP->maxNumTiles);
  1832.                 
  1833.                 tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  1834.                 SW_ASSERT(tileFrameP != NULL);
  1835.                 SW_ASSERT(tileFrameP->isFrameLocked);
  1836.                 
  1837.                 srcRect = tileFrameP->frameRect;
  1838.                 
  1839.                     // Clip new srcRect
  1840.                 if (row < updateRect.top)
  1841.                     srcRect.top += updateRect.top - row;
  1842.                 if (col < updateRect.left)
  1843.                     srcRect.left += updateRect.left - col;
  1844.                 if (row + tileHeight > updateRect.bottom)
  1845.                     srcRect.bottom -= row + tileHeight - updateRect.bottom;
  1846.                 if (col + tileWidth > updateRect.right)
  1847.                     srcRect.right -= col + tileWidth - updateRect.right;
  1848.                 
  1849.                     // Draw the tile
  1850.                 if (tileFrameP->maskPort == NULL && tileFrameP->maskRgn == NULL)
  1851.                 {
  1852.                         // Tile has no mask
  1853.                     (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  1854.                             spriteWorldP->backFrameP, &srcRect, &dstRect);
  1855.                 }
  1856.                 else
  1857.                 {
  1858.                         // Tile has a mask
  1859.                     (*spriteWorldP->tileMaskDrawProc)(tileFrameP, 
  1860.                             spriteWorldP->backFrameP, &srcRect, &dstRect);
  1861.                 }
  1862.             }
  1863.         }
  1864.     }
  1865. }
  1866.  
  1867.  
  1868. ///--------------------------------------------------------------------------------------
  1869. //    SWDrawTilesAboveSprite - draw tiles over sprite using the tiles' masks.
  1870. //    Assumes that updateRect fits within the bounds of the tileMap.
  1871. ///--------------------------------------------------------------------------------------
  1872.  
  1873. SW_FUNC void SWDrawTilesAboveSprite(
  1874.     SpriteWorldPtr    spriteWorldP,
  1875.     Rect*            updateRectP,
  1876.     short            startLayer)
  1877. {
  1878.     Rect*        backRectP = &spriteWorldP->backRect;
  1879.     Rect        updateRect = *updateRectP;
  1880.     short        tileLayer;
  1881.     short        tileWidth = spriteWorldP->tileWidth;
  1882.     short        tileHeight = spriteWorldP->tileHeight;
  1883.     short        row, col, tileRow, tileCol, tileID;
  1884.     short        startRow, startCol, stopRow, stopCol;
  1885.     short        startPixelRow, startPixelCol;
  1886.     Rect        srcRect, dstRect;
  1887.     FramePtr    tileFrameP;
  1888.  
  1889.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  1890.     SW_ASSERT(startLayer >= 0);
  1891.     
  1892.         // Convert pixel row and col into tile row and col
  1893.     startRow = updateRect.top / tileHeight;
  1894.     startCol = updateRect.left / tileWidth;
  1895.     stopRow = (updateRect.bottom-1) / tileHeight;
  1896.     stopCol = (updateRect.right-1) / tileWidth;
  1897.     
  1898.     startPixelRow = startRow * tileHeight;
  1899.     startPixelCol = startCol * tileWidth;
  1900.  
  1901.     for (tileLayer = startLayer; tileLayer <= spriteWorldP->lastActiveTileLayer; tileLayer++)
  1902.     {
  1903.         if (spriteWorldP->tileLayerArray[tileLayer] == NULL)
  1904.             continue;
  1905.         
  1906.         row = startPixelRow;
  1907.         for (tileRow = startRow; tileRow <= stopRow; tileRow++, row += tileHeight)
  1908.         {
  1909.             col = startPixelCol;
  1910.             for (tileCol = startCol; tileCol <= stopCol; tileCol++, col += tileWidth)
  1911.             {
  1912.                 SW_ASSERT(tileRow < spriteWorldP->tileLayerArray[tileLayer]->numRows);
  1913.                 SW_ASSERT(tileCol < spriteWorldP->tileLayerArray[tileLayer]->numCols);
  1914.     
  1915.                 tileID = spriteWorldP->tileLayerArray[tileLayer]->tileMap[tileRow][tileCol];
  1916.                 if (tileID < 0)
  1917.                     continue;
  1918.                 
  1919.                 SW_ASSERT(tileID < spriteWorldP->maxNumTiles);
  1920.                 
  1921.                 tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  1922.                 SW_ASSERT(tileFrameP != NULL);
  1923.                 
  1924.                     // Skip tiles in the bottom layer that have no mask, and therefore 
  1925.                     // aren't above the sprites, as long as no extraBackFrameP is installed.
  1926.                 if (tileLayer == 0 && spriteWorldP->extraBackFrameP == NULL &&
  1927.                     tileFrameP->maskPort == NULL && tileFrameP->maskRgn == NULL && 
  1928.                     tileFrameP->tileMaskIsSolid == false)
  1929.                 {
  1930.                     continue;
  1931.                 }
  1932.                 
  1933.                 srcRect = tileFrameP->frameRect;
  1934.                 dstRect.bottom = row + tileHeight;
  1935.                 dstRect.right = col + tileWidth;
  1936.                 
  1937.                     
  1938.                     // Clip tile dstRect with updateRect //
  1939.                 if (row < updateRect.top)
  1940.                 {
  1941.                     dstRect.top = updateRect.top;
  1942.                     srcRect.top += updateRect.top - row;
  1943.                 }
  1944.                 else
  1945.                     dstRect.top = row;
  1946.                 
  1947.                 if (col < updateRect.left)
  1948.                 {
  1949.                     dstRect.left = updateRect.left;
  1950.                     srcRect.left += updateRect.left - col;
  1951.                 }
  1952.                 else
  1953.                     dstRect.left = col;
  1954.                 
  1955.                 
  1956.                 if (dstRect.bottom > updateRect.bottom)
  1957.                 {
  1958.                     srcRect.bottom -= dstRect.bottom - updateRect.bottom;
  1959.                     dstRect.bottom = updateRect.bottom;
  1960.                 }
  1961.                 
  1962.                 if (dstRect.right > updateRect.right)
  1963.                 {
  1964.                     srcRect.right -= dstRect.right - updateRect.right;
  1965.                     dstRect.right = updateRect.right;
  1966.                 }
  1967.         
  1968.     
  1969.                 
  1970.                     // Make the tile's dest rect local to the offscreen area
  1971.                 dstRect.top -= spriteWorldP->vertScrollRectOffset;
  1972.                 dstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  1973.                 dstRect.left -= spriteWorldP->horizScrollRectOffset;
  1974.                 dstRect.right -= spriteWorldP->horizScrollRectOffset;
  1975.                 
  1976.                     // Wrap tile to top or bottom of offscreen area
  1977.                 if (dstRect.bottom > backRectP->bottom)
  1978.                 {
  1979.                     dstRect.top -= backRectP->bottom;
  1980.                     dstRect.bottom -= backRectP->bottom;
  1981.                 }
  1982.                 else if (dstRect.top < backRectP->top)
  1983.                 {
  1984.                     dstRect.top += backRectP->bottom;
  1985.                     dstRect.bottom += backRectP->bottom;
  1986.                 }
  1987.                 
  1988.                     // Wrap tile to left or right side of offscreen area
  1989.                 if (dstRect.right > backRectP->right)
  1990.                 {
  1991.                     dstRect.left -= backRectP->right;
  1992.                     dstRect.right -= backRectP->right;
  1993.                 }
  1994.                 else if (dstRect.left < backRectP->left)
  1995.                 {
  1996.                     dstRect.left += backRectP->right;
  1997.                     dstRect.right += backRectP->right;
  1998.                 }
  1999.                 
  2000.                 if (tileLayer == 0 && spriteWorldP->extraBackFrameP == NULL)
  2001.                 {
  2002.                         // The tile is in the bottom layer
  2003.                     if (tileFrameP->tileMaskIsSolid)
  2004.                     {
  2005.                             // Draw the tile without using a mask
  2006.                         (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  2007.                             spriteWorldP->workFrameP, &srcRect, &dstRect);
  2008.                     }
  2009.                     else
  2010.                     {
  2011.                             // Draw the masked part of the tile
  2012.                         (*spriteWorldP->partialMaskDrawProc)(tileFrameP, 
  2013.                                 spriteWorldP->workFrameP, &srcRect, &dstRect);
  2014.                     }
  2015.                 }
  2016.                 else
  2017.                 {
  2018.                         // The tile is in a higher layer, or is in the background layer and
  2019.                         // an extraBackFrameP is installed, and must be handled differently
  2020.                     if (tileFrameP->maskPort == NULL && tileFrameP->maskRgn == NULL)
  2021.                     {
  2022.                             // Tile has no mask
  2023.                         (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  2024.                                 spriteWorldP->workFrameP, &srcRect, &dstRect);
  2025.                     }
  2026.                     else
  2027.                     {
  2028.                             // Tile has a mask
  2029.                         (*spriteWorldP->tileMaskDrawProc)(tileFrameP, 
  2030.                                 spriteWorldP->workFrameP, &srcRect, &dstRect);
  2031.                     }
  2032.                 }
  2033.             }
  2034.         }
  2035.     }
  2036. }
  2037.  
  2038.  
  2039. ///--------------------------------------------------------------------------------------
  2040. //    SWResetTilingCache
  2041. ///--------------------------------------------------------------------------------------
  2042.  
  2043. SW_FUNC void SWResetTilingCache(
  2044.     SpriteWorldPtr    spriteWorldP)
  2045. {
  2046.     short    row, col;
  2047.     
  2048.     SW_ASSERT(spriteWorldP != NULL);
  2049.     SW_ASSERT(spriteWorldP->tilingIsInitialized);
  2050.     
  2051.         // Set all elements to -1 (indicating that each tile needs to be drawn)
  2052.     for (row = 0; row < spriteWorldP->numTilingCacheRows; row++)
  2053.     {
  2054.         for (col = 0; col < spriteWorldP->numTilingCacheCols; col++)
  2055.         {
  2056.             spriteWorldP->tilingCache[row][col] = -1;
  2057.         }
  2058.     }
  2059. }
  2060.  
  2061.  
  2062. ///--------------------------------------------------------------------------------------
  2063. //    SWAddChangedRect - used by SWDrawTile
  2064. ///--------------------------------------------------------------------------------------
  2065.  
  2066. SW_FUNC static void SWAddChangedRect(
  2067.     SpriteWorldPtr    spriteWorldP, 
  2068.     Rect            *changedRectP)
  2069. {
  2070.     short    index;
  2071.     Rect    *changedTileP;
  2072.     
  2073.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  2074.     SW_ASSERT(changedRectP->top >= 0 && changedRectP->left >= 0 &&
  2075.         changedRectP->right > changedRectP->left && changedRectP->bottom > changedRectP->top);
  2076.     
  2077.     changedTileP = spriteWorldP->changedTiles;
  2078.     for ( index = 0; index < spriteWorldP->numTilesChanged; index++, changedTileP++ )
  2079.     {
  2080.             // check for changedRectP entirely contained by changedTileP
  2081.         if ( changedTileP->left <= changedRectP->left && 
  2082.              changedTileP->top <= changedRectP->top && 
  2083.              changedTileP->right >= changedRectP->right && 
  2084.              changedTileP->bottom >= changedRectP->bottom ) 
  2085.         {
  2086.             return;
  2087.         }
  2088.     }
  2089.     
  2090.     changedTileP = spriteWorldP->changedTiles;
  2091.     for ( index = 0; index < spriteWorldP->numTilesChanged; index++, changedTileP++ )
  2092.     {
  2093.             // check for changedRectP horizontally adjacent to changedTileP
  2094.         if ( changedTileP->top == changedRectP->top && 
  2095.              changedTileP->bottom == changedRectP->bottom )
  2096.         {
  2097.             if ( changedRectP->left <= changedTileP->left &&         // changedRectP is to the left of changedTileP
  2098.                  changedRectP->right >= changedTileP->left ||        // or
  2099.                  changedRectP->left <= changedTileP->right &&         // changedRectP is to the right of changedTileP
  2100.                  changedRectP->right >= changedTileP->right )
  2101.             {
  2102.                 changedTileP->left = SW_MIN( changedTileP->left, changedRectP->left );
  2103.                 changedTileP->right = SW_MAX( changedTileP->right, changedRectP->right );
  2104.                 return;
  2105.             }
  2106.         }
  2107.         
  2108.             // check for changedRectP vertically adjacent to changedTileP
  2109.         if ( changedTileP->left == changedRectP->left && 
  2110.              changedTileP->right == changedRectP->right )
  2111.         {
  2112.             if ( changedRectP->top <= changedTileP->top &&             // changedRectP is above changedTileP
  2113.                  changedRectP->bottom >= changedTileP->top ||        // or
  2114.                  changedRectP->top <= changedTileP->bottom &&         // changedRectP is below changedTileP
  2115.                  changedRectP->bottom >= changedTileP->bottom )
  2116.             {
  2117.                 changedTileP->top = SW_MIN( changedTileP->top, changedRectP->top );
  2118.                 changedTileP->bottom = SW_MAX( changedTileP->bottom, changedRectP->bottom );
  2119.                 return;
  2120.             }
  2121.         }
  2122.     }
  2123.     
  2124.     if (spriteWorldP->numTilesChanged < spriteWorldP->changedTilesArraySize)
  2125.     {
  2126.         spriteWorldP->changedTiles[spriteWorldP->numTilesChanged++] = *changedRectP;
  2127.     }
  2128.     else
  2129.     {
  2130.             // This shouldn't ever happen, but if it does, we'll trip our Assert routine.
  2131.         SW_ASSERT(0);
  2132.         SWFlagRectAsChanged(spriteWorldP, changedRectP);
  2133.     }
  2134. }
  2135.  
  2136.  
  2137. ///--------------------------------------------------------------------------------------
  2138. //    SWChangeTileImage
  2139. ///--------------------------------------------------------------------------------------
  2140.  
  2141. SW_FUNC void SWChangeTileImage(
  2142.     SpriteWorldPtr    spriteWorldP,
  2143.     short            tileID,
  2144.     short            newImage)
  2145. {
  2146.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  2147.     SW_ASSERT(tileID < spriteWorldP->maxNumTiles);
  2148.     SW_ASSERT(newImage < spriteWorldP->maxNumTiles);
  2149.     
  2150.         // Set the current image
  2151.     spriteWorldP->curTileImage[tileID] = newImage;
  2152.     
  2153.         // Update the tile image on screen
  2154.     SWUpdateTileOnScreen(spriteWorldP, tileID);
  2155. }
  2156.  
  2157.  
  2158. ///--------------------------------------------------------------------------------------
  2159. //    SWUpdateTileOnScreen - render new tile image in offscreen areas
  2160. ///--------------------------------------------------------------------------------------
  2161.  
  2162. SW_FUNC void SWUpdateTileOnScreen(
  2163.     SpriteWorldPtr    spriteWorldP,
  2164.     short            tileID)
  2165. {
  2166.     short        tileRow, tileCol, tileLayer;
  2167.     short        startRow, startCol, stopRow, stopCol;
  2168.     
  2169.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  2170.     
  2171.         // Convert pixel row and col into tile row and col
  2172.     startRow = spriteWorldP->visScrollRect.top / spriteWorldP->tileHeight;
  2173.     startCol = spriteWorldP->visScrollRect.left / spriteWorldP->tileWidth;
  2174.     stopRow = (spriteWorldP->visScrollRect.bottom-1) / spriteWorldP->tileHeight;
  2175.     stopCol = (spriteWorldP->visScrollRect.right-1) / spriteWorldP->tileWidth;
  2176.     
  2177.     for (tileLayer = 0; tileLayer <= spriteWorldP->lastActiveTileLayer; tileLayer++)
  2178.     {
  2179.         if (spriteWorldP->tileLayerArray[tileLayer] == NULL)
  2180.             continue;
  2181.         
  2182.         for (tileRow = startRow; tileRow <= stopRow; tileRow++)
  2183.         {
  2184.             for (tileCol = startCol; tileCol <= stopCol; tileCol++)
  2185.             {
  2186.                 if (tileID == spriteWorldP->tileLayerArray[tileLayer]->tileMap[tileRow][tileCol])
  2187.                     SWDrawTile(spriteWorldP, tileLayer, tileRow, tileCol, tileID);
  2188.             }
  2189.         }
  2190.     }
  2191. }
  2192.  
  2193.  
  2194. ///--------------------------------------------------------------------------------------
  2195. //    SWResetCurrentTileImages
  2196. ///--------------------------------------------------------------------------------------
  2197.  
  2198. SW_FUNC void SWResetCurrentTileImages(
  2199.     SpriteWorldPtr    spriteWorldP)
  2200. {
  2201.     short    tileIndex;
  2202.     
  2203.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  2204.     
  2205.     if (spriteWorldP->tilingIsInitialized)
  2206.     {
  2207.         for (tileIndex = 0; tileIndex < spriteWorldP->maxNumTiles; tileIndex++)
  2208.             spriteWorldP->curTileImage[tileIndex] = tileIndex;
  2209.     }
  2210. }
  2211.  
  2212.  
  2213. ///--------------------------------------------------------------------------------------
  2214. //   SWReturnTileUnderPixel
  2215. ///--------------------------------------------------------------------------------------
  2216.  
  2217. SW_FUNC short SWReturnTileUnderPixel(
  2218.     SpriteWorldPtr    spriteWorldP,
  2219.     short    tileLayer,
  2220.     short    pixelCol,
  2221.     short    pixelRow)
  2222. {
  2223.     short     row, col;
  2224.     
  2225.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  2226.     SW_ASSERT(tileLayer < kNumTileLayers);
  2227.     
  2228.     if (spriteWorldP->tileLayerArray[tileLayer] == NULL)
  2229.         return -1;    // No tile here, since there is no tileMap!
  2230.     
  2231.     row = pixelRow / spriteWorldP->tileHeight;
  2232.     col = pixelCol / spriteWorldP->tileWidth;
  2233.     
  2234.     if (row < 0 || row >= spriteWorldP->tileLayerArray[tileLayer]->numRows ||
  2235.         col < 0 || col >= spriteWorldP->tileLayerArray[tileLayer]->numCols )
  2236.     {
  2237.         return -1;    // Pixel location is outside TileMap bounds!
  2238.     }
  2239.     else
  2240.     {
  2241.         return spriteWorldP->tileLayerArray[tileLayer]->tileMap[row][col];
  2242.     }
  2243. }
  2244.  
  2245.  
  2246. ///--------------------------------------------------------------------------------------
  2247. //   SWCheckSpriteWithTiles
  2248. ///--------------------------------------------------------------------------------------
  2249.  
  2250. SW_FUNC Boolean SWCheckSpriteWithTiles(
  2251.     SpriteWorldPtr    spriteWorldP,
  2252.     SpritePtr        srcSpriteP, 
  2253.     SWTileSearchType searchType,
  2254.     Rect            *insetRectP,
  2255.     short            startTileLayer,
  2256.     short            endTileLayer,
  2257.     short            firstTileID,
  2258.     short            lastTileID,
  2259.     Boolean            fixPosition)
  2260. {
  2261.     short             row, col, startRow, stopRow, startCol, stopCol;
  2262.     TileMapPtr        tileMap;
  2263.     Rect            oldFrameRect, destFrameRect;
  2264.     Boolean            foundTile = false;
  2265.     Boolean            rowLoopTest, colLoopTest;
  2266.     short            temp, tileID, tileLayer, rowIncrement, colIncrement;
  2267.     
  2268.     SW_ASSERT(spriteWorldP != NULL && spriteWorldP->tilingIsInitialized);
  2269.     SW_ASSERT(startTileLayer >= 0 && endTileLayer < kNumTileLayers);
  2270.     SW_ASSERT(srcSpriteP != NULL);
  2271.     
  2272.     oldFrameRect = srcSpriteP->oldFrameRect;
  2273.     destFrameRect = srcSpriteP->destFrameRect;
  2274.     
  2275.     if (insetRectP != NULL)
  2276.     {
  2277.         oldFrameRect.left += insetRectP->left;
  2278.         oldFrameRect.top += insetRectP->top;
  2279.         oldFrameRect.right -= insetRectP->right;
  2280.         oldFrameRect.bottom -= insetRectP->bottom;
  2281.         
  2282.         destFrameRect.left += insetRectP->left;
  2283.         destFrameRect.top += insetRectP->top;
  2284.         destFrameRect.right -= insetRectP->right;
  2285.         destFrameRect.bottom -= insetRectP->bottom;
  2286.     }
  2287.     
  2288.         // We must do this so sprites hanging off the top or left side of the TileMap
  2289.         // are still handled correctly. (The conversion from pixel to row won't work
  2290.         // correctly for negative numbers, so we "fix" the problem here.)
  2291.     if (oldFrameRect.top < 0)
  2292.         oldFrameRect.top -= spriteWorldP->tileHeight;
  2293.     if (oldFrameRect.bottom <= 0)    
  2294.         oldFrameRect.bottom -= spriteWorldP->tileHeight;
  2295.     
  2296.     if (oldFrameRect.left <= 0)
  2297.         oldFrameRect.left -= spriteWorldP->tileWidth;
  2298.     if (oldFrameRect.right <= 0)
  2299.         oldFrameRect.right -= spriteWorldP->tileWidth;
  2300.     
  2301.     if (destFrameRect.left < 0)
  2302.         destFrameRect.left -= spriteWorldP->tileWidth;
  2303.     if (destFrameRect.right <= 0)    
  2304.         destFrameRect.right -= spriteWorldP->tileWidth;
  2305.     
  2306.     if (destFrameRect.top < 0)
  2307.         destFrameRect.top -= spriteWorldP->tileHeight;
  2308.     if (destFrameRect.bottom <= 0)    
  2309.         destFrameRect.bottom -= spriteWorldP->tileHeight;
  2310.         
  2311.     
  2312.         // startRow = the tile the oldFrameRect.side was about to run into.
  2313.         // stopRow = the tile the destFrameRect.side is currently in.
  2314.         // Function returns early if the sprite didn't move over
  2315.         // a tile's bounds since last frame.
  2316.  
  2317.     if (searchType == kSWTopSide)
  2318.     {
  2319.         startRow = (oldFrameRect.top / spriteWorldP->tileHeight);
  2320.         stopRow = destFrameRect.top / spriteWorldP->tileHeight;
  2321.         startCol = destFrameRect.left / spriteWorldP->tileWidth;
  2322.         stopCol = (destFrameRect.right-1) / spriteWorldP->tileWidth;
  2323.         if (fixPosition)
  2324.             startRow--;        // Check tile just above startRow
  2325.         if (stopRow > startRow)
  2326.             return false;
  2327.     }
  2328.     else if (searchType == kSWBottomSide)
  2329.     {
  2330.         startRow = ((oldFrameRect.bottom-1) / spriteWorldP->tileHeight);
  2331.         stopRow = (destFrameRect.bottom-1) / spriteWorldP->tileHeight;
  2332.         startCol = destFrameRect.left / spriteWorldP->tileWidth;
  2333.         stopCol = (destFrameRect.right-1) / spriteWorldP->tileWidth;
  2334.         if (fixPosition)    // Check tile just below startRow
  2335.             startRow++;    
  2336.         if (stopRow < startRow)
  2337.             return false;
  2338.     }
  2339.     else if (searchType == kSWRightSide)
  2340.     {
  2341.         startCol = ((oldFrameRect.right-1) / spriteWorldP->tileWidth);
  2342.         stopCol = (destFrameRect.right-1) / spriteWorldP->tileWidth;
  2343.         startRow = destFrameRect.top / spriteWorldP->tileHeight;
  2344.         stopRow = (destFrameRect.bottom-1) / spriteWorldP->tileHeight;
  2345.         if (fixPosition)    // Check tile just to the right of startCol
  2346.             startCol++;
  2347.         if (stopCol < startCol)
  2348.             return false;
  2349.     }
  2350.     else if (searchType == kSWLeftSide)
  2351.     {
  2352.         startCol = oldFrameRect.left / spriteWorldP->tileWidth;
  2353.         stopCol = destFrameRect.left / spriteWorldP->tileWidth;
  2354.         startRow = destFrameRect.top / spriteWorldP->tileHeight;
  2355.         stopRow = (destFrameRect.bottom-1) / spriteWorldP->tileHeight;
  2356.         if (fixPosition)                // Check tile just to the left of startCol
  2357.             startCol--;        
  2358.         if (stopCol > startCol)
  2359.             return false;
  2360.     }
  2361.     else    // searchType == kSWEntireSprite
  2362.     {
  2363.         startRow = destFrameRect.top / spriteWorldP->tileHeight;
  2364.         stopRow = (destFrameRect.bottom-1) / spriteWorldP->tileHeight;
  2365.         startCol = destFrameRect.left / spriteWorldP->tileWidth;
  2366.         stopCol = (destFrameRect.right-1) / spriteWorldP->tileWidth;
  2367.     }
  2368.     
  2369.     if (startRow <= stopRow)
  2370.         rowIncrement = 1;
  2371.     else
  2372.         rowIncrement = -1;
  2373.     
  2374.     if (startCol <= stopCol)
  2375.         colIncrement = 1;
  2376.     else
  2377.         colIncrement = -1;
  2378.  
  2379.     
  2380.         // Find the first tileLayer that's not NULL
  2381.     for (tileLayer = startTileLayer; tileLayer <= endTileLayer; tileLayer++)
  2382.     {
  2383.         if (spriteWorldP->tileLayerArray[tileLayer] != NULL)
  2384.             break;
  2385.     }
  2386.     
  2387.     
  2388.         // Make sure things are within bounds (in case Sprite is hanging off edge of TileMap)
  2389.     if (rowIncrement > 0)
  2390.     {
  2391.         if (stopRow < 0)
  2392.             return false;
  2393.         else if (stopRow >= spriteWorldP->tileLayerArray[tileLayer]->numRows)
  2394.             stopRow = spriteWorldP->tileLayerArray[tileLayer]->numRows-1;
  2395.         
  2396.         if (startRow < 0)
  2397.             startRow = 0;
  2398.         else if (startRow >= spriteWorldP->tileLayerArray[tileLayer]->numRows)
  2399.             return false;
  2400.     }
  2401.     else    // rowIncrement < 0
  2402.     {
  2403.         if (startRow < 0)
  2404.             return false;
  2405.         else if (startRow >= spriteWorldP->tileLayerArray[tileLayer]->numRows)
  2406.             startRow = spriteWorldP->tileLayerArray[tileLayer]->numRows-1;
  2407.         
  2408.         if (stopRow < 0)
  2409.             stopRow = 0;
  2410.         else if (stopRow >= spriteWorldP->tileLayerArray[tileLayer]->numRows)
  2411.             return false;
  2412.     }
  2413.  
  2414.     if (colIncrement > 0)
  2415.     {
  2416.         if (stopCol < 0)
  2417.             return false;
  2418.         else if (stopCol >= spriteWorldP->tileLayerArray[tileLayer]->numCols)
  2419.             stopCol = spriteWorldP->tileLayerArray[tileLayer]->numCols-1;
  2420.         
  2421.         if (startCol < 0)
  2422.             startCol = 0;
  2423.         else if (startCol >= spriteWorldP->tileLayerArray[tileLayer]->numCols)
  2424.             return false;
  2425.     }
  2426.     else    // colIncrement < 0
  2427.     {
  2428.         if (startCol < 0)
  2429.             return false;
  2430.         else if (startCol >= spriteWorldP->tileLayerArray[tileLayer]->numCols)
  2431.             startCol = spriteWorldP->tileLayerArray[tileLayer]->numCols-1;
  2432.         
  2433.         if (stopCol < 0)
  2434.             stopCol = 0;
  2435.         else if (stopCol >= spriteWorldP->tileLayerArray[tileLayer]->numCols)
  2436.             return false;
  2437.     }
  2438.  
  2439.     
  2440.     
  2441.         // Look for the tiles in each layer. We have two separate loops: one that scans
  2442.         // through each row, then each col, and one that scans through each col, then each
  2443.         // row. You must use the correct type depending on which direction the sprite is moving.
  2444.         // (horizontally or vertically) for things to work correctly.
  2445.     
  2446.     if (searchType == kSWTopSide || searchType == kSWBottomSide || searchType == kSWEntireSprite)
  2447.     {
  2448.         for (tileLayer = startTileLayer; tileLayer <= endTileLayer; tileLayer++)
  2449.         {
  2450.             if (spriteWorldP->tileLayerArray[tileLayer] == NULL)
  2451.                 continue;
  2452.             
  2453.             tileMap = spriteWorldP->tileLayerArray[tileLayer]->tileMap;
  2454.             
  2455.                 // Scan through all cols in a row before moving to next row
  2456.             rowLoopTest = true;
  2457.             for (row = startRow; rowLoopTest; row += rowIncrement)
  2458.             {
  2459.                 rowLoopTest = row != stopRow;
  2460.                 
  2461.                 colLoopTest = true;
  2462.                 for (col = startCol; colLoopTest; col += colIncrement)
  2463.                 {
  2464.                     colLoopTest = col != stopCol;
  2465.                     tileID = tileMap[row][col];
  2466.                     if (tileID >= firstTileID && tileID <= lastTileID)
  2467.                     {
  2468.                         foundTile = true;
  2469.                         goto exit;
  2470.                     }
  2471.                 }
  2472.             }
  2473.         }
  2474.     }
  2475.     else
  2476.     {
  2477.         for (tileLayer = startTileLayer; tileLayer <= endTileLayer; tileLayer++)
  2478.         {
  2479.             if (spriteWorldP->tileLayerArray[tileLayer] == NULL)
  2480.                 continue;
  2481.             
  2482.             tileMap = spriteWorldP->tileLayerArray[tileLayer]->tileMap;
  2483.             
  2484.                 // Scan through all rows in a col before moving to next col
  2485.             colLoopTest = true;
  2486.             for (col = startCol; colLoopTest; col += colIncrement)
  2487.             {
  2488.                 colLoopTest = col != stopCol;
  2489.                 
  2490.                 rowLoopTest = true;
  2491.                 for (row = startRow; rowLoopTest; row += rowIncrement)
  2492.                 {
  2493.                     rowLoopTest = row != stopRow;
  2494.                     tileID = tileMap[row][col];
  2495.                     if (tileID >= firstTileID && tileID <= lastTileID)
  2496.                     {
  2497.                         foundTile = true;
  2498.                         goto exit;
  2499.                     }
  2500.                 }
  2501.             }
  2502.         }
  2503.     }
  2504.     
  2505. exit:
  2506.  
  2507.     
  2508.     if (foundTile && fixPosition)
  2509.     {
  2510.         if (searchType == kSWTopSide)
  2511.         {
  2512.                 // (top of tile just below the tile the sprite is in) - (curSpriteTop)
  2513.             temp = (row+1) * spriteWorldP->tileHeight - destFrameRect.top;
  2514.             srcSpriteP->destFrameRect.top += temp;
  2515.             srcSpriteP->destFrameRect.bottom += temp;
  2516.             srcSpriteP->needsToBeDrawn = true;
  2517.         }
  2518.         else if (searchType == kSWBottomSide)
  2519.         {
  2520.             temp = destFrameRect.bottom - row * spriteWorldP->tileHeight;
  2521.             srcSpriteP->destFrameRect.top -= temp;
  2522.             srcSpriteP->destFrameRect.bottom -= temp;
  2523.             srcSpriteP->needsToBeDrawn = true;
  2524.         }
  2525.         else if (searchType == kSWRightSide)
  2526.         {
  2527.             temp = destFrameRect.right - col * spriteWorldP->tileWidth;
  2528.             srcSpriteP->destFrameRect.left -= temp;
  2529.             srcSpriteP->destFrameRect.right -= temp;
  2530.             srcSpriteP->needsToBeDrawn = true;
  2531.         }
  2532.         else if (searchType == kSWLeftSide)
  2533.         {
  2534.             temp = (col+1) * spriteWorldP->tileWidth - destFrameRect.left;
  2535.             srcSpriteP->destFrameRect.left += temp;
  2536.             srcSpriteP->destFrameRect.right += temp;
  2537.             srcSpriteP->needsToBeDrawn = true;
  2538.         }
  2539.     }
  2540.     
  2541.     return foundTile;
  2542. }
  2543.  
  2544.  
  2545. ///--------------------------------------------------------------------------------------
  2546. //    SWWrapRectToWorkArea - I think this is identical to SWEraseWrappedSprite, and is here
  2547. //    simply so Scrolling.c isn't required during compiles.
  2548. ///--------------------------------------------------------------------------------------
  2549.  
  2550. SW_FUNC void SWWrapRectToWorkArea(
  2551.     SpriteWorldPtr    spriteWorldP,
  2552.     Rect*            destRectP)
  2553. {
  2554.     Rect        destRect = *destRectP;
  2555.     Rect        tempDestRect;
  2556.     FramePtr    srcFrameP = spriteWorldP->backFrameP;
  2557.     FramePtr    dstFrameP = spriteWorldP->workFrameP;
  2558.     
  2559.     SW_ASSERT(spriteWorldP != NULL);
  2560.     SW_ASSERT(spriteWorldP->backFrameP->isFrameLocked);
  2561.     SW_ASSERT(spriteWorldP->workFrameP->isFrameLocked);
  2562.     
  2563.     SetGWorld(spriteWorldP->workFrameP->framePort, nil);
  2564.     
  2565.         // Make destRect local to the offscreen area
  2566.     destRect.top -= spriteWorldP->vertScrollRectOffset;
  2567.     destRect.bottom -= spriteWorldP->vertScrollRectOffset;
  2568.     destRect.left -= spriteWorldP->horizScrollRectOffset;
  2569.     destRect.right -= spriteWorldP->horizScrollRectOffset;
  2570.     
  2571.     
  2572.         // Draw main image
  2573.     (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, &destRect, &destRect);
  2574.     
  2575.     
  2576.         // Wrap to top //
  2577.     if (destRect.bottom > dstFrameP->frameRect.bottom)
  2578.     {
  2579.         tempDestRect.top = destRect.top - dstFrameP->frameRect.bottom;
  2580.         tempDestRect.bottom = destRect.bottom - dstFrameP->frameRect.bottom;
  2581.         tempDestRect.left = destRect.left;
  2582.         tempDestRect.right = destRect.right;
  2583.         
  2584.         (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2585.             &tempDestRect, &tempDestRect);
  2586.         
  2587.             // Wrap to upper left or right corner //
  2588.         if (destRect.right > dstFrameP->frameRect.right)
  2589.         {
  2590.             tempDestRect.left -= dstFrameP->frameRect.right;
  2591.             tempDestRect.right -= dstFrameP->frameRect.right;
  2592.             
  2593.             (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2594.                 &tempDestRect, &tempDestRect);
  2595.         }
  2596.         else if (destRect.left < dstFrameP->frameRect.left)
  2597.         {
  2598.             tempDestRect.left += dstFrameP->frameRect.right;
  2599.             tempDestRect.right += dstFrameP->frameRect.right;
  2600.             
  2601.             (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2602.                 &tempDestRect, &tempDestRect);
  2603.         }
  2604.     }
  2605.     
  2606.             // Wrap to left or right side //
  2607.     if (destRect.right > dstFrameP->frameRect.right)
  2608.     {
  2609.         tempDestRect.top = destRect.top;
  2610.         tempDestRect.bottom = destRect.bottom;
  2611.         tempDestRect.left = destRect.left - dstFrameP->frameRect.right;
  2612.         tempDestRect.right = destRect.right - dstFrameP->frameRect.right;
  2613.         
  2614.         (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2615.             &tempDestRect, &tempDestRect);
  2616.     }
  2617.     else if (destRect.left < dstFrameP->frameRect.left)
  2618.     {
  2619.         tempDestRect.top = destRect.top;
  2620.         tempDestRect.bottom = destRect.bottom;
  2621.         tempDestRect.left = destRect.left + dstFrameP->frameRect.right;
  2622.         tempDestRect.right = destRect.right + dstFrameP->frameRect.right;
  2623.         
  2624.         (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2625.             &tempDestRect, &tempDestRect);
  2626.     }
  2627.     
  2628.     
  2629.             // Wrap to bottom //
  2630.     if (destRect.top < dstFrameP->frameRect.top)
  2631.     {
  2632.         tempDestRect.top = destRect.top + dstFrameP->frameRect.bottom;
  2633.         tempDestRect.bottom = destRect.bottom + dstFrameP->frameRect.bottom;
  2634.         tempDestRect.left = destRect.left;
  2635.         tempDestRect.right = destRect.right;
  2636.         
  2637.         (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2638.             &tempDestRect, &tempDestRect);
  2639.         
  2640.             // Wrap to lower left or right corner //
  2641.         if (destRect.right > dstFrameP->frameRect.right)
  2642.         {
  2643.             tempDestRect.left -= dstFrameP->frameRect.right;
  2644.             tempDestRect.right -= dstFrameP->frameRect.right;
  2645.             
  2646.             (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2647.                 &tempDestRect, &tempDestRect);
  2648.         }
  2649.         else if (destRect.left < dstFrameP->frameRect.left)
  2650.         {
  2651.             tempDestRect.left += dstFrameP->frameRect.right;
  2652.             tempDestRect.right += dstFrameP->frameRect.right;
  2653.             
  2654.             (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  2655.                 &tempDestRect, &tempDestRect);
  2656.         }
  2657.     }
  2658. }
  2659.  
  2660.  
  2661. ///--------------------------------------------------------------------------------------
  2662. //    SWWrapRectFromExtraBackFrame - similar to SWWrapRectToScreen, just modified so the
  2663. //    srcFramePtr is the extraBackFramePtr, the dstFrameP is the backFrameP, and the src
  2664. //    and dst rects are what they should be. Note: the dstRect you pass to this function is
  2665. //    the tile's rect *before* it's made local to the offscreen area and wrapped. It is also
  2666. //    important that the actual dstRectP is modified, not a copy, since the callers expect this.
  2667. ///--------------------------------------------------------------------------------------
  2668.  
  2669. SW_FUNC void SWWrapRectFromExtraBackFrame(
  2670.     SpriteWorldPtr    spriteWorldP,
  2671.     Rect            *dstRectP)
  2672. {
  2673.     FramePtr    srcFrameP = spriteWorldP->extraBackFrameP;
  2674.     FramePtr    dstFrameP = spriteWorldP->backFrameP;
  2675.     Rect        srcRect, tempSrcRect, tempDstRect;
  2676.     short        topClip=0, rightClip=0, bottomClip=0, leftClip=0;
  2677.     short        vertBackRectOffset, horizBackRectOffset;    
  2678.     
  2679.     SW_ASSERT(spriteWorldP != NULL);
  2680.     SW_ASSERT(srcFrameP->isFrameLocked);
  2681.     SW_ASSERT(dstFrameP->isFrameLocked);        
  2682.     
  2683.         // The code below is ripped from SWCalculateOffscreenScrollRect
  2684.         // It is modified to do a similar function for the extraBackFrameP.
  2685.     vertBackRectOffset = spriteWorldP->extraBackFrameP->frameRect.bottom * 
  2686.         (dstRectP->top / spriteWorldP->extraBackFrameP->frameRect.bottom);
  2687.     
  2688.     horizBackRectOffset = spriteWorldP->extraBackFrameP->frameRect.right *
  2689.         (dstRectP->left / spriteWorldP->extraBackFrameP->frameRect.right);
  2690.         
  2691.     srcRect.top = dstRectP->top - vertBackRectOffset;
  2692.     srcRect.bottom = dstRectP->bottom - vertBackRectOffset;
  2693.     srcRect.left = dstRectP->left - horizBackRectOffset;
  2694.     srcRect.right = dstRectP->right - horizBackRectOffset;
  2695.     
  2696.     // We must do the dstRect calculation below *after* the code above!
  2697.     
  2698.         // Make the tile's dest rect local to the offscreen area
  2699.     dstRectP->top -= spriteWorldP->vertScrollRectOffset;
  2700.     dstRectP->bottom -= spriteWorldP->vertScrollRectOffset;
  2701.     dstRectP->left -= spriteWorldP->horizScrollRectOffset;
  2702.     dstRectP->right -= spriteWorldP->horizScrollRectOffset;
  2703.     
  2704.         // Wrap dstRect to top or bottom of offscreen area
  2705.     if (dstRectP->bottom > dstFrameP->frameRect.bottom)
  2706.     {
  2707.         dstRectP->top -= dstFrameP->frameRect.bottom;
  2708.         dstRectP->bottom -= dstFrameP->frameRect.bottom;
  2709.     }
  2710.     else if (dstRectP->top < dstFrameP->frameRect.top)
  2711.     {
  2712.         dstRectP->top += dstFrameP->frameRect.bottom;
  2713.         dstRectP->bottom += dstFrameP->frameRect.bottom;
  2714.     }
  2715.     
  2716.         // Wrap dstRect to left or right side of offscreen area
  2717.     if (dstRectP->right > dstFrameP->frameRect.right)
  2718.     {
  2719.         dstRectP->left -= dstFrameP->frameRect.right;
  2720.         dstRectP->right -= dstFrameP->frameRect.right;
  2721.     }
  2722.     else if (dstRectP->left < dstFrameP->frameRect.left)
  2723.     {
  2724.         dstRectP->left += dstFrameP->frameRect.right;
  2725.         dstRectP->right += dstFrameP->frameRect.right;
  2726.     }
  2727.  
  2728.     
  2729.         // Clip the source rect, and save what we clipped for wrapping later //
  2730.     
  2731.         // clip off the top
  2732.     if (srcRect.top < srcFrameP->frameRect.top)
  2733.     {
  2734.         topClip = srcFrameP->frameRect.top - srcRect.top;
  2735.         srcRect.top += topClip;    
  2736.     }
  2737.     
  2738.         // clip off the bottom
  2739.     if (srcRect.bottom > srcFrameP->frameRect.bottom)
  2740.     {
  2741.         bottomClip = srcRect.bottom - srcFrameP->frameRect.bottom;
  2742.         srcRect.bottom -= bottomClip;
  2743.     }
  2744.     
  2745.         // clip off the left
  2746.     if (srcRect.left < srcFrameP->frameRect.left)
  2747.     {
  2748.         leftClip = srcFrameP->frameRect.left - srcRect.left;
  2749.         srcRect.left += leftClip;
  2750.     }
  2751.     
  2752.         // clip off the right
  2753.     if (srcRect.right > srcFrameP->frameRect.right)
  2754.     {
  2755.         rightClip = srcRect.right - srcFrameP->frameRect.right;
  2756.         srcRect.right -= rightClip;
  2757.     }
  2758.     
  2759.     
  2760.                     // Here we do the wrapping and drawing //
  2761.     
  2762.         // Draw top section //
  2763.     
  2764.     if (topClip)
  2765.     {
  2766.                 // Calculate top piece //
  2767.         
  2768.             // Wrap source rect to bottom side
  2769.         tempSrcRect.right = srcRect.right;                    // Copy clipped source rect
  2770.         tempSrcRect.left = srcRect.left;
  2771.         tempSrcRect.bottom = srcFrameP->frameRect.bottom;
  2772.         tempSrcRect.top = srcFrameP->frameRect.bottom - topClip;
  2773.         
  2774.             // Position dest rect at top side
  2775.         tempDstRect.top = dstRectP->top;
  2776.         tempDstRect.bottom = dstRectP->top + topClip;
  2777.         tempDstRect.left = dstRectP->left + leftClip;
  2778.         tempDstRect.right = dstRectP->right - rightClip;
  2779.         
  2780.         (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2781.         
  2782.         
  2783.         if (leftClip)    // Calculate top-left piece
  2784.         {
  2785.                 // Wrap source rect to lower-right corner
  2786.             tempSrcRect.bottom = srcFrameP->frameRect.bottom;
  2787.             tempSrcRect.right = srcFrameP->frameRect.right;
  2788.             tempSrcRect.top = srcFrameP->frameRect.bottom - topClip;
  2789.             tempSrcRect.left = srcFrameP->frameRect.right - leftClip;
  2790.             
  2791.                 // Position dest rect at top-left corner
  2792.             tempDstRect.left = dstRectP->left;
  2793.             tempDstRect.top = dstRectP->top;
  2794.             tempDstRect.right = dstRectP->left + leftClip;
  2795.             tempDstRect.bottom = dstRectP->top + topClip;
  2796.             
  2797.             (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2798.         }
  2799.         else if (rightClip)        // Calculate top-right piece
  2800.         {
  2801.                 // Wrap source rect to lower-left corner
  2802.             tempSrcRect.bottom = srcFrameP->frameRect.bottom;
  2803.             tempSrcRect.left = srcFrameP->frameRect.left;
  2804.             tempSrcRect.right = srcFrameP->frameRect.left + rightClip;
  2805.             tempSrcRect.top = srcFrameP->frameRect.bottom - topClip;
  2806.             
  2807.                 // Position dest rect at top-right corner
  2808.             tempDstRect.top = dstRectP->top;
  2809.             tempDstRect.right = dstRectP->right;
  2810.             tempDstRect.bottom = dstRectP->top + topClip;
  2811.             tempDstRect.left = dstRectP->right - rightClip;
  2812.             
  2813.             (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2814.         }
  2815.     }
  2816.     
  2817.     
  2818.             // Draw middle section //
  2819.     
  2820.         // Calculate main middle piece (not wrapped)
  2821.     tempDstRect.left = dstRectP->left + leftClip;
  2822.     tempDstRect.top = dstRectP->top + topClip;
  2823.     tempDstRect.right = dstRectP->right - rightClip;
  2824.     tempDstRect.bottom = dstRectP->bottom - bottomClip;
  2825.     
  2826.     (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &srcRect, &tempDstRect);
  2827.     
  2828.     
  2829.     if (leftClip)    // Draw left piece
  2830.     {
  2831.             // Wrap source rect to right side
  2832.         tempSrcRect.top = srcRect.top;                // Copy clipped source rect
  2833.         tempSrcRect.bottom = srcRect.bottom;
  2834.         tempSrcRect.right = srcFrameP->frameRect.right;
  2835.         tempSrcRect.left = srcFrameP->frameRect.right - leftClip;
  2836.         
  2837.             // Position dest rect at left side
  2838.         tempDstRect.left = dstRectP->left;
  2839.         tempDstRect.right = dstRectP->left + leftClip;
  2840.         tempDstRect.top = dstRectP->top + topClip;
  2841.         tempDstRect.bottom = dstRectP->bottom - bottomClip;
  2842.         
  2843.         (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2844.     }
  2845.     else if (rightClip)        // Draw right piece
  2846.     {
  2847.             // Wrap source rect to left side
  2848.         tempSrcRect.top = srcRect.top;                // Copy clipped source rect
  2849.         tempSrcRect.bottom = srcRect.bottom;
  2850.         tempSrcRect.left = srcFrameP->frameRect.left;
  2851.         tempSrcRect.right = srcFrameP->frameRect.left + rightClip;
  2852.         
  2853.             // Position dest rect at right side
  2854.         tempDstRect.right = dstRectP->right;
  2855.         tempDstRect.left = dstRectP->right - rightClip;
  2856.         tempDstRect.top = dstRectP->top + topClip;
  2857.         tempDstRect.bottom = dstRectP->bottom - bottomClip;
  2858.         
  2859.         (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2860.     }
  2861.     
  2862.     
  2863.         // Draw bottom section //
  2864.     
  2865.     if (bottomClip)
  2866.     {
  2867.             // Calculate bottom piece //
  2868.         
  2869.             // Wrap source rect to top side
  2870.         tempSrcRect.right = srcRect.right;                // Copy clipped source rect
  2871.         tempSrcRect.left = srcRect.left;
  2872.         tempSrcRect.top = srcFrameP->frameRect.top;
  2873.         tempSrcRect.bottom = srcFrameP->frameRect.top + bottomClip;
  2874.         
  2875.             // Position dest rect at bottom side
  2876.         tempDstRect.bottom = dstRectP->bottom;
  2877.         tempDstRect.top = dstRectP->bottom - bottomClip;
  2878.         tempDstRect.left = dstRectP->left + leftClip;
  2879.         tempDstRect.right = dstRectP->right - rightClip;
  2880.  
  2881.         (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2882.         
  2883.         if (leftClip)     // Draw bottom-left piece
  2884.         {
  2885.                 // Wrap source rect to upper-right corner
  2886.             tempSrcRect.top = srcFrameP->frameRect.top;
  2887.             tempSrcRect.right = srcFrameP->frameRect.right;
  2888.             tempSrcRect.bottom = srcFrameP->frameRect.top + bottomClip;
  2889.             tempSrcRect.left = srcFrameP->frameRect.right - leftClip;
  2890.             
  2891.                 // Position dest rect at bottom-left corner
  2892.             tempDstRect.bottom = dstRectP->bottom;
  2893.             tempDstRect.left = dstRectP->left;
  2894.             tempDstRect.top = dstRectP->bottom - bottomClip;
  2895.             tempDstRect.right = dstRectP->left + leftClip;
  2896.             
  2897.             (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2898.         }
  2899.         else if (rightClip)        // Draw bottom-right piece
  2900.         {
  2901.                 // Wrap source rect to upper-left corner
  2902.             tempSrcRect.top = srcFrameP->frameRect.top;
  2903.             tempSrcRect.left = srcFrameP->frameRect.left;
  2904.             tempSrcRect.bottom = srcFrameP->frameRect.top + bottomClip;
  2905.             tempSrcRect.right = srcFrameP->frameRect.left + rightClip;
  2906.             
  2907.                 // Position dest rect at bottom-right corner
  2908.             tempDstRect.bottom = dstRectP->bottom;
  2909.             tempDstRect.right = dstRectP->right;
  2910.             tempDstRect.top = dstRectP->bottom - bottomClip;
  2911.             tempDstRect.left = dstRectP->right - rightClip;
  2912.             
  2913.             (*spriteWorldP->screenDrawProc)(srcFrameP, dstFrameP, &tempSrcRect, &tempDstRect);
  2914.         }
  2915.     }
  2916. }
  2917.  
  2918.