home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Snippets / PNL Libraries / Libraries / SpriteWorld / SpriteWorld files / Sources / Tiling.c < prev   
Encoding:
Text File  |  1996-11-25  |  48.6 KB  |  1,779 lines  |  [TEXT/KAHL]

  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, row, col, numOffscreenCols, numOffscreenRows;
  55.     
  56.     SWAssert( spriteWorldP != NULL && !spriteWorldP->tilingIsInitialized && tileHeight > 0 && tileWidth > 0 && maxNumTiles > 0 );
  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->maxNumTiles = maxNumTiles;
  69.         spriteWorldP->tileHeight = tileHeight;
  70.         spriteWorldP->tileWidth = tileWidth;
  71.         spriteWorldP->tileMap = NULL;
  72.     
  73.         numOffscreenRows = spriteWorldP->backRect.bottom / tileHeight;
  74.         numOffscreenCols = spriteWorldP->backRect.right / tileWidth;
  75.         spriteWorldP->numOffscreenTileMapRows = numOffscreenRows;
  76.         spriteWorldP->numOffscreenTileMapCols = numOffscreenCols;
  77.     }
  78.     
  79.     
  80.     if (err == noErr)
  81.     {
  82.             // Allocate memory for offscreenTileMap
  83.         arraySize = (Size)numOffscreenRows * numOffscreenCols * sizeof(short);
  84.         spriteWorldP->offscreenTileMap = (short *)NewPtr(arraySize);
  85.         err = MemError();
  86.         
  87.         if (err == noErr)
  88.         {
  89.                 // Set all elements to -1 (indicating that each tile needs to be drawn)
  90.             for (row = 0; row < numOffscreenRows; row++)
  91.                 for (col = 0; col < numOffscreenCols; col++)
  92.                     spriteWorldP->offscreenTileMap[(long)row * numOffscreenCols + col] = -1;
  93.         }
  94.     }
  95.     
  96.     
  97.     if (err == noErr)
  98.     {
  99.             // Allocate memory for changedTiles array of rects
  100.         arraySize = (Size)(numOffscreenRows+1) * (numOffscreenCols+1) * sizeof(Rect);
  101.             // Warning, arraySize calculation used in assert in SWAddChangeRect - probably should be SpriteWorld field
  102.         spriteWorldP->changedTiles = (Rect *)NewPtr(arraySize);
  103.         err = MemError();
  104.     }
  105.     
  106.     
  107.     if (err == noErr)
  108.     {
  109.             // Allocate memory for tileFrameArray
  110.         arraySize = (Size)maxNumTiles * sizeof(FramePtr);
  111.         spriteWorldP->tileFrameArray = (FramePtr *)NewPtrClear(arraySize);
  112.         err = MemError();
  113.     }
  114.     
  115.     
  116.     if (err == noErr)
  117.     {
  118.             // Allocate memory for curTileImage array
  119.         arraySize = (Size)maxNumTiles * sizeof(short);
  120.         spriteWorldP->curTileImage = (short *)NewPtr(arraySize);
  121.         err = MemError();
  122.         
  123.         if (err == noErr)
  124.         {
  125.                 // Set up values in curTileImage array
  126.             for (tileIndex = 0; tileIndex < maxNumTiles; tileIndex++)
  127.                 spriteWorldP->curTileImage[tileIndex] = tileIndex;
  128.         }
  129.     }
  130.     
  131.     
  132.     SWSetStickyIfError(err);
  133.     return err;
  134. }
  135.  
  136.  
  137. ///--------------------------------------------------------------------------------------
  138. //    SWExitTiling
  139. ///--------------------------------------------------------------------------------------
  140.  
  141. SW_FUNC void SWExitTiling(
  142.     SpriteWorldPtr    spriteWorldP)
  143. {
  144.     short    tileIndex;
  145.     
  146.     SWAssert( spriteWorldP != NULL );
  147.  
  148.         // Was tiling ever initialized?
  149.     if (spriteWorldP->tilingIsInitialized)
  150.     {
  151.         tileIndex = spriteWorldP->maxNumTiles;
  152.         while ( tileIndex-- )
  153.         {
  154.             SWDisposeTile( spriteWorldP, tileIndex );
  155.         }
  156.         
  157.         SWDisposeTileMap(spriteWorldP);
  158.         
  159.         DisposePtr((Ptr)spriteWorldP->offscreenTileMap);
  160.         DisposePtr((Ptr)spriteWorldP->tileFrameArray);
  161.         DisposePtr((Ptr)spriteWorldP->changedTiles);
  162.         DisposePtr((Ptr)spriteWorldP->curTileImage);
  163.         
  164.         spriteWorldP->tilingIsInitialized = false;
  165.         spriteWorldP->tilingIsOn = false;
  166.     }
  167. }
  168.  
  169.  
  170. ///--------------------------------------------------------------------------------------
  171. //    SWCreateTileMap
  172. ///--------------------------------------------------------------------------------------
  173.  
  174. SW_FUNC OSErr SWCreateTileMap(
  175.     SpriteWorldPtr    spriteWorldP,
  176.     TileMapPtr        *tileMapP,
  177.     short             numTileMapRows,
  178.     short            numTileMapCols)
  179. {
  180.     TileMapPtr    tempTileMap;
  181.     Size        arraySize;
  182.     short        row;
  183.     OSErr        err = noErr;
  184.     
  185.     SWAssert( spriteWorldP != NULL && tileMapP != NULL && numTileMapRows > 0 && numTileMapCols > 0 );
  186.  
  187.         // Dispose the old TileMap if there is one
  188.     SWDisposeTileMap(spriteWorldP);
  189.     
  190.         // Allocate the first "dimension" of the array - tileMap[row]
  191.     arraySize = (Size)numTileMapRows * sizeof(short*);    // array of pointers
  192.     tempTileMap = (short**)NewPtr(arraySize);            // to the second array
  193.     err = MemError();
  194.     
  195.     if (err == noErr)
  196.     {
  197.             // Allocate the second "dimension" of the array - tileMap[row][col]
  198.         arraySize = (Size)numTileMapCols * sizeof(short);
  199.         for (row = 0; row < numTileMapRows; row++)
  200.         {
  201.             tempTileMap[row] = (short*)NewPtrClear(arraySize);
  202.             err = MemError();
  203.             
  204.             if (err)    // Out of memory! Dispose whatever we managed to create.
  205.             {
  206.                 while (--row >= 0)
  207.                 {
  208.                     DisposePtr((Ptr)tempTileMap[row]);
  209.                 }
  210.                 
  211.                 DisposePtr((Ptr)tempTileMap);
  212.                 tempTileMap = NULL;
  213.                 
  214.                 break;
  215.             }
  216.         }
  217.     }
  218.     
  219.         // Assign the new tileMap to the SpriteWorld
  220.     *tileMapP = spriteWorldP->tileMap = tempTileMap;
  221.     spriteWorldP->numTileMapRows = numTileMapRows;
  222.     spriteWorldP->numTileMapCols = numTileMapCols;
  223.     
  224.     SWSetStickyIfError(err);
  225.     return err;
  226. }
  227.  
  228.  
  229. ///--------------------------------------------------------------------------------------
  230. //    SWDisposeTileMap
  231. ///--------------------------------------------------------------------------------------
  232.  
  233. SW_FUNC void SWDisposeTileMap(
  234.     SpriteWorldPtr    spriteWorldP)
  235. {
  236.     short    row;
  237.  
  238.     SWAssert( spriteWorldP != NULL );
  239.  
  240.     if (spriteWorldP->tileMap != NULL)
  241.     {
  242.             // Dispose the second half of the tileMap
  243.         for (row = 0; row < spriteWorldP->numTileMapRows; row++)
  244.             DisposePtr((Ptr)spriteWorldP->tileMap[row]);
  245.         
  246.             // Dispose the first half (must be done in this order)
  247.         DisposePtr((Ptr)spriteWorldP->tileMap);
  248.         spriteWorldP->tileMap = NULL;
  249.     }
  250. }
  251.  
  252.  
  253. ///--------------------------------------------------------------------------------------
  254. //    SWResizeTileMap
  255. ///--------------------------------------------------------------------------------------
  256.  
  257. SW_FUNC OSErr SWResizeTileMap(
  258.     SpriteWorldPtr    spriteWorldP,
  259.     TileMapPtr        *tileMapP,
  260.     short             numNewTileMapRows,
  261.     short            numNewTileMapCols)
  262. {
  263.     short        *tileMapData;
  264.     short        **tileMapDataH;
  265.     Size        arraySize;
  266.     short        row, numTileMapRows, numTileMapCols;
  267.     short        numRowsToCopy, numColsToCopy;
  268.     OSErr        err = noErr;
  269.     
  270.     SWAssert( spriteWorldP != NULL && tileMapP != NULL && *tileMapP != NULL && numNewTileMapRows > 0 && numNewTileMapCols > 0 );
  271.  
  272.     numTileMapRows = spriteWorldP->numTileMapRows;
  273.     numTileMapCols = spriteWorldP->numTileMapCols;
  274.         
  275.     if (spriteWorldP->tileMap == NULL)
  276.     {
  277.         err = kNullTileMapErr;
  278.     }
  279.     
  280.         // Don't do anything if the TileMap is already the requested size.
  281.     if (numTileMapRows == numNewTileMapRows && numTileMapCols == numNewTileMapCols)
  282.     {
  283.         return noErr;
  284.     }
  285.     
  286.     
  287.     if (err == noErr)    // Allocate memory for the tileMapData
  288.     {
  289.         arraySize = (Size)numTileMapRows * numTileMapCols * sizeof(short);
  290.         tileMapDataH = (short **)NewHandle(arraySize);
  291.         if (tileMapDataH == NULL)
  292.             err = memFullErr;
  293.     }
  294.     
  295.     
  296.     if (err == noErr)
  297.     {
  298.         HLock((Handle)tileMapDataH);
  299.         tileMapData = *tileMapDataH;
  300.         
  301.             // Copy the old TileMap into the tileMapData
  302.         arraySize = (Size)numTileMapCols * sizeof(short);
  303.         for (row = 0; row < numTileMapRows; row++)
  304.         {
  305.             BlockMove(&spriteWorldP->tileMap[row][0], 
  306.                 &tileMapData[(long)row * numTileMapCols], arraySize);
  307.         }
  308.  
  309.         HUnlock((Handle)tileMapDataH);
  310.         
  311.             // Dispose the old TileMap now that we've saved its data
  312.         SWDisposeTileMap(spriteWorldP);
  313.         
  314.             // Create the new TileMap
  315.         err = SWCreateTileMap(spriteWorldP, tileMapP, numNewTileMapRows, 
  316.             numNewTileMapCols);
  317.     }
  318.     
  319.     
  320.     if (err == noErr)
  321.     {
  322.         numRowsToCopy = SW_MIN(numTileMapRows, numNewTileMapRows);
  323.         numColsToCopy = SW_MIN(numTileMapCols, numNewTileMapCols);
  324.         
  325.         HLock((Handle)tileMapDataH);
  326.         tileMapData = *tileMapDataH;
  327.         
  328.             // Copy the old tileMapData into the new TileMap
  329.         arraySize = (Size)numColsToCopy * sizeof(short);
  330.         for (row = 0; row < numRowsToCopy; row++)
  331.         {
  332.             BlockMove(&tileMapData[(long)row * numTileMapCols],
  333.                 &spriteWorldP->tileMap[row][0], arraySize);
  334.         }
  335.         
  336.         spriteWorldP->numTileMapRows = numNewTileMapRows;
  337.         spriteWorldP->numTileMapCols = numNewTileMapCols;
  338.         DisposeHandle((Handle)tileMapDataH);
  339.     }
  340.     else
  341.     {        // Not enough memory to create the resized TileMap!
  342.             // Put things back the way they were (recreate the old TileMap)
  343.         err = SWCreateTileMap(spriteWorldP, tileMapP, numTileMapRows, 
  344.             numTileMapCols);
  345.         
  346.         if (err == noErr)    // Copy the data back into the TileMap
  347.         {
  348.             HLock((Handle)tileMapDataH);
  349.             tileMapData = *tileMapDataH;
  350.             
  351.                 // Copy the tileMapData into the TileMap
  352.             arraySize = (Size)numTileMapCols * sizeof(short);
  353.             for (row = 0; row < numTileMapRows; row++)
  354.             {
  355.                 BlockMove(&tileMapData[(long)row * numTileMapCols],
  356.                     &spriteWorldP->tileMap[row][0], arraySize);
  357.             }
  358.         }
  359.         
  360.         DisposeHandle((Handle)tileMapDataH);
  361.         err = memFullErr;    // Couldn't create the resized TileMap
  362.     }
  363.     
  364.     
  365.     SWSetStickyIfError(err);
  366.     return err;
  367. }
  368.  
  369.  
  370. ///--------------------------------------------------------------------------------------
  371. //    SWLoadTileMap
  372. ///--------------------------------------------------------------------------------------
  373.  
  374. SW_FUNC OSErr SWLoadTileMap(
  375.     SpriteWorldPtr    spriteWorldP,
  376.     TileMapPtr        *tileMapP,
  377.     short             resourceID)
  378. {
  379.     short        *tileMapData;
  380.     short        **tileMapDataH;
  381.     short        row, numTileMapRows, numTileMapCols;
  382.     Size        arraySize;
  383.     OSErr        err = noErr;
  384.     
  385.     SWAssert( spriteWorldP != NULL && tileMapP != NULL );
  386.     
  387.     tileMapDataH = (short **)Get1Resource('TMAP', resourceID);
  388.     if (tileMapDataH == NULL)
  389.     {
  390.         err = ResError();
  391.         if (err == noErr)
  392.             err = resNotFound;
  393.     }
  394.     
  395.     if (err == noErr)        // Copy the resource data into the tileMap //
  396.     {    
  397.         HLock((Handle)tileMapDataH);
  398.         tileMapData = *tileMapDataH;
  399.         
  400.             // Get the variables saved in the first two elements of the tileMapData
  401.         numTileMapRows = tileMapData[0];
  402.         numTileMapCols = tileMapData[1];
  403.         
  404.             // Don't create a new tileMap if there is already one that's the same size
  405.         if (spriteWorldP->tileMap == NULL ||
  406.             numTileMapRows != spriteWorldP->numTileMapRows ||
  407.             numTileMapCols != spriteWorldP->numTileMapCols)
  408.         {
  409.                 // Dispose the old tileMap if there is one
  410.             SWDisposeTileMap(spriteWorldP);
  411.             
  412.                 // Let the new TileMap go as low in the heap as possible
  413.             HUnlock((Handle)tileMapDataH);
  414.     
  415.             err = SWCreateTileMap(spriteWorldP, tileMapP, numTileMapRows, 
  416.                     numTileMapCols);
  417.             
  418.             HLock((Handle)tileMapDataH);
  419.             tileMapData = *tileMapDataH;
  420.         }
  421.         else
  422.         {
  423.             *tileMapP = spriteWorldP->tileMap;
  424.         }
  425.     }
  426.     
  427.     
  428.     if (err == noErr)
  429.     {    
  430.             // Copy the data into the tileMap array
  431.         arraySize = (Size)numTileMapCols * sizeof(short);
  432.         for (row = 0; row < numTileMapRows; row++)
  433.         {
  434.             BlockMove(&tileMapData[(long)row * numTileMapCols + 2],
  435.                 &spriteWorldP->tileMap[row][0], arraySize);
  436.         }
  437.     }
  438.     
  439.     
  440.     if (tileMapDataH != NULL)
  441.     {
  442.         ReleaseResource((Handle)tileMapDataH);
  443.     }
  444.     
  445.     
  446.     SWSetStickyIfError(err);
  447.     return err;
  448. }
  449.  
  450.  
  451. ///--------------------------------------------------------------------------------------
  452. //    SWSaveTileMap
  453. ///--------------------------------------------------------------------------------------
  454.  
  455. SW_FUNC OSErr SWSaveTileMap(
  456.     SpriteWorldPtr    spriteWorldP,
  457.     short             resourceID)
  458. {
  459.     short        *tileMapData;
  460.     short        **tileMapDataH;
  461.     short        row, numTileMapRows, numTileMapCols;
  462.     Boolean        createdNewResource;
  463.     Size        arraySize;
  464.     OSErr        err = noErr;
  465.     
  466.     SWAssert( spriteWorldP != NULL );
  467.  
  468.     numTileMapRows = spriteWorldP->numTileMapRows,
  469.     numTileMapCols = spriteWorldP->numTileMapCols;
  470.     
  471.         // Make sure there is a tileMap to save
  472.     if (spriteWorldP->tileMap == NULL)
  473.     {
  474.         err = kNullTileMapErr;
  475.     }
  476.  
  477.  
  478.     if (err == noErr)        // Load or create the resource //
  479.     {
  480.         tileMapDataH = (short **)Get1Resource('TMAP', resourceID);
  481.         
  482.             // Is there already a resource with this ID?
  483.         if (tileMapDataH != NULL)
  484.         {
  485.             arraySize = ((Size)numTileMapRows * numTileMapCols + 2) * sizeof(short);
  486.             SetHandleSize((Handle)tileMapDataH, arraySize);
  487.             err = MemError();
  488.             
  489.             if (err != noErr)
  490.                 ReleaseResource((Handle)tileMapDataH);
  491.             
  492.             createdNewResource = false;
  493.         }
  494.         else if (ResError() == resNotFound || ResError() == noErr)
  495.         {
  496.             arraySize = ((Size)numTileMapRows * numTileMapCols + 2) * sizeof(short);
  497.             tileMapDataH = (short **)NewHandle(arraySize);
  498.             err = MemError();
  499.             
  500.             createdNewResource = true;
  501.         }
  502.         else
  503.         {
  504.             err = ResError();
  505.         }
  506.     }
  507.         
  508.     
  509.     if (err == noErr)        // Copy the data into the resource handle //
  510.     {    
  511.         HLock((Handle)tileMapDataH);
  512.         tileMapData = *tileMapDataH;
  513.         
  514.             // Save these variables in the first two elements of the tileMapData
  515.         tileMapData[0] = numTileMapRows;
  516.         tileMapData[1] = numTileMapCols;
  517.  
  518.             // Move the two-dimensional array into a one-dimensional array,
  519.             // so we can save it into a single resource.
  520.         arraySize = (Size)numTileMapCols * sizeof(short);
  521.         for (row = 0; row < numTileMapRows; row++)
  522.         {
  523.             BlockMove(&spriteWorldP->tileMap[row][0], 
  524.                 &tileMapData[(long)row * numTileMapCols + 2], arraySize);
  525.         }
  526.     }
  527.     
  528.     
  529.     if (err == noErr)        // Add the resource or mark it as changed //
  530.     {    
  531.         if (createdNewResource)
  532.         {
  533.             AddResource((Handle)tileMapDataH, 'TMAP', resourceID, "\p");
  534.             err = ResError();
  535.             
  536.             if (err != noErr)
  537.                 DisposHandle((Handle)tileMapDataH);
  538.         
  539.         }
  540.         else
  541.         {
  542.             ChangedResource((Handle)tileMapDataH);
  543.             err = ResError();
  544.             
  545.             if (err != noErr)
  546.                 ReleaseResource((Handle)tileMapDataH);
  547.         }
  548.     }
  549.     
  550.     
  551.     if (err == noErr)        // Update the resource file and clean up //
  552.     {
  553.         UpdateResFile( CurResFile() );
  554.         ReleaseResource((Handle)tileMapDataH);
  555.     }
  556.     
  557.     
  558.     SWSetStickyIfError(err);
  559.     return err;
  560. }
  561.  
  562.  
  563. ///--------------------------------------------------------------------------------------
  564. //    SWLockTiles
  565. ///--------------------------------------------------------------------------------------
  566.  
  567. SW_FUNC void SWLockTiles(
  568.     SpriteWorldPtr    spriteWorldP)
  569. {
  570.     short        tileIndex;
  571.     
  572.     SWAssert( spriteWorldP != NULL );
  573.  
  574.     if (spriteWorldP->tilingIsInitialized)
  575.     {
  576.         for (tileIndex = 0; tileIndex < spriteWorldP->maxNumTiles; tileIndex++)
  577.         {
  578.             if (spriteWorldP->tileFrameArray[tileIndex] != NULL)
  579.                 SWLockFrame(spriteWorldP->tileFrameArray[tileIndex]);
  580.         }
  581.     }
  582. }
  583.  
  584.  
  585. ///--------------------------------------------------------------------------------------
  586. //    SWUnlockTiles
  587. ///--------------------------------------------------------------------------------------
  588.  
  589. SW_FUNC void SWUnlockTiles(
  590.     SpriteWorldPtr    spriteWorldP)
  591. {
  592.     short        tileIndex;
  593.     
  594.     SWAssert( spriteWorldP != NULL );
  595.  
  596.     if (spriteWorldP->tilingIsInitialized)
  597.     {
  598.         for (tileIndex = 0; tileIndex < spriteWorldP->maxNumTiles; tileIndex++)
  599.         {
  600.             if (spriteWorldP->tileFrameArray[tileIndex] != NULL)
  601.                 SWUnlockFrame(spriteWorldP->tileFrameArray[tileIndex]);
  602.         }
  603.     }
  604. }
  605.  
  606.  
  607. ///--------------------------------------------------------------------------------------
  608. //    SWSetTilingOn
  609. ///--------------------------------------------------------------------------------------
  610.  
  611. SW_FUNC void SWSetTilingOn(
  612.     SpriteWorldPtr    spriteWorldP,
  613.     Boolean            tilingIsOn)
  614. {
  615.     SWAssert( spriteWorldP != NULL );
  616.  
  617.     spriteWorldP->tilingIsOn = tilingIsOn;
  618. }
  619.  
  620.  
  621. ///--------------------------------------------------------------------------------------
  622. //    SWSetSpriteUnderTiles
  623. ///--------------------------------------------------------------------------------------
  624.  
  625. SW_FUNC void SWSetSpriteUnderTiles(
  626.     SpritePtr    srcSpriteP,
  627.     Boolean        isUnder)
  628. {
  629.     SWAssert( srcSpriteP != NULL );
  630.  
  631.     srcSpriteP->isUnderTiles = isUnder;
  632.     
  633.         // Redraw sprite over/under tiles
  634.     srcSpriteP->needsToBeDrawn = true;
  635. }
  636.  
  637.  
  638. ///--------------------------------------------------------------------------------------
  639. //    SWSetTileMaskDrawProc
  640. ///--------------------------------------------------------------------------------------
  641.  
  642. SW_FUNC OSErr SWSetTileMaskDrawProc(
  643.     SpriteWorldPtr    spriteWorldP,
  644.     DrawProcPtr        drawProc)
  645. {
  646.     OSErr    err = noErr;
  647.     
  648.     SWAssert( spriteWorldP != NULL && drawProc != NULL );
  649.  
  650.     if (spriteWorldP->pixelDepth != 8)
  651.     {
  652.         if (drawProc == BlitPixie8BitMaskDrawProc || 
  653.             drawProc == BP8BitInterlacedMaskDrawProc ||
  654.             drawProc == BlitPixie8BitPartialMaskDrawProc || 
  655.             drawProc == BP8BitInterlacedPartialMaskDrawProc)
  656.         {
  657.             err = kWrongDepthErr;
  658.         }
  659.     }
  660.  
  661.     if ( err == noErr )
  662.         spriteWorldP->tileMaskDrawProc = drawProc;
  663.     
  664.     SWSetStickyIfError( err );
  665.     return err;
  666. }
  667.  
  668.  
  669. ///--------------------------------------------------------------------------------------
  670. //    SWLoadTileFromCicnResource
  671. ///--------------------------------------------------------------------------------------
  672.  
  673. SW_FUNC OSErr SWLoadTileFromCicnResource(
  674.     SpriteWorldPtr spriteWorldP, 
  675.     short tileID,
  676.     short cicnID, 
  677.     MaskType maskType)
  678. {
  679.     OSErr             err;
  680.     GWorldPtr         saveGWorld;
  681.     GDHandle         saveGDH;
  682.     FramePtr         newFrameP;
  683.     CIconHandle     cIconH;
  684.     Rect            frameRect;
  685.     Boolean            maskIsSolid = false;
  686.     
  687.     SWAssert( spriteWorldP != NULL && spriteWorldP->tilingIsInitialized );
  688.     SWAssert( spriteWorldP->tileWidth <= 32 && spriteWorldP->tileHeight <= 32 );
  689.     
  690.     err = noErr;
  691.     newFrameP = NULL;
  692.  
  693.     if ( !spriteWorldP->tilingIsInitialized )
  694.     {
  695.         err = kTilingNotInitialized;
  696.     }
  697.     else if ( tileID < 0 || tileID >= spriteWorldP->maxNumTiles)
  698.     {
  699.         err = kOutOfRangeErr;
  700.     }
  701.     
  702.     if (maskType == kSolidMask)
  703.     {
  704.         maskIsSolid = true;
  705.         maskType = kNoMask;
  706.     }
  707.     
  708.     if ( err == noErr )
  709.     {    
  710.         err = SWCreateFrameFromCicnResource(spriteWorldP, &newFrameP, cicnID, maskType);
  711.         
  712.         if ( err == noErr )
  713.         {    
  714.             newFrameP->tileMaskIsSolid = maskIsSolid;
  715.             newFrameP->frameRect.right = newFrameP->frameRect.left + spriteWorldP->tileWidth;
  716.             newFrameP->frameRect.bottom = newFrameP->frameRect.top + spriteWorldP->tileHeight;
  717. /*
  718.             cIconH = GetCIcon( cicnID );
  719.  
  720.             if (cIconH != NULL)
  721.             {
  722.                 GetGWorld(&saveGWorld, &saveGDH);
  723.                 
  724.                 HLock((Handle)cIconH);
  725.                 frameRect = ((**cIconH).iconPMap.bounds);
  726.                 (**cIconH).iconPMap.baseAddr = *(**cIconH).iconData;
  727.                 (**cIconH).iconBMap.baseAddr = (Ptr)&((**cIconH).iconMaskData ) +
  728.                     ((**cIconH).iconMask.rowBytes * (frameRect.bottom-frameRect.top));    
  729.                                 
  730.                 (void)LockPixels( GetGWorldPixMap( newFrameP->framePort ) );
  731.                 SetGWorld( newFrameP->framePort, NULL );
  732.                 if ( spriteWorldP->pixelDepth > 1 )
  733.                 {
  734.                     CopyBits( (BitMap*)(&((**cIconH).iconPMap)),
  735.                         (BitMap*)*GetGWorldPixMap( newFrameP->framePort ), 
  736.                         &frameRect, &newFrameP->frameRect, srcCopy, nil);
  737.                 }
  738.                 else
  739.                 {
  740.                     CopyBits( (BitMap*)(&((**cIconH).iconBMap)),
  741.                         (BitMap*)*GetGWorldPixMap( newFrameP->framePort ), 
  742.                         &frameRect,
  743.                         &newFrameP->frameRect, srcCopy, nil);
  744.                 }
  745.                 UnlockPixels( GetGWorldPixMap( newFrameP->framePort ) );
  746.                 DisposeCIcon( cIconH );
  747.                 SetGWorld( saveGWorld, saveGDH );
  748.             }
  749.             else
  750.             {
  751.                 err = MemError();
  752.             }
  753. */
  754.         }
  755.         
  756.         if ( err == noErr )
  757.         {
  758.                 // Are we replacing an old tile?
  759.             if (spriteWorldP->tileFrameArray[tileID] != NULL)
  760.             {
  761.                 SWDisposeTile( spriteWorldP, tileID );
  762.             }
  763.             spriteWorldP->tileFrameArray[tileID] = newFrameP;
  764.         }
  765.     }
  766.     
  767.     if ( err != noErr && newFrameP != NULL )
  768.     {
  769.         SWDisposeFrame(newFrameP);
  770.     }
  771.     
  772.     SWSetStickyIfError(err);
  773.     return err;
  774. }
  775.  
  776.  
  777. ///--------------------------------------------------------------------------------------
  778. //    SWLoadTilesFromPictResource
  779. ///--------------------------------------------------------------------------------------
  780.  
  781. SW_FUNC OSErr SWLoadTilesFromPictResource(
  782.     SpriteWorldPtr spriteWorldP, 
  783.     short startTileID,
  784.     short endTileID, 
  785.     short pictResID, 
  786.     short maskResID,
  787.     MaskType maskType,
  788.     short horizBorderWidth,
  789.     short vertBorderHeight)
  790. {
  791.     OSErr             err;
  792.     short            tileIndex;
  793.     FramePtr         newFrameP;
  794.     GWorldPtr        tempPictGWorldP,
  795.                     tempMaskGWorldP,
  796.                     tempTempMaskGWorldP,
  797.                     currentGWorld;
  798.     GDHandle        currentGDH;
  799.     Rect            currentTileRect;
  800.     short            horizOffset,
  801.                     vertOffset;
  802.     Boolean            allTilesDone,
  803.                     maskIsSolid = false;
  804.     
  805.     SWAssert( spriteWorldP != NULL && spriteWorldP->tilingIsInitialized );
  806.     SWAssert( 0 <= startTileID && startTileID <= endTileID && endTileID < spriteWorldP->maxNumTiles );
  807.     SWAssert( horizBorderWidth >= 0 && vertBorderHeight >= 0 );
  808.     
  809.     err = noErr;
  810.     newFrameP = NULL;
  811.     tempPictGWorldP = NULL;
  812.     tempMaskGWorldP = NULL;
  813.     
  814.     if ( !spriteWorldP->tilingIsInitialized )
  815.     {
  816.         err = kTilingNotInitialized;
  817.     }
  818.     else if ( startTileID < 0 || endTileID >= spriteWorldP->maxNumTiles)
  819.     {
  820.         err = kOutOfRangeErr;
  821.     }
  822.     
  823.     if (maskType == kSolidMask)
  824.     {
  825.         maskIsSolid = true;
  826.         maskType = kNoMask;
  827.     }
  828.     
  829.     if ( err == noErr )
  830.     {    
  831.         err = SWCreateGWorldFromPictResource( spriteWorldP, &tempPictGWorldP, pictResID );
  832.         
  833.         if ( err == noErr && maskType != kNoMask )
  834.             err = SWCreateGWorldFromPictResource( spriteWorldP, &tempMaskGWorldP, maskResID );
  835.         
  836.         if (err == noErr)
  837.         {
  838.             if ( pictResID == maskResID && tempMaskGWorldP != NULL )
  839.             {
  840.                 err = SWBlackenGWorld( tempMaskGWorldP );
  841.             }
  842.         }
  843.     
  844.         if ( err == noErr )
  845.         {
  846.             err = SWCreateFrameFromGWorldAndRectStart( &tempTempMaskGWorldP, spriteWorldP->tileWidth, spriteWorldP->tileHeight );
  847.         }
  848.         if ( err == noErr )
  849.         {
  850.             SetRect( ¤tTileRect, 0,  0, 
  851.                 spriteWorldP->tileWidth, spriteWorldP->tileHeight );
  852.             tileIndex = startTileID;
  853.             horizOffset = spriteWorldP->tileWidth + horizBorderWidth;
  854.             vertOffset = spriteWorldP->tileHeight + vertBorderHeight;
  855.             
  856.             allTilesDone = false;
  857.             while( !allTilesDone && err == noErr )
  858.             {
  859.                 err = SWCreateFrameFromGWorldAndRectPartial( &newFrameP, tempPictGWorldP, 
  860.                         tempMaskGWorldP, tempTempMaskGWorldP, ¤tTileRect, maskType);
  861.                 
  862.                 if ( newFrameP != NULL && err == noErr )
  863.                 {
  864.                     newFrameP->tileMaskIsSolid = maskIsSolid;
  865.                     
  866.                         // Are we replacing an old tile?
  867.                     if (spriteWorldP->tileFrameArray[tileIndex] != NULL)
  868.                     {
  869.                         SWDisposeTile( spriteWorldP, tileIndex );
  870.                     }
  871.                     spriteWorldP->tileFrameArray[tileIndex] = newFrameP;
  872.                     
  873.                     tileIndex++;
  874.                     if (tileIndex > endTileID )
  875.                     {
  876.                         allTilesDone = true;
  877.                     }
  878.                     else
  879.                     {
  880.                         if (tileIndex >= spriteWorldP->maxNumTiles)
  881.                         {
  882.                             err = kOutOfRangeErr;
  883.                         }
  884.                         currentTileRect.left += horizOffset;
  885.                         currentTileRect.right += horizOffset;
  886.                         if ( currentTileRect.right > tempPictGWorldP->portRect.right )
  887.                         {
  888.                             currentTileRect.left = 0;
  889.                             currentTileRect.right = spriteWorldP->tileWidth;
  890.                             currentTileRect.top += vertOffset;
  891.                             currentTileRect.bottom += vertOffset;
  892.                             if ( currentTileRect.bottom > tempPictGWorldP->portRect.bottom )
  893.                             {
  894.                                 err = kOutOfRangeErr;
  895.                             }
  896.                         }
  897.                     }
  898.                 }
  899.             }
  900.             
  901.             if (err == noErr)
  902.             {
  903.                     // make a pixel mask
  904.                 if ((maskType & kPixelMask) != 0)
  905.                 {
  906.                     GetGWorld( ¤tGWorld, ¤tGDH );
  907.                     (void)LockPixels( GetGWorldPixMap(tempMaskGWorldP) );
  908.                     SetGWorld(tempMaskGWorldP, nil);
  909.                     InvertRect(&tempMaskGWorldP->portRect);
  910.                     SetGWorld( currentGWorld, currentGDH );
  911.                     UnlockPixels( GetGWorldPixMap(tempMaskGWorldP) );
  912.                 }
  913.                     // If no pixel Mask wanted, dispose
  914.                     // of the GWorld we used to make region
  915.                 else
  916.                 {
  917.                     DisposeGWorld( tempMaskGWorldP );
  918.                 }
  919.             }
  920.         }
  921.         SWCreateFrameFromGWorldAndRectFinish( tempTempMaskGWorldP );
  922.     }
  923.     
  924.     SWSetStickyIfError(err);
  925.     return err;
  926. }
  927.  
  928.  
  929. ///--------------------------------------------------------------------------------------
  930. //    SWDisposeTile
  931. ///--------------------------------------------------------------------------------------
  932.  
  933. SW_FUNC void SWDisposeTile(
  934.     SpriteWorldPtr    spriteWorldP,
  935.     short tileID)
  936. {
  937.     short        tileIndex;
  938.     Boolean        gWorldStillInUse;
  939.     
  940.     SWAssert( spriteWorldP != NULL && spriteWorldP->tilingIsInitialized );
  941.     
  942.         // see if any other tile is using this tile's GWorld
  943.     gWorldStillInUse = false;
  944.     tileIndex = spriteWorldP->maxNumTiles;
  945.     while ( tileIndex-- )
  946.     {
  947.         if ( tileIndex != tileID )
  948.         {
  949.             if ( spriteWorldP->tileFrameArray[tileIndex] != NULL &&
  950.                 ((spriteWorldP->tileFrameArray[tileIndex])->framePort == 
  951.                 (spriteWorldP->tileFrameArray[tileID])->framePort) )
  952.             {
  953.                 gWorldStillInUse = true;
  954.             }
  955.         }
  956.     }
  957.         // set flag that tells SWDisposeFrame whether to dispose of GWorld
  958.     (spriteWorldP->tileFrameArray[tileID])->sharesGWorld = gWorldStillInUse;
  959.     
  960.     (void)SWDisposeFrame( spriteWorldP->tileFrameArray[tileID] );
  961. }
  962.  
  963.  
  964. ///--------------------------------------------------------------------------------------
  965. //    SWDrawTilesInBackground
  966. ///--------------------------------------------------------------------------------------
  967.  
  968. SW_FUNC OSErr SWDrawTilesInBackground(
  969.     SpriteWorldPtr spriteWorldP)
  970. {
  971.     GWorldPtr        holdGWorld;
  972.     GDHandle        holdGDH;
  973.     OSErr            err = noErr;
  974.     
  975.     SWAssert( spriteWorldP != NULL && spriteWorldP->tilingIsInitialized );
  976.  
  977.     GetGWorld( &holdGWorld, &holdGDH );
  978.     
  979.     if (spriteWorldP->tileMap == NULL)
  980.     {
  981.         err = kNullTileMapErr;
  982.     }
  983.     else if ( !spriteWorldP->tilingIsInitialized )
  984.     {
  985.         err = kTilingNotInitialized;
  986.     }
  987.     else
  988.     {
  989.         SWDrawTilesInRect(spriteWorldP, &spriteWorldP->visScrollRect, true);
  990.     }
  991.     
  992.     SetGWorld( holdGWorld, holdGDH );
  993.     SWSetStickyIfError(err);
  994.     return err;
  995. }
  996.  
  997.  
  998. ///--------------------------------------------------------------------------------------
  999. //    SWResetTilingCache
  1000. ///--------------------------------------------------------------------------------------
  1001.  
  1002. SW_FUNC void SWResetTilingCache(SpriteWorldPtr spriteWorldP)
  1003. {
  1004.     short    row, col;
  1005.     
  1006.     SWAssert( spriteWorldP != NULL && spriteWorldP->tilingIsInitialized );
  1007.  
  1008.         // Set all elements to -1 (indicating that each tile needs to be drawn)
  1009.     for (row = 0; row < spriteWorldP->numOffscreenTileMapRows; row++)
  1010.     {
  1011.         for (col = 0; col < spriteWorldP->numOffscreenTileMapCols; col++)
  1012.         {
  1013.             spriteWorldP->offscreenTileMap[(long)row * 
  1014.                 spriteWorldP->numOffscreenTileMapCols + col] = -1;
  1015.         }
  1016.     }
  1017. }
  1018.  
  1019. #define SW_DEBUG_DDCHANGERECT 0
  1020.  
  1021. #if SW_DEBUG_DDCHANGERECT
  1022. static RgnHandle DebugGetChangedRgn( SpriteWorldPtr spriteWorldP, Rect *addRectP )
  1023. {
  1024.     RgnHandle resultRgn;
  1025.     RgnHandle tempRgn;
  1026.     short index;
  1027.     
  1028.     resultRgn = NewRgn();
  1029.     tempRgn = NewRgn();
  1030.     for ( index = 0; index < spriteWorldP->numTilesChanged; index++ ) {
  1031.         RectRgn( tempRgn, &spriteWorldP->changedTiles[index] );
  1032.         UnionRgn( resultRgn, tempRgn, resultRgn );
  1033.     }
  1034.     if ( addRectP ) {
  1035.         RectRgn( tempRgn, addRectP );
  1036.         UnionRgn( resultRgn, tempRgn, resultRgn );
  1037.     }
  1038.     DisposeRgn( tempRgn );
  1039.     return resultRgn;
  1040. }
  1041.  
  1042. static DebugValidateChangeRgn( SpriteWorldPtr spriteWorldP, RgnHandle expected )
  1043. {
  1044.     RgnHandle after;
  1045.     
  1046.     after = DebugGetChangedRgn( spriteWorldP, NULL );
  1047.     SWAssert( EqualRgn( expected, after ) );
  1048.     DisposeRgn( expected );
  1049.     DisposeRgn( after );
  1050. }
  1051. #else
  1052.  
  1053. #define DebugGetChangedRgn( x ) NULL
  1054. #define DebugValidateChangeRgn( x, y )
  1055.  
  1056. #endif
  1057.  
  1058. static void SWAddChangeRect(SpriteWorldPtr spriteWorldP, Rect *changedRectP )
  1059. {
  1060.     short index;
  1061.     Rect *changedTileP;
  1062. #if SW_DEBUG_DDCHANGERECT
  1063.     RgnHandle before;
  1064. #endif
  1065.     
  1066.  
  1067.     SWAssert( spriteWorldP != NULL && spriteWorldP->changedTiles != NULL && changedRectP != NULL );
  1068.  
  1069. #if SW_DEBUG_DDCHANGERECT
  1070.     before = DebugGetChangedRgn( spriteWorldP, changedRectP );
  1071. #endif
  1072.  
  1073.     if ( changedRectP->left >= changedRectP->right || changedRectP->top >= changedRectP->bottom ) {
  1074.         DebugValidateChangeRgn( spriteWorldP, before );
  1075.         return; // empty changedRectP
  1076.     }
  1077.     
  1078.     changedTileP = spriteWorldP->changedTiles;
  1079.     for ( index = 0; index < spriteWorldP->numTilesChanged; index++, changedTileP++) {
  1080.         // check for changedRectP entirely contained inside changedTileP
  1081.         if ( changedTileP->left <= changedRectP->left && changedTileP->top <= changedRectP->top && 
  1082.                 changedTileP->right >= changedRectP->right && changedTileP->bottom >= changedRectP->bottom ) {
  1083.             DebugValidateChangeRgn( spriteWorldP, before );
  1084.             return;
  1085.         }
  1086.  
  1087.         // check for changedRectP entirely contained by changedTileP
  1088.         if ( changedTileP->left >= changedRectP->left && changedTileP->top >= changedRectP->top && 
  1089.                 changedTileP->right <= changedRectP->right && changedTileP->bottom <= changedRectP->bottom ) {
  1090.             *changedTileP = *changedRectP;
  1091.             DebugValidateChangeRgn( spriteWorldP, before );
  1092.             return;
  1093.         }
  1094.     }
  1095.     
  1096.     changedTileP = spriteWorldP->changedTiles;
  1097.     for ( index = 0; index < spriteWorldP->numTilesChanged; index++, changedTileP++) {
  1098.         // check for changedRectP vertically adjacent to changedTileP
  1099.         if ( changedTileP->left == changedRectP->left && changedTileP->right == changedRectP->right ) {
  1100.             if ( changedTileP->top <= changedRectP->bottom && changedRectP->bottom <= changedTileP->bottom ||
  1101.                     changedRectP->top <= changedTileP->bottom && changedTileP->bottom <= changedRectP->bottom ) {
  1102.                 changedTileP->top = SW_MIN( changedTileP->top, changedRectP->top );
  1103.                 changedTileP->bottom = SW_MAX( changedTileP->bottom, changedRectP->bottom );
  1104.                 DebugValidateChangeRgn( spriteWorldP, before );
  1105.                 return;
  1106.             }
  1107.         }
  1108.  
  1109.         // check for changedRectP horizontally adjacent to changedTileP
  1110.         if ( changedTileP->top == changedRectP->top && changedTileP->bottom == changedRectP->bottom ) {
  1111.             if ( changedTileP->left <= changedRectP->right && changedRectP->right <= changedTileP->right ||
  1112.                     changedRectP->left <= changedTileP->right && changedTileP->right <= changedRectP->right ) {
  1113.                 changedTileP->left = SW_MIN( changedTileP->left, changedRectP->left );
  1114.                 changedTileP->right = SW_MAX( changedTileP->right, changedRectP->right );
  1115.                 DebugValidateChangeRgn( spriteWorldP, before );
  1116.                 return;
  1117.             }
  1118.         }
  1119.     }
  1120.     
  1121.     SWAssert( spriteWorldP->numTilesChanged + 1 < (spriteWorldP->numOffscreenTileMapRows+1) * (spriteWorldP->numOffscreenTileMapCols+1) );
  1122.     spriteWorldP->changedTiles[spriteWorldP->numTilesChanged++] = *changedRectP;
  1123.     DebugValidateChangeRgn( spriteWorldP, before );
  1124. }
  1125.  
  1126. /*
  1127. static void SWDrawTileFrame( 
  1128.     SpriteWorldPtr spriteWorldP, 
  1129.     FramePtr tileFrameP,
  1130.     FramePtr dstFrameP,
  1131.     Rect *srcRectP,
  1132.     Rect *dstRectP )
  1133. {
  1134.         if (tileFrameP->tileMaskIsSolid)
  1135.         {
  1136.                 // Draw the tile without using a mask
  1137.             (*spriteWorldP->offscreenDrawProc)(tileFrameP, dstFrameP, srcRectP, dstRectP );
  1138.         }
  1139.         else
  1140.         {
  1141.                 // Draw the masked part of the tile
  1142.             (*spriteWorldP->tileMaskDrawProc)(tileFrameP, dstFrameP, srcRectP, dstRectP );
  1143.         }
  1144. }
  1145. */
  1146.  
  1147. ///--------------------------------------------------------------------------------------
  1148. //    SWDrawTile - sets value in tileMap and draws tile if visible in visScrollRect.
  1149. ///--------------------------------------------------------------------------------------
  1150.  
  1151. SW_FUNC void SWDrawTile(
  1152.     SpriteWorldPtr spriteWorldP,
  1153.     short tileRow,
  1154.     short tileCol,
  1155.     short tileID)
  1156. {
  1157.     short        row, col, offscreenTileRow, offscreenTileCol;
  1158.     Rect*        visScrollRectP = &spriteWorldP->visScrollRect;
  1159.     Rect*        backRectP = &spriteWorldP->backRect;
  1160.     Rect        srcRect, dstRect;
  1161.     FramePtr    tileFrameP;
  1162.     Boolean        tileClipped;
  1163.     
  1164.     SWAssert( spriteWorldP != NULL && spriteWorldP->tilingIsInitialized );
  1165.     SWAssert( 0 <= tileRow && tileRow < spriteWorldP->numTileMapRows );
  1166.     SWAssert( 0 <= tileCol && tileCol < spriteWorldP->numTileMapCols );
  1167.     SWAssert( 0 <= tileID && tileID < spriteWorldP->maxNumTiles );
  1168.     
  1169.         // Set value in tileMap and get tileFrameP
  1170.     spriteWorldP->tileMap[tileRow][tileCol] = tileID;
  1171.     tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  1172.     
  1173.     row = tileRow * spriteWorldP->tileHeight;
  1174.     col = tileCol * spriteWorldP->tileWidth;
  1175.     
  1176.     srcRect = tileFrameP->frameRect;
  1177.     dstRect.bottom = row + spriteWorldP->tileHeight;
  1178.     dstRect.right = col + spriteWorldP->tileWidth;
  1179.     
  1180.     
  1181.         // Clip tile with visScrollRect
  1182.     tileClipped = false;
  1183.     if (row < visScrollRectP->top)
  1184.     {
  1185.         dstRect.top = visScrollRectP->top;
  1186.         srcRect.top += visScrollRectP->top - row;
  1187.         tileClipped = true;
  1188.     }
  1189.     else
  1190.         dstRect.top = row;
  1191.     
  1192.     if (col < visScrollRectP->left)
  1193.     {
  1194.         dstRect.left = visScrollRectP->left;
  1195.         srcRect.left += visScrollRectP->left - col;
  1196.         tileClipped = true;
  1197.     }
  1198.     else
  1199.         dstRect.left = col;
  1200.     
  1201.     
  1202.     if (dstRect.bottom > visScrollRectP->bottom)
  1203.     {
  1204.         srcRect.bottom -= dstRect.bottom - visScrollRectP->bottom;
  1205.         dstRect.bottom = visScrollRectP->bottom;
  1206.         tileClipped = true;
  1207.     }
  1208.     
  1209.     if (dstRect.right > visScrollRectP->right)
  1210.     {
  1211.         srcRect.right -= dstRect.right - visScrollRectP->right;
  1212.         dstRect.right = visScrollRectP->right;
  1213.         tileClipped = true;
  1214.     }
  1215.  
  1216.         // Draw tile if visible on screen (in visScrollRect)
  1217.     if (dstRect.left < dstRect.right && dstRect.top < dstRect.bottom)
  1218.     {
  1219.             // Save rect as having been changed
  1220.         SWAddChangeRect( spriteWorldP, &dstRect );
  1221.         
  1222.             // Make the tile's dest rect local to the offscreen area
  1223.         dstRect.top -= spriteWorldP->vertScrollRectOffset;
  1224.         dstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  1225.         dstRect.left -= spriteWorldP->horizScrollRectOffset;
  1226.         dstRect.right -= spriteWorldP->horizScrollRectOffset;
  1227.         
  1228.         
  1229.             // Wrap tile to top or bottom of offscreen area
  1230.         if (dstRect.bottom > backRectP->bottom)
  1231.         {
  1232.             dstRect.top -= backRectP->bottom;
  1233.             dstRect.bottom -= backRectP->bottom;
  1234.         }
  1235.         else if (dstRect.top < backRectP->top)
  1236.         {
  1237.             dstRect.top += backRectP->bottom;
  1238.             dstRect.bottom += backRectP->bottom;
  1239.         }
  1240.         
  1241.             // Wrap tile to left or right side of offscreen area
  1242.         if (dstRect.right > backRectP->right)
  1243.         {
  1244.             dstRect.left -= backRectP->right;
  1245.             dstRect.right -= backRectP->right;
  1246.         }
  1247.         else if (dstRect.left < backRectP->left)
  1248.         {
  1249.             dstRect.left += backRectP->right;
  1250.             dstRect.right += backRectP->right;
  1251.         }
  1252.         
  1253.         
  1254.             // Draw tile in the background frame
  1255.         SetGWorld(spriteWorldP->backFrameP->framePort, nil);
  1256.         
  1257. //        SWDrawTileFrame( spriteWorldP, tileFrameP, spriteWorldP->backFrameP, &srcRect, &dstRect);
  1258.         (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  1259.                 spriteWorldP->backFrameP, &srcRect, &dstRect);
  1260.         
  1261.         
  1262.             // Copy tile to the work area
  1263.         SetGWorld(spriteWorldP->workFrameP->framePort, nil);
  1264.         (*spriteWorldP->offscreenDrawProc)(spriteWorldP->backFrameP, 
  1265.                 spriteWorldP->workFrameP, &dstRect, &dstRect);
  1266.         
  1267.         
  1268.         offscreenTileRow = dstRect.top / spriteWorldP->tileHeight;
  1269.         offscreenTileCol = dstRect.left / spriteWorldP->tileWidth;
  1270.         
  1271.             // Set new tile value in offscreenTileMap
  1272.         if (tileClipped)
  1273.         {
  1274.             spriteWorldP->offscreenTileMap[(long)offscreenTileRow * 
  1275.                 spriteWorldP->numOffscreenTileMapCols + offscreenTileCol] = -1;
  1276.         }
  1277.         else
  1278.         {
  1279.             spriteWorldP->offscreenTileMap[(long)offscreenTileRow * 
  1280.                 spriteWorldP->numOffscreenTileMapCols + offscreenTileCol] = 
  1281.                 spriteWorldP->curTileImage[tileID];
  1282.         }
  1283.     }
  1284. }
  1285.  
  1286.  
  1287. ///--------------------------------------------------------------------------------------
  1288. //    SWSetTileChangeProc
  1289. ///--------------------------------------------------------------------------------------
  1290.  
  1291. SW_FUNC void SWSetTileChangeProc(
  1292.     SpriteWorldPtr spriteWorldP,
  1293.     TileChangeProcPtr tileChangeProc)
  1294. {
  1295.     SWAssert( spriteWorldP != NULL && spriteWorldP->tilingIsInitialized && tileChangeProc != NULL );
  1296.     
  1297.     spriteWorldP->tileChangeProc = tileChangeProc;
  1298. }
  1299.  
  1300.  
  1301. ///--------------------------------------------------------------------------------------
  1302. //    SWChangeTileImage
  1303. ///--------------------------------------------------------------------------------------
  1304.  
  1305. SW_FUNC void SWChangeTileImage(
  1306.     SpriteWorldPtr spriteWorldP,
  1307.     short tileID,
  1308.     short newImage)
  1309. {
  1310.     SWAssert( spriteWorldP != NULL && spriteWorldP->tilingIsInitialized );
  1311.     SWAssert( 0 <= tileID && tileID < spriteWorldP->maxNumTiles );
  1312.     SWAssert( 0 <= newImage && newImage < spriteWorldP->maxNumTiles );
  1313.  
  1314.         // Set the current image
  1315.     spriteWorldP->curTileImage[tileID] = newImage;
  1316.     
  1317.         // Update the tile image on screen
  1318.     SWUpdateTileOnScreen(spriteWorldP, tileID);
  1319. }
  1320.  
  1321.  
  1322. ///--------------------------------------------------------------------------------------
  1323. //    SWUpdateTileOnScreen - render new tile image in offscreen areas
  1324. ///--------------------------------------------------------------------------------------
  1325.  
  1326. SW_FUNC void SWUpdateTileOnScreen(
  1327.     SpriteWorldPtr spriteWorldP,
  1328.     short tileID)
  1329. {
  1330.     short        tileRow, tileCol;
  1331.     short        startRow, startCol, stopRow, stopCol;
  1332.     short        tileWidth = spriteWorldP->tileWidth;
  1333.     short        tileHeight = spriteWorldP->tileHeight;
  1334.     
  1335.     SWAssert( spriteWorldP != NULL && spriteWorldP->tilingIsInitialized );
  1336.     SWAssert( 0 <= tileID && tileID < spriteWorldP->maxNumTiles );
  1337.     
  1338.         // Convert pixel row and col into tile row and col
  1339.     startRow = spriteWorldP->visScrollRect.top / tileHeight;
  1340.     startCol = spriteWorldP->visScrollRect.left / tileWidth;
  1341.     stopRow = (spriteWorldP->visScrollRect.bottom-1) / tileHeight;
  1342.     stopCol = (spriteWorldP->visScrollRect.right-1) / tileWidth;
  1343.     
  1344.     
  1345.     for (tileRow = startRow; tileRow <= stopRow; tileRow++)
  1346.     {
  1347.         for (tileCol = startCol; tileCol <= stopCol; tileCol++)
  1348.         {
  1349.             if (tileID == spriteWorldP->tileMap[tileRow][tileCol])
  1350.             {
  1351.                 SWDrawTile(spriteWorldP, tileRow, tileCol, tileID);
  1352.             }
  1353.         }
  1354.     }
  1355. }
  1356.  
  1357.  
  1358. ///--------------------------------------------------------------------------------------
  1359. //    SWResetCurrentTileImages
  1360. ///--------------------------------------------------------------------------------------
  1361.  
  1362. SW_FUNC void SWResetCurrentTileImages(
  1363.     SpriteWorldPtr spriteWorldP)
  1364. {
  1365.     short    tileIndex;
  1366.     
  1367.     SWAssert( spriteWorldP != NULL && spriteWorldP->tilingIsInitialized );
  1368.  
  1369.     if (spriteWorldP->tilingIsInitialized)
  1370.     {
  1371.         for (tileIndex = 0; tileIndex < spriteWorldP->maxNumTiles; tileIndex++)
  1372.             spriteWorldP->curTileImage[tileIndex] = tileIndex;
  1373.     }
  1374. }
  1375.  
  1376.  
  1377. ///--------------------------------------------------------------------------------------
  1378. //    SWDrawTilesInRect - draw tiles in updateRect of backFrame
  1379. ///--------------------------------------------------------------------------------------
  1380.  
  1381. SW_FUNC void SWDrawTilesInRect(
  1382.     SpriteWorldPtr spriteWorldP,
  1383.     Rect* updateRectP,
  1384.     Boolean optimizingOn)
  1385. {
  1386.     short        row, col, tileRow, tileCol, tileID;
  1387.     short        startRow, startCol, stopRow, stopCol;
  1388.     short        offscreenTileRow, offscreenTileCol;
  1389.     Rect        srcRect, dstRect;
  1390.     FramePtr    tileFrameP;
  1391.     Boolean        tileClipped;
  1392.     Rect*        visScrollRectP = &spriteWorldP->visScrollRect;
  1393.     Rect*        backRectP = &spriteWorldP->backRect;
  1394.     Rect        updateRect = *updateRectP;
  1395.     short        tileWidth = spriteWorldP->tileWidth;
  1396.     short        tileHeight = spriteWorldP->tileHeight;
  1397.     
  1398.     SWAssert( spriteWorldP != NULL && spriteWorldP->tilingIsInitialized && spriteWorldP->tileMap != NULL && updateRectP != NULL );
  1399.  
  1400.     SetGWorld(spriteWorldP->backFrameP->framePort, nil);
  1401.     
  1402.         // Convert pixel row and col into tile row and col
  1403.     startRow = updateRect.top / tileHeight;
  1404.     startCol = updateRect.left / tileWidth;
  1405.     stopRow = (updateRect.bottom-1) / tileHeight;
  1406.     stopCol = (updateRect.right-1) / tileWidth;
  1407.     
  1408.     SWAssert( 0 <= startRow && startRow <= spriteWorldP->numTileMapRows );
  1409.     SWAssert( 0 <= startCol && startCol <= spriteWorldP->numTileMapCols );
  1410.     SWAssert( 0 <= stopRow && stopRow <= spriteWorldP->numTileMapRows );
  1411.     SWAssert( 0 <= stopCol && stopCol <= spriteWorldP->numTileMapCols );
  1412.     
  1413.     for (tileRow = startRow; tileRow <= stopRow; tileRow++)
  1414.     {
  1415.         row = tileRow * tileHeight;
  1416.         
  1417.         for (tileCol = startCol; tileCol <= stopCol; tileCol++)
  1418.         {
  1419.             col = tileCol * tileWidth;
  1420.             
  1421.             tileID = spriteWorldP->tileMap[tileRow][tileCol];
  1422.             tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  1423.             
  1424.             srcRect = tileFrameP->frameRect;
  1425.             dstRect.bottom = row + tileHeight;
  1426.             dstRect.right = col + tileWidth;
  1427.             
  1428.             
  1429.                 // Is tile completely visible on screen?
  1430.             if (row >= visScrollRectP->top && col >= visScrollRectP->left &&
  1431.                 dstRect.bottom <= visScrollRectP->bottom && 
  1432.                 dstRect.right <= visScrollRectP->right)
  1433.             {
  1434.                 tileClipped = false;
  1435.             }
  1436.             else
  1437.             {
  1438.                 tileClipped = true;
  1439.             }
  1440.             
  1441.             
  1442.                 
  1443.                 // Clip tile dstRect with updateRect //
  1444.             if (row < updateRect.top)
  1445.             {
  1446.                 dstRect.top = updateRect.top;
  1447.                 srcRect.top += updateRect.top - row;
  1448.             }
  1449.             else
  1450.                 dstRect.top = row;
  1451.             
  1452.             if (col < updateRect.left)
  1453.             {
  1454.                 dstRect.left = updateRect.left;
  1455.                 srcRect.left += updateRect.left - col;
  1456.             }
  1457.             else
  1458.                 dstRect.left = col;
  1459.             
  1460.             
  1461.             if (dstRect.bottom > updateRect.bottom)
  1462.             {
  1463.                 srcRect.bottom -= dstRect.bottom - updateRect.bottom;
  1464.                 dstRect.bottom = updateRect.bottom;
  1465.             }
  1466.             
  1467.             if (dstRect.right > updateRect.right)
  1468.             {
  1469.                 srcRect.right -= dstRect.right - updateRect.right;
  1470.                 dstRect.right = updateRect.right;
  1471.             }
  1472.     
  1473.  
  1474.             
  1475.                 // Make the tile's dest rect local to the offscreen area
  1476.             dstRect.top -= spriteWorldP->vertScrollRectOffset;
  1477.             dstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  1478.             dstRect.left -= spriteWorldP->horizScrollRectOffset;
  1479.             dstRect.right -= spriteWorldP->horizScrollRectOffset;
  1480.             
  1481.                 // Wrap tile to top or bottom of offscreen area
  1482.             if (dstRect.bottom > backRectP->bottom)
  1483.             {
  1484.                 dstRect.top -= backRectP->bottom;
  1485.                 dstRect.bottom -= backRectP->bottom;
  1486.             }
  1487.             else if (dstRect.top < backRectP->top)
  1488.             {
  1489.                 dstRect.top += backRectP->bottom;
  1490.                 dstRect.bottom += backRectP->bottom;
  1491.             }
  1492.             
  1493.                 // Wrap tile to left or right side of offscreen area
  1494.             if (dstRect.right > backRectP->right)
  1495.             {
  1496.                 dstRect.left -= backRectP->right;
  1497.                 dstRect.right -= backRectP->right;
  1498.             }
  1499.             else if (dstRect.left < backRectP->left)
  1500.             {
  1501.                 dstRect.left += backRectP->right;
  1502.                 dstRect.right += backRectP->right;
  1503.             }
  1504.             
  1505.             offscreenTileRow = dstRect.top / tileHeight;
  1506.             offscreenTileCol = dstRect.left / tileWidth;
  1507.             
  1508.             
  1509.                 // Save time by not drawing tile if already the same
  1510.             if (spriteWorldP->offscreenTileMap[(long)offscreenTileRow * 
  1511.                 spriteWorldP->numOffscreenTileMapCols + offscreenTileCol] != 
  1512.                 spriteWorldP->curTileImage[tileID] || !optimizingOn)
  1513.             {    
  1514.                     // Draw the tile
  1515. //                SWDrawTileFrame( spriteWorldP, tileFrameP, spriteWorldP->backFrameP, &srcRect, &dstRect);
  1516.                 (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  1517.                         spriteWorldP->backFrameP, &srcRect, &dstRect);
  1518.                 
  1519.                     // Set new tile value in offscreenTileMap
  1520.                 if (tileClipped)
  1521.                 {
  1522.                     spriteWorldP->offscreenTileMap[(long)offscreenTileRow * 
  1523.                         spriteWorldP->numOffscreenTileMapCols + offscreenTileCol] = -1;
  1524.                 }
  1525.                 else
  1526.                 {
  1527.                     spriteWorldP->offscreenTileMap[(long)offscreenTileRow * 
  1528.                         spriteWorldP->numOffscreenTileMapCols + offscreenTileCol] = 
  1529.                         spriteWorldP->curTileImage[tileID];
  1530.                 }
  1531.             }
  1532.         }
  1533.     }
  1534. }
  1535.  
  1536.  
  1537. ///--------------------------------------------------------------------------------------
  1538. //    SWDrawTilesAboveSprite - draw tiles over sprite using the tiles' masks.
  1539. //    Assumes that updateRect fits within the bounds of the tileMap.
  1540. ///--------------------------------------------------------------------------------------
  1541.  
  1542. SW_FUNC void SWDrawTilesAboveSprite(
  1543.     SpriteWorldPtr spriteWorldP,
  1544.     Rect* updateRectP)
  1545. {
  1546.     Rect*        backRectP = &spriteWorldP->backRect;
  1547.     Rect        updateRect = *updateRectP;
  1548.     short        tileWidth = spriteWorldP->tileWidth;
  1549.     short        tileHeight = spriteWorldP->tileHeight;
  1550.     short        row, col, tileRow, tileCol, tileID;
  1551.     short        startRow, startCol, stopRow, stopCol;
  1552.     Rect        srcRect, dstRect;
  1553.     FramePtr    tileFrameP;
  1554.  
  1555.     SWAssert( spriteWorldP != NULL && spriteWorldP->tilingIsInitialized && updateRectP != NULL );
  1556.     
  1557.         // Convert pixel row and col into tile row and col
  1558.     startRow = updateRect.top / tileHeight;
  1559.     startCol = updateRect.left / tileWidth;
  1560.     stopRow = (updateRect.bottom-1) / tileHeight;
  1561.     stopCol = (updateRect.right-1) / tileWidth;
  1562.     
  1563.     
  1564.     for (tileRow = startRow; tileRow <= stopRow; tileRow++)
  1565.     {
  1566.         row = tileRow * tileHeight;
  1567.         
  1568.         for (tileCol = startCol; tileCol <= stopCol; tileCol++)
  1569.         {
  1570.             col = tileCol * tileWidth;
  1571.             
  1572.             tileID = spriteWorldP->tileMap[tileRow][tileCol];
  1573.             tileFrameP = spriteWorldP->tileFrameArray[spriteWorldP->curTileImage[tileID]];
  1574.             
  1575.                 // Skip tiles that have no mask, and therefore aren't above the sprites
  1576.             if (tileFrameP->maskPort == NULL && tileFrameP->maskRgn == NULL &&
  1577.                 tileFrameP->tileMaskIsSolid == false)
  1578.             {
  1579.                 continue;
  1580.             }
  1581.             
  1582.             srcRect = tileFrameP->frameRect;
  1583.             dstRect.bottom = row + tileHeight;
  1584.             dstRect.right = col + tileWidth;
  1585.             
  1586.                 
  1587.                 // Clip tile dstRect with updateRect //
  1588.             if (row < updateRect.top)
  1589.             {
  1590.                 dstRect.top = updateRect.top;
  1591.                 srcRect.top += updateRect.top - row;
  1592.             }
  1593.             else
  1594.                 dstRect.top = row;
  1595.             
  1596.             if (col < updateRect.left)
  1597.             {
  1598.                 dstRect.left = updateRect.left;
  1599.                 srcRect.left += updateRect.left - col;
  1600.             }
  1601.             else
  1602.                 dstRect.left = col;
  1603.             
  1604.             
  1605.             if (dstRect.bottom > updateRect.bottom)
  1606.             {
  1607.                 srcRect.bottom -= dstRect.bottom - updateRect.bottom;
  1608.                 dstRect.bottom = updateRect.bottom;
  1609.             }
  1610.             
  1611.             if (dstRect.right > updateRect.right)
  1612.             {
  1613.                 srcRect.right -= dstRect.right - updateRect.right;
  1614.                 dstRect.right = updateRect.right;
  1615.             }
  1616.     
  1617.  
  1618.             
  1619.                 // Make the tile's dest rect local to the offscreen area
  1620.             dstRect.top -= spriteWorldP->vertScrollRectOffset;
  1621.             dstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  1622.             dstRect.left -= spriteWorldP->horizScrollRectOffset;
  1623.             dstRect.right -= spriteWorldP->horizScrollRectOffset;
  1624.             
  1625.                 // Wrap tile to top or bottom of offscreen area
  1626.             if (dstRect.bottom > backRectP->bottom)
  1627.             {
  1628.                 dstRect.top -= backRectP->bottom;
  1629.                 dstRect.bottom -= backRectP->bottom;
  1630.             }
  1631.             else if (dstRect.top < backRectP->top)
  1632.             {
  1633.                 dstRect.top += backRectP->bottom;
  1634.                 dstRect.bottom += backRectP->bottom;
  1635.             }
  1636.             
  1637.                 // Wrap tile to left or right side of offscreen area
  1638.             if (dstRect.right > backRectP->right)
  1639.             {
  1640.                 dstRect.left -= backRectP->right;
  1641.                 dstRect.right -= backRectP->right;
  1642.             }
  1643.             else if (dstRect.left < backRectP->left)
  1644.             {
  1645.                 dstRect.left += backRectP->right;
  1646.                 dstRect.right += backRectP->right;
  1647.             }
  1648.             
  1649. //            SWDrawTileFrame( spriteWorldP, tileFrameP, spriteWorldP->workFrameP, &srcRect, &dstRect);
  1650.  
  1651.             if (tileFrameP->tileMaskIsSolid)
  1652.             {
  1653.                     // Draw the tile without using a mask
  1654.                 (*spriteWorldP->offscreenDrawProc)(tileFrameP, 
  1655.                     spriteWorldP->workFrameP, &srcRect, &dstRect);
  1656.             }
  1657.             else
  1658.             {
  1659.                     // Draw the masked part of the tile
  1660.                 (*spriteWorldP->tileMaskDrawProc)(tileFrameP, 
  1661.                         spriteWorldP->workFrameP, &srcRect, &dstRect);
  1662.             }
  1663.         }
  1664.     }
  1665. }
  1666.  
  1667.  
  1668. ///--------------------------------------------------------------------------------------
  1669. //    SWWrapRectToWorkArea
  1670. ///--------------------------------------------------------------------------------------
  1671.  
  1672. SW_FUNC void SWWrapRectToWorkArea(
  1673.     SpriteWorldPtr spriteWorldP,
  1674.     Rect* destRectP)
  1675. {
  1676.     Rect        destRect = *destRectP;
  1677.     Rect        tempDestRect;
  1678.     FramePtr    srcFrameP = spriteWorldP->backFrameP;
  1679.     FramePtr    dstFrameP = spriteWorldP->workFrameP;
  1680.     
  1681.     SWAssert( spriteWorldP != NULL && spriteWorldP->tilingIsInitialized && destRectP != NULL );
  1682.     
  1683.     SetGWorld(spriteWorldP->workFrameP->framePort, nil);
  1684.     
  1685.         // Make destRect local to the offscreen area
  1686.     destRect.top -= spriteWorldP->vertScrollRectOffset;
  1687.     destRect.bottom -= spriteWorldP->vertScrollRectOffset;
  1688.     destRect.left -= spriteWorldP->horizScrollRectOffset;
  1689.     destRect.right -= spriteWorldP->horizScrollRectOffset;
  1690.     
  1691.     
  1692.         // Draw main image
  1693.     (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, &destRect, &destRect);
  1694.     
  1695.     
  1696.         // Wrap to top //
  1697.     if (destRect.bottom > dstFrameP->frameRect.bottom)
  1698.     {
  1699.         tempDestRect.top = destRect.top - dstFrameP->frameRect.bottom;
  1700.         tempDestRect.bottom = destRect.bottom - dstFrameP->frameRect.bottom;
  1701.         tempDestRect.left = destRect.left;
  1702.         tempDestRect.right = destRect.right;
  1703.         
  1704.         (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  1705.             &tempDestRect, &tempDestRect);
  1706.         
  1707.             // Wrap to upper left or right corner //
  1708.         if (destRect.right > dstFrameP->frameRect.right)
  1709.         {
  1710.             tempDestRect.left -= dstFrameP->frameRect.right;
  1711.             tempDestRect.right -= dstFrameP->frameRect.right;
  1712.             
  1713.             (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  1714.                 &tempDestRect, &tempDestRect);
  1715.         }
  1716.         else if (destRect.left < dstFrameP->frameRect.left)
  1717.         {
  1718.             tempDestRect.left += dstFrameP->frameRect.right;
  1719.             tempDestRect.right += dstFrameP->frameRect.right;
  1720.             
  1721.             (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  1722.                 &tempDestRect, &tempDestRect);
  1723.         }
  1724.     }
  1725.     
  1726.             // Wrap to left or right side //
  1727.     if (destRect.right > dstFrameP->frameRect.right)
  1728.     {
  1729.         tempDestRect.top = destRect.top;
  1730.         tempDestRect.bottom = destRect.bottom;
  1731.         tempDestRect.left = destRect.left - dstFrameP->frameRect.right;
  1732.         tempDestRect.right = destRect.right - dstFrameP->frameRect.right;
  1733.         
  1734.         (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  1735.             &tempDestRect, &tempDestRect);
  1736.     }
  1737.     else if (destRect.left < dstFrameP->frameRect.left)
  1738.     {
  1739.         tempDestRect.top = destRect.top;
  1740.         tempDestRect.bottom = destRect.bottom;
  1741.         tempDestRect.left = destRect.left + dstFrameP->frameRect.right;
  1742.         tempDestRect.right = destRect.right + dstFrameP->frameRect.right;
  1743.         
  1744.         (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  1745.             &tempDestRect, &tempDestRect);
  1746.     }
  1747.     
  1748.     
  1749.             // Wrap to bottom //
  1750.     if (destRect.top < dstFrameP->frameRect.top)
  1751.     {
  1752.         tempDestRect.top = destRect.top + dstFrameP->frameRect.bottom;
  1753.         tempDestRect.bottom = destRect.bottom + dstFrameP->frameRect.bottom;
  1754.         tempDestRect.left = destRect.left;
  1755.         tempDestRect.right = destRect.right;
  1756.         
  1757.         (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  1758.             &tempDestRect, &tempDestRect);
  1759.         
  1760.             // Wrap to lower left or right corner //
  1761.         if (destRect.right > dstFrameP->frameRect.right)
  1762.         {
  1763.             tempDestRect.left -= dstFrameP->frameRect.right;
  1764.             tempDestRect.right -= dstFrameP->frameRect.right;
  1765.             
  1766.             (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  1767.                 &tempDestRect, &tempDestRect);
  1768.         }
  1769.         else if (destRect.left < dstFrameP->frameRect.left)
  1770.         {
  1771.             tempDestRect.left += dstFrameP->frameRect.right;
  1772.             tempDestRect.right += dstFrameP->frameRect.right;
  1773.             
  1774.             (*spriteWorldP->offscreenDrawProc)(srcFrameP, dstFrameP, 
  1775.                 &tempDestRect, &tempDestRect);
  1776.         }
  1777.     }
  1778. }
  1779.