home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection 1998 Fall: Game Toolkit / Disc.iso / Samples / Moofwars 1.02 / Tim's Libraries / TGraphic.cp < prev    next >
Encoding:
Text File  |  1998-08-14  |  78.6 KB  |  2,794 lines  |  [TEXT/CWIE]

  1. /*****************************************************************************
  2. TGraphic.cp
  3.  
  4. Author: Timothy Carroll
  5. Apple Developer Technical Support
  6. timc@apple.com
  7.  
  8. Copyright © 1996, 1997 Apple Computer, Inc., All Rights Reserved
  9.  
  10. You may incorporate this sample code into your applications without
  11. restriction, though the sample code has been provided "AS IS" and the
  12. responsibility for its operation is 100% yours.  However, what you are
  13. not permitted to do is to redistribute the source as "DSC Sample Code"
  14. after having made changes. If you're going to re-distribute the source,
  15. we require that you make it clear in the source that the code was
  16. descended from Apple Sample Code, but that you've made changes.
  17.  
  18.  
  19. Description
  20. -----------
  21.  
  22. The TGraphic class encapsulates custom blitting of a graphic to an offscreen
  23. environment, such as a GWorld or a DrawSprocket buffer.  The current blitters
  24. are refined versions of the RLE sprites in "Tips of the Mac Gaming Gurus".
  25. The core blitters do not do any work to align data to proper boundaries, so
  26. this code currently does not use doubles to move data (this would be
  27. horribly slow on the 603/604 chips).
  28.  
  29. In addition to the drawing code, this class also encorporates hit testing
  30. graphics to each other or a single point, and using just the mask data to do
  31. an erase function. It also has some generalized loading and unloading code.
  32.  
  33.  
  34. Assumptions
  35. -----------
  36.  
  37. Currently the encoders are only designed for 8-bit images, and assume that
  38. the same color table is being used between the TGraphic encoder and whatever
  39. the destination GWorld will be.  The blitters don't really care and should
  40. work in anything >= 8 bits in depth, although they haven't been tested in
  41. anything other than 8 bits.
  42.  
  43. Currently, this class is definitely not intended to be subclassed, so
  44. all the methods are non-virtual.
  45.  
  46.  
  47. Modification History
  48. --------------------
  49. 11/5/97        Replaced naked c-types with standard types from types.h.
  50.  
  51. 9/18/97        CreateGraphic and the utility functions that it was based on
  52.             were cleaned up.  Now, the utility functions are responsible
  53.             for cleaning up if they have an error.  Fixed a few bugs in
  54.             the CIcon code as well.
  55.  
  56. 9/18/97        Updated code to Universal Headers 3.0.  Cleaned up some of the
  57.             comments.  Revised code to use OSStatus everywhere.
  58.             
  59. 5/22/97        Writes to resource file now call UpdateResFile.
  60.  
  61. 5/21/97        The list that keeps the TGraphics was never being initialized.
  62.             Perhaps the compiler automatically initializes the variables to
  63.             NULL, otherwise I would have expected it to explode.  We now
  64.             explictly initialize the list variables.
  65.             
  66. 5/21/97        No major changes or bugs fixed, but the list management code has
  67.             been tidied up.
  68.             
  69. 5/19/97        WriteToPICTResource could fail to restore the ports properly 
  70.             if QuickDraw returned an error.  This is fixed now.
  71.             
  72. 4/2/97        RELEASE OF 1.01
  73.  
  74. 4/2/97        LoadFromGraphicResource called ReleaseResource twice because I
  75.             duplicated some code to the cleanup section. Onyx's Spotlight
  76.             spotted it. Buy it!
  77.  
  78.  
  79. 2/24/97        TGraphic relies on an application to allocate a color table. This
  80.             handle is now declared inside TGraphic.h
  81.  
  82. 2/24/97        Assert macros were moved to a separate file, which we explictly
  83.             include.  MrC can build it now.
  84.  
  85. 1/23/97        If garbage were fit into the blitter, it is possible that we
  86.             could draw before destPtr was initialized.  This could never
  87.             happen with a valid sprite, but the debug build now initializes
  88.             the pointer to DEADBEEF to force a bus error.  MrC's optimizer
  89.             spotted this case in the code.
  90.  
  91. *************************************************************************************/
  92.  
  93. #include <Memory.h>
  94. #include <Resources.h>
  95.  
  96. #include <Icons.h>
  97. #include "TGraphic.h"
  98. #include "Scaling.h"
  99.  
  100.  
  101. /*************************************************************************************
  102. Internal Declarations
  103.  
  104. We define a number of constants used by the encoders and decoders.  Each TGraphic
  105. consists of a number of drawing commands, each of which is a 32-bit unsigned int with
  106. an 8-bit operator and a 24-bit value, followed by zero or more bytes of associated data.
  107.  
  108. Currently, each command is aligned to a 4-byte boundary, so a change in format would
  109. be required to use 8-byte floats.
  110. *************************************************************************************/
  111.  
  112. enum
  113. {
  114. // An EndShape token must appear at the end of all TGraphics.  The value is ignored.
  115.     kEndShapeToken    = 0L,
  116.  
  117. // Each line must be preceded by a LineStart token, even lines with no drawing. The
  118. // data field is the offset to the next line, used for clipping and hit testing.
  119.     kLineStartToken = 1L,
  120.  
  121. // This is the only token that currently has additional data.  The value field is the
  122. // number of bytes of pixel data, and the op-code is followed by that data.  The data
  123. // is padded to a 4-byte boundary.
  124.     kDrawPixelsToken = 2L,
  125.  
  126. // This is the "draw" equivalent in the hit mask.  We encode the hit mask separately
  127. // to allow for certain pixels to be drawn but not hit tested.
  128.     kHitTestPixelsToken = 2L,
  129.  
  130. // Skips a range of pixels, without drawing.
  131.     kSkipPixelsToken = 3L,
  132.  
  133. // The actual colors tested against in the hit mask.  Alpha blending could be added,
  134. // but should be a different opcode to allow opaque pixels to be drawn quickly.
  135.     kClearColorIndex = 0,
  136.     kMaskColorIndex = 255
  137. };
  138.  
  139. // This macro could be modified to support almost any alignment necessary.
  140. #define ALIGN_TO_NEXT_LONG(x)  ( ((UInt32) x + 3) & ~3)
  141.  
  142.  
  143. // Standard declarations for our resource type and format.
  144.  
  145. #define kTGraphicResourceType 'Gfic'
  146.  
  147. struct TGraphicResHeader
  148. {
  149.     UInt32 version;
  150.     SInt16 depth;
  151.     UInt16 flags;
  152.     Rect   bounds;
  153.     UInt32 imageSize;
  154.     UInt32 maskSize;
  155. };
  156. typedef TGraphicResHeader **TGraphicResHeaderHandle;
  157.  
  158.  
  159. // Preferred depth for the encoder.
  160. #define kPreferredDepth 8
  161.  
  162.  
  163. /*************************************************************************************
  164. TGraphic Allocation and List Management
  165.  
  166. TGraphic objects are allocated and maintained in a list internally by this class.
  167. Each object is reference counted, to reduce the amount of time spent loading and
  168. preparing TGraphics.  This is particularly important when you are loading sprites
  169. from PICT resources, since processing the sprites can take a long time.
  170.  
  171. For truly high performance apps, you can preload all the TGraphics once, and use
  172. them, so that no time in the game loop actually gets spent preparing the sprites.
  173.  
  174. The list is sorted by the TGraphic's resource ID, and uses standard C array indexing.
  175. The list is searched using a binary search.    
  176. *************************************************************************************/
  177.  
  178. static Handle gTGraphicList = NULL;
  179. static UInt32 gNumberGraphics = 0;
  180.  
  181. static OSStatus InsertGraphicIntoList (TGraphic *theGraphic, UInt32 index);
  182. static OSStatus DeleteGraphicFromList (UInt32 index);
  183. static OSStatus SearchGraphicList (SInt16 resID, Boolean *found, UInt32 *index);
  184.  
  185.  
  186. /*************************************************************************************
  187. InsertGraphicIntoList
  188.  
  189. This routine creates the list if it hasn't been initialized.  Otherwise, it just
  190. inserts the TGraphic into the spot pointed to by the index.  If an error occurs, the
  191. list is left in an indeterminate state.
  192. *************************************************************************************/
  193.  
  194. OSStatus InsertGraphicIntoList (TGraphic *theGraphic, UInt32 index)
  195. {
  196.     OSStatus theErr = noErr;
  197.  
  198. #if qDebugging
  199.     if (theGraphic == NULL)
  200.         SIGNAL_ERROR ("\pError: Attempted to insert a NULL TGraphic in list.")
  201.     if ((index < 0) || (index > gNumberGraphics))
  202.         SIGNAL_ERROR ("\pError: Attempted to insert TGraphic at invalid index.")
  203. #endif
  204.     
  205.     // If we don't have a list, allocate one.
  206.     if (gTGraphicList == NULL)
  207.     {
  208.         gNumberGraphics = 1;
  209.     
  210.         gTGraphicList = NewHandleClear (sizeof (TGraphic *));
  211.         theErr = MemError();
  212.         FAIL_OSERR (theErr, "\pERROR: Couldn't allocate TGraphic list.")
  213.         FAIL_NIL (gTGraphicList, "\pERROR: Couldn't allocate TGraphic list.")
  214.     }
  215.     else
  216.     // if we do have a list, expand it by one node
  217.     {
  218.         gNumberGraphics++;
  219.         
  220.         SetHandleSize(gTGraphicList,gNumberGraphics*sizeof(TGraphic *));
  221.         theErr = MemError();
  222.         FAIL_OSERR (theErr, "\pERROR: Couldn't resize TGraphic list")
  223.         FAIL_NIL (gTGraphicList, "\pERROR: Couldn't resize TGraphic list")
  224.         
  225.         // Make room in the list for a node at the correct index.
  226.         BlockMoveData(    (*(TGraphic ***)gTGraphicList)+index,
  227.                         (*(TGraphic ***)gTGraphicList)+index+1,
  228.                         (gNumberGraphics - index-1) * sizeof(TGraphic *));
  229.     }
  230.     
  231.     // Copy the TGraphic into the list.
  232.     *((*(TGraphic ***) gTGraphicList)+index) = theGraphic;
  233.  
  234.     // We succeeded, cleanup and exit.
  235.     goto cleanup;
  236.     
  237. error:
  238.     if (theErr == noErr)
  239.         theErr = paramErr;
  240.         
  241. cleanup:
  242.     return theErr;
  243. }
  244.  
  245.  
  246. /*************************************************************************************
  247. DeleteGraphicFromList
  248.     
  249. This routine removes the graphic from the list.  If the list is then empty,
  250. it disposes of the handle.
  251. *************************************************************************************/
  252. OSStatus DeleteGraphicFromList (UInt32 index)
  253. {
  254.     OSStatus theErr = noErr;
  255.     
  256. #if qDebugging
  257.     if ((index < 0) || (index > gNumberGraphics-1))
  258.         SIGNAL_ERROR ("\pError: Attempted to delete outside of the list.")
  259. #endif
  260.     
  261.     gNumberGraphics--;
  262.     
  263.     // If there are elements in the list, slide them up and shrink the handle
  264.     if (gNumberGraphics > 0)
  265.     {
  266.         BlockMoveData(    (*(TGraphic ***)gTGraphicList)+index+1,
  267.                         (*(TGraphic ***)gTGraphicList)+index,
  268.                         (gNumberGraphics - index) * sizeof(TGraphic *));
  269.  
  270.         SetHandleSize((Handle) gTGraphicList,gNumberGraphics*sizeof(TGraphic *));
  271.         theErr = MemError();
  272.         FAIL_OSERR (theErr, "\pCouldn't resize the list handle")
  273.         FAIL_NIL (gTGraphicList, "\pCouldn't resize the list handle")
  274.     }
  275.     else
  276.     // Otherwise, the list is empty and we can dispose of it.
  277.     {
  278.         DisposeHandle (gTGraphicList);
  279.         gTGraphicList = NULL;
  280.     }
  281.     
  282.     // We succeeded, cleanup and exit.
  283.     goto cleanup;
  284.     
  285. error:
  286.     if (theErr == noErr)
  287.         theErr = paramErr;
  288. cleanup:
  289.     return theErr;
  290. }
  291.  
  292.  
  293. /*************************************************************************************
  294. SearchGraphicList
  295.  
  296. This routine searches for a TGraphic with the resID parameter.  If it doesn't find
  297. one, the index it returns is the location where the new element should be inserted
  298. into the list.
  299. *************************************************************************************/
  300. OSStatus SearchGraphicList (SInt16 resID, Boolean *found, UInt32 *index)
  301. {    
  302.     OSStatus theErr = noErr;
  303.     UInt32 low = 0;
  304.     UInt32 high = gNumberGraphics;
  305.     UInt32 tempIndex;
  306.     SInt16 tempID;
  307.     TGraphic *theItem = NULL;
  308.     
  309.     // For an empty list, we fall through immediately.
  310.     while (low < high)
  311.     {
  312.         tempIndex = (low+high) >> 1;
  313.         theItem = (*(TGraphic ***)gTGraphicList)[tempIndex];
  314. #if qDebugging
  315.         FAIL_NIL (theItem, "\pERROR: List items should never be NULL!")
  316. #endif
  317.         tempID = theItem->GetResID();
  318.         if (resID == tempID)
  319.         {
  320.         // We found the object, return it
  321.             *found = true;
  322.             *index = tempIndex;
  323.             goto cleanup;
  324.         }
  325.         else if (resID < tempID)
  326.         // element must be below the current index
  327.             high = tempIndex;
  328.         else
  329.         // element must be above the current index
  330.             low = tempIndex+1;
  331.     }
  332.     
  333.     // We fell through, so we didn't find the item in the list.
  334.     *found = false;
  335.     *index = (low+high) >> 1;
  336.     goto cleanup;
  337.     
  338. error:
  339.     if (theErr == noErr)
  340.         theErr = paramErr;
  341.     
  342. cleanup:
  343.     return theErr;
  344. }
  345.  
  346. /*************************************************************************************
  347. TGraphic::NewGraphic
  348.  
  349. This uses the list management code to create new graphics when needed, and to manage
  350. the reference counts.
  351. *************************************************************************************/
  352. TGraphic
  353. *TGraphic::NewGraphic (SInt16 resID)
  354. {
  355.     OSStatus    theErr = noErr;
  356.     UInt32        listIndex;
  357.     Boolean     graphicAlreadyExists;
  358.     TGraphic    *newGraphic = NULL;
  359.     
  360.     theErr = SearchGraphicList (resID, &graphicAlreadyExists, &listIndex);
  361.     FAIL_OSERR(theErr,"\pERROR: Failed to search the graphic list")
  362.     
  363.     if (graphicAlreadyExists)
  364.     {
  365.         // Bump the reference count on the existing graphic
  366.         newGraphic = (*(TGraphic ***)gTGraphicList)[listIndex];
  367.         newGraphic->AddReference();
  368.     }
  369.     else
  370.     {
  371.         // Create a new graphic and insert it into the list
  372.         newGraphic = new TGraphic(resID);
  373.         theErr = newGraphic->CreateGraphic();
  374.         FAIL_OSERR(theErr,"\pERROR: Failed to create the new TGraphic.")
  375.         theErr = InsertGraphicIntoList(newGraphic, listIndex);
  376.         FAIL_OSERR(theErr, "\pERROR: Failed to insert TGraphic into list")
  377.         newGraphic->AddReference();
  378.     }
  379.     
  380.     // We succeeded, cleanup and return the TGraphic.
  381.     goto cleanup;
  382.     
  383. error:
  384.     if (newGraphic != NULL)
  385.     {
  386.         delete newGraphic;
  387.         newGraphic = NULL;
  388.     }
  389.     
  390. cleanup:    
  391.     return newGraphic;
  392. }
  393.  
  394.  
  395. /*************************************************************************************
  396. TGraphic::AddReference
  397. *************************************************************************************/
  398.  
  399. void
  400. TGraphic::AddReference (void)
  401.    {
  402.        fReferenceCount++;
  403.    }
  404.    
  405.    
  406. /*************************************************************************************
  407. TGraphic::DisposeReference
  408. *************************************************************************************/
  409.  
  410. void 
  411. TGraphic::DisposeReference (void)
  412. {
  413.        fReferenceCount--;
  414.        
  415.        // If no one cares about us, remove us from the list and delete ourself.
  416.        
  417.        if (fReferenceCount == 0)
  418.        {
  419.            UInt32                listIndex;
  420.         Boolean             tableEntry;
  421.         OSStatus            theErr = noErr;
  422.  
  423.         theErr = SearchGraphicList (fResID, &tableEntry, &listIndex);
  424. #if qDebugging
  425.         FAIL_OSERR (theErr, "\pERROR: List search reported an error")
  426.         FAIL_FALSE (tableEntry, "\pERROR: TGraphic should have been in the list!")
  427. #endif                
  428.         theErr = DeleteGraphicFromList(listIndex);
  429.         FAIL_OSERR (theErr, "\pFailed to delete graphic from the list")
  430.  
  431.            delete this;
  432.        }
  433.            
  434. error:
  435.        return;
  436. }
  437.  
  438.    
  439.    
  440. /*************************************************************************************
  441. TGraphic::TGraphic
  442.  
  443. Just puts some sane values in the member variables.
  444. *************************************************************************************/
  445. TGraphic::TGraphic (SInt16 resID)
  446. {
  447.     fResID = resID;
  448.     fReferenceCount = 0;
  449.     fImage = NULL;
  450.     fHitMask = NULL;
  451.     
  452. }
  453.  
  454.  
  455. /*************************************************************************************
  456. TGraphic::~TGraphic
  457.  
  458. If we have real, allocated graphics, we should dispose of them.
  459. *************************************************************************************/
  460. TGraphic::~TGraphic (void)
  461. {
  462.     DestroyGraphic();
  463. }
  464.  
  465.  
  466. /*************************************************************************************
  467. TGraphic::CreateGraphic
  468.  
  469. Attempt to load the graphic from a resource.  The preferred format is a pre-encoded
  470. sprite, since this loads very quickly, but if we don't find one, we'll use another
  471. format we recognize.
  472.  
  473. This is useful because you can use other graphics formats while under development.
  474. *************************************************************************************/
  475. OSStatus TGraphic::CreateGraphic(void)
  476. {
  477.     OSStatus theErr = noErr;
  478.  
  479.     theErr = LoadFromGraphicResource();
  480.     if (theErr == noErr) goto cleanup;
  481.     
  482.     theErr = LoadFromPICTResource ();
  483.     if (theErr == noErr) goto cleanup;
  484.  
  485.     theErr = LoadFromCIconResource ();
  486.     if (theErr == noErr) goto cleanup;
  487.     
  488.     theErr = LoadFromICN8Resource ();
  489.     if (theErr == noErr) goto cleanup;
  490.     
  491. error:
  492.  
  493.     SIGNAL_ERROR ("\pError: No resource was found!")
  494.     if (theErr == noErr)
  495.         theErr = paramErr;
  496.  
  497. cleanup:
  498.     return theErr;
  499.     
  500. }
  501.  
  502.  
  503. /*************************************************************************************
  504. TGraphic::DestroyGraphic
  505.     
  506. All this needs to do is dispose of the image handle we created earlier.
  507. *************************************************************************************/
  508.  
  509. OSStatus
  510. TGraphic::DestroyGraphic (void)
  511. {
  512.     if (fImage != NULL)
  513.         DisposeHandle (fImage);
  514.     if (fHitMask != NULL)
  515.         DisposeHandle (fHitMask);
  516.         
  517.     fImage = NULL;
  518.     fHitMask = NULL;
  519.     
  520.     return noErr;
  521. }
  522.  
  523.  
  524.  
  525. /*************************************************************************************
  526. TGraphic::LoadFromGraphicResource
  527.     
  528. This routine loaded a previously encoded sprite.
  529. *************************************************************************************/
  530. OSStatus TGraphic::LoadFromGraphicResource(void)
  531. {
  532.     Handle         graphicResource = NULL;
  533.     OSStatus    theErr = noErr;
  534.     Size        imageSize = 0, maskSize = 0;
  535.     TGraphicResHeaderHandle header;
  536.     
  537. // STEP 1 -- determine if the resource exists and try to load it.
  538.     graphicResource = Get1Resource (kTGraphicResourceType, fResID);
  539.     theErr = ResError();
  540.     
  541.     if ((theErr != noErr) || (graphicResource == NULL))
  542.         goto error;
  543.  
  544. // STEP 2 -- Parse the resource header
  545.     
  546.     header = (TGraphicResHeaderHandle) graphicResource;
  547.     
  548.     // This code only parses version 0 formats.
  549.     if ((**header).version != 0L)
  550.         goto error;
  551.         
  552.     fBitDepth = (**header).depth;
  553.     fFlags    = (**header).flags;
  554.     fBounds   = (**header).bounds;
  555.  
  556.     imageSize = (**header).imageSize;
  557.     maskSize =  (**header).maskSize;
  558.  
  559. // Step 3 -- Allocate the image and mask data and copy from the resource.    
  560.     fImage = NewHandle(imageSize);
  561.     theErr = MemError();
  562.     FAIL_OSERR (theErr, "\pFailed to allocate the image handle")
  563.     FAIL_NIL   (fImage, "\pFailed to allocate the image handle")
  564.     
  565.     fHitMask = NewHandle (maskSize);
  566.     theErr = MemError();
  567.     FAIL_OSERR (theErr, "\pFailed to allocate the mask handle")
  568.     FAIL_NIL   (fHitMask, "\pFailed to allocate the mask handle")
  569.     
  570.     BlockMoveData(((*graphicResource)+sizeof(TGraphicResHeader)), *fImage, imageSize);
  571.     BlockMoveData(((*graphicResource)+sizeof(TGraphicResHeader)+imageSize), *fHitMask, maskSize);
  572.     
  573. // We're done, cleanup and exit!
  574.     goto cleanup;
  575.     
  576. error:
  577.     
  578.     DestroyGraphic();
  579.     
  580.     if (theErr == noErr)
  581.         theErr = paramErr;
  582.         
  583. cleanup:
  584.     if (graphicResource != NULL)
  585.         ReleaseResource (graphicResource);
  586.     
  587.     return theErr;
  588. }
  589.  
  590.  
  591.  
  592. /*************************************************************************************
  593. TGraphic::LoadFromPICTResource
  594.     
  595. This routine reads a specially formatted pict, with image, drawing mask and hit mask
  596. going from left to right.
  597. *************************************************************************************/
  598. OSStatus
  599. TGraphic::LoadFromPICTResource (void)
  600. {
  601.     PicHandle        thePicture = NULL;
  602.     OSStatus        theErr = noErr;
  603.     GWorldPtr        graphicGWorld = NULL;
  604.     PixMapHandle    graphicPixMap = NULL;
  605.     Rect            pictRect;
  606.     
  607. // STEP 1 -- Attempt to load the PICT
  608.     thePicture = (PicHandle) Get1Resource ('PICT', fResID);
  609.     theErr = ResError();
  610.     
  611.     if ((theErr != noErr) || (thePicture == NULL))
  612.         goto error;
  613.  
  614. // STEP 2 -- Normalize the picture rectangle, and use it to build a GWorld.
  615.  
  616.     pictRect = (**thePicture).picFrame;
  617.     
  618.     pictRect.right -= pictRect.left;  pictRect.left = 0;
  619.     pictRect.bottom -= pictRect.top;  pictRect.top = 0;
  620.     
  621.     if (pictRect.right % 3 != 0)
  622.         SIGNAL_ERROR ("\pImproper size pict to load as a graphic")
  623.  
  624.     theErr = NewGWorld(&graphicGWorld, kPreferredDepth, &pictRect, gAppColorTable, NULL, keepLocal);
  625.     FAIL_OSERR (theErr, "\pCouldn't allocate GWorld for encoding")
  626.     
  627.     graphicPixMap  = GetGWorldPixMap(graphicGWorld);
  628.     FAIL_NIL (graphicPixMap, "\pCouldn't get the GWorld's PixMap")
  629.     FAIL_FALSE ( LockPixels(graphicPixMap), "\pCouldn't lock GWorld PixMap")
  630.     
  631.     // Erase the GWorld and draw our picture
  632.     {
  633.         CGrafPtr savePort;
  634.         GDHandle saveDevice;
  635.         
  636.         GetGWorld (&savePort, &saveDevice);
  637.         SetGWorld (graphicGWorld, NULL);
  638.     
  639.         EraseRect (&pictRect);
  640.         DrawPicture (thePicture, &pictRect);
  641.     
  642.         SetGWorld (savePort, saveDevice);
  643.     }
  644.  
  645. // STEP 4 -- feed the GWorld to the encoder.
  646.     
  647.     pictRect.right /=3;
  648.     theErr = EncodeGraphic (graphicPixMap, &pictRect);
  649.     
  650.     if (theErr == noErr)
  651.         goto cleanup;
  652.  
  653. error:
  654.     DestroyGraphic();
  655.         
  656.     if (theErr == noErr)
  657.         theErr = paramErr;
  658.         
  659. cleanup:
  660.     if (thePicture != NULL)
  661.         ReleaseResource ((Handle)thePicture);
  662.     
  663.     if (graphicGWorld != NULL)
  664.         DisposeGWorld (graphicGWorld);
  665.     
  666.     return theErr;
  667.  
  668. }
  669.  
  670.  
  671.  
  672. /*************************************************************************************
  673. TGraphic::LoadFromICN8Resource
  674.  
  675. This routine reads an ICL8 resource and uses the mask as both the drawing and hit
  676. mask.  It isn't quite as versatile as the PICT format, but is probably easier to
  677. find tools to build sprites with.
  678. *************************************************************************************/
  679. OSStatus
  680. TGraphic::LoadFromICN8Resource (void)
  681. {
  682.     OSStatus        theErr = noErr;
  683.     GWorldPtr        graphicGWorld = NULL;
  684.     PixMapHandle     graphicPixMap = NULL;
  685.     Rect             graphicRect = {0,0,32,96};
  686.     Rect             iconRect = {0,0,32,32};
  687.     Handle            theIconSuite = NULL;
  688.     RgnHandle        theMask = NULL;
  689.  
  690. // STEP 1 -- Attempt to load the icon
  691.     theErr = GetIconSuite(&theIconSuite, fResID, svAllAvailableData);
  692.  
  693.     if ((theErr != noErr) || (theIconSuite == NULL))
  694.         goto error;
  695.  
  696. // STEP 2 -- Create a region from the IconSuite's mask
  697.     
  698.     theMask = NewRgn();
  699.     theErr = QDError();
  700.     FAIL_OSERR (theErr, "\pError: Failed to create the mask region")
  701.     FAIL_NIL (theMask, "\pError: Failed to create the mask region")
  702.     
  703.     theErr = IconSuiteToRgn (theMask, &iconRect, atNone, theIconSuite);
  704.     FAIL_OSERR (theErr, "\pError: Failed to load the mask data into the region")
  705.     OffsetRgn (theMask, -(**theMask).rgnBBox.left, -(**theMask).rgnBBox.top);
  706.  
  707. // STEP 3 -- Create a GWorld the size of 3 ICL8s.
  708.  
  709.     theErr = NewGWorld(&graphicGWorld, kPreferredDepth, &graphicRect, gAppColorTable, NULL, keepLocal);
  710.     FAIL_OSERR (theErr, "\pCouldn't allocate GWorld for encoding")
  711.     
  712.     graphicPixMap  = GetGWorldPixMap(graphicGWorld);
  713.     FAIL_NIL (graphicPixMap, "\pCouldn't get the GWorld's PixMap")
  714.     FAIL_FALSE ( LockPixels(graphicPixMap), "\pCouldn't lock GWorld PixMap")
  715.     
  716. // STEP 4 -- Erase the GWorld and draw our icons
  717.     {
  718.         CGrafPtr savePort;
  719.         GDHandle saveDevice;
  720.         
  721.         GetGWorld (&savePort, &saveDevice);
  722.         SetGWorld (graphicGWorld, NULL);
  723.     
  724.         EraseRect (&graphicRect);
  725.         theErr = PlotIconSuite(&iconRect, atNone, ttNone, theIconSuite);  // icon
  726.         
  727.         OffsetRgn(theMask, 32, 0);
  728.         FillRgn (theMask, &qd.black); // drawing mask
  729.         OffsetRgn(theMask, 32, 0);
  730.         FillRgn (theMask, &qd.black); // hit mask
  731.  
  732.         SetGWorld (savePort, saveDevice);
  733.     }
  734.  
  735. // STEP 5 -- feed the GWorld to the encoder.
  736.     
  737.     graphicRect.right /=3;
  738.     theErr = EncodeGraphic (graphicPixMap, &graphicRect);
  739.     
  740.     if (theErr == noErr)
  741.         goto cleanup;
  742.  
  743. error:
  744.     DestroyGraphic();
  745.         
  746.     if (theErr == noErr)
  747.         theErr = paramErr;
  748.         
  749. cleanup:
  750.     if (theMask != NULL)
  751.         DisposeRgn (theMask);
  752.     if (theIconSuite != NULL)
  753.         DisposeIconSuite (theIconSuite, true);
  754.     if (graphicGWorld != NULL)
  755.         DisposeGWorld (graphicGWorld);
  756.     
  757.     return theErr;
  758.  
  759. }
  760.  
  761.  
  762. /*************************************************************************************
  763. TGraphic::LoadFromCIconResource
  764.  
  765. This is much like LoadFromICN8Resource, but loads from a CIcon instead.
  766. *************************************************************************************/
  767. OSStatus
  768. TGraphic::LoadFromCIconResource (void)
  769. {
  770.     OSStatus        theErr = noErr;
  771.     GWorldPtr        graphicGWorld = NULL;
  772.     PixMapHandle     graphicPixMap = NULL;
  773.     Rect            graphicRect, iconRect;
  774.     CIconHandle        theCIcon = NULL;
  775.     RgnHandle        theMask = NULL;
  776.     
  777. // STEP 1 -- Load the CIcon resource
  778.     theCIcon = GetCIcon (fResID);
  779.     theErr = ResError();
  780.     
  781.     if ((theCIcon == NULL) || (theErr != noErr))
  782.         goto error;
  783.  
  784. // STEP 2 -- Create a region from the Icon's mask
  785.  
  786.     theMask = NewRgn();
  787.     theErr = QDError();
  788.     FAIL_OSERR (theErr, "\pError: Failed to create the mask region")
  789.     FAIL_NIL (theMask, "\pError: Failed to create the mask region")
  790.     
  791.     // Fill in the baseAddr of the BitMap.
  792.     ( (**theCIcon).iconMask ).baseAddr = ( char* )(**theCIcon).iconMaskData;
  793.     
  794.     theErr = BitMapToRegion (theMask, &(**theCIcon).iconMask);
  795.     FAIL_OSERR (theErr, "\pFailed to load the mask data into the region")
  796.     OffsetRgn (theMask, -(**theMask).rgnBBox.left, -(**theMask).rgnBBox.top);
  797.  
  798.  
  799. // STEP 3 -- Build a GWorld the size of 3 CIcons
  800.  
  801.     iconRect = (**theCIcon).iconPMap.bounds;
  802.     iconRect.right -= iconRect.left; iconRect.left = 0;
  803.     iconRect.bottom -= iconRect.top; iconRect.top = 0;
  804.     
  805.     graphicRect = iconRect;
  806.     graphicRect.right *= 3;
  807.  
  808.     theErr = NewGWorld(&graphicGWorld, kPreferredDepth, &graphicRect, gAppColorTable, NULL, keepLocal);
  809.     FAIL_OSERR (theErr, "\pCouldn't allocate GWorld for encoding")
  810.     
  811.     graphicPixMap  = GetGWorldPixMap(graphicGWorld);
  812.     FAIL_NIL (graphicPixMap, "\pCouldn't get the GWorld's PixMap")
  813.     FAIL_FALSE ( LockPixels(graphicPixMap), "\pCouldn't lock GWorld PixMap")
  814.     
  815. // STEP 4 -- Erase the GWorld and draw our icons
  816.     {
  817.         CGrafPtr savePort;
  818.         GDHandle saveDevice;
  819.         
  820.         GetGWorld (&savePort, &saveDevice);
  821.         SetGWorld (graphicGWorld, NULL);
  822.     
  823.         EraseRect (&graphicRect);
  824.         
  825.         PlotCIcon (&iconRect, theCIcon); // image
  826.         OffsetRgn(theMask, iconRect.right, 0); 
  827.         FillRgn (theMask, &qd.black); // draw mask
  828.         OffsetRgn(theMask, iconRect.right, 0); 
  829.         FillRgn (theMask, &qd.black); // hit mask
  830.  
  831.         SetGWorld (savePort, saveDevice);
  832.     }
  833.  
  834. // STEP 5 -- feed the GWorld to the encoder.
  835.     
  836.     graphicRect.right /=3;
  837.     theErr = EncodeGraphic (graphicPixMap, &graphicRect);
  838.     
  839.     if (theErr == noErr)
  840.         goto cleanup;
  841.  
  842. error:
  843.     DestroyGraphic();
  844.         
  845.     if (theErr == noErr)
  846.         theErr = paramErr;
  847.         
  848. cleanup:
  849.     if (theMask != NULL)
  850.         DisposeRgn (theMask);
  851.     if (theCIcon != NULL)
  852.         DisposeCIcon (theCIcon);
  853.     if (graphicGWorld != NULL)
  854.         DisposeGWorld (graphicGWorld);
  855.     
  856.     return theErr;
  857.  
  858. }
  859.  
  860.  
  861.  
  862. /*************************************************************************************
  863. TGraphic::EncodeGraphic
  864.  
  865. Takes a previously prepared pixmap and compresses it into our format.
  866. *************************************************************************************/
  867. OSStatus    TGraphic::EncodeGraphic (PixMapHandle theGraphic, Rect *encodeRect)
  868. {
  869.     OSStatus theErr = noErr;
  870.     
  871.     UInt16        shapeHeight;        // the height of the shape
  872.     UInt16        shapeWidth;            // the width of the shape
  873.     
  874.     UInt32        rowBytes;            // the rowbytes of our source pixmap
  875.     UInt8        *baseAddr;            // the base address of the source pixmap
  876.     
  877.     UInt8        *dataPtr;            // points to where we are saving/encoding the data
  878.     UInt8        *sourcePtr;            // points to the graphics data we are saving in our image
  879.     UInt8        *maskPtr;            // points to whichever mask we are currently encoding
  880.     
  881.     UInt8        *sourceStartPtr;    // points to the beginning of a source row.
  882.  
  883.     UInt32        yCounter;            // a counter to scan the shape vertically
  884.     UInt32        xCounter;            // a counter to scan the shape horizontally
  885.  
  886.     Size        newSize;            // used to calculate the size of the new handle.
  887.  
  888.     // We preset the values to make the optimizer happy
  889.     UInt8        *runTokenPtr = NULL;    // where is the token for the current run
  890.     UInt32        runCounter = 0;        // how long is the current run? 
  891.  
  892. // STEP 1 -- precalculate the size of the shape.
  893. // Allocate enough memory to hold the RLE encoded shapes.
  894.  
  895.     shapeHeight = encodeRect->bottom - encodeRect->top;
  896.     shapeWidth = encodeRect->right - encodeRect->left;
  897.     
  898.     // initialize the standard member data for our shape.
  899.     fBounds.left = 0;
  900.     fBounds.top = 0;
  901.     fBounds.right = shapeWidth;
  902.     fBounds.bottom = shapeHeight;
  903.     fFlags = 0;
  904.     fBitDepth = (**theGraphic).pixelSize;
  905.     
  906.     if (fBitDepth != 8)
  907.         SIGNAL_ERROR ("\pError: This encoder only supports 8 bit images")
  908.         
  909.     //the memory totals are for the worse case shape.
  910.     
  911.     fImage = NewHandle (8*shapeHeight * shapeWidth + 4*shapeHeight +4);
  912.     theErr = MemError();
  913.     FAIL_OSERR (theErr, "\pFailed to allocate a handle for the shape data")
  914.     FAIL_NIL (fImage, "\pFailed to allocate a handle for the shape data")
  915.     
  916.     fHitMask = NewHandle (4*shapeHeight * shapeWidth + 4*shapeHeight +4);
  917.     theErr = MemError();
  918.     FAIL_OSERR (theErr, "\pFailed to allocate a handle for the hit mask data")
  919.     FAIL_NIL (fHitMask, "\pFailed to allocate a handle for the hit mask data")
  920.     
  921.     // Get some of the standard data we'll need when encoding the pixels
  922.     
  923.     baseAddr = (UInt8  *)GetPixBaseAddr( theGraphic );
  924.     rowBytes = (*theGraphic)->rowBytes & 0x3fff;
  925.  
  926.  
  927. // STEP 2 -- Encode the shape data.  We use a separate mask rather than using
  928. // chroma keying.  This was mostly done to allow more flexibility in the
  929. // image design, but the other way works very similar.
  930.     
  931.     HLock (fImage);
  932.     dataPtr = (UInt8 *) (*fImage);
  933.     
  934.     sourceStartPtr = baseAddr + rowBytes * encodeRect->top + encodeRect->left;
  935.     
  936.     // scan the shape row by row
  937.     for( yCounter = 0; yCounter < shapeHeight; yCounter++ )
  938.     {
  939.         // store where the line starts, so we can fill in the lineStart token.
  940.         UInt8    *lineStartPtr = dataPtr;
  941.         
  942.         // Flags to determine which run we are currently in.  Initially false,
  943.         // we don't start in a run.
  944.         UInt8    drawRunFlag = false;                // are we in a draw pixels run?
  945.         UInt8    skipRunFlag = false;                // are we in a skip pixels run?
  946.         
  947.         // reserve space for the lineStart token.
  948.         dataPtr += sizeof( UInt32 );
  949.         
  950.         // move to the start of the row and begin scanning the pixels of the row.
  951.         sourcePtr = sourceStartPtr;
  952.         maskPtr = sourceStartPtr + shapeWidth;
  953.             
  954.         for( xCounter = 0; xCounter < shapeWidth; xCounter++ )
  955.         {
  956.             if ( *maskPtr == kClearColorIndex )
  957.             {
  958.                 // Finish the draw run if we are in one.
  959.                 if ( drawRunFlag )
  960.                 {
  961.                     drawRunFlag = false;
  962.                                     
  963.                     // create the draw token, and pad the line to a multiple of four.
  964.                     *( (UInt32 *)runTokenPtr ) = ( kDrawPixelsToken << 24 ) + runCounter;
  965.                                     
  966.                     *( (UInt32 *)dataPtr ) = 0L;
  967.                     dataPtr = (UInt8 *) ALIGN_TO_NEXT_LONG(dataPtr);
  968.                 }
  969.                             
  970.                 // Start a new skip run, or continue the existing one.
  971.                 if ( skipRunFlag )
  972.                 {
  973.                     runCounter++;
  974.                 }
  975.                 else
  976.                 {
  977.                     // start a new skip run
  978.                     skipRunFlag = true;
  979.                     runCounter = 1;
  980.                 }
  981.             }
  982.             else
  983.             {
  984.                 // Finish the skip run, if we're in one.
  985.                 if ( skipRunFlag )
  986.                 {
  987.                     skipRunFlag = false;
  988.                     
  989.                     // create the skip token
  990.                     *( ( UInt32 * )dataPtr ) = ( kSkipPixelsToken << 24 ) + runCounter;
  991.                     dataPtr += sizeof( UInt32 );
  992.                 }
  993.                 
  994.                 // Start a new draw run, or continue the existing one.
  995.                 if ( drawRunFlag )
  996.                 {
  997.                     // continue it
  998.                     runCounter++;
  999.                                     
  1000.                     // copy the pixel
  1001.                     *dataPtr = *sourcePtr;
  1002.                     dataPtr++;
  1003.                 }
  1004.                 else
  1005.                 {
  1006.                     // start one
  1007.                     drawRunFlag = true;
  1008.                     runCounter = 1;
  1009.                                     
  1010.                     // save the location of the token (so we can fill it in later)
  1011.                     runTokenPtr = dataPtr;
  1012.                     dataPtr += sizeof( UInt32 );
  1013.                                     
  1014.                     // copy the pixel
  1015.                     *dataPtr = *sourcePtr;
  1016.                     dataPtr++;
  1017.                 }
  1018.             }
  1019.                     
  1020.             // move to the next pixel
  1021.             sourcePtr++;
  1022.             maskPtr++;
  1023.         }
  1024.         
  1025.         // no need to write a skip at the end of a line, but we do need to finish
  1026.         // up a draw run if that's what we were working on.
  1027.         if( drawRunFlag )
  1028.         {
  1029.             // create the draw token
  1030.             *((UInt32 *) runTokenPtr) = ( kDrawPixelsToken << 24 ) + runCounter;
  1031.                                     
  1032.             // clear and pad to a mulitple of four
  1033.             *((UInt32 *)dataPtr ) = 0L;
  1034.             dataPtr = (UInt8 *) ALIGN_TO_NEXT_LONG(dataPtr);
  1035.         }
  1036.         
  1037.         // finish the line start token, and move to the next row.
  1038.         *( (UInt32 *)lineStartPtr ) = ( kLineStartToken << 24 ) + ( dataPtr - ( lineStartPtr + 4 ) );
  1039.         sourceStartPtr += rowBytes;
  1040.     }
  1041.     
  1042.     // create the end of shape token
  1043.     *((UInt32 *) dataPtr) = kEndShapeToken << 24;
  1044.     dataPtr += sizeof( UInt32 );
  1045.  
  1046.     // Resize the handle to match the real size of the shape
  1047.     HUnlock( fImage );
  1048.     newSize = dataPtr - (UInt8 *)( *fImage );
  1049.     SetHandleSize( fImage, newSize );
  1050.     theErr = MemError();
  1051.     FAIL_OSERR (theErr, "\p Failed to resize the handle")
  1052.     
  1053. // STEP 3-- Encode the Mask data.  Unlike the previous encoder, we don't have to copy any pixel
  1054. // data.
  1055.  
  1056.     HLock (fHitMask);
  1057.     dataPtr = (UInt8 *)( *fHitMask );
  1058.     
  1059.     sourceStartPtr = baseAddr + rowBytes * encodeRect->top + encodeRect->left + shapeWidth+shapeWidth;
  1060.     
  1061.     // scan the shape row by row
  1062.     for( yCounter = 0; yCounter < shapeHeight; yCounter++ )
  1063.     {
  1064.         // we need to store where this line starts so we can fill in the lineStart token later.
  1065.         UInt8    *lineStartPtr = dataPtr;
  1066.         UInt8    drawRunFlag = false;                // are we in a draw pixels run?
  1067.         UInt8    skipRunFlag = false;                // are we in a skip pixels run?
  1068.         
  1069.         // reserve a place for the line start token.
  1070.         dataPtr += sizeof( UInt32 );
  1071.         maskPtr = sourceStartPtr;
  1072.             
  1073.         // scan each pixel of the mask.
  1074.         for( xCounter = 0; xCounter < shapeWidth; xCounter++ )
  1075.         {
  1076.             // is this pixel clear?
  1077.             if ( *maskPtr == kClearColorIndex )
  1078.             {
  1079.                 // are we in a draw run?
  1080.                 if ( drawRunFlag )
  1081.                 {
  1082.                     // end the draw run
  1083.                     drawRunFlag = false;
  1084.                                     
  1085.                     // create the draw token
  1086.                     *( (UInt32 *)dataPtr ) = ( kDrawPixelsToken << 24 ) + runCounter;
  1087.                     dataPtr += sizeof( UInt32 );
  1088.                 }
  1089.                             
  1090.                 // are we in a skip run
  1091.                 if ( skipRunFlag )
  1092.                 {
  1093.                 // continue it
  1094.                     runCounter++;
  1095.                 }
  1096.                 else
  1097.                 {
  1098.                     // start one
  1099.                     skipRunFlag = true;
  1100.                     runCounter = 1;
  1101.                 }
  1102.             }
  1103.             else
  1104.             {
  1105.             // are we in a skip run
  1106.                 if ( skipRunFlag )
  1107.                 {
  1108.                     // end the skip run
  1109.                     skipRunFlag = false;
  1110.                     // create the skip token
  1111.                     *( (UInt32 *)dataPtr ) = ( kSkipPixelsToken << 24 ) + runCounter;
  1112.                     dataPtr += sizeof( UInt32 );
  1113.                 }
  1114.                             
  1115.                 // are we in a draw run
  1116.                 if ( drawRunFlag )
  1117.                 {
  1118.                     // continue it
  1119.                     runCounter++;
  1120.                 }
  1121.                 else
  1122.                 {
  1123.                     // start one
  1124.                     drawRunFlag = true;
  1125.                     runCounter = 1;
  1126.                 }
  1127.             }
  1128.                     
  1129.             // move to the next byte
  1130.                     maskPtr++;
  1131.         }
  1132.         
  1133.         // if we're finishing up a draw run, we need to write out the token
  1134.  
  1135.         if( drawRunFlag )
  1136.         {
  1137.             *( (UInt32 *)dataPtr ) = ( kDrawPixelsToken << 24 ) + runCounter;
  1138.             dataPtr += sizeof( UInt32 );
  1139.         }
  1140.             
  1141.         // create the line start token
  1142.         *( (UInt32 *)lineStartPtr ) = ( kLineStartToken << 24 ) + ( dataPtr - ( lineStartPtr + 4 ) );
  1143.             
  1144.         // move the row start to the next row
  1145.         sourceStartPtr += rowBytes;
  1146.     }
  1147.     
  1148.     // create the end of shape token
  1149.     *( (UInt32 *)dataPtr ) = kEndShapeToken << 24;
  1150.     dataPtr += sizeof( UInt32 );
  1151.     
  1152.     
  1153.     
  1154.     // Resize the handle to match the real size of the shape
  1155.     HUnlock( fHitMask );
  1156.     newSize = dataPtr - (UInt8 *)( *fHitMask );
  1157.     SetHandleSize( fHitMask, newSize );
  1158.     theErr = MemError();
  1159.     FAIL_OSERR (theErr, "\p Failed to resize the handle")
  1160.  
  1161.     goto cleanup;
  1162.  
  1163. error:
  1164.     
  1165.     if (theErr == noErr)
  1166.         theErr = paramErr;
  1167.         
  1168. cleanup:
  1169.     // cleanup is actually the responsibility of the calling function.
  1170.     return theErr;
  1171. }
  1172.     
  1173.     
  1174.  
  1175. /*************************************************************************************
  1176. TGraphic::WriteToGraphicResource
  1177.     
  1178. This takes a previously created graphic and writes out our custom resource format.
  1179. *************************************************************************************/
  1180. OSStatus
  1181. TGraphic::WriteToGraphicResource (void)
  1182. {
  1183.     Handle    graphicResource = NULL;
  1184.     OSStatus    theErr;
  1185.     Size imageSize;
  1186.     Size maskSize;
  1187.     
  1188.     imageSize = GetHandleSize(fImage);
  1189.     theErr = MemError();
  1190.     FAIL_OSERR (theErr, "\pCouldn't obtain image handle size")
  1191.     
  1192.     maskSize = GetHandleSize (fHitMask);
  1193.     theErr = MemError();
  1194.     FAIL_OSERR (theErr, "\pCouldn't obtain mask handle size")
  1195.     
  1196.     graphicResource = NewHandle (sizeof(TGraphicResHeader) + imageSize + maskSize);
  1197.     theErr = MemError();
  1198.     FAIL_OSERR (theErr, "\pCouldn't allocate handle to hold new resource")
  1199.     FAIL_NIL (graphicResource, "\pCouldn't allocate handle to hold new resource")
  1200.     
  1201.     // Now to fill in the header and block move all of the data over into the new resource.
  1202.     
  1203.     (**(TGraphicResHeaderHandle)graphicResource).version   = 0L;
  1204.     (**(TGraphicResHeaderHandle)graphicResource).depth     = fBitDepth;
  1205.     (**(TGraphicResHeaderHandle)graphicResource).flags     = fFlags;
  1206.     (**(TGraphicResHeaderHandle)graphicResource).bounds    = fBounds;
  1207.     (**(TGraphicResHeaderHandle)graphicResource).imageSize = imageSize;
  1208.     (**(TGraphicResHeaderHandle)graphicResource).maskSize  = maskSize;
  1209.     
  1210.     BlockMoveData(*fImage, ((*graphicResource)+sizeof(TGraphicResHeader)), imageSize);
  1211.     BlockMoveData(*fHitMask, ((*graphicResource)+sizeof(TGraphicResHeader)+imageSize), maskSize);
  1212.     
  1213.     // **TO DO:  Check to see if there is already a resource with that ID!
  1214.     
  1215.     // Add the resource to the file.
  1216.     AddResource( graphicResource, kTGraphicResourceType, fResID, "\p" );
  1217.     theErr = ResError();
  1218.     FAIL_OSERR (theErr, "\pFailed to add the TGraphic resource to the file")
  1219.     
  1220.     WriteResource( graphicResource );
  1221.     theErr = ResError();
  1222.     FAIL_OSERR (theErr, "\pError: Failed to write the resource")
  1223.     
  1224.     UpdateResFile (CurResFile());
  1225.     theErr = ResError();
  1226.     
  1227.     ReleaseResource( graphicResource );
  1228.     
  1229.     return theErr;
  1230.     
  1231. error:
  1232.     if (graphicResource != NULL)
  1233.         DisposeHandle (graphicResource);
  1234.     if (theErr == noErr)
  1235.         theErr = paramErr;
  1236.         
  1237.     return theErr;
  1238. }
  1239.  
  1240.  
  1241.  
  1242. /*************************************************************************************
  1243. TGraphic::WriteToPICTResource
  1244.     
  1245. This takes a previously created graphic and writes out a PICT with the 3 images.
  1246. *************************************************************************************/
  1247. OSStatus
  1248. TGraphic::WriteToPICTResource (void)
  1249. {    
  1250.     Rect            pictRect = fBounds;
  1251.     OSStatus        theErr = NULL;
  1252.     GWorldPtr        graphicGWorld = NULL;
  1253.     PixMapHandle     graphicPixMap = NULL;
  1254.     PicHandle        thePicture = NULL;
  1255.         
  1256.     // Create a locked GWorld with the proper depth, dimensions and color table.
  1257.     pictRect.right += (pictRect.right+pictRect.right);
  1258.     
  1259.     theErr = NewGWorld(&graphicGWorld, kPreferredDepth, &pictRect, gAppColorTable, NULL, keepLocal);
  1260.     FAIL_OSERR (theErr, "\pCouldn't allocate GWorld for encoding")
  1261.     graphicPixMap  = GetGWorldPixMap(graphicGWorld);
  1262.     FAIL_NIL (graphicPixMap, "\pCouldn't get the GWorld's PixMap")
  1263.     FAIL_FALSE ( LockPixels(graphicPixMap), "\pCouldn't lock GWorld PixMap")
  1264.     
  1265.     // Erase the GWorld to white and draw the graphics into it.
  1266.     // HACK alert -- this code knows way too much about the information saved off in scaling.cp.
  1267.     // The real way to do this is to have some sort of structure analogous to a grafPort, and
  1268.     // switch the existing destination that way.  Was slated for 1.1, but if that doesn't
  1269.     // happen, I'll move it back into this code.
  1270.     
  1271.     {
  1272.         CGrafPtr savePort;
  1273.         GDHandle saveDevice;
  1274.         
  1275.         Rect             saveRect             = gClipRect;
  1276.         PixMapHandle    saveDestPixMap        = gDestPixMap;
  1277.         PixMapHandle    saveBackPixMap        = gBackPixMap;
  1278.         UInt8            *saveDestBaseAddr    = gDestBaseAddr;
  1279.         UInt8            *saveBackBaseAddr    = gBackBaseAddr;
  1280.         UInt32            saveRowBytes        = gRowBytes;
  1281.  
  1282.         SInt32            top, left;
  1283.         OpenCPicParams    pictParams;
  1284.                 
  1285.         GetGWorld (&savePort, &saveDevice);
  1286.         SetGWorld (graphicGWorld, NULL);
  1287.         
  1288.         ClipRect (&pictRect);
  1289.         EraseRect (&pictRect);
  1290.                 
  1291.         SetDestinationBuffer (graphicPixMap, NULL);
  1292.  
  1293.         // finally, we draw the three images
  1294.         top = fBounds.top;
  1295.         left = fBounds.left;
  1296.         
  1297.         GraphicUnclipped (top, left);
  1298.         left += fBounds.right;
  1299.         DrawMaskUnclipped (top, left);
  1300.         left += fBounds.right;
  1301.         HitMaskUnclipped (top, left);
  1302.         
  1303.         // restore everything 
  1304.         
  1305.         gClipRect = saveRect;
  1306.         gDestPixMap = saveDestPixMap;
  1307.         gBackPixMap = saveBackPixMap;
  1308.         gDestBaseAddr = saveDestBaseAddr;
  1309.         gBackBaseAddr = saveBackBaseAddr;
  1310.         gRowBytes = saveRowBytes;
  1311.         
  1312.         // create the pict
  1313.         pictParams.srcRect = pictRect;
  1314.         pictParams.hRes = 0x00480000;
  1315.         pictParams.vRes = 0x00480000;
  1316.         pictParams.version = -2;
  1317.         pictParams.reserved1 = 0;
  1318.         pictParams.reserved2 = 0;
  1319.         
  1320.         thePicture = OpenCPicture (&pictParams);
  1321.         
  1322.         ClipRect(&pictRect);
  1323.         CopyBits ((BitMap *) *graphicPixMap, (BitMap *) *graphicPixMap, 
  1324.                     &pictRect, &pictRect, srcCopy, NULL);
  1325.         
  1326.         ClosePicture();
  1327.         theErr = QDError();
  1328.         
  1329.         SetGWorld (savePort, saveDevice);
  1330.     }
  1331.     
  1332.     FAIL_NIL (thePicture, "\p Couldn't open the new picture")
  1333.     FAIL_OSERR (theErr, "\pFailed to create new picture")
  1334.     
  1335.     // Add the PICT to the resource fork.
  1336.     
  1337.     AddResource( (Handle) thePicture, 'PICT', fResID, "\p" );
  1338.     theErr = ResError();
  1339.     FAIL_OSERR (theErr, "\pFailed to add the PICT resource to the file")
  1340.     
  1341.     WriteResource( (Handle) thePicture );
  1342.     FAIL_OSERR (theErr, "\pError: Failed to write the resource")
  1343.     
  1344.     UpdateResFile (CurResFile());
  1345.     theErr = ResError();
  1346.     FAIL_OSERR (theErr, "\pError: Failed to update the resource fork")
  1347.     
  1348.     goto cleanup;
  1349.  
  1350. error:
  1351.     if (theErr == noErr)
  1352.         theErr = paramErr;
  1353.         
  1354.  
  1355. cleanup:
  1356.     if (graphicGWorld != NULL)
  1357.         DisposeGWorld (graphicGWorld);
  1358.     
  1359.     if (thePicture != NULL)
  1360.     {
  1361.         SInt8    memState = HGetState((Handle)thePicture);
  1362.         if (memState & 0x20)
  1363.             ReleaseResource ((Handle) thePicture);
  1364.         else
  1365.             DisposeHandle ((Handle) thePicture);
  1366.     }
  1367.     
  1368.     return theErr;
  1369.  
  1370. }
  1371.  
  1372.  
  1373.  
  1374. /*************************************************************************************
  1375. TGraphic::LockGraphic
  1376.  
  1377. Move all fo the data high and lock it down in memory.
  1378. *************************************************************************************/
  1379. OSStatus
  1380. TGraphic::LockGraphic (void)
  1381. {
  1382.     OSStatus theErr;
  1383.     MoveHHi (fImage);
  1384.     theErr = MemError();
  1385.     FAIL_OSERR (theErr, "\pFailed to move the draw data high")
  1386.     HLock (fImage);
  1387.     theErr = MemError();
  1388.     FAIL_OSERR (theErr, "\pFailed to lock the draw data")
  1389.  
  1390.     MoveHHi (fHitMask);
  1391.     theErr = MemError();
  1392.     FAIL_OSERR (theErr, "\pFailed to move the mask data high")
  1393.     HLock (fHitMask);
  1394.     theErr = MemError();
  1395.     FAIL_OSERR (theErr, "\pFailed to lock the mask data")    
  1396.     return noErr;
  1397.     
  1398.     error:
  1399.     return theErr;
  1400. }
  1401.  
  1402.  
  1403. /*************************************************************************************
  1404. TGraphic::UnlockGraphic
  1405.     
  1406. Unlock the previously locked memory.
  1407. *************************************************************************************/
  1408.  
  1409. OSStatus
  1410. TGraphic::UnlockGraphic (void)
  1411. {
  1412.     OSStatus theErr;
  1413.     HUnlock (fImage);
  1414.     theErr = MemError();
  1415.     FAIL_OSERR (theErr, "\pFailed to unlock the draw data")
  1416.     HUnlock (fHitMask);
  1417.     theErr = MemError();
  1418.     FAIL_OSERR (theErr, "\pFailed to unlock the draw data")    
  1419.     return noErr;
  1420.     
  1421.     error:
  1422.     
  1423.     return theErr;
  1424. }
  1425.  
  1426.  
  1427.  
  1428.  
  1429.  
  1430.  
  1431. /*************************************************************************************
  1432. TGraphic::CopyImage
  1433.  
  1434. This routine checks against the clipping rectangle and dispatches to the correct
  1435. utility routine.
  1436. *************************************************************************************/
  1437. void
  1438. TGraphic::CopyImage (SInt32 top, SInt32 left, Boolean useBackground)
  1439. {
  1440. #if qDebugging
  1441.     if (gDestPixMap == NULL)
  1442.         SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap")
  1443.         
  1444.     if (useBackground && (gBackPixMap == NULL))
  1445.         SIGNAL_ERROR ("\pAttepting to draw from an NULL background pixmap.")
  1446.         
  1447.     if (EmptyRect (&gClipRect))
  1448.         SIGNAL_ERROR ("\pEmpty Clipping Region")
  1449. #endif
  1450.     // We'll do all our calculations in variables rather than use a structure.
  1451.     // hopefully this should speed things up
  1452.     SInt32 destTop, destBottom, destLeft, destRight;
  1453.     
  1454.     destTop    = fBounds.top + top;
  1455.     destBottom = fBounds.bottom + top;
  1456.     destLeft   = fBounds.left + left;
  1457.     destRight  = fBounds.right + left;
  1458.     
  1459.     // determine if the spite needs to be drawn at all
  1460.     if    (destTop >= gClipRect.bottom || destBottom <= gClipRect.top ||
  1461.          destLeft >= gClipRect.right || destRight <= gClipRect.left )
  1462.         // no need to draw, goodbye
  1463.         return;
  1464.     
  1465.     // determine if the sprite will be clipped
  1466.     if     (destTop < gClipRect.top || destBottom > gClipRect.bottom ||
  1467.          destLeft < gClipRect.left || destRight > gClipRect.right)
  1468.     {
  1469.         // calculate the clipped bounding box in object local coordinates
  1470.         UInt32 clipTop, clipBottom, clipLeft, clipRight;
  1471.                 
  1472.         clipTop    = destTop < gClipRect.top       ? gClipRect.top - destTop  : 0;
  1473.         clipBottom = destBottom > gClipRect.bottom ? gClipRect.bottom-destTop : destBottom-destTop;
  1474.         clipLeft   = destLeft < gClipRect.left     ? gClipRect.left-destLeft  : 0;
  1475.         clipRight  = destRight > gClipRect.right   ? gClipRect.right-destLeft : destRight-destLeft;
  1476.  
  1477.         if (useBackground)
  1478.             BackgroundClipped (destTop, destLeft, clipLeft, clipRight, clipTop, clipBottom);
  1479.         else
  1480.             GraphicClipped(destTop, destLeft, clipLeft, clipRight, clipTop, clipBottom );
  1481.     }
  1482.     else
  1483.     {
  1484.         if (useBackground)
  1485.             BackgroundUnclipped (destTop, destLeft);
  1486.         else
  1487.             GraphicUnclipped(destTop, destLeft );
  1488.     }
  1489.  
  1490. error:
  1491.     return;
  1492. }
  1493.  
  1494.  
  1495. /*************************************************************************************
  1496. TGraphic::HitTest
  1497.     
  1498. This code walks the mask and returns true if the point intersects inside the mask.
  1499.  
  1500. We make sure the point is inside the rectangle.  If it in, we find the line in the
  1501. shape that corresponds to that point and walk it, looking for lines inside the mask.
  1502.  
  1503. Note that on the right side, we test greater than or equal, and on the left we only
  1504. test less than.  This is because the point that corresponds to a coord goes down and
  1505. to the left.  Think about it and you'll understand. :-)
  1506. *************************************************************************************/
  1507. Boolean
  1508. TGraphic::HitTest (SInt32 v, SInt32 h)
  1509. {    
  1510.     if( v >= fBounds.bottom || v < fBounds.top ||
  1511.         h >= fBounds.right || h < fBounds.left )
  1512.     {
  1513.         return false;
  1514.     }
  1515.     
  1516.     // Our standard things to read the sprite
  1517.     UInt8 *dataPtr;
  1518.     UInt32 tokenOp;
  1519.     UInt32 tokenData;
  1520.     
  1521.     // We use these to count where we are in the image, to move to our point.
  1522.         
  1523.     UInt32 yCount = 0;
  1524.     UInt32 xCount = 0; 
  1525.     
  1526.     // Move to the start of our hit testing data
  1527.     dataPtr = (UInt8 *)(*fHitMask);
  1528.  
  1529.     // Do a quick walk to the line which holds the point.
  1530.     while (v > 0)
  1531.     {
  1532.         v--;
  1533.         tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
  1534.             
  1535.         dataPtr += sizeof( UInt32 );
  1536.         dataPtr += tokenData;
  1537.     }
  1538.     
  1539.     // Skip the newLine token
  1540.     dataPtr += sizeof( UInt32 );
  1541.         
  1542.     // Start reading draw commands.  Any end or newLine tokens mean we're done.
  1543.     // We'll exit out of the While loop via a return.
  1544.     do 
  1545.     {
  1546.         // get a token
  1547.         tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
  1548.         tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
  1549.         dataPtr += sizeof( UInt32 );
  1550.             
  1551.         // depending on the token, we take an action
  1552.         
  1553.         // Note that line starts will be very common to begin with, so we'll move them up to the top
  1554.         switch( tokenOp )
  1555.         {
  1556.             case kHitTestPixelsToken:
  1557.  
  1558.     // We can only generate a hit in a draw command.  If our point is between
  1559.     // xCount and xCount+tokenData, then it is on a drawn line, so return true.
  1560.                 if ((xCount <= h) && (xCount+tokenData>h))
  1561.                     return true;
  1562.                 else if (xCount > h)
  1563.                     return false;
  1564.                 xCount += tokenData;
  1565.                 
  1566.                 break;
  1567.                     
  1568.             case kSkipPixelsToken:
  1569.                     
  1570.                 xCount += tokenData;
  1571.                         
  1572.                 if (xCount > h)
  1573.                     return false;
  1574.                             
  1575.                 break;
  1576.                     
  1577.             case kLineStartToken:
  1578.             case kEndShapeToken:
  1579.                 return false;
  1580. #if qDebugging        
  1581.             default:
  1582.                 SIGNAL_ERROR ("\pInvalid TGraphic drawing operation")
  1583.                 break;
  1584. #endif
  1585.         }
  1586.     } while ( true );
  1587.  
  1588. error:
  1589. return false;
  1590. }
  1591.  
  1592.  
  1593.  
  1594. /*************************************************************************************
  1595. TGraphic::Intersect
  1596.     
  1597. This compares two TGraphic objects and two points in the SAME coordinate system
  1598. and returns true if any two drawing commands intersect in the two objects.
  1599. *************************************************************************************/
  1600.  
  1601.  
  1602. Boolean TGraphic::Intersect (TGraphic *object1, TGraphic *object2, SInt32 v1, SInt32 h1, SInt32 v2, SInt32 h2)
  1603. {
  1604.     SInt32         differenceX, differenceY;
  1605.     
  1606.     SInt32        object1right, object1bottom;
  1607.     SInt32        object2top, object2bottom, object2left, object2right;
  1608.     
  1609.     UInt32        xIntersectLeft, xIntersectRight, yHeight;
  1610.     
  1611.     Boolean        intersect = false;
  1612.     
  1613.     // First, we sort the two objects in order of the x coordinate.
  1614.     
  1615.     if (h2 < h1)
  1616.     {
  1617.         SInt32 tempNum;
  1618.         TGraphic *tempGraphic;
  1619.         
  1620.         tempGraphic = object1; object1 = object2; object2 = tempGraphic;
  1621.  
  1622.         tempNum = h2; h2 = h1; h1 = tempNum;
  1623.         tempNum = v2; v2 = v1; v1 = tempNum;
  1624.     }
  1625.  
  1626.     // Next we calculate the bounding boxes of the two graphics and check to see if they overlap.
  1627.     // if they don't we can drop out and exit.
  1628.     
  1629.     differenceX = h2-h1;
  1630.     differenceY = v2-v1;
  1631.     // create two rectangles based on the object locations.
  1632.     
  1633.     object1right = (object1->fBounds).right;
  1634.     object1bottom = (object1->fBounds).bottom;
  1635.     
  1636.     object2left = differenceX;
  1637.     object2right = object2->fBounds.right + differenceX;
  1638.     object2top = differenceY;
  1639.     object2bottom = object2->fBounds.bottom + differenceY;
  1640.  
  1641.     if (object2bottom <= 0 || object2top >= object1bottom ||
  1642.         object2left >= object1right)
  1643.         goto done;
  1644.  
  1645.     // Next we want to do some calculations that we'll use to parse the list.  Basically, we are
  1646.     // determining the coordinates we're going to use for to search for an intersection.
  1647.     
  1648.     xIntersectLeft = object2left;
  1649.     xIntersectRight = object1right > object2right  ? object2right  :  object1right;
  1650.     
  1651.     {
  1652.         UInt32 yTop, yBottom;
  1653.     
  1654.         yTop    = object2top    > 0             ? object2top     :     0;
  1655.         yBottom = object1bottom > object2bottom ? object2bottom  :     object1bottom;
  1656.  
  1657.         yHeight = yBottom-yTop; // the number of row's we'll need to test.
  1658.     }
  1659.             
  1660. // These will hold whichever command we are looking at.
  1661.     UInt32 tokenOp;
  1662.     UInt32 tokenData;
  1663.     
  1664.     // These will hold our current pointers to commands for both objects.
  1665.     UInt8 *dataPtr1, *dataPtr2;
  1666.     
  1667.     // We'll precalculate the pointers for the next line, to make it easier to change
  1668.     // both objects at the same time.
  1669.     
  1670.     UInt8 *nextDataPtr1, *nextDataPtr2;
  1671.     
  1672.     // Whenever we hit an end of line, we need to drop out and make sure both data pointers are incremented.
  1673.         
  1674.     UInt8 lineDone = false;
  1675.     
  1676.     // We occasionally need to drop out of just the inner loop -- we'll set this to true.
  1677.     
  1678.     UInt8 innerObjectDone = false;
  1679.     
  1680.     // These count where we're at in each of the two object's scanlines.
  1681.     
  1682.     UInt32 xCount1 = 0, xCount2 = 0;
  1683.  
  1684.  
  1685.  
  1686.     // move to the start of each shape's data.
  1687.     dataPtr1 = (UInt8 *)(*(object1->fHitMask));
  1688.     dataPtr2 = (UInt8 *)(*(object2->fHitMask));
  1689.  
  1690.     // One of the two objects will probably need to be advanced in the vertical coordinate to put us
  1691.     // in the correct position.  We'll count out a number of skips equal to the previous y difference
  1692.     // we calculated.
  1693.     // now we need to skip lines until we get to the correct starting location for each shape.
  1694.     // With the current encoder, all objects start with startline commands.  So we'll cound out a number
  1695.     // of skips equal to the intersection rect's top Y coordinate.
  1696.     if (differenceY > 0)
  1697.         do
  1698.         {
  1699.             tokenData = ( *( (UInt32 *)dataPtr1 ) ) & 0x00ffffff;
  1700.             
  1701.             dataPtr1 += sizeof( UInt32 );
  1702.             dataPtr1 += tokenData;
  1703.         }
  1704.         while (--differenceY > 0);
  1705.     else
  1706.         while (differenceY++ < 0)
  1707.         {
  1708.             tokenData = ( *( (UInt32 *)dataPtr2 ) ) & 0x00ffffff;
  1709.             
  1710.             dataPtr2 += sizeof( UInt32 );
  1711.             dataPtr2 += tokenData;
  1712.         }
  1713.     // Now we're ready to begin.  For the most part, we loop inside object1 looking for a draw command
  1714.     // inside the intersected area.  If we find one, then we run a second loop inside this, looking
  1715.     // for a draw commmand in object2 that intersects the one from object1.  If we find one, we return
  1716.     // true.  If we hit the end of the shape, or the intersected area, we return false.
  1717.     
  1718.     // If we hit the end of a particular line, then we drop out of both loops and advance the pointers
  1719.     // appropriately, and run the next line.
  1720.     
  1721.     do 
  1722.     {
  1723.     // First, we retrieve the start of line command for each of the objects -- from this we can
  1724.     // calculate the pointers for the next scanline, which we use when we drop out of the search
  1725.     // loops.  
  1726.         tokenOp = ( *( (UInt32 *)dataPtr1 ) ) >> 24;
  1727.         tokenData = ( *( (UInt32 *)dataPtr1 ) ) & 0x00ffffff;
  1728.             
  1729.         dataPtr1 += sizeof( UInt32 );
  1730.         nextDataPtr1 = dataPtr1+ tokenData;
  1731.         
  1732.         tokenOp = ( *( (UInt32 *)dataPtr2 ) ) >> 24;
  1733.         tokenData = ( *( (UInt32 *)dataPtr2 ) ) & 0x00ffffff;
  1734.             
  1735.         dataPtr2 += sizeof( UInt32 );
  1736.         nextDataPtr2 = dataPtr2+ tokenData;
  1737.         
  1738.         // reset our booleans and our horizontal positions.
  1739.         lineDone = false;
  1740.         xCount1 = 0;
  1741.         xCount2 = xIntersectLeft;
  1742.         
  1743.  
  1744.         
  1745.         while (!lineDone)
  1746.         {
  1747.         // Loop in object1 looking for a draw command inside the intersected area.  If we hit the end
  1748.         // of our intersected area or a new line token, we'll drop out of the loop.
  1749.         // Get the next operation
  1750.             tokenOp = ( *( (UInt32 *)dataPtr1 ) ) >> 24;
  1751.             tokenData = ( *( (UInt32 *)dataPtr1 ) ) & 0x00ffffff;
  1752.             
  1753.             dataPtr1 += sizeof( UInt32 );
  1754.         
  1755.             switch (tokenOp)
  1756.             {
  1757.                 case kHitTestPixelsToken:
  1758.                     // kDrawPixels is the ugly token to parse, because if the drawing command
  1759.                     // is inside the intersected area, we have to run ANOTHER loop for object 2.
  1760.                     {
  1761.                     UInt32 x1RightDraw = xCount1+tokenData;
  1762.                     UInt32 x1LeftDraw = xCount1;
  1763.                     // skip to next command
  1764.                     
  1765.                     // if we're still to the left of our intersection, skip to next set
  1766.                     if (x1RightDraw <= xIntersectLeft)
  1767.                         break;
  1768.                         
  1769.                     // pin left side to intersection
  1770.                     if (x1LeftDraw < xIntersectLeft)
  1771.                         x1LeftDraw = xIntersectLeft;
  1772.                         
  1773.                     // pin to right side to intersection
  1774.                     if (x1RightDraw > xIntersectRight)
  1775.                         x1RightDraw = xIntersectRight;
  1776.                     
  1777.                     // Now we loop inside of object 2 until we find an intersecting draw command
  1778.                     // or skip past object1's draw area.
  1779.                     innerObjectDone = false;
  1780.                     
  1781.                     while (!(lineDone || innerObjectDone)) 
  1782.                     {
  1783.                         tokenOp = ( *( (UInt32 *)dataPtr2 ) ) >> 24;
  1784.                         tokenData = ( *( (UInt32 *)dataPtr2 ) ) & 0x00ffffff;
  1785.                         
  1786.                         switch (tokenOp)
  1787.                         {
  1788.                             case kHitTestPixelsToken:
  1789.                                 // Now we can finally check for an intersection!!
  1790.                                     
  1791.                                 if (!(((xCount2 <= x1LeftDraw) && (xCount2+tokenData <= x1LeftDraw)) ||
  1792.                                       ((xCount2 >= x1RightDraw) && (xCount2+tokenData > x1RightDraw))))
  1793.                                 {
  1794.                                     intersect = true;
  1795.                                     goto done;
  1796.                                 }
  1797.                                     
  1798.                                 // if we are to the right of object1's drawing command, then we drop out of
  1799.                                 // the object2 loop.  Note that in this case we do not advance to the next
  1800.                                 // draw command in object2, as we might need to check the next drawing command
  1801.                                 // in object1 against it.
  1802.                                     
  1803.                                 if (xCount2+tokenData >= x1RightDraw)
  1804.                                 {
  1805.                                     innerObjectDone = true;
  1806.                                 }
  1807.                                 else
  1808.                                 {
  1809.                                     xCount2 += tokenData;
  1810.                                     dataPtr2 += sizeof( UInt32 );
  1811.                                 }
  1812.                                 break;
  1813.                                 
  1814.                             case kSkipPixelsToken:
  1815.                                 xCount2 += tokenData;
  1816.                                 dataPtr2 += sizeof( UInt32 );
  1817.                                 if (xCount2 > xIntersectRight)
  1818.                                     innerObjectDone = true;
  1819.                                 break;
  1820.                                 
  1821.                             case kLineStartToken:
  1822.                                 lineDone = true;
  1823.                                 break;
  1824.                             case kEndShapeToken:
  1825.                                 goto done;
  1826.                                 break;
  1827. #if qDebugging
  1828.                             default:
  1829.                                 Debugger();
  1830.                                 break;
  1831. #endif
  1832.                         } // end inner switch
  1833.                     } // end inner while loop
  1834.                     
  1835.                     // and make sure we exit if were at the end of the line in object1.
  1836.                     if (xCount1 >= xIntersectRight)
  1837.                         lineDone = true;
  1838.                     }
  1839.                     break;
  1840.                     
  1841.                 case kSkipPixelsToken:
  1842.                     xCount1 += tokenData;
  1843.                     if (xCount1 >= xIntersectRight)
  1844.                         lineDone = true;
  1845.                     break;
  1846.                 case kLineStartToken:
  1847.                     lineDone = true;
  1848.                     break;
  1849.                 case kEndShapeToken:
  1850.                     goto done;
  1851.                     break;
  1852. #if qDebugging
  1853.                 default:
  1854.                     Debugger();
  1855.                     break;
  1856. #endif
  1857.             }
  1858.         }            
  1859.         // skip to the next line for both and increment the count.
  1860.         dataPtr1 = nextDataPtr1;
  1861.         dataPtr2 = nextDataPtr2;
  1862.     } while (--yHeight > 0);
  1863.     
  1864.     
  1865.     done: 
  1866.     // If we got this far, we've dropped out of the bottom of the intersect area. 
  1867.     return intersect;
  1868. }
  1869.  
  1870.  
  1871.  
  1872. /*************************************************************************************
  1873. TGraphic::GraphicClipped
  1874. *************************************************************************************/
  1875.     
  1876. void
  1877. TGraphic::GraphicClipped (SInt32 top, SInt32 left, UInt32 clipLeft, UInt32 clipRight,
  1878.                           UInt32 clipTop, UInt32 clipBottom)
  1879.  
  1880. // This routine is almost identical to the one from Tips of the Mac Game Programming Gurus.
  1881. {
  1882.     UInt8    *rowStart;        // the pointer to the start of this row
  1883.     UInt8    *srcPtr;        // the current position in the sprite data
  1884.     UInt8    *destPtr;        // the current position in the destination pixmap
  1885.     UInt32    miscCounter;    // a counter for various purposes
  1886.     UInt32    extraCounter;    // a counter for right clippling purposes ( how much extra was there? )
  1887.     UInt32    tokenOp;        // the op code from the token
  1888.     UInt32    tokenData;        // the data from the token
  1889.     UInt32    yCount;            // how many lines do we have left to scan.
  1890.     UInt32    xCount;            // where are we in this line?
  1891.     
  1892.     // Determine the actual clipping area we're going to need to draw, we do these as UInt32s because
  1893.     // that's what we'll use when drawing.
  1894.         
  1895.     // set up the initial count of rows we'll want to search
  1896.     yCount = clipBottom-clipTop;
  1897.  
  1898.     // determine characteristics about the pixmap
  1899.     rowStart = gDestBaseAddr + (top + clipTop) * gRowBytes + left;
  1900.  
  1901.     // move to the start of the image data.  We'll do a quick skip of any initial pixel rows that we don't
  1902.     // need to worry about.
  1903.     srcPtr = (UInt8 *)( *fImage);
  1904.  
  1905.     // We do this to get rid of an optimizer error.  Normally, the destPtr and xCount get
  1906.     // set as part of the first token that gets interpreted by the loop.
  1907.     
  1908. #if qDebugging
  1909.     destPtr = (UInt8 *)0xDDDDDDDD;
  1910. #else
  1911.     destPtr = rowStart;
  1912. #endif    
  1913.     xCount = 0;  
  1914.  
  1915.     while (clipTop > 0)
  1916.     {
  1917.         clipTop--;
  1918.         tokenData = ( *( (UInt32 *)srcPtr ) ) & 0x00ffffff;
  1919.         srcPtr += sizeof( UInt32 ) + tokenData;
  1920.     }
  1921.     
  1922.     // start the loop
  1923.     do
  1924.     {
  1925.         // get a token
  1926.         tokenOp = ( *( (UInt32 *)srcPtr ) ) >> 24;
  1927.         tokenData = ( *( (UInt32 *)srcPtr ) ) & 0x00ffffff;
  1928.         srcPtr += sizeof( UInt32 );
  1929.             
  1930.         // depending on the token
  1931.         switch( tokenOp )
  1932.         {
  1933.             case kDrawPixelsToken:
  1934.                 miscCounter = tokenData;
  1935.                 extraCounter = 0;
  1936.                         
  1937.                 // if we need to, clip to the left
  1938.                 if( xCount < clipLeft )
  1939.                 {
  1940.                     // if this run does not appear at all, don't draw it
  1941.                     if ( miscCounter < clipLeft - xCount )
  1942.                     {
  1943.                         destPtr += miscCounter;
  1944.                         xCount += miscCounter;
  1945.                         miscCounter = ALIGN_TO_NEXT_LONG(miscCounter);                    
  1946.                         srcPtr += miscCounter;
  1947.  
  1948.                         break;
  1949.                     }
  1950.                     else
  1951.                     {
  1952.                         // if it does, skip to where we can draw
  1953.                         miscCounter -= clipLeft - xCount;
  1954.                         destPtr += clipLeft - xCount;
  1955.                         srcPtr += clipLeft - xCount;
  1956.                         xCount = clipLeft;
  1957.                     }
  1958.                 }
  1959.                         
  1960.                 // if we need to, clip to the right
  1961.                 if ( xCount + miscCounter > clipRight )
  1962.                 {
  1963.                     // if this run does not appear at all, skip it
  1964.                     if ( xCount > clipRight )
  1965.                     {
  1966.                         // once xCount is greater than xRight, no drawing commands will ever
  1967.                         // be issued on that line, so I changed the "gurus" code, which was actually
  1968.                         // wasting a couple of instructions setting variables that aren't needed.
  1969.                         //destPtr += miscCounter;
  1970.                         //xCount += miscCounter;
  1971.                         miscCounter = ALIGN_TO_NEXT_LONG(miscCounter);                    
  1972.                         srcPtr += miscCounter;
  1973.                         break;
  1974.                     }
  1975.                     else
  1976.                     {
  1977.                         // if it does, setup to draw what we can
  1978.                         extraCounter = (xCount + miscCounter) - clipRight;
  1979.                         miscCounter -= extraCounter;
  1980.                     }
  1981.                 }
  1982.                 
  1983.                 // adjust xCount for the run
  1984.                 xCount += miscCounter;
  1985.                         
  1986.                 // This blit loop is optimized to move 32 bytes or less.  On 604 machines, using an 8 byte move
  1987.                 // is faster in those rare cases where you can get them to align, and way slower when they don't.
  1988.                 // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
  1989.                 
  1990.                 
  1991.                 {
  1992.                 register UInt32 sixteenblits, blitloop;
  1993.                 sixteenblits = miscCounter >> 4;
  1994.                 for ( blitloop = 0; blitloop < sixteenblits; blitloop++)
  1995.                 {
  1996.                         register UInt32 temp1, temp2, temp3, temp4;
  1997.                         temp1 = ((UInt32 *) srcPtr)[0];
  1998.                         temp2 = ((UInt32 *) srcPtr)[1];
  1999.                         temp3 = ((UInt32 *) srcPtr)[2];
  2000.                         temp4 = ((UInt32 *) srcPtr)[3];
  2001.                         ((UInt32 *) destPtr)[0] = temp1;
  2002.                         ((UInt32 *) destPtr)[1] = temp2;
  2003.                         ((UInt32 *) destPtr)[2] = temp3;
  2004.                         ((UInt32 *) destPtr)[3] = temp4;
  2005.                         srcPtr += 16;
  2006.                         destPtr += 16;
  2007.                 }
  2008.                 // move any remaining data, up to 15 bytes total
  2009.                 if (miscCounter & 0x8)
  2010.                 {
  2011.                     register UInt32 temp1, temp2;
  2012.                     temp1 = ((UInt32 *) srcPtr)[0];
  2013.                     temp2 = ((UInt32 *) srcPtr)[1];
  2014.                     ((UInt32 *) destPtr)[0] = temp1;
  2015.                     ((UInt32 *) destPtr)[1] = temp2;
  2016.                     srcPtr += 8;
  2017.                     destPtr += 8;
  2018.                 }
  2019.                 if (miscCounter & 0x4)
  2020.                 {
  2021.                     register UInt32 temp1;
  2022.                     temp1 = *((UInt32 *) srcPtr);
  2023.                     srcPtr +=4;
  2024.                     *((UInt32 *) destPtr)  = temp1;
  2025.                     destPtr +=4;
  2026.                 }
  2027.                 if (miscCounter & 0x2)
  2028.                 {
  2029.                     register UInt16 temp1;
  2030.                     temp1 = *((UInt16 *) srcPtr);
  2031.                     srcPtr +=2;
  2032.                     *((UInt16 *) destPtr)  = temp1;
  2033.                     destPtr +=2;
  2034.                 }
  2035.                 if (miscCounter & 0x1)
  2036.                     *destPtr++ = *srcPtr++;
  2037.         
  2038.                 }
  2039.                         
  2040.                 // adjust for right clipping
  2041.                 destPtr += extraCounter;
  2042.                 srcPtr += extraCounter;
  2043.                 xCount += extraCounter;
  2044.                         
  2045.                 // adjust for the padding
  2046.                 srcPtr = (UInt8 *) ALIGN_TO_NEXT_LONG(srcPtr);    
  2047.                 break;
  2048.                         
  2049.             case kSkipPixelsToken:
  2050.                 destPtr += tokenData;
  2051.                 xCount += tokenData;
  2052.                 break;
  2053.                         
  2054.             case kLineStartToken:
  2055.                 // check to see if we're done drawing
  2056.                 if (yCount == 0)
  2057.                     return;
  2058.                 else
  2059.                 {
  2060.                     // set all the counters up
  2061.                     yCount--;
  2062.                     xCount = 0;
  2063.                     // set up the destination pointer
  2064.                     destPtr = rowStart;
  2065.                     rowStart += gRowBytes;
  2066.                 }
  2067.                 break;
  2068.                         
  2069.             case kEndShapeToken:
  2070.                 // exit.
  2071.                 return;
  2072.                 break;
  2073. #if qDebugging                        
  2074.             default:
  2075.                 // we should never get here
  2076.                 Debugger();
  2077.                 break;
  2078. #endif
  2079.         }
  2080.     } while (true);
  2081. }
  2082.  
  2083.  
  2084. /*************************************************************************************
  2085. TGraphic::GraphicUnclipped
  2086. *************************************************************************************/
  2087.  
  2088. void 
  2089. TGraphic::GraphicUnclipped (SInt32 top, SInt32 left)
  2090. {
  2091. // This routine is almost identical to the one from Tips of the Mac Game Programming Gurus.
  2092.  
  2093.     UInt8 *rowStart;        // the pointer to the start of this row
  2094.     UInt8 *srcPtr;            // the current position in the sprite data
  2095.     UInt8 *destPtr;            // the current position in the destination pixmap
  2096.     UInt32 miscCounter;        // a counter for various purposes
  2097.     UInt32 tokenOp;            // the op code from the token
  2098.     UInt32 tokenData;        // the data from the token
  2099.  
  2100.  
  2101. // If we are debugging and we have an invalid graphic, then destPtr might never be set
  2102. // up correctly.  This will force us to attempt to write to a bad location in memory.
  2103.     
  2104.     // determine characteristics about the pixmap
  2105.     rowStart = gDestBaseAddr + top * gRowBytes + left;
  2106.     
  2107.     // move to the start of the image data.
  2108.     srcPtr = (UInt8 *)( *fImage );
  2109.     
  2110. #if qDebugging
  2111.     destPtr = (UInt8 *) 0xDDDDDDDD;
  2112. #else
  2113.     destPtr = rowStart;
  2114. #endif    
  2115.     
  2116.     // Start looping
  2117.     do
  2118.     {
  2119.         // get a token
  2120.         tokenOp = ( *( (UInt32 *)srcPtr ) ) >> 24;
  2121.         tokenData = ( *( (UInt32 *)srcPtr ) ) & 0x00ffffff;
  2122.         srcPtr += sizeof( UInt32 );
  2123.             
  2124.         // depending on the token
  2125.         switch( tokenOp )
  2126.         {
  2127.             case kDrawPixelsToken:
  2128.                 miscCounter = tokenData;
  2129.                 
  2130.                 // This blit loop is optimized to move 32 bytes or less.  On 604 machines, using an 8 byte move
  2131.                 // is faster in those rare cases where you can get them to align, and way slower when they don't.
  2132.                 // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
  2133.                 
  2134.                 
  2135.                 {
  2136.                 register UInt32 sixteenblits, blitloop;
  2137.                 sixteenblits = miscCounter >> 4;
  2138.                 for ( blitloop = 0; blitloop < sixteenblits; blitloop++)
  2139.                 {
  2140.                         register UInt32 temp1, temp2, temp3, temp4;
  2141.                         temp1 = ((UInt32 *) srcPtr)[0];
  2142.                         temp2 = ((UInt32 *) srcPtr)[1];
  2143.                         temp3 = ((UInt32 *) srcPtr)[2];
  2144.                         temp4 = ((UInt32 *) srcPtr)[3];
  2145.                         ((UInt32 *) destPtr)[0] = temp1;
  2146.                         ((UInt32 *) destPtr)[1] = temp2;
  2147.                         ((UInt32 *) destPtr)[2] = temp3;
  2148.                         ((UInt32 *) destPtr)[3] = temp4;
  2149.                         srcPtr += 16;
  2150.                         destPtr += 16;
  2151.                 }
  2152.                 // move any remaining data, up to 15 bytes total
  2153.                 if (miscCounter & 0x8)
  2154.                 {
  2155.                     register UInt32 temp1, temp2;
  2156.                     temp1 = ((UInt32 *) srcPtr)[0];
  2157.                     temp2 = ((UInt32 *) srcPtr)[1];
  2158.                     ((UInt32 *) destPtr)[0] = temp1;
  2159.                     ((UInt32 *) destPtr)[1] = temp2;
  2160.                     srcPtr += 8;
  2161.                     destPtr += 8;
  2162.                 }
  2163.                 if (miscCounter & 0x4)
  2164.                 {
  2165.                     register UInt32 temp1;
  2166.                     temp1 = *((UInt32 *) srcPtr);
  2167.                     srcPtr +=4;
  2168.                     *((UInt32 *) destPtr)  = temp1;
  2169.                     destPtr +=4;
  2170.                 }
  2171.                 if (miscCounter & 0x2)
  2172.                 {
  2173.                     register UInt16 temp1;
  2174.                     temp1 = *((UInt16 *) srcPtr);
  2175.                     srcPtr +=2;
  2176.                     *((UInt16 *) destPtr)  = temp1;
  2177.                     destPtr +=2;
  2178.                 }
  2179.                 if (miscCounter & 0x1)
  2180.                     *destPtr++ = *srcPtr++;
  2181.         
  2182.                 }
  2183.                 
  2184.                 // adjust for the padding
  2185.                 srcPtr = (UInt8 *) ALIGN_TO_NEXT_LONG(srcPtr);    
  2186.                 break;
  2187.                         
  2188.             case kSkipPixelsToken:
  2189.                 destPtr += tokenData;
  2190.                 break;
  2191.                         
  2192.             case kLineStartToken:
  2193.                 // set up the destination pointer
  2194.                 destPtr = rowStart;
  2195.                 rowStart += gRowBytes;
  2196.                 break;
  2197.                         
  2198.             case kEndShapeToken:
  2199.                 // exit the routine
  2200.                 return;
  2201.                 break;
  2202. #if qDebugging
  2203.             default:
  2204.                 // we should never get here
  2205.                 Debugger();
  2206.                 break;
  2207. #endif
  2208.         }
  2209.     }    while( true );
  2210. }
  2211.  
  2212.  
  2213. /*************************************************************************************
  2214. TGraphic::BackgroundClipped
  2215.     
  2216. The Background routines work similarly to the standard graphic drawing routines,
  2217. but we keep an additional pointer to the destination graphics world, and we draw from
  2218. it, not the graphic data.  Later, we might optimize this routine further as we know
  2219. the two are always in sync.
  2220. *************************************************************************************/
  2221.  
  2222.  
  2223. void
  2224. TGraphic::BackgroundClipped (SInt32 top, SInt32 left, UInt32 clipLeft, UInt32 clipRight, 
  2225.                              UInt32 clipTop, UInt32 clipBottom)
  2226. {
  2227.     UInt8 *sourceRowStart;    // the pointer to the start of this row in the source
  2228.     UInt8 *destRowStart;    // the pointer to the start of this row in the dest
  2229.     UInt8 *srcPtr;            // the current position in the source pixmap
  2230.     UInt8 *destPtr;            // the current position in the destination pixmap
  2231.     UInt8 *dataPtr;            // the current position in the sprite data;
  2232.     UInt32 miscCounter;        // a counter for various purposes
  2233.     UInt32 extraCounter;    // a counter for right clippling purposes ( how much extra was there? )
  2234.     UInt32 tokenOp;            // the op code from the token
  2235.     UInt32 tokenData;        // the data from the token
  2236.     UInt32 yCount;            // how many lines do we still have to draw
  2237.     UInt32 xCount;            // where are we in this line?
  2238.  
  2239.     // determine characteristics about the pixmap
  2240.     sourceRowStart = gBackBaseAddr + (top + clipTop) * gRowBytes + left;
  2241.     destRowStart   = gDestBaseAddr + (top + clipTop) * gRowBytes + left;
  2242.     
  2243.     // move to the start of the image data.  We'll do a quick skip of any initial pixel
  2244.     // rows that we don't need to worry about.
  2245.     dataPtr = (UInt8 *)( *fImage);
  2246.     
  2247.     yCount = clipBottom - clipTop;
  2248.  
  2249. #if qDebugging
  2250.     srcPtr =  (UInt8 *) 0xDDDDDDDD;
  2251.     destPtr = (UInt8 *) 0xDDDDDDDD;
  2252. #else
  2253.     srcPtr = sourceRowStart;
  2254.     destPtr = destRowStart;
  2255. #endif    
  2256.     xCount = 0;
  2257.     
  2258.     while (clipTop > 0)
  2259.     {
  2260.         clipTop--;
  2261.         tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
  2262.         dataPtr += sizeof( UInt32 ) + tokenData;
  2263.     }
  2264.     
  2265.     do
  2266.     {
  2267.         // get a token
  2268.         tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
  2269.         tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
  2270.         dataPtr += sizeof( UInt32 );
  2271.             
  2272.         // depending on the token
  2273.         switch( tokenOp )
  2274.         {
  2275.             case kDrawPixelsToken:
  2276.                 miscCounter = tokenData;
  2277.                 extraCounter = 0;
  2278.                         
  2279.                 // advance the data pointer for free
  2280.                 tokenData = ALIGN_TO_NEXT_LONG (tokenData);
  2281.                 dataPtr += tokenData;
  2282.                         
  2283.                 // if we need to, clip to the left
  2284.                 if (xCount < clipLeft )
  2285.                 {
  2286.                     // if this run does not appear at all, don't draw it
  2287.                     if ( miscCounter < clipLeft - xCount )
  2288.                     {
  2289.                         destPtr += miscCounter;
  2290.                         srcPtr += miscCounter;
  2291.                         xCount += miscCounter;
  2292.                         break;
  2293.                     }
  2294.                     else
  2295.                     {
  2296.                     // if it does, skip to where we can draw
  2297.                         miscCounter -= clipLeft - xCount;
  2298.                         destPtr += clipLeft - xCount;
  2299.                         srcPtr += clipLeft - xCount;
  2300.                         xCount = clipLeft;
  2301.                     }
  2302.                 }
  2303.                         
  2304.                 // if we need to, clip to the right
  2305.                 if ( xCount + miscCounter > clipRight )
  2306.                 {
  2307.                     // if this run does not appear at all, skip it
  2308.                     if ( xCount > clipRight )
  2309.                         // once xCount is greater than xRight, no drawing commands will ever
  2310.                         // be issued on that line, so I changed the "gurus" code, which was actually
  2311.                         // wasting a couple of instructions setting variables that aren't needed.
  2312.                         //destPtr += miscCounter;
  2313.                         //srcPtr += miscCounter;
  2314.                         //xCount += miscCounter;
  2315.                         break;
  2316.                     else
  2317.                     {
  2318.                         // if it does, setup to draw what we can
  2319.                         extraCounter = (xCount + miscCounter) - clipRight;
  2320.                         miscCounter -= extraCounter;
  2321.                     }
  2322.                 }
  2323.                         
  2324.                 // adjust xCount for the run
  2325.                 xCount += miscCounter;
  2326.                 // This blit loop is optimized to move 32 bytes or less.  On 604 machines, using an 8 byte move
  2327.                 // is faster in those rare cases where you can get them to align, and way slower when they don't.
  2328.                 // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
  2329.                 
  2330.                 
  2331.                 {
  2332.                 register UInt32 sixteenblits, blitloop;
  2333.                 sixteenblits = miscCounter >> 4;
  2334.                 for ( blitloop = 0; blitloop < sixteenblits; blitloop++)
  2335.                 {
  2336.                         register UInt32 temp1, temp2, temp3, temp4;
  2337.                         temp1 = ((UInt32 *) srcPtr)[0];
  2338.                         temp2 = ((UInt32 *) srcPtr)[1];
  2339.                         temp3 = ((UInt32 *) srcPtr)[2];
  2340.                         temp4 = ((UInt32 *) srcPtr)[3];
  2341.                         ((UInt32 *) destPtr)[0] = temp1;
  2342.                         ((UInt32 *) destPtr)[1] = temp2;
  2343.                         ((UInt32 *) destPtr)[2] = temp3;
  2344.                         ((UInt32 *) destPtr)[3] = temp4;
  2345.                         srcPtr += 16;
  2346.                         destPtr += 16;
  2347.                 }
  2348.                 // move any remaining data, up to 15 bytes total
  2349.                 if (miscCounter & 0x8)
  2350.                 {
  2351.                     register UInt32 temp1, temp2;
  2352.                     temp1 = ((UInt32 *) srcPtr)[0];
  2353.                     temp2 = ((UInt32 *) srcPtr)[1];
  2354.                     ((UInt32 *) destPtr)[0] = temp1;
  2355.                     ((UInt32 *) destPtr)[1] = temp2;
  2356.                     srcPtr += 8;
  2357.                     destPtr += 8;
  2358.                 }
  2359.                 if (miscCounter & 0x4)
  2360.                 {
  2361.                     register UInt32 temp1;
  2362.                     temp1 = *((UInt32 *) srcPtr);
  2363.                     srcPtr +=4;
  2364.                     *((UInt32 *) destPtr)  = temp1;
  2365.                     destPtr +=4;
  2366.                 }
  2367.                 if (miscCounter & 0x2)
  2368.                 {
  2369.                     register UInt16 temp1;
  2370.                     temp1 = *((UInt16 *) srcPtr);
  2371.                     srcPtr +=2;
  2372.                     *((UInt16 *) destPtr)  = temp1;
  2373.                     destPtr +=2;
  2374.                 }
  2375.                 if (miscCounter & 0x1)
  2376.                     *destPtr++ = *srcPtr++;
  2377.         
  2378.                 }
  2379.                             
  2380.                 // adjust for right clipping
  2381.                 destPtr += extraCounter;
  2382.                 srcPtr += extraCounter;
  2383.                 xCount += extraCounter;
  2384.                         
  2385.                 break;
  2386.                         
  2387.             case kSkipPixelsToken:
  2388.                 destPtr += tokenData;
  2389.                 srcPtr += tokenData;
  2390.                         
  2391.                 xCount += tokenData;
  2392.                 break;
  2393.                         
  2394.             case kLineStartToken:
  2395.                 // check to see if we're done drawing
  2396.                 if (yCount == 0)
  2397.                     return;
  2398.                 else
  2399.                 {
  2400.                     // set all the counters up
  2401.                     yCount--;
  2402.                     xCount = 0;
  2403.                     // set up the source and destination pointers
  2404.                     destPtr = destRowStart;
  2405.                     srcPtr = sourceRowStart;
  2406.                     destRowStart += gRowBytes;
  2407.                     sourceRowStart += gRowBytes;
  2408.                 }
  2409.                 break;
  2410.             case kEndShapeToken:
  2411.                 return;
  2412.                 break;
  2413. #if qDebugging
  2414.             default:
  2415.             // we should never get here
  2416.             Debugger();
  2417.             break;
  2418. #endif
  2419.         }
  2420.     } while (true);
  2421. }
  2422.  
  2423. /*************************************************************************************
  2424. TGraphic::BackgroundUnclipped
  2425.     
  2426. The Background routines work similarly to the standard graphic drawing routines, but
  2427. we keep an additional pointer to the destination graphics world, and we draw from it,
  2428. not the graphic data.  Later, we might optimize this routine further as we know the
  2429. two are always in sync.
  2430. *************************************************************************************/
  2431.  
  2432. void 
  2433. TGraphic::BackgroundUnclipped (SInt32 top, SInt32 left)
  2434. {
  2435.     UInt8 *destRowStart;                // the pointer to the start of this row
  2436.     UInt8 *sourceRowStart;
  2437.     UInt8 *srcPtr;                        // the current position in the source pixmap
  2438.     UInt8 *destPtr;                        // the current position in the destination pixmap
  2439.     UInt8 *dataPtr;                        // the current position in the sprite data
  2440.     UInt32 miscCounter;                    // a counter for various purposes
  2441.     UInt32 tokenOp;                        // the op code from the token
  2442.     UInt32 tokenData;                    // the data from the token
  2443.     
  2444.     // determine characteristics about the pixmap
  2445.     destRowStart   = gDestBaseAddr + top * gRowBytes + left;
  2446.     sourceRowStart = gBackBaseAddr + top * gRowBytes + left;
  2447.     
  2448.     // move to the start of the graphic data
  2449.     dataPtr = (UInt8 *)( *fImage );
  2450.  
  2451. #if qDebugging
  2452.     srcPtr  = (UInt8 *) 0xDDDDDDDD;
  2453.     destPtr = (UInt8 *) 0xDDDDDDDD;
  2454. #else
  2455.     srcPtr = sourceRowStart;
  2456.     destPtr = destRowStart;
  2457. #endif    
  2458.     
  2459.     // loop until we are done
  2460.     do
  2461.     {
  2462.         // get a token
  2463.         tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
  2464.         tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
  2465.         dataPtr += sizeof( UInt32 );
  2466.             
  2467.         // depending on the token
  2468.         switch( tokenOp )
  2469.         {
  2470.         case kDrawPixelsToken:
  2471.             miscCounter = tokenData;
  2472.             // adjust the data pointer
  2473.             tokenData = ALIGN_TO_NEXT_LONG (tokenData);
  2474.             dataPtr += tokenData;
  2475.     
  2476.                 // This blit loop is optimized to move 32 bytes or less.  On 604 machines, using an 8 byte move
  2477.                 // is faster in those rare cases where you can get them to align, and way slower when they don't.
  2478.                 // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
  2479.                 
  2480.                 
  2481.                 {
  2482.                 register UInt32 sixteenblits, blitloop;
  2483.                 sixteenblits = miscCounter >> 4;
  2484.                 for ( blitloop = 0; blitloop < sixteenblits; blitloop++)
  2485.                 {
  2486.                         register UInt32 temp1, temp2, temp3, temp4;
  2487.                         temp1 = ((UInt32 *) srcPtr)[0];
  2488.                         temp2 = ((UInt32 *) srcPtr)[1];
  2489.                         temp3 = ((UInt32 *) srcPtr)[2];
  2490.                         temp4 = ((UInt32 *) srcPtr)[3];
  2491.                         ((UInt32 *) destPtr)[0] = temp1;
  2492.                         ((UInt32 *) destPtr)[1] = temp2;
  2493.                         ((UInt32 *) destPtr)[2] = temp3;
  2494.                         ((UInt32 *) destPtr)[3] = temp4;
  2495.                         srcPtr += 16;
  2496.                         destPtr += 16;
  2497.                 }
  2498.                 // move any remaining data, up to 15 bytes total
  2499.                 if (miscCounter & 0x8)
  2500.                 {
  2501.                     register UInt32 temp1, temp2;
  2502.                     temp1 = ((UInt32 *) srcPtr)[0];
  2503.                     temp2 = ((UInt32 *) srcPtr)[1];
  2504.                     ((UInt32 *) destPtr)[0] = temp1;
  2505.                     ((UInt32 *) destPtr)[1] = temp2;
  2506.                     srcPtr += 8;
  2507.                     destPtr += 8;
  2508.                 }
  2509.                 if (miscCounter & 0x4)
  2510.                 {
  2511.                     register UInt32 temp1;
  2512.                     temp1 = *((UInt32 *) srcPtr);
  2513.                     srcPtr +=4;
  2514.                     *((UInt32 *) destPtr)  = temp1;
  2515.                     destPtr +=4;
  2516.                 }
  2517.                 if (miscCounter & 0x2)
  2518.                 {
  2519.                     register UInt16 temp1;
  2520.                     temp1 = *((UInt16 *) srcPtr);
  2521.                     srcPtr +=2;
  2522.                     *((UInt16 *) destPtr)  = temp1;
  2523.                     destPtr +=2;
  2524.                 }
  2525.                 if (miscCounter & 0x1)
  2526.                     *destPtr++ = *srcPtr++;
  2527.         
  2528.                 }
  2529.     
  2530.                 break;
  2531.                         
  2532.             case kSkipPixelsToken:
  2533.                 destPtr += tokenData;
  2534.                 srcPtr += tokenData;    
  2535.                 break;
  2536.                     
  2537.             case kLineStartToken:
  2538.                 // set up the source and destination
  2539.                 destPtr = destRowStart;
  2540.                 srcPtr = sourceRowStart;
  2541.                 destRowStart += gRowBytes;
  2542.                 sourceRowStart += gRowBytes;
  2543.                 break;
  2544.                         
  2545.             case kEndShapeToken:
  2546.                 // signal a loop exit
  2547.                 return;
  2548.                 break;
  2549. #ifdef qDebugging
  2550.             default:
  2551.                 // we should never get here
  2552.                 Debugger();
  2553.                 break;
  2554. #endif
  2555.         }
  2556.     } while (true);
  2557. }
  2558.  
  2559.  
  2560. /*************************************************************************************
  2561. TGraphic::DrawMaskUnclipped
  2562.     
  2563. This version of the drawing loop draws black anywhere the draw mask is active.
  2564. Useful for writing a PICT out to disk with the mask information.
  2565. *************************************************************************************/
  2566.  
  2567. void 
  2568. TGraphic::DrawMaskUnclipped (SInt32 top, SInt32 left)
  2569. {
  2570.     UInt8 *destRowStart;                // the pointer to the start of this row
  2571.     UInt8 *destPtr;                        // the current position in the destination pixmap
  2572.     UInt8 *dataPtr;                        // the current position in the sprite data
  2573.     UInt32 miscCounter;                    // a counter for various purposes
  2574.     UInt32 tokenOp;                        // the op code from the token
  2575.     UInt32 tokenData;                    // the data from the token
  2576.     UInt32 indexSmear;
  2577.     UInt32 indexSmear2;
  2578.     
  2579.     indexSmear = kMaskColorIndex;
  2580.     indexSmear |= (kMaskColorIndex << 8);
  2581.     indexSmear |= (indexSmear << 16);
  2582.     
  2583.     indexSmear2 = indexSmear;
  2584.     
  2585.     // determine characteristics about the pixmap
  2586.     destRowStart = gDestBaseAddr + top * gRowBytes + left;
  2587.     
  2588.     // move to the start of the graphic data
  2589.     dataPtr = (UInt8 *)( *fImage );
  2590.     
  2591. #if qDebugging
  2592.     destPtr = (UInt8 *) 0xDDDDDDDD;
  2593. #else
  2594.     destPtr = (UInt8 *) destRowStart;
  2595. #endif    
  2596.  
  2597.     // loop until we are done
  2598.     do
  2599.     {
  2600.         // get a token
  2601.         tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
  2602.         tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
  2603.         dataPtr += sizeof( UInt32 );
  2604.             
  2605.         // depending on the token
  2606.         switch( tokenOp )
  2607.         {
  2608.         case kDrawPixelsToken:
  2609.             miscCounter = tokenData;
  2610.             // adjust the data pointer
  2611.             tokenData = ALIGN_TO_NEXT_LONG (tokenData);
  2612.             dataPtr += tokenData;
  2613.                 // This blit loop is optimized to move 32 bytes or less.  On 604 machines, using an 8 byte move
  2614.                 // is faster in those rare cases where you can get them to align, and way slower when they don't.
  2615.                 // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
  2616.                 
  2617.                 
  2618.                 {
  2619.                 register UInt32 sixteenblits, blitloop;
  2620.                 sixteenblits = miscCounter >> 4;
  2621.                 for (blitloop = 0; blitloop < sixteenblits; blitloop++)
  2622.                 {
  2623.                     ((UInt32 *) destPtr)[0] = *((UInt32 *) &indexSmear);
  2624.                     ((UInt32 *) destPtr)[1] = *((UInt32 *) &indexSmear);
  2625.                     ((UInt32 *) destPtr)[2] = *((UInt32 *) &indexSmear);
  2626.                     ((UInt32 *) destPtr)[3] = *((UInt32 *) &indexSmear);
  2627.                     destPtr += 16;
  2628.                 }
  2629.                 // move any remaining data, up to 15 bytes total
  2630.                 if (miscCounter & 0x8)
  2631.                 {
  2632.                     ((UInt32 *) destPtr)[0] = *((UInt32 *) &indexSmear);
  2633.                     ((UInt32 *) destPtr)[1] = *((UInt32 *) &indexSmear);
  2634.                     destPtr += 8;
  2635.                 }
  2636.                 if (miscCounter & 0x4)
  2637.                 {
  2638.                     *((UInt32 *) destPtr)  = *((UInt32 *) &indexSmear);
  2639.                     destPtr +=4;
  2640.                 }
  2641.                 if (miscCounter & 0x2)
  2642.                 {
  2643.                     *((UInt16 *) destPtr) = *((UInt16 *) &indexSmear);
  2644.                     destPtr +=2;
  2645.                 }
  2646.                 if (miscCounter & 0x1)
  2647.                     *destPtr++ = *((UInt8 *) &indexSmear);
  2648.         
  2649.                 }
  2650.     
  2651.                 break;
  2652.                         
  2653.             case kSkipPixelsToken:
  2654.                 destPtr += tokenData;
  2655.                 break;
  2656.                     
  2657.             case kLineStartToken:
  2658.                 // set up the source and destination
  2659.                 destPtr = destRowStart;
  2660.                 destRowStart += gRowBytes;
  2661.                 break;
  2662.                         
  2663.             case kEndShapeToken:
  2664.                 // signal a loop exit
  2665.                 return;
  2666.                 break;
  2667. #ifdef qDebugging
  2668.             default:
  2669.                 // we should never get here
  2670.                 Debugger();
  2671.                 break;
  2672. #endif
  2673.         }
  2674.     } while (true);
  2675. }
  2676.  
  2677. /*************************************************************************************
  2678. TGraphic::HitMaskUnclipped
  2679.     
  2680. Same as DrawMaskUnclipped, but using the fHitMask data instead.
  2681. *************************************************************************************/
  2682.  
  2683. void 
  2684. TGraphic::HitMaskUnclipped (SInt32 top, SInt32 left)
  2685. {
  2686.     UInt8 *destRowStart;                // the pointer to the start of this row
  2687.     UInt8 *destPtr;                        // the current position in the destination pixmap
  2688.     UInt8 *dataPtr;                        // the current position in the sprite data
  2689.     UInt32 miscCounter;                    // a counter for various purposes
  2690.     UInt32 tokenOp;                        // the op code from the token
  2691.     UInt32 tokenData;                    // the data from the token
  2692.     UInt32 indexSmear;
  2693.     UInt32 indexSmear2;
  2694.     
  2695.     indexSmear = kMaskColorIndex;
  2696.     indexSmear |= (kMaskColorIndex << 8);
  2697.     indexSmear |= (indexSmear << 16);
  2698.     
  2699.     indexSmear2 = indexSmear;
  2700.     
  2701.     // determine characteristics about the pixmap
  2702.     destRowStart = gDestBaseAddr + top * gRowBytes + left;
  2703.     
  2704.     // move to the start of the graphic data
  2705.     dataPtr = (UInt8 *)( *fHitMask );
  2706.  
  2707. #if qDebugging
  2708.     destPtr = (UInt8 *) 0xDDDDDDDD;
  2709. #else
  2710.     destPtr = destRowStart;
  2711. #endif    
  2712.     
  2713.     // loop until we are done
  2714.     do
  2715.     {
  2716.         // get a token
  2717.         tokenOp = ( *( (UInt32 *)dataPtr ) ) >> 24;
  2718.         tokenData = ( *( (UInt32 *)dataPtr ) ) & 0x00ffffff;
  2719.         dataPtr += sizeof( UInt32 );
  2720.             
  2721.         // depending on the token
  2722.         switch( tokenOp )
  2723.         {
  2724.         case kDrawPixelsToken:
  2725.             miscCounter = tokenData;
  2726.     
  2727.                 // This blit loop is optimized to move 32 bytes or less.  On 604 machines, using an 8 byte move
  2728.                 // is faster in those rare cases where you can get them to align, and way slower when they don't.
  2729.                 // because of the rarity of these cases, this blit loop doesn't do anything fancy with doubles.
  2730.                 
  2731.                 
  2732.                 {
  2733.                 register UInt32 sixteenblits;
  2734.                 sixteenblits = miscCounter >> 4;
  2735.                 if (sixteenblits)
  2736.                 {
  2737.                     do
  2738.                     {
  2739.                         ((UInt32 *) destPtr)[0] = *((UInt32 *) &indexSmear);
  2740.                         ((UInt32 *) destPtr)[1] = *((UInt32 *) &indexSmear);
  2741.                         ((UInt32 *) destPtr)[2] = *((UInt32 *) &indexSmear);
  2742.                         ((UInt32 *) destPtr)[3] = *((UInt32 *) &indexSmear);
  2743.                         destPtr += 16;
  2744.                     }  while (--sixteenblits != 0);
  2745.                 }
  2746.                 // move any remaining data, up to 15 bytes total
  2747.                 if (miscCounter & 0x8)
  2748.                 {
  2749.                     ((UInt32 *) destPtr)[0] = *((UInt32 *) &indexSmear);
  2750.                     ((UInt32 *) destPtr)[1] = *((UInt32 *) &indexSmear);
  2751.                     destPtr += 8;
  2752.                 }
  2753.                 if (miscCounter & 0x4)
  2754.                 {
  2755.                     *((UInt32 *) destPtr)  = *((UInt32 *) &indexSmear);
  2756.                     destPtr +=4;
  2757.                 }
  2758.                 if (miscCounter & 0x2)
  2759.                 {
  2760.                     *((UInt16 *) destPtr) = *((UInt16 *) &indexSmear);
  2761.                     destPtr +=2;
  2762.                 }
  2763.                 if (miscCounter & 0x1)
  2764.                     *destPtr++ = *((UInt8 *) &indexSmear);
  2765.         
  2766.                 }
  2767.  
  2768.                 break;
  2769.                         
  2770.             case kSkipPixelsToken:
  2771.                 destPtr += tokenData;
  2772.                 break;
  2773.                     
  2774.             case kLineStartToken:
  2775.                 // set up the source and destination
  2776.                 destPtr = destRowStart;
  2777.                 destRowStart += gRowBytes;
  2778.                 break;
  2779.                         
  2780.             case kEndShapeToken:
  2781.                 // signal a loop exit
  2782.                 return;
  2783.                 break;
  2784. #ifdef qDebugging
  2785.             default:
  2786.                 // we should never get here
  2787.                 Debugger();
  2788.                 break;
  2789. #endif
  2790.         }
  2791.     } while (true);
  2792. }
  2793.  
  2794.