home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1999 Spring / macformat-077.iso / Shareware Plus / Development / SpriteWorld 2.2 / SpriteWorld files / Utils / Multi-Screen Scrolling.c < prev    next >
Encoding:
Text File  |  1999-01-12  |  32.4 KB  |  966 lines  |  [TEXT/CWIE]

  1. ///--------------------------------------------------------------------------------------
  2. //    Multi-Screen Scrolling.c
  3. //
  4. //    By Vern Jensen. Created 1/1/97
  5. ///--------------------------------------------------------------------------------------
  6.  
  7.  
  8. #ifndef __SPRITEWORLD__
  9. #include "SpriteWorld.h"
  10. #endif
  11.  
  12. #ifndef __SPRITEWORLDUTILS__
  13. #include "SpriteWorldUtils.h"
  14. #endif
  15.  
  16. #ifndef __SCROLLING__
  17. #include "Scrolling.h"
  18. #endif
  19.  
  20. #ifndef __TILING__
  21. #include "Tiling.h"
  22. #endif
  23.  
  24. #ifndef __MULTISCREENSCROLLING__
  25. #include "Multi-Screen Scrolling.h"
  26. #endif
  27.  
  28.  
  29. extern    SpritePtr        gCurrentSpriteBeingDrawn;
  30.  
  31.  
  32. ///--------------------------------------------------------------------------------------
  33. //    SWSetUpDuplicateSpriteWorld
  34. ///--------------------------------------------------------------------------------------
  35.  
  36. SW_FUNC void SWSetUpDuplicateSpriteWorld(
  37.     SpriteWorldPtr masterSpriteWorldP,
  38.     SpriteWorldPtr duplicateSpriteWorldP)
  39. {
  40.         // Dispose the deadSpriteLayer of the duplicateSpriteWorldP
  41.     SWDisposeSpriteLayer(&duplicateSpriteWorldP->deadSpriteLayerP);
  42.     
  43.         // Share SpriteLayers
  44.     duplicateSpriteWorldP->headSpriteLayerP = masterSpriteWorldP->headSpriteLayerP;
  45.     duplicateSpriteWorldP->tailSpriteLayerP = masterSpriteWorldP->tailSpriteLayerP;
  46.     duplicateSpriteWorldP->deadSpriteLayerP = masterSpriteWorldP->deadSpriteLayerP;
  47.     
  48.         // Copy DrawProc info and scrollRectMoveBounds
  49.     duplicateSpriteWorldP->offscreenDrawProc = masterSpriteWorldP->offscreenDrawProc;
  50.     duplicateSpriteWorldP->screenDrawProc = masterSpriteWorldP->screenDrawProc;
  51.     duplicateSpriteWorldP->doubleRectDrawProc = masterSpriteWorldP->doubleRectDrawProc;
  52.     duplicateSpriteWorldP->scrollRectMoveBounds = masterSpriteWorldP->scrollRectMoveBounds;
  53.     
  54.         // Copy tiling stuff
  55.     duplicateSpriteWorldP->extraBackFrameP = masterSpriteWorldP->extraBackFrameP;
  56.     duplicateSpriteWorldP->tileLayerArray = masterSpriteWorldP->tileLayerArray;
  57.     duplicateSpriteWorldP->lastActiveTileLayer = masterSpriteWorldP->lastActiveTileLayer;
  58.     duplicateSpriteWorldP->tileRectDrawProc = masterSpriteWorldP->tileRectDrawProc;
  59.     duplicateSpriteWorldP->tileFrameArray = masterSpriteWorldP->tileFrameArray;
  60.     duplicateSpriteWorldP->curTileImage = masterSpriteWorldP->curTileImage;
  61.     duplicateSpriteWorldP->maxNumTiles = masterSpriteWorldP->maxNumTiles;
  62.     duplicateSpriteWorldP->tileWidth = masterSpriteWorldP->tileWidth;
  63.     duplicateSpriteWorldP->tileHeight = masterSpriteWorldP->tileHeight;
  64.     duplicateSpriteWorldP->tileMaskDrawProc = masterSpriteWorldP->tileMaskDrawProc;
  65.     duplicateSpriteWorldP->partialMaskDrawProc = masterSpriteWorldP->partialMaskDrawProc;
  66. }
  67.  
  68.  
  69. ///--------------------------------------------------------------------------------------
  70. //    SWDisposeDuplicateSpriteWorld
  71. ///--------------------------------------------------------------------------------------
  72.  
  73. SW_FUNC void SWDisposeDuplicateSpriteWorld(
  74.     SpriteWorldPtr    spriteWorldP)
  75. {
  76.     if (spriteWorldP != NULL)
  77.     {
  78.         SWUnlockSpriteWorld(spriteWorldP);
  79.  
  80.         SWDisposeFrame(&spriteWorldP->backFrameP);
  81.         SWDisposeFrame(&spriteWorldP->workFrameP);
  82.         SWDisposeWindowFrame(&spriteWorldP->windowFrameP);
  83.         
  84.         SWExitTilingForDuplicateSpriteWorld(spriteWorldP);
  85.         SWSyncSpriteWorldToVBL(spriteWorldP, false);
  86.         
  87.         DisposePtr((Ptr)spriteWorldP);
  88.     }
  89. }
  90.  
  91.  
  92. ///--------------------------------------------------------------------------------------
  93. //    SWInitTilingForDuplicateSpriteWorld
  94. ///--------------------------------------------------------------------------------------
  95.  
  96. SW_FUNC OSErr SWInitTilingForDuplicateSpriteWorld(
  97.     SpriteWorldPtr    spriteWorldP,
  98.     short             tileHeight,
  99.     short            tileWidth)
  100. {
  101.     OSErr     err = noErr;
  102.     Size    arraySize;
  103.     short    row, col, numTilingCacheRows, numTilingCacheCols, *tilingCacheData;
  104.     
  105.     
  106.     if (spriteWorldP->tilingIsInitialized)
  107.     {
  108.         err = kTilingAlreadyInitialized;
  109.     }
  110.     
  111.     
  112.     if (err == noErr)
  113.     {
  114.         spriteWorldP->tilingIsOn = true;
  115.         spriteWorldP->tilingIsInitialized = true;
  116.         spriteWorldP->tileHeight = tileHeight;
  117.         spriteWorldP->tileWidth = tileWidth;
  118.     
  119.         numTilingCacheRows = spriteWorldP->backRect.bottom / tileHeight;
  120.         numTilingCacheCols = spriteWorldP->backRect.right / tileWidth;
  121.         spriteWorldP->numTilingCacheRows = numTilingCacheRows;
  122.         spriteWorldP->numTilingCacheCols = numTilingCacheCols;
  123.     }
  124.     
  125.     
  126.     if (err == noErr)
  127.     {
  128.             // Allocate the array of pointers for the tiling Cache
  129.         arraySize = (Size)numTilingCacheRows * sizeof(short*);
  130.         spriteWorldP->tilingCache = (short **)NewPtr(arraySize);
  131.         err = MemError();
  132.         
  133.         if (err == noErr)
  134.         {
  135.                 // Allocate memory for the actual data of the tiling Cache
  136.             arraySize = (Size)numTilingCacheRows * numTilingCacheCols * sizeof(short);
  137.             tilingCacheData = (short *)NewPtr(arraySize);
  138.             err = MemError();
  139.             
  140.                 // If there was an error, dispose what we already created earlier
  141.             if (err != noErr)
  142.                 DisposePtr((Ptr)spriteWorldP->tilingCache);
  143.         }
  144.         
  145.         if (err == noErr)
  146.         {
  147.                 // Point each element of the tilingCache array to each row of the data
  148.             for (row = 0; row < numTilingCacheRows; row++)
  149.                 spriteWorldP->tilingCache[row] = &tilingCacheData[(long)row * numTilingCacheCols];
  150.  
  151.                 // Set all elements to -1 (indicating that each tile needs to be drawn)
  152.             for (row = 0; row < numTilingCacheRows; row++)
  153.                 for (col = 0; col < numTilingCacheCols; col++)
  154.                     spriteWorldP->tilingCache[row][col] = -1;
  155.         }
  156.     }
  157.     
  158.     
  159.     if (err == noErr)
  160.     {
  161.             // Allocate memory for changedTiles array of rects
  162.         spriteWorldP->changedTilesArraySize = (numTilingCacheRows+1) * (numTilingCacheCols+1);
  163.         arraySize = (Size)(numTilingCacheRows+1) * (numTilingCacheCols+1) * sizeof(Rect);
  164.         spriteWorldP->changedTiles = (Rect *)NewPtr(arraySize);
  165.         err = MemError();
  166.     }
  167.     
  168.     
  169.     SWSetStickyIfError(err);
  170.     return err;
  171. }
  172.  
  173.  
  174. ///--------------------------------------------------------------------------------------
  175. //    SWExitTilingForDuplicateSpriteWorld
  176. ///--------------------------------------------------------------------------------------
  177.  
  178. SW_FUNC void SWExitTilingForDuplicateSpriteWorld(
  179.     SpriteWorldPtr    spriteWorldP)
  180. {
  181.         // Was tiling ever initialized?
  182.     if (spriteWorldP->tilingIsInitialized)
  183.     {
  184.         DisposePtr((Ptr)spriteWorldP->changedTiles);
  185.         DisposePtr((Ptr)spriteWorldP->tilingCache[0]);    // Dispose the data
  186.         DisposePtr((Ptr)spriteWorldP->tilingCache);        // Dispose the array of pointers
  187.         
  188.         spriteWorldP->tilingIsInitialized = false;
  189.         spriteWorldP->tilingIsOn = false;
  190.     }
  191. }
  192.  
  193.  
  194. #pragma mark -
  195. ///--------------------------------------------------------------------------------------
  196. //    SWProcessMultiScreenSpriteWorld
  197. ///--------------------------------------------------------------------------------------
  198.  
  199. SW_FUNC void SWProcessMultiScreenSpriteWorld(
  200.     SpriteWorldPtr spriteWorldP)
  201. {
  202.         // Call the scrolling world move proc
  203.     if (spriteWorldP->worldMoveProc != NULL)
  204.     {
  205.         (*spriteWorldP->worldMoveProc)(spriteWorldP, spriteWorldP->followSpriteP);
  206.     }
  207.     
  208.     
  209.         // Move visScrollRect
  210.     if (spriteWorldP->horizScrollDelta || spriteWorldP->vertScrollDelta)
  211.     {
  212.         SWOffsetVisScrollRect(spriteWorldP, 
  213.             spriteWorldP->horizScrollDelta, 
  214.             spriteWorldP->vertScrollDelta);
  215.     }
  216. }
  217.  
  218.  
  219. ///--------------------------------------------------------------------------------------
  220. //    SWAnimateMultiScreenSpriteWorld. The only differences between this function
  221. //    and the normal SWAnimateScrollingSpriteWorld are:
  222. //    A) This function recalculates the oldOffscreenRect each frame, instead of using 
  223. //       the value that was stored in the sprite the previous frame.
  224. //    B) The section of code directly below was added.
  225. //    C) The code that assigns the destFrameRect to the oldFrameRect, etc. was moved to
  226. //     SWFinishMultiScreenAnimation where applicable.
  227. //    D) The code at the very beginning of this function that checks the frameHasOccurred
  228. //       variable was removed, since the user has to do this for multi-screen animations.
  229. //    E) The following variables were added to this function:
  230. //        short                        oldVertScrollRectOffset, oldHorizScrollRectOffset;
  231. //    F) The name was changed. :-)
  232. ///--------------------------------------------------------------------------------------
  233.  
  234. SW_FUNC void SWAnimateMultiScreenSpriteWorld(
  235.     SpriteWorldPtr spriteWorldP)
  236. {
  237.     UpdateRectStructPtr            curRectStructP,
  238.                                 nextRectStructP;
  239.     register SpriteLayerPtr     curSpriteLayerP;
  240.     register SpritePtr             curSpriteP;
  241.     SpritePtr                     headActiveSpriteP = NULL;    // Tail of active sprite list
  242.     SpritePtr                    headIdleSpriteP = NULL;        // Tail of idle sprite list
  243.     SpritePtr                     curActiveSpriteP = NULL;
  244.     SpritePtr                     curIdleSpriteP = NULL;
  245.     Rect                        *visScrollRectP = &spriteWorldP->visScrollRect;
  246.     Rect                        tempDstRect, tempSrcRect;
  247.     short                        hScrollDelta, vScrollDelta, curTileLayer;
  248.     short                        oldVertScrollRectOffset, oldHorizScrollRectOffset;
  249.  
  250.     SW_ASSERT(spriteWorldP != NULL);
  251.     SW_ASSERT(spriteWorldP->backFrameP->isFrameLocked);
  252.     SW_ASSERT(spriteWorldP->workFrameP->isFrameLocked);
  253.     SW_ASSERT(spriteWorldP->windowFrameP->isFrameLocked);
  254.     
  255.     /////////////////////////////////////////////
  256.     // The code below is new to this function. //
  257.     /////////////////////////////////////////////
  258.     
  259.     oldVertScrollRectOffset = spriteWorldP->backRect.bottom * 
  260.         (spriteWorldP->oldVisScrollRect.top / spriteWorldP->backRect.bottom);
  261.     
  262.     oldHorizScrollRectOffset = spriteWorldP->backRect.right *
  263.         (spriteWorldP->oldVisScrollRect.left / spriteWorldP->backRect.right);
  264.         
  265.     /////////////////////////////////////////////
  266.     
  267.     
  268.         // Add the deadSpriteLayer if there are any Sprites in it.
  269.     if ( spriteWorldP->deadSpriteLayerP->headSpriteP != NULL )
  270.     {
  271.         SWAddSpriteLayer(spriteWorldP, spriteWorldP->deadSpriteLayerP);
  272.     }
  273.     
  274.     
  275.     hScrollDelta = visScrollRectP->left - spriteWorldP->oldVisScrollRect.left;
  276.     vScrollDelta = visScrollRectP->top - spriteWorldP->oldVisScrollRect.top;
  277.     
  278.     
  279.         // Update tiles as we scroll if tiling is turned on
  280.     if (spriteWorldP->tilingIsOn)
  281.     {
  282.             // VisScrollRect moved horizontally
  283.         if (hScrollDelta)
  284.         {
  285.                 // Get rect of new vertical section to update
  286.             tempDstRect = *visScrollRectP;
  287.             
  288.                 // Moved left
  289.             if (hScrollDelta < 0)
  290.             {
  291.                 if (tempDstRect.right > spriteWorldP->oldVisScrollRect.left)
  292.                     tempDstRect.right = spriteWorldP->oldVisScrollRect.left;
  293.             }
  294.             else    // Moved right
  295.             {
  296.                 if (tempDstRect.left < spriteWorldP->oldVisScrollRect.right)
  297.                     tempDstRect.left = spriteWorldP->oldVisScrollRect.right;
  298.             }
  299.     
  300.             (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &tempDstRect, true);
  301.             SWWrapRectToWorkArea(spriteWorldP, &tempDstRect);
  302.             
  303.             
  304.                 // Did VisScrollRect moved diagonally?
  305.             if (vScrollDelta)
  306.             {
  307.                     // Get rect of new horizontal section to update
  308.                 tempDstRect = spriteWorldP->visScrollRect;
  309.                 
  310.                     // Moved up
  311.                 if (vScrollDelta < 0)
  312.                 {
  313.                     if (tempDstRect.bottom > spriteWorldP->oldVisScrollRect.top)
  314.                         tempDstRect.bottom = spriteWorldP->oldVisScrollRect.top;
  315.                 }
  316.                 else    // Moved down
  317.                 {
  318.                     if (tempDstRect.top < spriteWorldP->oldVisScrollRect.bottom)
  319.                         tempDstRect.top = spriteWorldP->oldVisScrollRect.bottom;
  320.                 }
  321.                 
  322.                     // Clip off the part we've already updated
  323.                 if (hScrollDelta < 0)
  324.                 {
  325.                     if (tempDstRect.left < spriteWorldP->oldVisScrollRect.left)
  326.                         tempDstRect.left = spriteWorldP->oldVisScrollRect.left;
  327.                 }
  328.                 else
  329.                 {
  330.                     if (tempDstRect.right > spriteWorldP->oldVisScrollRect.right)
  331.                         tempDstRect.right = spriteWorldP->oldVisScrollRect.right;
  332.                 }
  333.                 
  334.                     // We pass false here to avoid a bug which occured in the
  335.                     // tile optimizing code when updating tiles twice in one frame
  336.                 if (tempDstRect.right > tempDstRect.left)
  337.                 {
  338.                     (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &tempDstRect, false);
  339.                     SWWrapRectToWorkArea(spriteWorldP, &tempDstRect);
  340.                 }
  341.             }
  342.         }        // VisScrollRect moved vertically only
  343.         else if (vScrollDelta)
  344.         {
  345.                 // Get rect of new horizontal section to update
  346.             tempDstRect = *visScrollRectP;
  347.             
  348.                 // Moved up
  349.             if (vScrollDelta < 0)
  350.             {
  351.                 if (tempDstRect.bottom > spriteWorldP->oldVisScrollRect.top)
  352.                     tempDstRect.bottom = spriteWorldP->oldVisScrollRect.top;
  353.             }
  354.             else    // Moved down
  355.             {
  356.                 if (tempDstRect.top < spriteWorldP->oldVisScrollRect.bottom)
  357.                     tempDstRect.top = spriteWorldP->oldVisScrollRect.bottom;
  358.             }
  359.  
  360.             (*spriteWorldP->tileRectDrawProc)(spriteWorldP, &tempDstRect, true);
  361.             SWWrapRectToWorkArea(spriteWorldP, &tempDstRect);
  362.         }
  363.     }
  364.     
  365.     
  366.     //-----------------erase the sprites--------------------
  367.     
  368.         // Set the port to the work area so we can draw in it
  369.     SetGWorld(spriteWorldP->workFrameP->framePort, nil);
  370.     
  371.     curSpriteLayerP = spriteWorldP->headSpriteLayerP;
  372.     curTileLayer = 0;
  373.     
  374.         // iterate through the layers in this world
  375.     while (curSpriteLayerP != NULL)
  376.     {
  377.         curSpriteP = curSpriteLayerP->headSpriteP;
  378.         
  379.         if (curSpriteLayerP->tileLayer > curTileLayer)
  380.             curTileLayer = curSpriteLayerP->tileLayer;
  381.         
  382.             // iterate through the sprites in this layer
  383.         while (curSpriteP != NULL)
  384.         {
  385.             SW_ASSERT(curSpriteP->curFrameP->isFrameLocked);
  386.             curSpriteP->tileDepth = curTileLayer;
  387.             
  388.                 // Clip the sprite's destOffscreenRect with visScrollRect.
  389.             if (curSpriteP->isVisible)
  390.             {
  391.                 curSpriteP->destOffscreenRect = curSpriteP->destFrameRect;
  392.                 curSpriteP->clippedSourceRect = curSpriteP->curFrameP->frameRect;
  393.                 
  394.  
  395.                 if (curSpriteP->destOffscreenRect.top < visScrollRectP->top)
  396.                 {
  397.                     curSpriteP->clippedSourceRect.top += visScrollRectP->top - 
  398.                             curSpriteP->destOffscreenRect.top;
  399.                     curSpriteP->destOffscreenRect.top = visScrollRectP->top;
  400.                 }
  401.                 
  402.                 if (curSpriteP->destOffscreenRect.bottom > visScrollRectP->bottom)
  403.                 {
  404.                     curSpriteP->clippedSourceRect.bottom += visScrollRectP->bottom - 
  405.                             curSpriteP->destOffscreenRect.bottom;
  406.                     curSpriteP->destOffscreenRect.bottom = visScrollRectP->bottom;
  407.                 }
  408.                 
  409.                 if (curSpriteP->destOffscreenRect.left < visScrollRectP->left)
  410.                 {
  411.                     curSpriteP->clippedSourceRect.left += visScrollRectP->left - 
  412.                             curSpriteP->destOffscreenRect.left;
  413.                     curSpriteP->destOffscreenRect.left = visScrollRectP->left;
  414.                 }
  415.                 
  416.                 if (curSpriteP->destOffscreenRect.right > visScrollRectP->right)
  417.                 {
  418.                     curSpriteP->clippedSourceRect.right += visScrollRectP->right - 
  419.                             curSpriteP->destOffscreenRect.right;
  420.                     curSpriteP->destOffscreenRect.right = visScrollRectP->right;
  421.                 }
  422.                 
  423.                 curSpriteP->destRectIsVisible =
  424.                         (curSpriteP->destOffscreenRect.right >
  425.                         curSpriteP->destOffscreenRect.left &&
  426.                         curSpriteP->destOffscreenRect.bottom >
  427.                         curSpriteP->destOffscreenRect.top);
  428.             }
  429.             
  430.             
  431.             
  432.             // Clip the sprite's oldOffscreenRect with oldVisScrollRect. This section
  433.             // of code is the only difference between SWAnimateMultiScreenSpriteWorld
  434.             // and SWAnimateScrollingSpriteWorld, besides destOffscreenRect not being
  435.             // assigned to oldOffscreenRect at the end of this function, and some code
  436.             // at the very beginning of this function.
  437.                 
  438.             curSpriteP->oldOffscreenRect = curSpriteP->oldFrameRect;
  439.             
  440.             if (curSpriteP->oldOffscreenRect.top < spriteWorldP->oldVisScrollRect.top)
  441.                 curSpriteP->oldOffscreenRect.top = spriteWorldP->oldVisScrollRect.top;
  442.             
  443.             if (curSpriteP->oldOffscreenRect.bottom > spriteWorldP->oldVisScrollRect.bottom)
  444.                 curSpriteP->oldOffscreenRect.bottom = spriteWorldP->oldVisScrollRect.bottom;
  445.             
  446.             if (curSpriteP->oldOffscreenRect.left < spriteWorldP->oldVisScrollRect.left)
  447.                 curSpriteP->oldOffscreenRect.left = spriteWorldP->oldVisScrollRect.left;
  448.             
  449.             if (curSpriteP->oldOffscreenRect.right > spriteWorldP->oldVisScrollRect.right)
  450.                 curSpriteP->oldOffscreenRect.right = spriteWorldP->oldVisScrollRect.right;
  451.             
  452.             curSpriteP->oldRectIsVisible =
  453.                     (curSpriteP->oldOffscreenRect.right >
  454.                     curSpriteP->oldOffscreenRect.left &&
  455.                     curSpriteP->oldOffscreenRect.bottom >
  456.                     curSpriteP->oldOffscreenRect.top);
  457.             
  458.                 // Make the sprite's rect local to the offscreen area
  459.             curSpriteP->oldOffscreenRect.top -= oldVertScrollRectOffset;
  460.             curSpriteP->oldOffscreenRect.bottom -= oldVertScrollRectOffset;
  461.             curSpriteP->oldOffscreenRect.left -= oldHorizScrollRectOffset;
  462.             curSpriteP->oldOffscreenRect.right -= oldHorizScrollRectOffset;
  463.             
  464.             
  465.             /////////////////////////////////////////////////////////////////////////
  466.             
  467.             
  468.             
  469.             
  470.             
  471.                 // Erase the sprites
  472.             if (curSpriteP->needsToBeDrawn && curSpriteP->isVisible ||
  473.                 curSpriteP->needsToBeErased && !curSpriteP->isVisible)
  474.             {
  475.                     // Was the sprite visible on the screen last frame?
  476.                 if (curSpriteP->oldRectIsVisible)
  477.                 {
  478.                         // Add sprite to active sprite list
  479.                     if (headActiveSpriteP == NULL)
  480.                         headActiveSpriteP = curSpriteP;
  481.                     
  482.                     if (curActiveSpriteP != NULL)
  483.                             curActiveSpriteP->nextActiveSpriteP = curSpriteP;
  484.                     
  485.                     curActiveSpriteP = curSpriteP;
  486.                     
  487.                     {
  488.                         short temp;
  489.                         
  490.                             // align left edge of oldOffscreenRect for erasing
  491.                         curSpriteP->oldOffscreenRect.left &=
  492.                             (spriteWorldP->workFrameP->leftAlignFactor);
  493.                         
  494.                             // align the right edge to long word boundary
  495.                         temp = curSpriteP->oldOffscreenRect.right &
  496.                             spriteWorldP->workFrameP->rightAlignFactor;
  497.                         if (temp != 0)
  498.                         {
  499.                             curSpriteP->oldOffscreenRect.right +=
  500.                                 (spriteWorldP->workFrameP->rightAlignFactor + 1) - temp;
  501.                         }
  502.  
  503.                             // align left edge of oldFrameRect - necessary for
  504.                             // deltaFrameRect below, used by idle sprite collision
  505.                         curSpriteP->oldFrameRect.left &=
  506.                             (spriteWorldP->workFrameP->leftAlignFactor);
  507.                         
  508.                             // align the right edge to long word boundary
  509.                         temp = curSpriteP->oldFrameRect.right &
  510.                             spriteWorldP->workFrameP->rightAlignFactor;
  511.                         if (temp != 0)
  512.                         {
  513.                             curSpriteP->oldFrameRect.right +=
  514.                                 (spriteWorldP->workFrameP->rightAlignFactor + 1) - temp;
  515.                         }
  516.                     }
  517.                     
  518.                         // union last rect and current rect - this is necessary for 
  519.                         // the proper redrawing of idle sprites
  520.                     curSpriteP->deltaFrameRect.top = 
  521.                         SW_MIN(curSpriteP->oldFrameRect.top, curSpriteP->destFrameRect.top);
  522.                     curSpriteP->deltaFrameRect.left = 
  523.                         SW_MIN(curSpriteP->oldFrameRect.left, curSpriteP->destFrameRect.left);
  524.                     curSpriteP->deltaFrameRect.bottom = 
  525.                         SW_MAX(curSpriteP->oldFrameRect.bottom, curSpriteP->destFrameRect.bottom);
  526.                     curSpriteP->deltaFrameRect.right = 
  527.                         SW_MAX(curSpriteP->oldFrameRect.right, curSpriteP->destFrameRect.right);
  528.                     
  529.                     
  530.                         // Erase the sprite from the work area
  531.                     SWEraseWrappedSprite(spriteWorldP, &curSpriteP->oldOffscreenRect);
  532.                 }
  533.                 else if (curSpriteP->destRectIsVisible)    // Sprite will be drawn
  534.                 {
  535.                         // Add sprite to active sprite list
  536.                     if (headActiveSpriteP == NULL)
  537.                         headActiveSpriteP = curSpriteP;
  538.                     
  539.                     if (curActiveSpriteP != NULL)
  540.                             curActiveSpriteP->nextActiveSpriteP = curSpriteP;
  541.                     
  542.                     curActiveSpriteP = curSpriteP;
  543.                 }
  544.             }
  545.             else if (curSpriteP->isVisible)        // Visible, idle sprites
  546.             {
  547.                 if (curSpriteP->oldRectIsVisible)
  548.                 {
  549.                         // Is idle sprite moving outside the visScrollRect?
  550.                     if ((hScrollDelta > 0 &&
  551.                         (curIdleSpriteP->destFrameRect.left < visScrollRectP->left) &&
  552.                         (curIdleSpriteP->destFrameRect.right > spriteWorldP->oldVisScrollRect.left)) ||
  553.                         (hScrollDelta < 0 &&
  554.                         (curIdleSpriteP->destFrameRect.left < spriteWorldP->oldVisScrollRect.right) &&
  555.                         (curIdleSpriteP->destFrameRect.right > visScrollRectP->right)) )
  556.                     {
  557.                             // Erase piece of idle sprite outside of visScrollRect
  558.                         tempDstRect = curSpriteP->oldFrameRect;
  559.                         
  560.                             // Get section of sprite outside visScrollRect
  561.                         if (hScrollDelta > 0)
  562.                         {
  563.                             if (tempDstRect.right > visScrollRectP->left)
  564.                                 tempDstRect.right = visScrollRectP->left;
  565.                         }
  566.                         else
  567.                         {
  568.                             if (tempDstRect.left < visScrollRectP->right)
  569.                                 tempDstRect.left = visScrollRectP->right;
  570.                         }
  571.                         
  572.                             // Clip tempDstRect with oldVisScrollRect
  573.                         if (tempDstRect.top < spriteWorldP->oldVisScrollRect.top)
  574.                             tempDstRect.top = spriteWorldP->oldVisScrollRect.top;
  575.                         if (tempDstRect.bottom > spriteWorldP->oldVisScrollRect.bottom)
  576.                             tempDstRect.bottom = spriteWorldP->oldVisScrollRect.bottom;
  577.                         if (tempDstRect.left < spriteWorldP->oldVisScrollRect.left)
  578.                             tempDstRect.left = spriteWorldP->oldVisScrollRect.left;
  579.                         if (tempDstRect.right > spriteWorldP->oldVisScrollRect.right)
  580.                             tempDstRect.right = spriteWorldP->oldVisScrollRect.right;
  581.                         
  582.                             // Make the rect local to the offscreen area
  583.                         tempDstRect.top -= spriteWorldP->vertScrollRectOffset;
  584.                         tempDstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  585.                         tempDstRect.left -= spriteWorldP->horizScrollRectOffset;
  586.                         tempDstRect.right -= spriteWorldP->horizScrollRectOffset;
  587.                         
  588.                         SWEraseWrappedSprite(spriteWorldP, &tempDstRect);
  589.                     }
  590.                     
  591.                         // Is idle sprite moving outside the visScrollRect?
  592.                     if ((vScrollDelta > 0 &&
  593.                         (curIdleSpriteP->destFrameRect.top < visScrollRectP->top) &&
  594.                         (curIdleSpriteP->destFrameRect.bottom > spriteWorldP->oldVisScrollRect.top)) ||
  595.                         (vScrollDelta < 0 &&
  596.                         (curIdleSpriteP->destFrameRect.top < spriteWorldP->oldVisScrollRect.bottom) &&
  597.                         (curIdleSpriteP->destFrameRect.bottom > visScrollRectP->bottom)) )
  598.                     {
  599.                             // Erase piece of idle sprite outside of visScrollRect
  600.                         tempDstRect = curSpriteP->oldFrameRect;
  601.                         
  602.                             // Get section of sprite outside visScrollRect
  603.                         if (vScrollDelta > 0)
  604.                         {
  605.                             if (tempDstRect.bottom > visScrollRectP->top)
  606.                                 tempDstRect.bottom = visScrollRectP->top;
  607.                         }
  608.                         else
  609.                         {
  610.                             if (tempDstRect.top < visScrollRectP->bottom)
  611.                                 tempDstRect.top = visScrollRectP->bottom;
  612.                         }
  613.                         
  614.                             // Clip tempDstRect with oldVisScrollRect
  615.                         if (tempDstRect.top < spriteWorldP->oldVisScrollRect.top)
  616.                             tempDstRect.top = spriteWorldP->oldVisScrollRect.top;
  617.                         if (tempDstRect.bottom > spriteWorldP->oldVisScrollRect.bottom)
  618.                             tempDstRect.bottom = spriteWorldP->oldVisScrollRect.bottom;
  619.                         if (tempDstRect.left < spriteWorldP->oldVisScrollRect.left)
  620.                             tempDstRect.left = spriteWorldP->oldVisScrollRect.left;
  621.                         if (tempDstRect.right > spriteWorldP->oldVisScrollRect.right)
  622.                             tempDstRect.right = spriteWorldP->oldVisScrollRect.right;
  623.                         
  624.                             // Make the rect local to the offscreen area
  625.                         tempDstRect.top -= spriteWorldP->vertScrollRectOffset;
  626.                         tempDstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  627.                         tempDstRect.left -= spriteWorldP->horizScrollRectOffset;
  628.                         tempDstRect.right -= spriteWorldP->horizScrollRectOffset;
  629.                         
  630.                         SWEraseWrappedSprite(spriteWorldP, &tempDstRect);
  631.                     }
  632.                 }
  633.                             
  634.                 
  635.                     // Is the idle sprite visible on the screen?
  636.                 if (curSpriteP->destRectIsVisible)
  637.                 {
  638.                         // Add sprite to idle sprite list
  639.                     if (headIdleSpriteP == NULL)
  640.                         headIdleSpriteP = curSpriteP;
  641.                     
  642.                     if (curIdleSpriteP != NULL)
  643.                         curIdleSpriteP->nextIdleSpriteP = curSpriteP;
  644.                     
  645.                     curIdleSpriteP = curSpriteP;
  646.                 }
  647.             }
  648.  
  649.             curSpriteP = curSpriteP->nextSpriteP;
  650.         }
  651.  
  652.         curSpriteLayerP = curSpriteLayerP->nextSpriteLayerP;    
  653.     }
  654.     
  655.     if (curActiveSpriteP != NULL)
  656.         curActiveSpriteP->nextActiveSpriteP = NULL;
  657.     
  658.     if (curIdleSpriteP != NULL)
  659.         curIdleSpriteP->nextIdleSpriteP = NULL;
  660.     
  661.  
  662.     
  663.         // This section of code iterates through the idle sprite list, drawing the tiny
  664.         // sliver of any idle sprites that have just entered the visScrollRect.
  665.     curIdleSpriteP = headIdleSpriteP;
  666.     while (curIdleSpriteP != NULL)
  667.     {
  668.             // Draw vertical piece of idle sprite if it is coming into the visScrollRect.
  669.         if ((vScrollDelta > 0 &&
  670.             (curIdleSpriteP->destFrameRect.top < visScrollRectP->bottom) &&
  671.             (curIdleSpriteP->destFrameRect.bottom > spriteWorldP->oldVisScrollRect.bottom) ) ||
  672.             (vScrollDelta < 0 &&
  673.             (curIdleSpriteP->destFrameRect.top < spriteWorldP->oldVisScrollRect.top) &&
  674.             (curIdleSpriteP->destFrameRect.bottom > visScrollRectP->top)) )
  675.         {
  676.             tempDstRect = curIdleSpriteP->destOffscreenRect;
  677.             tempSrcRect = curIdleSpriteP->clippedSourceRect;
  678.             
  679.                 // Determine whether scrolling up or down, then get 
  680.                 // section of sprite outside oldVisScrollRect.
  681.             if (vScrollDelta < 0)
  682.             {
  683.                     // Scrolling up, so get section above oldVisScrollRect
  684.                 if (tempDstRect.bottom > spriteWorldP->oldVisScrollRect.top)
  685.                 {
  686.                     tempSrcRect.bottom += spriteWorldP->oldVisScrollRect.top - 
  687.                         tempDstRect.bottom;
  688.                     tempDstRect.bottom = spriteWorldP->oldVisScrollRect.top;
  689.                 }
  690.             }
  691.             else
  692.             {
  693.                     // Scrolling down, so get section below oldVisScrollRect
  694.                 if (tempDstRect.top < spriteWorldP->oldVisScrollRect.bottom)
  695.                 {
  696.                     tempSrcRect.top += spriteWorldP->oldVisScrollRect.bottom - 
  697.                         tempDstRect.top;
  698.                     tempDstRect.top = spriteWorldP->oldVisScrollRect.bottom;
  699.                 }
  700.             }
  701.             
  702.                 // Make the sprite's rect local to the offscreen area
  703.             tempDstRect.top -= spriteWorldP->vertScrollRectOffset;
  704.             tempDstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  705.             tempDstRect.left -= spriteWorldP->horizScrollRectOffset;
  706.             tempDstRect.right -= spriteWorldP->horizScrollRectOffset;
  707.  
  708.                 // Draw the sprite in the work area
  709.             SWDrawWrappedSprite(curIdleSpriteP, spriteWorldP->workFrameP,
  710.                     &tempSrcRect, &tempDstRect);
  711.             
  712.                 // Draw tiles above sprite
  713.             if (spriteWorldP->tilingIsOn &&
  714.                 curIdleSpriteP->tileDepth <= spriteWorldP->lastActiveTileLayer)
  715.             {
  716.                 tempDstRect.top += spriteWorldP->vertScrollRectOffset;
  717.                 tempDstRect.bottom += spriteWorldP->vertScrollRectOffset;
  718.                 tempDstRect.left += spriteWorldP->horizScrollRectOffset;
  719.                 tempDstRect.right += spriteWorldP->horizScrollRectOffset;
  720.                 SWDrawTilesAboveSprite(spriteWorldP, &tempDstRect, curIdleSpriteP->tileDepth);
  721.             }
  722.         }
  723.         
  724.         
  725.             // Draw horizontal piece of idle sprite if it is coming into the visScrollRect.
  726.         if ((hScrollDelta > 0 &&
  727.             (curIdleSpriteP->destFrameRect.left < visScrollRectP->right) &&
  728.             (curIdleSpriteP->destFrameRect.right > spriteWorldP->oldVisScrollRect.right) ) ||
  729.             (hScrollDelta < 0 &&
  730.             (curIdleSpriteP->destFrameRect.left < spriteWorldP->oldVisScrollRect.left) &&
  731.             (curIdleSpriteP->destFrameRect.right > visScrollRectP->left)) )
  732.         {
  733.             tempDstRect = curIdleSpriteP->destOffscreenRect;
  734.             tempSrcRect = curIdleSpriteP->clippedSourceRect;
  735.             
  736.                 // Determine whether scrolling left or right, then get 
  737.                 // section of sprite outside oldVisScrollRect.
  738.             if (hScrollDelta < 0)
  739.             {
  740.                     // Scrolling left, so get section to the left of oldVisScrollRect
  741.                 if (tempDstRect.right > spriteWorldP->oldVisScrollRect.left)
  742.                 {
  743.                     tempSrcRect.right += spriteWorldP->oldVisScrollRect.left - 
  744.                         tempDstRect.right;
  745.                     tempDstRect.right = spriteWorldP->oldVisScrollRect.left;
  746.                 }
  747.             }
  748.             else
  749.             {
  750.                     // Scrolling right, so get section to the right of oldVisScrollRect
  751.                 if (tempDstRect.left < spriteWorldP->oldVisScrollRect.right)
  752.                 {
  753.                     tempSrcRect.left += spriteWorldP->oldVisScrollRect.right - 
  754.                         tempDstRect.left;
  755.                     tempDstRect.left = spriteWorldP->oldVisScrollRect.right;
  756.                 }
  757.             }
  758.             
  759.             
  760.                 // Make the sprite's rect local to the offscreen area
  761.             tempDstRect.top -= spriteWorldP->vertScrollRectOffset;
  762.             tempDstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  763.             tempDstRect.left -= spriteWorldP->horizScrollRectOffset;
  764.             tempDstRect.right -= spriteWorldP->horizScrollRectOffset;
  765.  
  766.                 // Draw the sprite in the work area
  767.             SWDrawWrappedSprite(curIdleSpriteP, spriteWorldP->workFrameP,
  768.                     &tempSrcRect, &tempDstRect);
  769.             
  770.                 // Draw tiles above sprite
  771.             if (spriteWorldP->tilingIsOn &&
  772.                 curIdleSpriteP->tileDepth <= spriteWorldP->lastActiveTileLayer)
  773.             {
  774.                 tempDstRect.top += spriteWorldP->vertScrollRectOffset;
  775.                 tempDstRect.bottom += spriteWorldP->vertScrollRectOffset;
  776.                 tempDstRect.left += spriteWorldP->horizScrollRectOffset;
  777.                 tempDstRect.right += spriteWorldP->horizScrollRectOffset;
  778.                 SWDrawTilesAboveSprite(spriteWorldP, &tempDstRect, curIdleSpriteP->tileDepth);
  779.             }
  780.         }
  781.     
  782.         curIdleSpriteP = curIdleSpriteP->nextIdleSpriteP;
  783.     }
  784.     
  785.  
  786.         // update flagged background rects
  787.     curRectStructP = spriteWorldP->headUpdateRectP;
  788.     while ( curRectStructP != NULL )
  789.     {
  790.         tempDstRect = curRectStructP->updateRect;
  791.         
  792.             // Make the rect local to the offscreen area
  793.         tempDstRect.top -= spriteWorldP->vertScrollRectOffset;
  794.         tempDstRect.bottom -= spriteWorldP->vertScrollRectOffset;
  795.         tempDstRect.left -= spriteWorldP->horizScrollRectOffset;
  796.         tempDstRect.right -= spriteWorldP->horizScrollRectOffset;
  797.         
  798.             // We're not really erasing a sprite, just copying while wrapping
  799.         SWEraseWrappedSprite(spriteWorldP, &tempDstRect);
  800.         curRectStructP = curRectStructP->nextRectStructP;
  801.     }
  802.     
  803.         // Redraw idle sprites that were erased by a tile
  804.     if (spriteWorldP->numTilesChanged > 0)
  805.         SWCheckWrappedIdleSpritesWithTiles(spriteWorldP, headIdleSpriteP);
  806.  
  807.         // Redraw idle sprites that were erased by an updateRect
  808.     if (spriteWorldP->headUpdateRectP != NULL)
  809.         SWCheckWrappedIdleSpritesWithRects(spriteWorldP, headIdleSpriteP);
  810.     
  811.         // Call the postEraseCallBack
  812.     if (spriteWorldP->postEraseCallBack != NULL)
  813.         (*spriteWorldP->postEraseCallBack)(spriteWorldP);
  814.  
  815.  
  816.     //-----------------draw the sprites-------------------
  817.  
  818.     curSpriteLayerP = spriteWorldP->headSpriteLayerP;
  819.  
  820.         // iterate through the layers in this world
  821.     while (curSpriteLayerP != NULL)
  822.     {
  823.         curSpriteP = curSpriteLayerP->headSpriteP;
  824.  
  825.             // iterate through the sprites in this layer
  826.         while (curSpriteP != NULL)
  827.         {
  828.             if (curSpriteP->isVisible)
  829.             {
  830.                     // Make the sprite's rect local to the offscreen area
  831.                 curSpriteP->destOffscreenRect.top -= spriteWorldP->vertScrollRectOffset;
  832.                 curSpriteP->destOffscreenRect.bottom -= spriteWorldP->vertScrollRectOffset;
  833.                 curSpriteP->destOffscreenRect.left -= spriteWorldP->horizScrollRectOffset;
  834.                 curSpriteP->destOffscreenRect.right -= spriteWorldP->horizScrollRectOffset;
  835.                 
  836.                 if (curSpriteP->needsToBeDrawn)
  837.                 {
  838.                         // Is the sprite visible on the screen?
  839.                     if (curSpriteP->destRectIsVisible)
  840.                     {
  841.                         gCurrentSpriteBeingDrawn = curSpriteP;
  842.                         
  843.                             // Draw the sprite in the work area
  844.                         SWDrawWrappedSprite(curSpriteP, spriteWorldP->workFrameP,
  845.                             &curSpriteP->clippedSourceRect, 
  846.                             &curSpriteP->destOffscreenRect);
  847.                         
  848.                         gCurrentSpriteBeingDrawn = NULL;
  849.                         
  850.                             // Draw tiles above sprite
  851.                         if (spriteWorldP->tilingIsOn &&
  852.                             curSpriteP->tileDepth <= spriteWorldP->lastActiveTileLayer)
  853.                         {
  854.                             tempDstRect = curSpriteP->destOffscreenRect;
  855.                             tempDstRect.top += spriteWorldP->vertScrollRectOffset;
  856.                             tempDstRect.bottom += spriteWorldP->vertScrollRectOffset;
  857.                             tempDstRect.left += spriteWorldP->horizScrollRectOffset;
  858.                             tempDstRect.right += spriteWorldP->horizScrollRectOffset;
  859.                             SWDrawTilesAboveSprite(spriteWorldP, &tempDstRect, curSpriteP->tileDepth);
  860.                         }
  861.                     }
  862.                 }
  863.                 else
  864.                 {
  865.                         // Is the idle sprite visible on the screen?
  866.                     if (curSpriteP->destRectIsVisible)
  867.                     {
  868.                         SWCheckWrappedIdleSpriteOverlap(spriteWorldP, 
  869.                             curSpriteP, headActiveSpriteP);
  870.                     }
  871.                 }
  872.             }
  873.             
  874.             
  875.             ///
  876.             //  This is where a lot of code was removed.
  877.             //  (most of it moved to SWFinishMultiScreenAnimation)
  878.             ///
  879.             
  880.  
  881.             curSpriteP = curSpriteP->nextSpriteP;
  882.         }
  883.         
  884.         curSpriteLayerP = curSpriteLayerP->nextSpriteLayerP;
  885.     }
  886.     
  887.     spriteWorldP->oldVisScrollRect = spriteWorldP->visScrollRect;
  888.     
  889.     
  890.         // Call the postDrawCallBack
  891.     if (spriteWorldP->postDrawCallBack != NULL)
  892.         (*spriteWorldP->postDrawCallBack)(spriteWorldP);
  893.     
  894.     
  895.     //-----------------update the screen--------------------
  896.     
  897.         // Set the port to the window
  898.     SetGWorld(spriteWorldP->windowFrameP->framePort, nil);
  899.     
  900.     if (spriteWorldP->usingVBL)
  901.     {  
  902.         spriteWorldP->vblTaskRec.hasVBLFired = false;
  903.         while ( !spriteWorldP->vblTaskRec.hasVBLFired )
  904.         {}
  905.     }
  906.     
  907.         // Copy offscreen area to screen while wrapping
  908.     SWWrapWorldToScreen(spriteWorldP);
  909.     
  910.     
  911.             // dispose of flagged background rects
  912.     nextRectStructP = spriteWorldP->headUpdateRectP;
  913.     while ( nextRectStructP != NULL )
  914.     {
  915.         curRectStructP = nextRectStructP;
  916.         nextRectStructP = curRectStructP->nextRectStructP;
  917.         DisposePtr( (Ptr)curRectStructP );
  918.     }
  919.     spriteWorldP->headUpdateRectP = NULL;
  920.     
  921.     spriteWorldP->numTilesChanged = 0;
  922.     
  923.     
  924.         // Remove the deadSpriteLayer if we added it earlier.
  925.     if ( spriteWorldP->deadSpriteLayerP->headSpriteP != NULL )
  926.     {
  927.         SWRemoveSpriteLayer(spriteWorldP, spriteWorldP->deadSpriteLayerP);
  928.     }
  929. }
  930.  
  931.  
  932. ///--------------------------------------------------------------------------------------
  933. //    SWFinishMultiScreenAnimation
  934. ///--------------------------------------------------------------------------------------
  935.  
  936. SW_FUNC void SWFinishMultiScreenAnimation(
  937.     SpriteWorldPtr spriteWorldP)
  938. {
  939.     register SpriteLayerPtr     curSpriteLayerP;
  940.     register SpritePtr             curSpriteP;
  941.     
  942.     
  943.     curSpriteLayerP = spriteWorldP->headSpriteLayerP;
  944.  
  945.         // iterate through the layers in this world
  946.     while (curSpriteLayerP != NULL)
  947.     {
  948.         curSpriteP = curSpriteLayerP->headSpriteP;
  949.  
  950.             // iterate through the sprites in this layer
  951.         while (curSpriteP != NULL)
  952.         {
  953.                 // Set last rect to current rect
  954.             curSpriteP->oldFrameRect = curSpriteP->destFrameRect;
  955.             
  956.             curSpriteP->needsToBeDrawn = false;
  957.             curSpriteP->needsToBeErased = false;
  958.  
  959.             curSpriteP = curSpriteP->nextSpriteP;
  960.         }
  961.         
  962.         curSpriteLayerP = curSpriteLayerP->nextSpriteLayerP;
  963.     }
  964. }
  965.  
  966.