home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 December / macformat-031.iso / mac / Shareware City / Developers / CopyBits Demo 3.1 / CopyBits Demo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-08  |  84.2 KB  |  3,013 lines  |  [TEXT/MMCC]

  1. //
  2. // CopyBits Demo.c
  3. //
  4. // Written in May 1995 using Metrowerks CodeWarrior v5.
  5. //
  6. // The CopyBits Demo project v3.1 by Kenneth Worley.
  7. // This code is Copyright 1995. All Rights Reserved.
  8. // You may use this code in any project of your own. You may also
  9. // redistribute this project to anyone else as long as 1) all the
  10. // project files (including documentation files) are kept together,
  11. // and 2) nothing is charged for the project.
  12. //
  13. // Please ask my permission before including this code on any
  14. // disk or CD for sale.
  15. //
  16. // This is a tutorial project that demonstrates the use of
  17. // CopyBits and offscreen Graphics Worlds (GWorlds). It shows
  18. // several instances of copying images to and from offscreen
  19. // graphics worlds using CopyBits, provides several macros that
  20. // make the process a little easier, shows an example of
  21. // drawing into an offscreen graphics world and how that can
  22. // improve onscreen animation, and it demonstrates a "fade"
  23. // using CopyBits to fade a portion of the screen to black.
  24. //
  25. // Version 1.5 adds a fade from image to image using CopyBits.
  26. // Cool!
  27. //
  28. // In a nutshell, the app puts up a dialog that shows two
  29. // "source" pictures (1 & 2) and a destination area. Clicking
  30. // on the "Copy" buttons above each of the source pictures
  31. // causes the picture to be copied to the destination area.
  32. // Picture 1 is labelled as "flickery animation" and picture 2
  33. // is labelled as "smooth animation." When you put the cursor
  34. // over each picture, you should see a difference in how a
  35. // colored circle is animated over the picture. You should
  36. // occasionally see the background "flicker" through on
  37. // picture 1, but not on picture 2 because it uses an
  38. // intermediary GWorld to draw in.
  39. //
  40. // The Fade to black button over the destination area will
  41. // cause that area to fade to black from whatever happens to
  42. // be in there. It does this by repeatedly copying a gray
  43. // rectangle from a GWorld into the destination area using
  44. // the subPin transfer mode of CopyBits. The erase button
  45. // erases the destination area.
  46. //
  47. // The Fade picture buttons cause the picture under the
  48. // button to be faded into whatever is currently in the
  49. // destination area. This is accomplished using CopyBits'
  50. // blend transfer mode.
  51. //
  52. // Questions? Comments? Praise? Criticism? Jobs? Send them
  53. // all to me at KNEworley@aol.com. I'm a 'freelance'
  54. // programmer. I work on applications as well as low-level
  55. // software (control panels, INITs, etc.)
  56. //
  57.  
  58. #include <QDOffscreen.h>
  59. #include <PictUtil.h>
  60. #include "System Utilities.h"
  61. #include "Dialog Utilities.h"
  62. #include "Alert Utilities.h"
  63.  
  64. // ===================== DEFINES =====================
  65.  
  66. // The main dialog's resource ID.
  67.  
  68. #define kMainDlgID                128
  69.  
  70. // The two pictures in the main dialog.
  71.  
  72. #define kPict1ID                128
  73. #define kPict2ID                129
  74.  
  75. // Item numbers in the main dialog.
  76.  
  77. #define kMainDlgQuit            1
  78. #define kMainDlgCopyOne            2
  79. #define kMainDlgFadeOne            3
  80. #define kMainDlgCopyTwo            4
  81. #define kMainDlgFadeTwo            5
  82. #define kMainDlgErase            6
  83. #define kMainDlgPICTOne            8
  84. #define kMainDlgPICTTwo            9
  85. #define kMainDlgDestPICT        10
  86. #define kMainDlgFadeSpeed        15
  87. #define kMainDlgFullScreen        20
  88. #define kMainDlgPixelize        21
  89. #define kMainDlgDepixelizeOne    22
  90. #define kMainDlgDepixelizeTwo    23
  91. #define kMainDlgFadeToBlack1    7
  92. #define kMainDlgFadeToBlack2    24
  93. #define kMainDlgFadeToBlack3    25
  94. #define kMainDlgBlur            27
  95. #define kMainDlgFlipHoriz        29
  96. #define kMainDlgFlipVert        30
  97. #define kMainDlgSlideL            34
  98. #define kMainDlgSlideR            35
  99. #define kMainDlgSlideT            36
  100. #define kMainDlgSlideB            37
  101. #define kMainDlgApertureIn        32
  102. #define kMainDlgApertureOut        38
  103. #define kMainDlgTechDemo        39
  104.  
  105. // The CopyBits Technical Demo dialog ID.
  106.  
  107. #define kTechDemoDlgID            130
  108.  
  109. // Item numbers in the Technical Demo dialog.
  110.  
  111. #define kTechDemoSourceFirst    10
  112. #define kTechDemoSourceLast        14
  113. #define kTechDemoMaskFirst        15
  114. #define kTechDemoMaskLast        18
  115. #define kTechDemoModeFirst        21
  116. #define kTechDemoModeLast        36
  117. #define kTechDemoDither            37
  118. #define kTechDemoHilite            38
  119. #define kTechDemoOpColorFirst    42
  120. #define kTechDemoOpColorLast    46
  121. #define kTechDemoDestPict        9
  122. #define kTechDemoCopyBits        49
  123. #define kTechDemoCopyMask        50
  124. #define kTechDemoDone            51
  125. #define kTechDemoSourcePict1    1
  126. #define kTechDemoSourcePict2    2
  127. #define kTechDemoSourcePict3    3
  128. #define kTechDemoSourcePict4    4
  129. #define kTechDemoSourcePict5    5
  130. #define kTechDemoMaskPict1        6
  131. #define kTechDemoMaskPict2        7
  132. #define kTechDemoMaskPict3        8
  133. #define kTechDemoMaskNone        53
  134. #define kTechDemoOpColorPict    40
  135. #define kTechDemoErase            54
  136. #define kTechDemoCopyDeepMask    55
  137. #define kTechDemoMaskRPict1        56
  138. #define kTechDemoMaskRPict2        57
  139. #define kTechDemoMaskRPict3        58
  140. #define kTechDemoMaskRNone        60
  141. #define kTechDemoMaskRFirst        61
  142. #define kTechDemoMaskRLast        64
  143.  
  144. // Error messages. ('STR ' resource IDs).
  145.  
  146. #define kSys7Required            128
  147. #define kMemoryOut                129
  148. #define kGWorldErr                130
  149. #define kNotYetImplemented        131
  150. #define kMissingResource        132
  151.  
  152. // The generic error alert ID.
  153.  
  154. #define kAlertDialogID            129
  155.  
  156. // Item numbers in the generic alert dialog.
  157.  
  158. #define kAlertOKButton            1
  159.  
  160. // Codes sent to the Slide routine to indicate which
  161. // way to slide the new picture in (from).
  162. enum
  163. {
  164.     kLeft =        1,
  165.     kRight =    2,
  166.     kTop =        3,
  167.     kBottom =    4
  168. };
  169.  
  170. // Codes sent to the Aperture routine to indicate which
  171. // way to do the effect.
  172. enum
  173. {
  174.     kIn =        1,
  175.     kOut =        2
  176. };
  177.  
  178. // Easy way to access colors in the global colors array.
  179. enum
  180. {
  181.     kWhite =    0,
  182.     kLtGray =    1,
  183.     kGray =        2,
  184.     kDkGray =    3,
  185.     kBlack =    4
  186. };
  187.  
  188. // ===================== GLOBALS =====================
  189.  
  190. RGBColor    colors[5];    // white, black, and 3 grays
  191.  
  192. // ===================== MACROS =====================
  193.  
  194. // w can be a WindowPtr, a DialogPtr, or a GWorldPtr. In any of these
  195. // cases, it returns the correct "bitmap" to send to CopyBits in the
  196. // source or destination bitmap parameter.
  197. //#define WINBITMAP(w)        ((((WindowPeek)(w))->port).portBits)
  198. #define WINBITMAP(w)        (((GrafPtr)(w))->portBits)
  199.  
  200. // w can also be a WindowPtr, DialogPtr, or GWorldPtr for any of these.
  201. #define WINPORTRECT(w)        ((((WindowPeek)(w))->port).portRect)
  202. #define WINDOWWIDTH(w)        (WINPORTRECT(w).right - WINPORTRECT(w).left)
  203. #define WINDOWHEIGHT(w)        (WINPORTRECT(w).bottom - WINPORTRECT(w).top)
  204. #define WINCONTENTRECT(w)    ((**((WindowPeek)(w))->contRgn).rgnBBox)
  205. #define WINCONTENTRGN(w)    (((WindowPeek)(w))->contRgn)
  206. #define WINVISIBLERGN(w)    (((WindowPeek)(w))->port.visRgn)
  207. #define WINSTRUCTRECT(w)    ((**((WindowPeek)(w))->strucRgn).rgnBBox)
  208. #define WINSTRUCTRGN(w)        (((WindowPeek)(w))->strucRgn)
  209. #define WINUPDATERECT(w)    ((**((WindowPeek)(w))->updateRgn).rgnBBox)
  210. #define WINUPDATERGN(w)        (((WindowPeek)(w))->updateRgn)
  211.  
  212. // This takes a GDHandle (device handle)
  213. #define PIXELDEPTH(x)        ((**((**(x)).gdPMap)).pixelSize)
  214.  
  215. // r is a Rect
  216. #define TOPLEFT(r)            (* (Point*) &(r.top) )
  217. #define BOTRIGHT(r)            (* (Point*) &(r.bottom) )
  218.  
  219. // ===================== PROTOTYPES =====================
  220.  
  221. void main( void );
  222.  
  223. void FadeToBlack1( WindowPtr destWin, Rect *destRect, short fadeSpeed );
  224. void FadeToBlack2( WindowPtr destWin, Rect *destRect, short fadeSpeed );
  225. void FadeToBlack3( WindowPtr destWin, Rect *destRect, short fadeSpeed );
  226.  
  227. void FadeToImage( GWorldPtr srcImage, Rect *srcRect,
  228.     WindowPtr destWin, Rect *destRect, short fadeSpeed );
  229.  
  230. void Pixelize( WindowPtr srcWin, Rect *srcRect,
  231.     WindowPtr destWin, Rect *destRect, short speed, Boolean pixelizing );
  232.  
  233. void FlickerAnimate( GWorldPtr srcPict, Rect *destRect );
  234. void SmoothAnimate( GWorldPtr srcPict, Rect *destRect );
  235.  
  236. void FullScreenDemo( GWorldPtr pict1, GWorldPtr pict2, short fadeSpeed );
  237.  
  238. void Blur( WindowPtr destWin, Rect *destRect );
  239.  
  240. void FlipHorizontal( WindowPtr destWin, Rect *destRect );
  241. void FlipVertical( WindowPtr destWin, Rect *destRect );
  242.  
  243. void Slide( WindowPtr srcWin, Rect *srcRect,
  244.     WindowPtr destWin, Rect *destRect, short speed, short whichWay );
  245. void Aperture( WindowPtr srcWin, Rect *srcRect,
  246.     WindowPtr destWin, Rect *destRect, short speed, short inOrOut );
  247.  
  248. void DoTechDemo( void );
  249.  
  250. void DrawMaskRegion( WindowPtr win, short drawWhere, short whichMask );
  251.  
  252. // ===================== FUNCTIONS =====================
  253.  
  254. void main( void )
  255. {
  256.     DialogPtr        mainDlg;
  257.     DialogPtr        aDlg;
  258.     Rect            pict1Rect;
  259.     Rect            pict2Rect;
  260.     Rect            destRect;
  261.     PenState        savedPen;
  262.     short            itemHit;
  263.     RGBColor        savedFore;
  264.     RGBColor        savedBack;
  265.     short            fadeSpeed;
  266.     OSErr            myErr;
  267.     Rect            pict1GRect;
  268.     Rect            pict2GRect;
  269.     GWorldPtr        pict1GWorld;
  270.     GWorldPtr        pict2GWorld;
  271.     EventRecord        myEvent;
  272.     PicHandle        aPict;
  273.     PictInfo        pictInfo;
  274.     
  275.     // Create some colors (white, 3 grays, and black).
  276.     
  277.     colors[0].red = colors[0].green = colors[0].blue = 0xFFFF;            // white
  278.     colors[1].red = colors[1].green = colors[1].blue = 0xFFFF * 0.75;    // lt gray
  279.     colors[2].red = colors[2].green = colors[2].blue = 0xFFFF * 0.5;    // gray
  280.     colors[3].red = colors[3].green = colors[3].blue = 0xFFFF * 0.25;    // dk gray
  281.     colors[4].red = colors[4].green = colors[4].blue = 0x0000;            // black
  282.     
  283.     // Make sure the main monitor is using a 5 bits per color inverse
  284.     // table rather than the default 4. This will make CopyBits
  285.     // operations using arithmetic transfer modes a bit more smooth
  286.     // (but uses a little more memory).
  287.     
  288.     {
  289.         GDHandle        aDevice;
  290.         
  291.         aDevice = GetGDevice();
  292.         SetGDevice( GetMainDevice() );
  293.         MakeITable( NULL, NULL, 5 );
  294.         SetGDevice( aDevice );
  295.     }
  296.     
  297.     // Initialize the Mac Toolbox
  298.     
  299.     InitToolbox();
  300.     
  301.     // Check the system version. This project requires System 7
  302.     // or later for the GWorlds.
  303.     
  304.     if ( GetSysVersion() < 7 )
  305.     {
  306.         DoAlertStrID( kAlertDialogID, true, kSys7Required );
  307.         ExitToShell();
  308.     }
  309.     
  310.     // Load the main dialog and display it on screen. This
  311.     // automatically displays our two source PICTS. Since there is
  312.     // a 'dctb' (Dialog Color Table) resource with the same ID
  313.     // as the dialog, the Dialog Manager uses NewColorDialog to
  314.     // make the dialog, thus giving us a color drawing port.
  315.     // In ResEdit, creating a 'dctb' resource for a dialog is as
  316.     // easy as clicking Custom for the color scheme rather than
  317.     // default when you have the 'DLOG' resource open.
  318.     
  319.     mainDlg = GetNewDialog( kMainDlgID, NULL, (WindowPtr)(-1L) );
  320.     if ( !mainDlg )
  321.     {
  322.         DoAlertStrID( kAlertDialogID, true, kMemoryOut );
  323.         ExitToShell();
  324.     }
  325.     
  326.     // Select the text in the fade speed text edit box.
  327.     
  328.     SelectTextField( mainDlg, kMainDlgFadeSpeed );
  329.     
  330.     // Make sure the dialog is visible and that it's the current port.
  331.     
  332.     ShowWindow( mainDlg );
  333.     SetGWorld( (CGrafPtr)mainDlg, NULL );
  334.     
  335.     // Get the picture rectangles and the destination picture's
  336.     // rectangle. Save them for later use.
  337.     
  338.     GetItemRect( mainDlg, kMainDlgPICTOne, &pict1Rect );
  339.     GetItemRect( mainDlg, kMainDlgPICTTwo, &pict2Rect );
  340.     GetItemRect( mainDlg, kMainDlgDestPICT, &destRect );
  341.     
  342.     // Draw a box around each of the picture areas to better
  343.     // define them on screen.
  344.     {
  345.         Rect        tempRect;
  346.         
  347.         tempRect = destRect;
  348.         InsetRect( &tempRect, -1, -1 );
  349.         FrameRect( &tempRect );
  350.         tempRect = pict1Rect;
  351.         InsetRect( &tempRect, -1, -1 );
  352.         FrameRect( &tempRect );
  353.         tempRect = pict2Rect;
  354.         InsetRect( &tempRect, -1, -1 );
  355.         FrameRect( &tempRect );
  356.     }
  357.     
  358.     // Draw each of the two "source" pictures into an offscreen
  359.     // Graphics World for use later. For example, when the user
  360.     // passes the cursor over the left picture, regular animation
  361.     // techniques are used to make a circle "float" above the
  362.     // picture (causes flicker). This involves repeatedly
  363.     // copying the original picture to the window, then drawing
  364.     // the circle over it. When the user passes the cursor over
  365.     // the right picture, the original picture is drawn to an
  366.     // offscreen gworld and the circle is drawn over it, then
  367.     // that image is drawn to the window resulting in flicker-free
  368.     // animation of the floating circle.
  369.     //
  370.     // We need the two gworlds here so we have the original
  371.     // pictures to copy from.
  372.     
  373.         // Load picture 1 from resource.
  374.         aPict = GetPicture( kPict1ID );
  375.         if ( !aPict )
  376.         {
  377.             DoAlertStrID( kAlertDialogID, true, kMissingResource );
  378.             ExitToShell();
  379.         }
  380.         
  381.         // Get it's optimum rectangle.
  382.         myErr = GetPictInfo( aPict, &pictInfo, 0, 0, 0, 0 );
  383.         pict1GRect = pictInfo.sourceRect;
  384.         
  385.         // Release any extra items GetPictInfo may have allocated
  386.         // if we're not going to use them.
  387.         if ( pictInfo.commentHandle )
  388.             DisposeHandle( (Handle)pictInfo.commentHandle );
  389.         if ( pictInfo.fontHandle )
  390.             DisposeHandle( (Handle)pictInfo.fontHandle );
  391.         
  392.         // Make a GWorld for the picture.
  393.         myErr = NewGWorld( &pict1GWorld, 0, &pict1GRect, NULL, NULL, 0L );
  394.         if ( myErr || !pict1GWorld )
  395.         {
  396.             DoAlertStrID( kAlertDialogID, true, kGWorldErr );
  397.             ExitToShell();
  398.         }
  399.  
  400.         // Lock the GWorld's pixels and draw the picture into it.
  401.         LockPixels( GetGWorldPixMap( pict1GWorld ) );
  402.         SetGWorld( (CGrafPtr)pict1GWorld, NULL );
  403.         PaintRect( &pict1GRect );    // first paint it all black
  404.         DrawPicture( aPict, &pict1GRect );
  405.         UnlockPixels( GetGWorldPixMap( pict1GWorld ) );
  406.         
  407.         // Load picture 2 from resource.
  408.         aPict = GetPicture( kPict2ID );
  409.         if ( !aPict )
  410.         {
  411.             DoAlertStrID( kAlertDialogID, true, kMissingResource );
  412.             ExitToShell();
  413.         }
  414.         
  415.         // Get it's optimum rectangle.
  416.         myErr = GetPictInfo( aPict, &pictInfo, 0, 0, 0, 0 );
  417.         pict2GRect = pictInfo.sourceRect;
  418.  
  419.         // Release any extra items GetPictInfo may have allocated
  420.         // if we're not going to use them.
  421.         if ( pictInfo.commentHandle )
  422.             DisposeHandle( (Handle)pictInfo.commentHandle );
  423.         if ( pictInfo.fontHandle )
  424.             DisposeHandle( (Handle)pictInfo.fontHandle );
  425.         
  426.         // Make a GWorld for the picture.
  427.         myErr = NewGWorld( &pict2GWorld, 0, &pict2GRect, NULL, NULL, 0L );
  428.         if ( myErr || !pict1GWorld )
  429.         {
  430.             DoAlertStrID( kAlertDialogID, true, kGWorldErr );
  431.             ExitToShell();
  432.         }
  433.  
  434.         // Lock the GWorld's pixels and draw the picture into it.
  435.         LockPixels( GetGWorldPixMap( pict2GWorld ) );
  436.         SetGWorld( (CGrafPtr)pict2GWorld, NULL );
  437.         PaintRect( &pict2GRect );    // first paint it all black
  438.         DrawPicture( aPict, &pict2GRect );
  439.         UnlockPixels( GetGWorldPixMap( pict2GWorld ) );
  440.         
  441.     // Make sure and restore the dialog as the current port.
  442.     
  443.     SetGWorld( (CGrafPtr)mainDlg, NULL );
  444.         
  445.     // Now wait for the user to press a button in the dialog.
  446.     
  447.     itemHit = -1;
  448.     while ( itemHit != kMainDlgQuit )
  449.     {
  450.         WaitNextEvent( everyEvent, &myEvent, GetCaretTime(), NULL );        
  451.         
  452.         // Check for disk events (bad disk mount).
  453.         
  454.         if ( (myEvent.what == diskEvt) &&
  455.             (HiWord(myEvent.message) != noErr) )
  456.         {
  457.             Point        dlgUpLeftCorner = { 100, 80 };    // ignored in Sys 7
  458.             
  459.             DIBadMount( dlgUpLeftCorner, myEvent.message );    // ignore result
  460.         }
  461.         // If we get an update event, redraw the squares around the
  462.         // picture areas.
  463.         else if ( myEvent.what == updateEvt )
  464.         {
  465.             Rect        tempRect;
  466.             
  467.             tempRect = destRect;
  468.             InsetRect( &tempRect, -1, -1 );
  469.             FrameRect( &tempRect );
  470.             tempRect = pict1Rect;
  471.             InsetRect( &tempRect, -1, -1 );
  472.             FrameRect( &tempRect );
  473.             tempRect = pict2Rect;
  474.             InsetRect( &tempRect, -1, -1 );
  475.             FrameRect( &tempRect );
  476.         }
  477.         
  478.         // If the mouse is over one of the pictures, call a routine
  479.         // to animate a "floating circle" over the picture. A
  480.         // different method is used for each picture to demonstrate
  481.         // the differences.
  482.         {
  483.             Point        mouseLoc;
  484.             
  485.             GetMouse( &mouseLoc );
  486.             
  487.             if ( PtInRect( mouseLoc, &pict1Rect ) )
  488.                 FlickerAnimate( pict1GWorld, &pict1Rect );
  489.             else if ( PtInRect( mouseLoc, &pict2Rect ) )
  490.                 SmoothAnimate( pict2GWorld, &pict2Rect );
  491.         }
  492.  
  493.         // Pass the event to DialogSelect which takes care of tracking
  494.         // controls and updating everything (except the destination
  495.         // area) for us.
  496.         
  497.         if ( DialogSelect( &myEvent, &aDlg, &itemHit ) )
  498.         {
  499.             if ( myEvent.what == mouseDown )
  500.             {
  501.                 // Select the fade speed text field.
  502.                 
  503.                 SelectTextField( mainDlg, kMainDlgFadeSpeed );
  504.                 
  505.                 // Get the fade speed from the dialog (as a number).
  506.                 
  507.                 fadeSpeed = GetDialogNumberField( mainDlg,
  508.                     kMainDlgFadeSpeed );
  509.             }
  510.             
  511.             // What we do here depends on what the user clicked
  512.             
  513.             switch( itemHit )
  514.             {
  515.                 case kMainDlgCopyOne:
  516.                 
  517.                     // This is an example of a very courteous CopyBits
  518.                     // operation saving and restoring the pen state as
  519.                     // well as the fore and background colors and restoring
  520.                     // them afterwards. I don't really need to do this here
  521.                     // because I know they're all set right in the first
  522.                     // place, but they're here as an example.
  523.                     
  524.                     // Save the pen state and foreground/background colors
  525.                     
  526.                         GetPenState( &savedPen );
  527.                         GetForeColor( &savedFore );
  528.                         GetBackColor( &savedBack );
  529.                     
  530.                     // Set foreground color to black, background color to white
  531.                     
  532.                         RGBForeColor( &colors[kBlack] );
  533.                         RGBBackColor( &colors[kWhite] );
  534.                         
  535.                     // Just use CopyBits to copy the PICT. We're actually
  536.                     // copying from one place on the dialog to another here.
  537.  
  538.                         CopyBits( &WINBITMAP( mainDlg ), &WINBITMAP( mainDlg ),
  539.                             &pict1Rect, &destRect, srcCopy, NULL );
  540.                     
  541.                     // Restore the saved pen state and colors
  542.                     
  543.                         SetPenState( &savedPen );
  544.                         RGBForeColor( &savedFore );
  545.                         RGBBackColor( &savedBack );
  546.                         
  547.                     break;
  548.     
  549.                 case kMainDlgFadeOne:
  550.                 
  551.                     // Call FadeToImage to fade picture 1 into the
  552.                     // destination area.
  553.                     
  554.                     FadeToImage( pict1GWorld, &WINPORTRECT( pict1GWorld ),
  555.                         mainDlg, &destRect, fadeSpeed );
  556.                     
  557.                     break;
  558.     
  559.                 case kMainDlgCopyTwo:
  560.                 
  561.                     // Just use CopyBits to copy the PICT from one place in
  562.                     // the window to another.
  563.                     
  564.                         CopyBits( &WINBITMAP( mainDlg ), &WINBITMAP( mainDlg ),
  565.                             &pict2Rect, &destRect, srcCopy, NULL );
  566.                         
  567.                     break;
  568.     
  569.                 case kMainDlgFadeTwo:
  570.                 
  571.                     // Call FadeToImage to fade picture 2 into the
  572.                     // destination area.
  573.                     
  574.                     FadeToImage( pict2GWorld, &WINPORTRECT( pict2GWorld ),
  575.                         mainDlg, &destRect, fadeSpeed );
  576.                                         
  577.                     break;
  578.     
  579.                 case kMainDlgErase:
  580.                 
  581.                     // Erase the destination area.
  582.                     
  583.                     EraseRect( &destRect );
  584.                     
  585.                     break;
  586.     
  587.                 case kMainDlgFadeToBlack1:
  588.                     
  589.                     // Call FadeToBlack to fade the destination rectangle.
  590.                     
  591.                     FadeToBlack1( mainDlg, &destRect, fadeSpeed );
  592.  
  593.                     break;
  594.     
  595.                 case kMainDlgFadeToBlack2:
  596.                     
  597.                     // Call FadeToBlack to fade the destination rectangle.
  598.                     
  599.                     FadeToBlack2( mainDlg, &destRect, fadeSpeed );
  600.  
  601.                     break;
  602.     
  603.                 case kMainDlgFadeToBlack3:
  604.                     
  605.                     // Call FadeToBlack to fade the destination rectangle.
  606.                     
  607.                     FadeToBlack3( mainDlg, &destRect, fadeSpeed );
  608.  
  609.                     break;
  610.     
  611.                 case kMainDlgPixelize:
  612.                 
  613.                     // Call Pixelize.
  614.                     
  615.                     Pixelize( mainDlg, &destRect,
  616.                         mainDlg, &destRect, fadeSpeed, true );
  617.                     
  618.                     break;
  619.                 
  620.                 case kMainDlgDepixelizeOne:
  621.                 
  622.                     // Call Pixelize.
  623.                     
  624.                     LockPixels( GetGWorldPixMap( pict1GWorld ) );
  625.                     Pixelize( (WindowPtr)pict1GWorld, &WINPORTRECT( pict1GWorld ),
  626.                         mainDlg, &destRect, fadeSpeed, false );
  627.                     UnlockPixels( GetGWorldPixMap( pict1GWorld ) );
  628.                     
  629.                     break;
  630.                     
  631.                 case kMainDlgDepixelizeTwo:
  632.                 
  633.                     // Call Pixelize.
  634.                     
  635.                     LockPixels( GetGWorldPixMap( pict2GWorld ) );
  636.                     Pixelize( (WindowPtr)pict2GWorld, &WINPORTRECT( pict2GWorld ),
  637.                         mainDlg, &destRect, fadeSpeed, false );
  638.                     UnlockPixels( GetGWorldPixMap( pict2GWorld ) );
  639.                     
  640.                     break;
  641.                     
  642.                 case kMainDlgFullScreen:
  643.                 
  644.                     // Fade full screen to black, then image 1, then image 2,
  645.                     // then back to original.
  646.  
  647.                     FullScreenDemo( pict1GWorld, pict2GWorld, fadeSpeed );
  648.  
  649.                     break;
  650.                     
  651.                 case kMainDlgBlur:
  652.                 
  653.                     // Blur the destination area.
  654.                     
  655.                     Blur( (WindowPtr)mainDlg, &destRect );
  656.                 
  657.                     break;
  658.                     
  659.                 case kMainDlgFlipHoriz:
  660.                 
  661.                     // Flip the destination area horizontally.
  662.                     
  663.                     FlipHorizontal( (WindowPtr)mainDlg, &destRect );
  664.                     
  665.                     break;
  666.                     
  667.                 case kMainDlgFlipVert:
  668.                 
  669.                     // Flip the destination area horizontally.
  670.                     
  671.                     FlipVertical( (WindowPtr)mainDlg, &destRect );
  672.                     
  673.                     break;
  674.                 
  675.                 case kMainDlgSlideL:
  676.                     
  677.                     // Slide picture one into destination from left.
  678.                     
  679.                     LockPixels( GetGWorldPixMap( pict1GWorld ) );
  680.                     Slide( (WindowPtr)pict1GWorld, &WINPORTRECT( pict1GWorld ),
  681.                         mainDlg, &destRect, fadeSpeed, kLeft );
  682.                     UnlockPixels( GetGWorldPixMap( pict1GWorld ) );
  683.                     
  684.                     break;
  685.                 
  686.                 case kMainDlgSlideR:
  687.                 
  688.                     // Slide picture one into destination from right.
  689.                     
  690.                     LockPixels( GetGWorldPixMap( pict1GWorld ) );
  691.                     Slide( (WindowPtr)pict1GWorld, &WINPORTRECT( pict1GWorld ),
  692.                         mainDlg, &destRect, fadeSpeed, kRight );
  693.                     UnlockPixels( GetGWorldPixMap( pict1GWorld ) );
  694.                     
  695.                     break;
  696.                 
  697.                 case kMainDlgSlideT:
  698.                 
  699.                     // Slide picture one into destination from top.
  700.                     
  701.                     LockPixels( GetGWorldPixMap( pict1GWorld ) );
  702.                     Slide( (WindowPtr)pict1GWorld, &WINPORTRECT( pict1GWorld ),
  703.                         mainDlg, &destRect, fadeSpeed, kTop );
  704.                     UnlockPixels( GetGWorldPixMap( pict1GWorld ) );
  705.                     
  706.                     break;
  707.                 
  708.                 case kMainDlgSlideB:
  709.                 
  710.                     // Slide picture one into destination from bottom.
  711.                     
  712.                     LockPixels( GetGWorldPixMap( pict1GWorld ) );
  713.                     Slide( (WindowPtr)pict1GWorld, &WINPORTRECT( pict1GWorld ),
  714.                         mainDlg, &destRect, fadeSpeed, kBottom );
  715.                     UnlockPixels( GetGWorldPixMap( pict1GWorld ) );
  716.                     
  717.                     break;
  718.                 
  719.                 case kMainDlgApertureIn:
  720.                 
  721.                     // Close a circle in on the destination revealing
  722.                     // picture two outside the circle.
  723.                     
  724.                     LockPixels( GetGWorldPixMap( pict2GWorld ) );
  725.                     Aperture( (WindowPtr)pict2GWorld, &WINPORTRECT( pict2GWorld ),
  726.                         mainDlg, &destRect, fadeSpeed, kIn );
  727.                     UnlockPixels( GetGWorldPixMap( pict2GWorld ) );
  728.                     
  729.                     break;
  730.                 
  731.                 case kMainDlgApertureOut:
  732.                 
  733.                     // Open a circle out on the destination revealing
  734.                     // picture two inside the circle.
  735.                     
  736.                     LockPixels( GetGWorldPixMap( pict2GWorld ) );
  737.                     Aperture( (WindowPtr)pict2GWorld, &WINPORTRECT( pict2GWorld ),
  738.                         mainDlg, &destRect, fadeSpeed, kOut );
  739.                     UnlockPixels( GetGWorldPixMap( pict2GWorld ) );
  740.                     
  741.                     break;
  742.                 
  743.                 case kMainDlgTechDemo:
  744.                 
  745.                     // Open the technical demo window and let the user
  746.                     // mess around.
  747.                     
  748.                     DoTechDemo();
  749.  
  750.                     // Make sure the current port is set back to the
  751.                     // main dialog.
  752.                     
  753.                     SetGWorld( (CGrafPtr)mainDlg, NULL );
  754.  
  755.                     break;
  756.                     
  757.                 case kMainDlgQuit:
  758.                 
  759.                     break;
  760.             }
  761.         }
  762.     }
  763.     
  764.     // Get rid of the main dialog.
  765.     
  766.     DisposeDialog( mainDlg );
  767.     
  768.     // Restore the main monitor's inverse table to 4 bits per
  769.     // color (which is the default).
  770.  
  771.     {
  772.         GDHandle        aDevice;
  773.         
  774.         aDevice = GetGDevice();
  775.         SetGDevice( GetMainDevice() );
  776.         MakeITable( NULL, NULL, 4 );
  777.         SetGDevice( aDevice );
  778.     }
  779. }
  780.  
  781. // FadeToBlack1 creates a black rectangle in an offscreen GWorld that
  782. // is the same size as the destination area. It then calls FadetoImage
  783. // to fade this into the destination thus fading it to black.
  784. //
  785. void FadeToBlack1( WindowPtr destWin, Rect *destRect, short fadeSpeed )
  786. {
  787.     CGrafPtr        savedPort;
  788.     GDHandle        savedDevice;
  789.     GWorldPtr        offscreenWorld;
  790.     OSErr            myErr;
  791.     
  792.     // Save the current port/device. This should be used instead
  793.     // of GetPort. Though savedPort is defined as a CGrafPtr,
  794.     // the routine may return a GrafPtr or pointer to a GWorld
  795.     // instead (GWorldPtr).
  796.     
  797.         GetGWorld( &savedPort, &savedDevice );
  798.  
  799.     // Create an offscreen GWorld with the same depth and size as the
  800.     // destination window/rectangle. Even though the rectangle is all the
  801.     // same shade, we make it the same size as the destination because
  802.     // CopyBits works much faster when it doesn't have to resize the
  803.     // image. The parameters are as follows:
  804.     //        &offscreenWorld        ptr to new graphics world
  805.     //        0                    bit depth same as graphics device of dest rect
  806.     //        destRect            bounds rectangle of my GWorld
  807.     //        NULL                handle to a color table record - NULL means
  808.     //                            use the default record for that depth
  809.     //        NULL                handle to a graphics device record - we aren't
  810.     //                            creating a new graphics device
  811.     //        0L                    no flags
  812.     
  813.         myErr = NewGWorld( &offscreenWorld, 0, destRect, NULL, NULL, 0L );
  814.     
  815.     // Make sure the GWorld was created
  816.     
  817.         if ( myErr )
  818.         {
  819.             DoAlertStrID( kAlertDialogID, true, kGWorldErr );
  820.             ExitToShell();
  821.         }
  822.     
  823.     // Get the GWorld's pixel map handle and lock the pixels while we're
  824.     // drawing to the GWorld. We have to do this because a GWorld actually
  825.     // holds its pixel map in a handle rather than a pointer. LockPixels
  826.     // makes sure the pixel map doesn't move. You should lock a GWorld's
  827.     // pixels before drawing to or copying from the GWorld (and unlock
  828.     // them afterward).
  829.     
  830.         LockPixels( GetGWorldPixMap( offscreenWorld ) );
  831.     
  832.     // Make the GWorld the current port.
  833.     
  834.         SetGWorld( offscreenWorld, NULL );
  835.         
  836.     // Paint the offscreen GWorld all black.
  837.     
  838.         PaintRect( &WINPORTRECT( offscreenWorld ) );
  839.             
  840.     // Restore the saved port/device.
  841.     
  842.         SetGWorld( savedPort, savedDevice );
  843.         
  844.     // Unlock the pixels of the GWorld.
  845.     
  846.         UnlockPixels( GetGWorldPixMap( offscreenWorld ) );
  847.     
  848.     // Call FadeToImage to fade the black rectangle to the destination.
  849.     
  850.         FadeToImage( offscreenWorld, &WINPORTRECT( offscreenWorld ),
  851.             destWin, destRect, fadeSpeed );
  852.     
  853.     // Now get rid of the black GWorld.
  854.     
  855.         DisposeGWorld( offscreenWorld );
  856. }
  857.  
  858. // FadeToBlack2 uses CopyBits and an offscreen graphics world to
  859. // fade an area (specified by destRect) in a window (specified
  860. // by destWin) to black. It does this by creating an offscreen
  861. // graphics world, painting the GWorld gray, then repeatedly
  862. // copying the gray rectangle to the destination area using the
  863. // subPin transfer method of CopyBits. This causes the destination
  864. // to grow darker and darker.
  865. //
  866. void FadeToBlack2( WindowPtr destWin, Rect *destRect, short fadeSpeed )
  867. {
  868.     CGrafPtr        savedPort;
  869.     GDHandle        savedDevice;
  870.     GWorldPtr        offscreenWorld;
  871.     Rect            offscreenRect;
  872.     OSErr            myErr;
  873.     PenState        savedPen;
  874.     RGBColor        savedFore;
  875.     RGBColor        savedBack;
  876.     long            repetitions;
  877.     RGBColor        grayColor;
  878.     
  879.     // Save the current port/device. This should be used instead
  880.     // of GetPort. Though savedPort is defined as a CGrafPtr,
  881.     // the routine may return a GrafPtr or pointer to a GWorld
  882.     // instead (GWorldPtr).
  883.     
  884.         GetGWorld( &savedPort, &savedDevice );
  885.  
  886.     // Set the current port to the destination window
  887.     
  888.         SetGWorld( (CGrafPtr)destWin, NULL );
  889.     
  890.     // Save the pen state and color info of the destination window
  891.     
  892.         GetPenState( &savedPen );
  893.         GetForeColor( &savedFore );
  894.         GetBackColor( &savedBack );
  895.     
  896.     // Make sure the foreground color of the destination window
  897.     // is black and the background color is white.
  898.     
  899.         RGBForeColor( &colors[kBlack] );
  900.         RGBBackColor( &colors[kWhite] );
  901.         
  902.     // Convert the destination rectangle into global coordinates
  903.     
  904.         offscreenRect = (*destRect);
  905.         LocalToGlobal( &TOPLEFT(offscreenRect) );
  906.         LocalToGlobal( &BOTRIGHT(offscreenRect) );
  907.     
  908.     // Make the offscreen rectangle smaller. It doesn't matter since it's
  909.     // all the same color and it'll use up less memory.
  910.     
  911.         offscreenRect.right = offscreenRect.left + 2;
  912.         offscreenRect.bottom = offscreenRect.top + 2;
  913.         
  914.     // Create an offscreen GWorld with the same depth as the
  915.     // destination window/rectangle. The parameters are as follows:
  916.     //        &offscreenWorld        ptr to new graphics world
  917.     //        0                    bit depth same as graphics device of dest rect
  918.     //        &offscreenRect        bounds rectangle of my GWorld
  919.     //        NULL                handle to a color table record - NULL means
  920.     //                            use the default record for that depth
  921.     //        NULL                handle to a graphics device record - we aren't
  922.     //                            creating a new graphics device
  923.     //        0L                    no flags
  924.     
  925.         myErr = NewGWorld( &offscreenWorld, 0, &offscreenRect, NULL, NULL, 0L );
  926.     
  927.     // Make sure the GWorld was created
  928.     
  929.         if ( myErr )
  930.         {
  931.             DoAlertStrID( kAlertDialogID, true, kGWorldErr );
  932.             ExitToShell();
  933.         }
  934.     
  935.     // Make the GWorld the current port
  936.     
  937.         SetGWorld( offscreenWorld, NULL );
  938.         
  939.     // Get the GWorld's pixel map handle and lock the pixels while we're
  940.     // drawing in the GWorld. We have to do this because a GWorld actually
  941.     // holds its pixel map in a handle rather than a pointer. LockPixels
  942.     // makes sure the pixel map doesn't move. You should lock a GWorld's
  943.     // pixels before drawing to or copying from the GWorld (and unlock
  944.     // them afterward).
  945.     
  946.         LockPixels( GetGWorldPixMap( offscreenWorld ) );
  947.     
  948.     // The speed of the fade determines what shade of gray we'll paint
  949.     // the offscreen GWorld. fadeSpeed can range from 0 to 20 with 20
  950.     // being the fastest.
  951.     {
  952.         unsigned short    maxValue=0xFFFF;
  953.         
  954.         if ( fadeSpeed <= 0 ) fadeSpeed = 1;    // make sure speed is not zero
  955.         if ( fadeSpeed > 20 ) fadeSpeed = 20;    // make sure not over 20
  956.         
  957.         grayColor.blue = (fadeSpeed * 625) + 8000;
  958.         grayColor.red = grayColor.green = grayColor.blue;
  959.         RGBForeColor( &grayColor );
  960.         repetitions = maxValue / grayColor.blue;
  961.     }
  962.  
  963.     // Paint it all gray
  964.     
  965.         PaintRect( &(offscreenWorld->portRect) );
  966.     
  967.     // Make the destination window the current port
  968.     
  969.         SetGWorld( (CGrafPtr)destWin, NULL );
  970.         
  971.     // Loop and use CopyBits to copy the gray rectangle into the
  972.     // destination window/rect using the subPin transfer method
  973.     // so that the picture gets darker and darker.
  974.     
  975.         while ( repetitions )
  976.         {
  977.             CopyBits( &WINBITMAP( offscreenWorld ), &WINBITMAP( destWin ),
  978.                 &(offscreenWorld->portRect), destRect, subPin, NULL );
  979.  
  980.             repetitions--;
  981.         }
  982.  
  983.     // Make the GWorld the current port
  984.     
  985.         SetGWorld( offscreenWorld, NULL );
  986.         
  987.     // Now we'll do a fast fade just to make sure everything went completely
  988.     // to black.
  989.     {
  990.         unsigned short    maxValue=0xFFFF;
  991.         
  992.         grayColor.blue = 20500;
  993.         grayColor.red = grayColor.green = grayColor.blue;
  994.         RGBForeColor( &grayColor );
  995.         repetitions = maxValue / grayColor.blue + 1;
  996.     }
  997.  
  998.     // Paint it all gray
  999.     
  1000.         PaintRect( &(offscreenWorld->portRect) );
  1001.     
  1002.     // Make the destination window the current port
  1003.     
  1004.         SetGWorld( (CGrafPtr)destWin, NULL );
  1005.         
  1006.     // Loop and use CopyBits to copy the gray rectangle into the
  1007.     // destination window/rect using the subPin transfer method
  1008.     // so that the picture gets darker and darker.
  1009.     
  1010.         while ( repetitions )
  1011.         {
  1012.             CopyBits( &WINBITMAP( offscreenWorld ), &WINBITMAP( destWin ),
  1013.                 &(offscreenWorld->portRect), destRect, subPin, NULL );
  1014.  
  1015.             repetitions--;
  1016.         }
  1017.  
  1018.     // Unlock the pixels again.
  1019.     
  1020.         UnlockPixels( GetGWorldPixMap( offscreenWorld ) );
  1021.     
  1022.     // Paint the destination rectangle all black.
  1023.     
  1024.         PaintRect( destRect );
  1025.         
  1026.     // Restore the saved port/device
  1027.     
  1028.         SetGWorld( savedPort, savedDevice );
  1029.         
  1030.     // Restore the pen state and color info of the destination window
  1031.     
  1032.         SetPenState( &savedPen );
  1033.         RGBForeColor( &savedFore );
  1034.         RGBBackColor( &savedBack );
  1035.         
  1036.     // Dispose of the GWorld
  1037.     
  1038.         DisposeGWorld( offscreenWorld );
  1039. }
  1040.  
  1041.  
  1042. // FadeToBlack3 uses CopyBits and an offscreen graphics world to
  1043. // fade an area (specified by destRect) in a window (specified
  1044. // by destWin) to black. It does this by creating an offscreen
  1045. // graphics world, and repeatedly copying darker and darker
  1046. // shades of gray into the destination using the adMin transfer
  1047. // method of CopyBits. This method compares the pixels in the
  1048. // source (gray) and destination images and replaces the pixel
  1049. // in the destination if the source is darker (closer to zero).
  1050. // This has the effect of making the destination darker and
  1051. // darker starting with the lighter colors and ending with the
  1052. // darker colors and eventually blacking the destination out.
  1053. //
  1054. void FadeToBlack3( WindowPtr destWin, Rect *destRect, short fadeSpeed )
  1055. {
  1056.     CGrafPtr        savedPort;
  1057.     GDHandle        savedDevice;
  1058.     GWorldPtr        offscreenWorld;
  1059.     Rect            offscreenRect;
  1060.     OSErr            myErr;
  1061.     RGBColor        savedFore;
  1062.     RGBColor        savedBack;
  1063.     RGBColor        grayColor;
  1064.     long            colorStep;
  1065.     short            speed;
  1066.     
  1067.     // Save the current port/device. This should be used instead
  1068.     // of GetPort. Though savedPort is defined as a CGrafPtr,
  1069.     // the routine may return a GrafPtr or pointer to a GWorld
  1070.     // instead (GWorldPtr).
  1071.     
  1072.         GetGWorld( &savedPort, &savedDevice );
  1073.  
  1074.     // Set the current port to the destination window.
  1075.     
  1076.         SetGWorld( (CGrafPtr)destWin, NULL );
  1077.     
  1078.     // Save the color info of the destination window.
  1079.     
  1080.         GetForeColor( &savedFore );
  1081.         GetBackColor( &savedBack );
  1082.     
  1083.     // Make sure the foreground color of the destination window
  1084.     // is black and the background color is white.
  1085.     
  1086.         RGBForeColor( &colors[kBlack] );
  1087.         RGBBackColor( &colors[kWhite] );
  1088.         
  1089.     // Convert the destination rectangle into global coordinates.
  1090.     
  1091.         offscreenRect = (*destRect);
  1092.         LocalToGlobal( &TOPLEFT(offscreenRect) );
  1093.         LocalToGlobal( &BOTRIGHT(offscreenRect) );
  1094.     
  1095.     // Create an offscreen GWorld with the same depth and size as the
  1096.     // destination window/rectangle. Even though the rectangle is all the
  1097.     // same shade, we make it the same size as the destination because
  1098.     // CopyBits works much faster when it doesn't have to resize the
  1099.     // image. The parameters are as follows:
  1100.     //        &offscreenWorld        ptr to new graphics world
  1101.     //        0                    bit depth same as graphics device of dest rect
  1102.     //        &offscreenRect        bounds rectangle of my GWorld
  1103.     //        NULL                handle to a color table record - NULL means
  1104.     //                            use the default record for that depth
  1105.     //        NULL                handle to a graphics device record - we aren't
  1106.     //                            creating a new graphics device
  1107.     //        0L                    no flags
  1108.     
  1109.         myErr = NewGWorld( &offscreenWorld, 0, &offscreenRect, NULL, NULL, 0L );
  1110.     
  1111.     // Make sure the GWorld was created
  1112.     
  1113.         if ( myErr )
  1114.         {
  1115.             DoAlertStrID( kAlertDialogID, true, kGWorldErr );
  1116.             ExitToShell();
  1117.         }
  1118.     
  1119.     // Get the GWorld's pixel map handle and lock the pixels while we're
  1120.     // drawing to the GWorld. We have to do this because a GWorld actually
  1121.     // holds its pixel map in a handle rather than a pointer. LockPixels
  1122.     // makes sure the pixel map doesn't move. You should lock a GWorld's
  1123.     // pixels before drawing to or copying from the GWorld (and unlock
  1124.     // them afterward).
  1125.     
  1126.         LockPixels( GetGWorldPixMap( offscreenWorld ) );
  1127.     
  1128.     // Determine the number to subtract from the gray shade every time we
  1129.     // loop. This is determined by the fadeSpeed parameter.
  1130.     
  1131.         if ( fadeSpeed < 0 )
  1132.             speed = 0;
  1133.         else if ( fadeSpeed > 20 )
  1134.             speed = 20;
  1135.         else
  1136.             speed = fadeSpeed;
  1137.             
  1138.         colorStep = ( 0xFFFF / (21-fadeSpeed) ) / 2;
  1139.         
  1140.     // Our gray color just starts out as white.
  1141.     
  1142.         grayColor = colors[kWhite];
  1143.     
  1144.     // Loop until the gray color is black.
  1145.     
  1146.         while ( grayColor.blue > 0 )
  1147.         {
  1148.             // Make the GWorld the current port.
  1149.             
  1150.             SetGWorld( offscreenWorld, NULL );
  1151.                 
  1152.             // Subtract the color step value from the gray value and
  1153.             // paint the offscreen GWorld.
  1154.             
  1155.             if ( grayColor.blue > colorStep )
  1156.                 grayColor.blue -= colorStep;
  1157.             else
  1158.                 grayColor.blue = 0;
  1159.             grayColor.green = grayColor.red = grayColor.blue;
  1160.             RGBForeColor( &grayColor );
  1161.             PaintRect( &WINPORTRECT( offscreenWorld ) );
  1162.             
  1163.             // Make the destination window the current port.
  1164.             
  1165.             SetGWorld( (CGrafPtr)destWin, NULL );
  1166.             
  1167.             // Use CopyBits with the adMin transfer mode to copy the
  1168.             // gray rectangle to the destination window/area.
  1169.             
  1170.             CopyBits( &WINBITMAP( offscreenWorld ),
  1171.                 &WINBITMAP( destWin ),
  1172.                 &WINPORTRECT( offscreenWorld ),
  1173.                 destRect, adMin, NULL );
  1174.         }
  1175.         
  1176.     // Set the current port to the destination window.
  1177.     
  1178.         SetGWorld( (CGrafPtr)destWin, NULL );
  1179.     
  1180.     // Restore the color info of the destination window.
  1181.     
  1182.         RGBForeColor( &savedFore );
  1183.         RGBBackColor( &savedBack );
  1184.         
  1185.     // Restore the saved port/device.
  1186.     
  1187.         SetGWorld( savedPort, savedDevice );
  1188.         
  1189.     // Unlock the pixels of the GWorld and dispose of it.
  1190.     
  1191.         UnlockPixels( GetGWorldPixMap( offscreenWorld ) );
  1192.         DisposeGWorld( offscreenWorld );
  1193. }
  1194.  
  1195. // FadeToImage takes the source image and does a smooth fade in
  1196. // the destination window and rect from the image that is currently
  1197. // there to the source image. This is done using CopyBits with
  1198. // the "blend" transfer mode.
  1199. //
  1200. void FadeToImage( GWorldPtr srcImage, Rect *srcRect,
  1201.     WindowPtr destWin, Rect *destRect, short fadeSpeed )
  1202. {
  1203.     CGrafPtr            savedPort;
  1204.     GDHandle            savedDevice;
  1205.     RGBColor            savedFore, savedBack;
  1206.     PenState            savedPen;
  1207.     RGBColor            grayColor;
  1208.     float                speed;
  1209.     unsigned short        lastColor;
  1210.     
  1211.     // Make sure speed is within our limits and set it appropriately.
  1212.     // We want to end up with a range of 1.2 to 3.2 from the original
  1213.     // 0 to 20 range.
  1214.     
  1215.     if ( fadeSpeed < 1 ) speed = 1.2;
  1216.     else if ( fadeSpeed > 20 ) speed = 3.2;
  1217.     else
  1218.     {
  1219.         speed = fadeSpeed;
  1220.         speed = 1.2 + (speed/10);
  1221.     }
  1222.     
  1223.     // Save the current port and device
  1224.     
  1225.         GetGWorld( &savedPort, &savedDevice );
  1226.         
  1227.     // Set the port to the destination window and save its
  1228.     // pen state and fore/background color values.
  1229.     
  1230.         SetGWorld( (CGrafPtr)destWin, NULL );
  1231.         GetPenState( &savedPen );
  1232.         GetForeColor( &savedFore );
  1233.         GetBackColor( &savedBack );
  1234.     
  1235.     // Make sure the port's fore and background colors are set
  1236.     // correctly for CopyBits to work correctly.
  1237.         
  1238.         RGBForeColor( &colors[kBlack] );
  1239.         RGBBackColor( &colors[kWhite] );
  1240.             
  1241.     // Lock the pixels in the source image. This is required
  1242.     // when copying from a GWorld.
  1243.         
  1244.         LockPixels( GetGWorldPixMap( srcImage ) );
  1245.     
  1246.     // Set the beginning blend weight. This will be multiplied by
  1247.     // speed before being used the first time.
  1248.     
  1249.         grayColor.blue = grayColor.green = grayColor.red = 0x0F00;
  1250.         lastColor = 0;
  1251.         
  1252.     // Loop and copy the source image to the destination
  1253.     // blending more and more of the source image in by using
  1254.     // a lighter and lighter "blend weight" (set by the OpColor
  1255.     // function).
  1256.  
  1257.         while ( grayColor.blue < 0xFFFF )
  1258.         {
  1259.             // Lighten the blend weight color.
  1260.             
  1261.             grayColor.blue *= speed;
  1262.             
  1263.             // Make sure the number didn't roll over.
  1264.             
  1265.             if ( grayColor.blue < lastColor )
  1266.                 grayColor.blue = 0xFFFF;
  1267.             
  1268.             grayColor.red = grayColor.green = grayColor.blue;
  1269.  
  1270.             // Remember the number for next time.
  1271.             
  1272.             lastColor = grayColor.blue;
  1273.             
  1274.             // Set the new blend weight.
  1275.             
  1276.             OpColor( &grayColor );
  1277.             
  1278.             // copy the image
  1279.             
  1280.             CopyBits( &WINBITMAP( srcImage ),
  1281.                 &WINBITMAP( destWin ),
  1282.                 srcRect, destRect, blend, NULL );
  1283.         }
  1284.  
  1285.     // Finally, just copy the source image to the destination
  1286.     // window unchanged to make sure the transformation is
  1287.     // complete.
  1288.     
  1289.         CopyBits( &WINBITMAP( srcImage ),
  1290.             &WINBITMAP( destWin ),
  1291.             srcRect, destRect, srcCopy, NULL );
  1292.     
  1293.     // Reset the blend weight to black.
  1294.     // This is the "normal" weight.
  1295.     
  1296.         OpColor( &colors[kBlack] );
  1297.     
  1298.     // Unlock the pixels in the source image.
  1299.     
  1300.         UnlockPixels( GetGWorldPixMap( srcImage ) );
  1301.         
  1302.     // Restore the destination window's properties.
  1303.     
  1304.         SetPenState( &savedPen );
  1305.         RGBForeColor( &savedFore );
  1306.         RGBBackColor( &savedBack );
  1307.         
  1308.     // Restore the current port and device.
  1309.     
  1310.         SetGWorld( savedPort, savedDevice );
  1311. }
  1312.  
  1313. // Pixelize makes a picture "blockier" in several steps.
  1314. // It first copies the original picture from the destination
  1315. // area, then repeatedly copies the original picture
  1316. // into areas smaller than the size of the previous one,
  1317. // using CopyBits to scale the picture back up into the
  1318. // destination window at the original size.
  1319. //
  1320. // The srcWin/srcRect and destWin/destRect may be the same
  1321. // window/area to pixelize, but not to depixelize.
  1322. // When depixelizing, srcWin will usually be a GWorldPtr
  1323. // containing an image the same size as the destination area.
  1324. //
  1325. void Pixelize( WindowPtr srcWin, Rect *srcRect,
  1326.     WindowPtr destWin, Rect *destRect, short speed, Boolean pixelizing )
  1327. {
  1328.     GWorldPtr        srcImage;
  1329.     GWorldPtr        intermedImage;
  1330.     Rect            intermedRect;
  1331.     CGrafPtr        savedPort;
  1332.     GDHandle        savedDevice;
  1333.     OSErr            myErr;
  1334.     float            theSpeed;
  1335.     Boolean            done;
  1336.     
  1337.     // Make sure speed is within our limits and set it appropriately.
  1338.     // We want to end up with a range of 1.1 to 2.1 from the original
  1339.     // 0 to 20 range.
  1340.     
  1341.     if ( speed < 1 ) theSpeed = 1.1;
  1342.     else if ( speed > 20 ) theSpeed = 2.1;
  1343.     else
  1344.     {
  1345.         theSpeed = speed;
  1346.         theSpeed = 1.1 + (theSpeed/20);
  1347.     }
  1348.     
  1349.     // Save the original port and device.
  1350.     
  1351.     GetGWorld( &savedPort, &savedDevice );
  1352.     
  1353.     // Create an offscreen GWorld with the same depth as the
  1354.     // destination window/rectangle. The parameters are as follows:
  1355.     //        &srcImage            ptr to new graphics world
  1356.     //        0                    bit depth same as graphics device of dest rect
  1357.     //        destRect            bounds rectangle of my GWorld
  1358.     //        NULL                handle to a color table record - NULL means
  1359.     //                            use the default record for that depth
  1360.     //        NULL                handle to a graphics device record - we aren't
  1361.     //                            creating a new graphics device
  1362.     //        0L                    no flags
  1363.     
  1364.         myErr = NewGWorld( &srcImage, 0, destRect, NULL, NULL, 0L );
  1365.     
  1366.     // Make sure the GWorld was created
  1367.     
  1368.         if ( myErr )
  1369.         {
  1370.             DoAlertStrID( kAlertDialogID, true, kGWorldErr );
  1371.             ExitToShell();
  1372.         }
  1373.     
  1374.     // Also create an intermediate GWorld used in the scaling/copying.
  1375.     
  1376.         myErr = NewGWorld( &intermedImage, 0, destRect, NULL, NULL, 0L );
  1377.         
  1378.     // Make sure the GWorld was created
  1379.     
  1380.         if ( myErr )
  1381.         {
  1382.             DoAlertStrID( kAlertDialogID, true, kGWorldErr );
  1383.             ExitToShell();
  1384.         }
  1385.     
  1386.     // Copy the source image into the GWorld.
  1387.     
  1388.     SetGWorld( srcImage, NULL );
  1389.     CopyBits( &WINBITMAP( srcWin ), &WINBITMAP( srcImage ),
  1390.         srcRect, &WINPORTRECT( srcImage ), srcCopy, NULL );
  1391.     
  1392.     // Lock the pixels of the source and intermediate GWorlds
  1393.     // since we'll be copying from them.
  1394.     
  1395.     LockPixels( GetGWorldPixMap( srcImage ) );
  1396.     LockPixels( GetGWorldPixMap( intermedImage ) );
  1397.     
  1398.     // We need a beginning intermediate image size.
  1399.     
  1400.     if ( pixelizing )
  1401.         intermedRect = WINPORTRECT( intermedImage );
  1402.     else
  1403.     {
  1404.         intermedRect = WINPORTRECT( intermedImage );
  1405.         intermedRect.bottom /= 15;
  1406.         intermedRect.right /= 15;
  1407.     }
  1408.     
  1409.     // Loop and copy the image into smaller GWorlds.
  1410.     
  1411.     done = false;
  1412.     while ( !done )
  1413.     {
  1414.         // Adjust the intermediate rectangle size and determine if
  1415.         // this will be the last time through the loop.
  1416.         
  1417.         if ( pixelizing )
  1418.         {
  1419.             intermedRect.bottom /= theSpeed;
  1420.             intermedRect.right /= theSpeed;
  1421.  
  1422.             if ( intermedRect.bottom < ( WINPORTRECT( intermedImage ).bottom / 10 ) )
  1423.                 done = true;
  1424.         }
  1425.         else
  1426.         {
  1427.             intermedRect.bottom *= theSpeed;
  1428.             intermedRect.right *= theSpeed;
  1429.             
  1430.             if (( intermedRect.bottom > WINPORTRECT( intermedImage ).bottom ) ||
  1431.                 ( intermedRect.right > WINPORTRECT( intermedImage ).right ))
  1432.             {
  1433.                 intermedRect = WINPORTRECT( intermedImage );
  1434.                 done = true;
  1435.             }
  1436.         }
  1437.         
  1438.         // Copy the original image into the intermediate GWorld.
  1439.         
  1440.         SetGWorld( (CGrafPtr)intermedImage, NULL );
  1441.         CopyBits( &WINBITMAP( srcImage ), &WINBITMAP( intermedImage ),
  1442.             &WINPORTRECT( srcImage ), &intermedRect, srcCopy, NULL );
  1443.         
  1444.         // Copy the intermediate GWorld to the destination.
  1445.         
  1446.         SetGWorld( (CGrafPtr)destWin, NULL );
  1447.         CopyBits( &WINBITMAP( intermedImage ), &WINBITMAP( destWin ),
  1448.             &intermedRect, destRect, srcCopy, NULL );
  1449.     }
  1450.     
  1451.     // Unlock everyone's pixels again.
  1452.  
  1453.     UnlockPixels( GetGWorldPixMap( srcImage ) );
  1454.     UnlockPixels( GetGWorldPixMap( intermedImage ) );
  1455.  
  1456.     // Restore the original port and device.
  1457.     
  1458.     SetGWorld( savedPort, savedDevice );
  1459.     
  1460.     // Destroy the GWorld holding the original image and the
  1461.     // intermediate GWorld.
  1462.     
  1463.     DisposeGWorld( srcImage );
  1464.     DisposeGWorld( intermedImage );
  1465. }
  1466.  
  1467. // FlickerAnimate animates a colored circle floating over
  1468. // a picture at the mouse location. It draws directly to
  1469. // the screen resulting in a circle that the background
  1470. // occasionally "flickers" through. Drawing will occur in
  1471. // the current port.
  1472. //
  1473. void FlickerAnimate( GWorldPtr srcPict, Rect *destRect )
  1474. {
  1475.     Point        mouseLoc;
  1476.     Rect        mouseRect;
  1477.     RGBColor    savedFore, savedBack;
  1478.     RgnHandle        savedClip;
  1479.     RGBColor    redColor;
  1480.     long        ignore;
  1481.         
  1482.     // Make the color to draw the circle with.
  1483.     
  1484.     redColor.blue = redColor.green = 0;
  1485.     redColor.red = 0xFFFF;
  1486.     
  1487.     // Save fore and background colors and make them
  1488.     // fore-black and back-white.
  1489.     
  1490.     GetForeColor( &savedFore ); GetBackColor( &savedBack );
  1491.     RGBForeColor( &colors[kBlack] ); RGBBackColor( &colors[kWhite] );
  1492.     
  1493.     // Save the clipping region.
  1494.     
  1495.     savedClip = NewRgn();
  1496.     GetClip( savedClip );
  1497.  
  1498.     // Set the clipping region to just cover the picture.
  1499.     
  1500.     ClipRect( destRect );
  1501.  
  1502.     // Lock the pixel map of the src GWorld while copying from it.
  1503.     
  1504.     LockPixels( GetGWorldPixMap( srcPict ) );
  1505.  
  1506.     // Loop and draw the picture and circle repeatedly.
  1507.     
  1508.     do
  1509.     {
  1510.         // Get a mouse location.
  1511.         
  1512.             GetMouse( &mouseLoc );
  1513.         
  1514.         // Make a square around the mouse location to draw
  1515.         // the circle in.
  1516.         
  1517.             mouseRect.left = mouseRect.right = mouseLoc.h;
  1518.             mouseRect.top = mouseRect.bottom = mouseLoc.v;
  1519.             InsetRect( &mouseRect, -20, -20 );
  1520.     
  1521.         // Copy the picture to the window.
  1522.  
  1523.             CopyBits( &WINBITMAP( srcPict ),
  1524.                 &WINBITMAP( FrontWindow() ),
  1525.                 &WINPORTRECT( srcPict ),
  1526.                 destRect, srcCopy, NULL );
  1527.             
  1528.         // Draw the circle at the mouse location.
  1529.         
  1530.             RGBForeColor( &redColor );
  1531.             PaintOval( &mouseRect );
  1532.             RGBForeColor( &colors[kBlack] );
  1533.         
  1534.         // Delay for a fraction of a second here. If we
  1535.         // don't, the flickering is really, really bad.
  1536.         
  1537.             Delay( 2, &ignore );
  1538.             
  1539.     } while ( PtInRect( mouseLoc, destRect ) );
  1540.  
  1541.     // Draw the picture one more time to make sure the
  1542.     // circle is erased.
  1543.     
  1544.         CopyBits( &WINBITMAP( srcPict ),
  1545.             &WINBITMAP( FrontWindow() ),
  1546.             &WINPORTRECT( srcPict ),
  1547.             destRect, srcCopy, NULL );
  1548.  
  1549.     // Unlock the GWorld's pixel map.
  1550.     
  1551.         UnlockPixels( GetGWorldPixMap( srcPict ) );
  1552.  
  1553.     // Restore the clipping region.
  1554.     
  1555.         SetClip( savedClip );
  1556.     
  1557.     // Restore the saved fore and background colors.
  1558.     
  1559.         RGBForeColor( &savedFore );
  1560.         RGBBackColor( &savedBack );
  1561. }
  1562.  
  1563. // SmoothAnimate animates a colored circle floating over
  1564. // a picture at the mouse location. It draws to a GWorld
  1565. // then copies the GWorld to the screen. This results in
  1566. // flicker-free animation where the background never
  1567. // shows through the floating circle.
  1568. //
  1569. void SmoothAnimate( GWorldPtr srcPict, Rect *destRect )
  1570. {
  1571.     Point            mouseLoc;
  1572.     Rect            mouseRect;
  1573.     RGBColor        savedFore, savedBack;
  1574.     PixMapHandle    srcPixMap, midPixMap;
  1575.     GWorldPtr        middleMan;
  1576.     CGrafPtr        thisWindow;
  1577.     GDHandle        thisDevice;
  1578.     RGBColor        purpleColor;
  1579.     OSErr            myErr;
  1580.     
  1581.     // Save the current window and device (this is the window
  1582.     // we're drawing into.)
  1583.     
  1584.     GetGWorld( &thisWindow, &thisDevice );
  1585.     
  1586.     // Make the color to draw the circle with.
  1587.     
  1588.     purpleColor.blue = purpleColor.red = 0xFFFF;
  1589.     purpleColor.green = 0;
  1590.     
  1591.     // Save fore and background colors and make them
  1592.     // fore-black and back-white.
  1593.     
  1594.     GetForeColor( &savedFore ); GetBackColor( &savedBack );
  1595.     RGBForeColor( &colors[kBlack] ); RGBBackColor( &colors[kWhite] );
  1596.     
  1597.     // Make a GWorld to draw the picture and circle into. The
  1598.     // onscreen image will be copied from this "middle man."
  1599.     // It is the same size and depth as the destination
  1600.     // on screen.
  1601.     //        &middleMan            ptr to new graphics world
  1602.     //        0                    bit depth same as graphics device of dest rect
  1603.     //        destRect            bounds rectangle of new GWorld
  1604.     //        NULL                handle to a color table record - NULL means
  1605.     //                            use the default record for that depth
  1606.     //        NULL                handle to a graphics device record - we aren't
  1607.     //                            creating a new graphics device
  1608.     //        0L                    no flags
  1609.     
  1610.         myErr = NewGWorld( &middleMan, 0, destRect, NULL, NULL, 0L );
  1611.  
  1612.     // Make sure the GWorld was created
  1613.     
  1614.         if ( myErr || !middleMan )
  1615.         {
  1616.             DoAlertStrID( kAlertDialogID, true, kGWorldErr );
  1617.             ExitToShell();
  1618.         }
  1619.     
  1620.     // Lock the pixel map of the src GWorld and the middleMan
  1621.     // GWorld while copying from them.
  1622.     
  1623.         srcPixMap = GetGWorldPixMap( srcPict );
  1624.         LockPixels( srcPixMap );
  1625.         midPixMap = GetGWorldPixMap( middleMan );
  1626.         LockPixels( midPixMap );
  1627.  
  1628.     // Loop and draw the pict and the circle repeatedly.
  1629.     
  1630.     do
  1631.     {
  1632.         // Get a mouse location and translate into coordinates
  1633.         // local to the middleMan GWorld.
  1634.         
  1635.             GetMouse( &mouseLoc );
  1636.             mouseLoc.h -= destRect->left;
  1637.             mouseLoc.v -= destRect->top;
  1638.  
  1639.         // Make a square around the mouse location to draw
  1640.         // the circle in.
  1641.         
  1642.             mouseRect.left = mouseRect.right = mouseLoc.h;
  1643.             mouseRect.top = mouseRect.bottom = mouseLoc.v;
  1644.             InsetRect( &mouseRect, -20, -20 );
  1645.     
  1646.         // Set the current port to middleMan.
  1647.         
  1648.             SetGWorld( (CGrafPtr)middleMan, NULL );
  1649.         
  1650.         // Copy the picture to the middleMan GWorld.
  1651.  
  1652.             CopyBits( &WINBITMAP( srcPict ),
  1653.                 &WINBITMAP( middleMan ),
  1654.                 &WINPORTRECT( srcPict ),
  1655.                 &WINPORTRECT( middleMan ), srcCopy, NULL );
  1656.         
  1657.         // Draw the circle at the mouse location.
  1658.         
  1659.             RGBForeColor( &purpleColor );
  1660.             PaintOval( &mouseRect );
  1661.             RGBForeColor( &colors[kBlack] );
  1662.         
  1663.         // Reset the current port to the destination window.
  1664.         
  1665.             SetGWorld( thisWindow, thisDevice );
  1666.         
  1667.         // Now copy the middleMan image to the destination
  1668.         // window on screen.
  1669.         
  1670.             CopyBits( &WINBITMAP( middleMan ),
  1671.                 &WINBITMAP( thisWindow ),
  1672.                 &WINPORTRECT( middleMan ),
  1673.                 destRect, srcCopy, NULL );
  1674.                 
  1675.     } while ( PtInRect( mouseLoc, &WINPORTRECT( middleMan ) ) );
  1676.  
  1677.     // Draw the picture one more time to make sure the
  1678.     // circle is erased.
  1679.     
  1680.         CopyBits( &WINBITMAP( srcPict ),
  1681.             &WINBITMAP( FrontWindow() ),
  1682.             &WINPORTRECT( srcPict ),
  1683.             destRect, srcCopy, NULL );
  1684.  
  1685.     // Unlock the GWorld's and middleMan's pixel maps.
  1686.     
  1687.         UnlockPixels( srcPixMap );
  1688.         UnlockPixels( midPixMap );
  1689.     
  1690.     // Dispose of the middleMan GWorld.
  1691.     
  1692.         DisposeGWorld( middleMan );
  1693.  
  1694.     // Restore the saved fore and background colors.
  1695.     
  1696.         RGBForeColor( &savedFore );
  1697.         RGBBackColor( &savedBack );
  1698. }
  1699.  
  1700. // FullScreenDemo fades the whole screen to black, then to picture one
  1701. // then to picture two and finally to the original screen (which is
  1702. // saved in a GWorld).
  1703. //
  1704. void FullScreenDemo( GWorldPtr pict1, GWorldPtr pict2, short fadeSpeed )
  1705. {
  1706.     // Fade full screen to black, then image 1, then image 2,
  1707.     // then back to original.
  1708.     
  1709.     OSErr            myErr;
  1710.     GWorldPtr        theScreen;
  1711.     CGrafPort        myPort;
  1712.     CGrafPtr        savedPort;
  1713.     GDHandle        savedDevice;
  1714.     
  1715.     // If Color QuickDraw is not available, don't do this.
  1716.     
  1717.         if ( !HasColorQuickDraw() )
  1718.             return;
  1719.     
  1720.     // Save the current port and device.
  1721.     
  1722.         GetGWorld( &savedPort, &savedDevice );
  1723.     
  1724.     // Open a port that covers the main screen. OpenCPort, by default,
  1725.     // makes the port the same size as the main screen.
  1726.     
  1727.         OpenCPort( &myPort );
  1728.         SetGWorld( &myPort, NULL );
  1729.     
  1730.     // Make a GWorld to store the current screen picture in.
  1731.     
  1732.         myErr = NewGWorld( &theScreen, 0, &WINPORTRECT( &myPort ), NULL, NULL, 0L );
  1733.         if ( myErr )
  1734.         {
  1735.             CloseCPort( &myPort );
  1736.             DoAlertStrID( kAlertDialogID, true, kGWorldErr );
  1737.             ExitToShell();
  1738.             return;
  1739.         }
  1740.  
  1741.     // Copy the screen picture into the GWorld.
  1742.     
  1743.         CopyBits( &WINBITMAP( &myPort ),
  1744.                     &WINBITMAP( theScreen ),
  1745.                     &WINPORTRECT( &myPort ),
  1746.                     &WINPORTRECT( theScreen ),
  1747.                     srcCopy, NULL );
  1748.  
  1749.     // Now fade the screen to black.
  1750.     
  1751.         FadeToBlack2( (WindowPtr)&myPort, &WINPORTRECT( &myPort ), fadeSpeed );
  1752.         
  1753.     // Slide the first image in from the left.
  1754.     
  1755.         LockPixels( GetGWorldPixMap( pict1 ) );
  1756.         Slide( (WindowPtr)pict1, &WINPORTRECT( pict1 ),
  1757.             (WindowPtr)&myPort, &WINPORTRECT( &myPort ), fadeSpeed, kLeft );
  1758.         UnlockPixels( GetGWorldPixMap( pict1 ) );
  1759.         
  1760.     // Fade the second image in.
  1761.     
  1762.         FadeToImage( pict2, &WINPORTRECT( pict2 ),
  1763.             (WindowPtr)&myPort, &WINPORTRECT( &myPort ), fadeSpeed );
  1764.             
  1765.     // Slide the original screen back in from the right.
  1766.     
  1767.         LockPixels( GetGWorldPixMap( theScreen ) );
  1768.         Slide( (WindowPtr)theScreen, &WINPORTRECT( theScreen ),
  1769.             (WindowPtr)&myPort, &WINPORTRECT( &myPort ), fadeSpeed, kRight );
  1770.         UnlockPixels( GetGWorldPixMap( theScreen ) );
  1771.     
  1772.     // Now get rid of the GWorld we used to hold the screen image.
  1773.     
  1774.         DisposeGWorld( theScreen );
  1775.  
  1776.     // Close the port.
  1777.     
  1778.         CloseCPort( &myPort );
  1779.     
  1780.     // Restore the saved port and device.
  1781.     
  1782.         SetGWorld( savedPort, savedDevice );
  1783. }
  1784.  
  1785. // Blur blurs the destination picture by varying the destination image
  1786. // in an offscreen GWorld slightly and blending the varied images back
  1787. // into the original destination image.
  1788. //
  1789. void Blur( WindowPtr destWin, Rect *destRect )
  1790. {
  1791.     CGrafPtr        savedPort;
  1792.     GDHandle        savedDevice;
  1793.     GWorldPtr        offscreenWorld;
  1794.     Rect            copyRect;
  1795.     RGBColor        savedFore, savedBack;
  1796.     RGBColor        grayColor;
  1797.     OSErr            myErr;
  1798.     short            x;
  1799.     RgnHandle        savedClip;
  1800.     
  1801.     // Save the current device and port.
  1802.     
  1803.     GetGWorld( &savedPort, &savedDevice );
  1804.     
  1805.     // Create a GWorld the same size as the destination image
  1806.     // with the same depth as the destination window/rectangle.
  1807.     // The parameters are as follows:
  1808.     //        &offscreenWorld        ptr to new graphics world
  1809.     //        0                    bit depth same as graphics device of dest rect
  1810.     //        destRect            bounds rectangle of my GWorld
  1811.     //        NULL                handle to a color table record - NULL means
  1812.     //                            use the default record for that depth
  1813.     //        NULL                handle to a graphics device record - we aren't
  1814.     //                            creating a new graphics device
  1815.     //        0L                    no flags
  1816.     
  1817.         myErr = NewGWorld( &offscreenWorld, 0, destRect, NULL, NULL, 0L );
  1818.     
  1819.     // Make sure the GWorld was created
  1820.     
  1821.         if ( myErr )
  1822.         {
  1823.             DoAlertStrID( kAlertDialogID, true, kGWorldErr );
  1824.             ExitToShell();
  1825.         }
  1826.         
  1827.     // Make the GWorld the current port.
  1828.     
  1829.     SetGWorld( (CGrafPtr)offscreenWorld, NULL );
  1830.     
  1831.     // Copy the destination image into the GWorld.
  1832.     
  1833.     CopyBits( &WINBITMAP( destWin ), &WINBITMAP( offscreenWorld ),
  1834.         destRect, &WINPORTRECT( offscreenWorld ), srcCopy, NULL );
  1835.     
  1836.     // Make the destination window the current port.
  1837.     
  1838.     SetGWorld( (CGrafPtr)destWin, NULL );
  1839.     
  1840.     // Save the destination window's fore/background colors.
  1841.     
  1842.     GetBackColor( &savedBack );
  1843.     GetForeColor( &savedFore );
  1844.     
  1845.     // Make sure the destination window's fore/background colors
  1846.     // are black/white.
  1847.     
  1848.     RGBForeColor( &colors[kBlack] );
  1849.     RGBBackColor( &colors[kWhite] );
  1850.     
  1851.     // Save the destination window's clip region and set it to
  1852.     // the destination rectangle.
  1853.     
  1854.     savedClip = NewRgn();
  1855.     GetClip( savedClip );
  1856.     ClipRect( destRect );
  1857.     
  1858.     // Set the OpColor for blending.
  1859.  
  1860.     grayColor.red = grayColor.green = grayColor.blue = 0x4000;
  1861.     OpColor( &grayColor );
  1862.  
  1863.     // Lock the GWorld's pixels while we copy from it.
  1864.     
  1865.     LockPixels( GetGWorldPixMap( offscreenWorld ) );
  1866.     
  1867.     // Blend the GWorld image back into the destination image in
  1868.     // a circular pattern.
  1869.     
  1870.     for ( x=1; x<9; x++ )
  1871.     {
  1872.         copyRect = *destRect;
  1873.         
  1874.         switch( x )
  1875.         {
  1876.             case 1:
  1877.                 OffsetRect( ©Rect, -2, 0 );
  1878.                 break;
  1879.             case 2:
  1880.                 OffsetRect( ©Rect, -1, -1 );
  1881.                 break;
  1882.             case 3:
  1883.                 OffsetRect( ©Rect, 0, -2 );
  1884.                 break;
  1885.             case 4:
  1886.                 OffsetRect( ©Rect, 1, -1 );
  1887.                 break;
  1888.             case 5:
  1889.                 OffsetRect( ©Rect, 2, 0 );
  1890.                 break;
  1891.             case 6:
  1892.                 OffsetRect( ©Rect, 1, 1 );
  1893.                 break;
  1894.             case 7:
  1895.                 OffsetRect( ©Rect, 0, 2 );
  1896.                 break;
  1897.             case 8:
  1898.                 OffsetRect( ©Rect, -1, 1 );
  1899.                 break;
  1900.         }
  1901.         
  1902.         CopyBits( &WINBITMAP( offscreenWorld ), &WINBITMAP( destWin ),
  1903.             &WINPORTRECT( offscreenWorld ), ©Rect, blend, NULL );
  1904.     }
  1905.  
  1906.     // Unlock the GWorld's pixels.
  1907.     
  1908.     UnlockPixels( GetGWorldPixMap( offscreenWorld ) );
  1909.     
  1910.     // Reset OpColor to black.
  1911.     
  1912.     OpColor( &colors[kBlack] );
  1913.     
  1914.     // Get rid of the GWorld.
  1915.     
  1916.     DisposeGWorld( offscreenWorld );
  1917.     
  1918.     // Restore the destination window's fore/background colors.
  1919.     
  1920.     RGBForeColor( &savedFore );
  1921.     RGBBackColor( &savedBack );
  1922.     
  1923.     // Restore the destination window's clipping region.
  1924.     
  1925.     SetClip( savedClip );
  1926.     DisposeRgn( savedClip );
  1927.     
  1928.     // Restore the saved port and device.
  1929.     
  1930.     SetGWorld( savedPort, savedDevice );
  1931. }
  1932.  
  1933. // FlipHorizontal copies the image in the window and rectangle
  1934. // specified and draws it back out reversed horizontally.
  1935. //
  1936. void FlipHorizontal( WindowPtr destWin, Rect *destRect )
  1937. {
  1938.     CGrafPtr        savedPort;
  1939.     GDHandle        savedDevice;
  1940.     GWorldPtr        offscreenWorld;
  1941.     RGBColor        savedFore, savedBack;
  1942.     OSErr            myErr;
  1943.     short            x;
  1944.     Rect            copyFrom, copyTo;
  1945.     
  1946.     // Save the current device and port.
  1947.     
  1948.     GetGWorld( &savedPort, &savedDevice );
  1949.     
  1950.     // Create a GWorld the same size as the destination image
  1951.     // with the same depth as the destination window/rectangle.
  1952.     // The parameters are as follows:
  1953.     //        &offscreenWorld        ptr to new graphics world
  1954.     //        0                    bit depth same as graphics device of dest rect
  1955.     //        destRect            bounds rectangle of my GWorld
  1956.     //        NULL                handle to a color table record - NULL means
  1957.     //                            use the default record for that depth
  1958.     //        NULL                handle to a graphics device record - we aren't
  1959.     //                            creating a new graphics device
  1960.     //        0L                    no flags
  1961.     
  1962.         myErr = NewGWorld( &offscreenWorld, 0, destRect, NULL, NULL, 0L );
  1963.     
  1964.     // Make sure the GWorld was created
  1965.     
  1966.         if ( myErr )
  1967.         {
  1968.             DoAlertStrID( kAlertDialogID, true, kGWorldErr );
  1969.             ExitToShell();
  1970.         }
  1971.         
  1972.     // Make the GWorld the current port.
  1973.     
  1974.     SetGWorld( (CGrafPtr)offscreenWorld, NULL );
  1975.     
  1976.     // Set up the copy from and to rectangles.
  1977.     
  1978.     copyFrom = *destRect;
  1979.     copyFrom.right = copyFrom.left + 1;
  1980.     copyTo = WINPORTRECT( offscreenWorld );
  1981.     copyTo.left = copyTo.right - 1;
  1982.     
  1983.     // Copy the destination image into the GWorld column by column
  1984.     // reversing it as we go.
  1985.     
  1986.     for ( x=0; x<WINDOWWIDTH(destWin); x++ )
  1987.     {
  1988.         CopyBits( &WINBITMAP( destWin ), &WINBITMAP( offscreenWorld ),
  1989.             ©From, ©To, srcCopy, NULL );
  1990.         
  1991.         OffsetRect( ©From, 1, 0 );
  1992.         OffsetRect( ©To, -1, 0 );
  1993.     }
  1994.     
  1995.     // Make the destination window the current port.
  1996.     
  1997.     SetGWorld( (CGrafPtr)destWin, NULL );
  1998.     
  1999.     // Save the destination window's fore/background colors.
  2000.     
  2001.     GetBackColor( &savedBack );
  2002.     GetForeColor( &savedFore );
  2003.     
  2004.     // Make sure the destination window's fore/background colors
  2005.     // are black/white.
  2006.     
  2007.     RGBForeColor( &colors[kBlack] );
  2008.     RGBBackColor( &colors[kWhite] );
  2009.     
  2010.     // Lock the GWorld's pixels while we copy from it.
  2011.     
  2012.     LockPixels( GetGWorldPixMap( offscreenWorld ) );
  2013.     
  2014.     // Now copy the reversed image back to the destination window.
  2015.     
  2016.     CopyBits( &WINBITMAP( offscreenWorld ), &WINBITMAP( destWin ),
  2017.         &WINPORTRECT( offscreenWorld ), destRect, srcCopy, NULL );
  2018.         
  2019.     // Unlock the GWorld's pixels now.
  2020.     
  2021.     UnlockPixels( GetGWorldPixMap( offscreenWorld ) );
  2022.     
  2023.     // Get rid of the GWorld.
  2024.     
  2025.     DisposeGWorld( offscreenWorld );
  2026.     
  2027.     // Restore the destination window's fore/background colors.
  2028.     
  2029.     RGBForeColor( &savedFore );
  2030.     RGBBackColor( &savedBack );
  2031.     
  2032.     // Restore the saved port and device.
  2033.     
  2034.     SetGWorld( savedPort, savedDevice );
  2035. }
  2036.  
  2037. // FlipVertical copies the image in the window and rectangle
  2038. // specified and draws it back out reversed vertically.
  2039. //
  2040. void FlipVertical( WindowPtr destWin, Rect *destRect )
  2041. {
  2042.     CGrafPtr        savedPort;
  2043.     GDHandle        savedDevice;
  2044.     GWorldPtr        offscreenWorld;
  2045.     RGBColor        savedFore, savedBack;
  2046.     OSErr            myErr;
  2047.     short            x;
  2048.     Rect            copyFrom, copyTo;
  2049.     
  2050.     // Save the current device and port.
  2051.     
  2052.     GetGWorld( &savedPort, &savedDevice );
  2053.     
  2054.     // Create a GWorld the same size as the destination image
  2055.     // with the same depth as the destination window/rectangle.
  2056.     // The parameters are as follows:
  2057.     //        &offscreenWorld        ptr to new graphics world
  2058.     //        0                    bit depth same as graphics device of dest rect
  2059.     //        destRect            bounds rectangle of my GWorld
  2060.     //        NULL                handle to a color table record - NULL means
  2061.     //                            use the default record for that depth
  2062.     //        NULL                handle to a graphics device record - we aren't
  2063.     //                            creating a new graphics device
  2064.     //        0L                    no flags
  2065.     
  2066.         myErr = NewGWorld( &offscreenWorld, 0, destRect, NULL, NULL, 0L );
  2067.     
  2068.     // Make sure the GWorld was created
  2069.     
  2070.         if ( myErr )
  2071.         {
  2072.             DoAlertStrID( kAlertDialogID, true, kGWorldErr );
  2073.             ExitToShell();
  2074.         }
  2075.         
  2076.     // Make the GWorld the current port.
  2077.     
  2078.     SetGWorld( (CGrafPtr)offscreenWorld, NULL );
  2079.     
  2080.     // Set up the copy from and to rectangles.
  2081.     
  2082.     copyFrom = *destRect;
  2083.     copyFrom.bottom = copyFrom.top + 1;
  2084.     copyTo = WINPORTRECT( offscreenWorld );
  2085.     copyTo.top = copyTo.bottom - 1;
  2086.     
  2087.     // Copy the destination image into the GWorld row by row
  2088.     // reversing it as we go.
  2089.     
  2090.     for ( x=0; x<WINDOWHEIGHT(destWin); x++ )
  2091.     {
  2092.         CopyBits( &WINBITMAP( destWin ), &WINBITMAP( offscreenWorld ),
  2093.             ©From, ©To, srcCopy, NULL );
  2094.         
  2095.         OffsetRect( ©From, 0, 1 );
  2096.         OffsetRect( ©To, 0, -1 );
  2097.     }
  2098.     
  2099.     // Make the destination window the current port.
  2100.     
  2101.     SetGWorld( (CGrafPtr)destWin, NULL );
  2102.     
  2103.     // Save the destination window's fore/background colors.
  2104.     
  2105.     GetBackColor( &savedBack );
  2106.     GetForeColor( &savedFore );
  2107.     
  2108.     // Make sure the destination window's fore/background colors
  2109.     // are black/white.
  2110.     
  2111.     RGBForeColor( &colors[kBlack] );
  2112.     RGBBackColor( &colors[kWhite] );
  2113.     
  2114.     // Lock the GWorld's pixels while we copy from it.
  2115.     
  2116.     LockPixels( GetGWorldPixMap( offscreenWorld ) );
  2117.     
  2118.     // Now copy the reversed image back to the destination window.
  2119.     
  2120.     CopyBits( &WINBITMAP( offscreenWorld ), &WINBITMAP( destWin ),
  2121.         &WINPORTRECT( offscreenWorld ), destRect, srcCopy, NULL );
  2122.         
  2123.     // Unlock the GWorld's pixels now.
  2124.     
  2125.     UnlockPixels( GetGWorldPixMap( offscreenWorld ) );
  2126.     
  2127.     // Get rid of the GWorld.
  2128.     
  2129.     DisposeGWorld( offscreenWorld );
  2130.     
  2131.     // Restore the destination window's fore/background colors.
  2132.     
  2133.     RGBForeColor( &savedFore );
  2134.     RGBBackColor( &savedBack );
  2135.     
  2136.     // Restore the saved port and device.
  2137.     
  2138.     SetGWorld( savedPort, savedDevice );
  2139. }
  2140.  
  2141. // Slide slides the source image onto the destination from the
  2142. // direction specified in whichWay.
  2143. //
  2144. void Slide( WindowPtr srcWin, Rect *srcRect,
  2145.     WindowPtr destWin, Rect *destRect, short speed, short whichWay )
  2146. {
  2147.     RGBColor            savedFore, savedBack;
  2148.     CGrafPtr            savedPort;
  2149.     GDHandle            savedDevice;
  2150.     short                x;
  2151.     short                speedToUse, pixelsPerLoop;
  2152.     short                pixelsToMove;
  2153.     RgnHandle            savedClip;
  2154.     Rect                drawDest;
  2155.     short                hDelta, vDelta;
  2156.     short                iterations;
  2157.     long                delayPerLoop, ignore;
  2158.     
  2159.     // Make sure the speed is within acceptable range. Normally
  2160.     // zero is the slowest speed, but we're changing that to 1
  2161.     // for this routine.
  2162.     
  2163.     if ( speed <= 0 ) speedToUse = 1;
  2164.     else if ( speed > 20 ) speedToUse = 20;
  2165.     else speedToUse = speed;
  2166.     
  2167.     // Determine how much to delay each loop based on the size
  2168.     // of the destination.
  2169.     
  2170.     x = (destRect->right - destRect->left);
  2171.     if ( x < 200 ) delayPerLoop = 5;
  2172.     else if ( x < 400 ) delayPerLoop = 4;
  2173.     else if ( x < 600 ) delayPerLoop = 3;
  2174.     else if ( x < 800 ) delayPerLoop = 2;
  2175.     else if ( x < 1000 ) delayPerLoop = 1;
  2176.     else delayPerLoop = 0;
  2177.     
  2178.     // If the destination is not the same size as the source,
  2179.     // cut the delay in half to compensate for sizing the picture.
  2180.     // I could, of course just copy the source into a GWorld that
  2181.     // is the same size as the destination and the sizing would only
  2182.     // take place once, but that would also require much more
  2183.     // memory than the way I'm doing it now (just copying/sizing
  2184.     // each time).
  2185.     
  2186.     if ( ((destRect->right - destRect->left) != (srcRect->right - srcRect->left)) ||
  2187.         ((destRect->bottom - destRect->top) != (srcRect->bottom - srcRect->top)) )
  2188.         delayPerLoop /= 2;
  2189.     
  2190.     // Determine how many pixels the source will have to move to
  2191.     // completely cover the destination. This depends on the
  2192.     // direction that we're moving.
  2193.     
  2194.     if ( whichWay == kLeft || whichWay == kRight )
  2195.         pixelsToMove = destRect->right - destRect->left;
  2196.     else
  2197.         pixelsToMove = destRect->bottom - destRect->top;
  2198.         
  2199.     // Determine how many pixels to move the source over onto the
  2200.     // destination each time through the loop based on the speed
  2201.     // parameter.
  2202.     
  2203.     pixelsPerLoop = speedToUse * 2;
  2204.     
  2205.     // Save the current port and set it to the destination window.
  2206.     
  2207.     GetGWorld( &savedPort, &savedDevice );
  2208.     SetGWorld( (CGrafPtr)destWin, NULL );
  2209.     
  2210.     // Save the dest window's colors and set them to black/white.
  2211.     
  2212.     GetForeColor( &savedFore );  RGBForeColor( &colors[kBlack] );
  2213.     GetBackColor( &savedBack );  RGBBackColor( &colors[kWhite] );
  2214.     
  2215.     // Save the destination window's clipping region and clip
  2216.     // to the destination rectangle.
  2217.     
  2218.     savedClip = NewRgn();
  2219.     GetClip( savedClip );
  2220.     ClipRect( destRect );
  2221.     
  2222.     // Determine where the drawing destination rectangle should
  2223.     // initially be. At the same time, set the horizontal and
  2224.     // vertical deltas for moving the rectangle.
  2225.     
  2226.     drawDest = *destRect;
  2227.     hDelta = 0;
  2228.     vDelta = 0;
  2229.     
  2230.     switch( whichWay )
  2231.     {
  2232.         case kLeft:
  2233.             OffsetRect( &drawDest, -pixelsToMove, 0 );
  2234.             hDelta = pixelsPerLoop;
  2235.             break;
  2236.         case kRight:
  2237.             OffsetRect( &drawDest, pixelsToMove, 0 );
  2238.             hDelta = -pixelsPerLoop;
  2239.             break;
  2240.         case kTop:
  2241.             OffsetRect( &drawDest, 0, -pixelsToMove );
  2242.             vDelta = pixelsPerLoop;
  2243.             break;
  2244.         case kBottom:
  2245.             OffsetRect( &drawDest, 0, pixelsToMove );
  2246.             vDelta = -pixelsPerLoop;
  2247.     }
  2248.  
  2249.     // Loop how many times?
  2250.     
  2251.     iterations = pixelsToMove / pixelsPerLoop;
  2252.     
  2253.     // Loop and move the source onto the image.
  2254.     
  2255.     for ( x=1; x<=iterations; x++ )
  2256.     {
  2257.         // Move the drawing destination rectangle.
  2258.         
  2259.         OffsetRect( &drawDest, hDelta, vDelta );
  2260.         
  2261.         // Now copy the source image into the drawing
  2262.         // destination rectangle we just moved.
  2263.         
  2264.         CopyBits( &WINBITMAP( srcWin ), &WINBITMAP( destWin ),
  2265.             srcRect, &drawDest, srcCopy, NULL );
  2266.         
  2267.         // Delay.
  2268.         
  2269.         if ( delayPerLoop )
  2270.             Delay( delayPerLoop, &ignore );
  2271.     }
  2272.     
  2273.     // Copy the image directly into the destination to make
  2274.     // sure the move is complete.
  2275.     
  2276.     CopyBits( &WINBITMAP( srcWin ), &WINBITMAP( destWin ),
  2277.             srcRect, destRect, srcCopy, NULL );
  2278.             
  2279.     // Restore the clipping region.
  2280.     
  2281.     SetClip( savedClip );
  2282.     DisposeRgn( savedClip );
  2283.     
  2284.     // Restore the dest window's colors.
  2285.     
  2286.     RGBForeColor( &savedFore );
  2287.     RGBBackColor( &savedBack );
  2288.     
  2289.     // Restore the saved port.
  2290.     
  2291.     SetGWorld( savedPort, savedDevice );
  2292. }
  2293.  
  2294. // Aperture introduces the source image onto the destination either
  2295. // from the inside of a growing circle, or the outside of a shrinking
  2296. // circle. We use CopyMask along with a circle drawn in a GWorld to
  2297. // accomplish this.
  2298. //
  2299. void Aperture( WindowPtr srcWin, Rect *srcRect,
  2300.     WindowPtr destWin, Rect *destRect, short speed, short inOrOut )
  2301. {
  2302.     short        speedToUse;
  2303.     CGrafPtr    savedPort;
  2304.     GDHandle    savedDevice;
  2305.     RGBColor    savedFore, savedBack;
  2306.     RgnHandle    savedClip;
  2307.     GWorldPtr    maskWorld;
  2308.     Rect        maskRect;
  2309.     short        sizeDelta;
  2310.     short        destSize;
  2311.     short        x;
  2312.     short        steps;
  2313.     
  2314.     // Save the current port/device.
  2315.     
  2316.     GetGWorld( &savedPort, &savedDevice );
  2317.     
  2318.     // Create a GWorld for the mask image the same size as the
  2319.     // destination rectangle.
  2320.     
  2321.     SetGWorld( (CGrafPtr)srcWin, NULL );
  2322.     
  2323.     if ( NewGWorld( &maskWorld, 0, srcRect, NULL, NULL, 0 ) != noErr )
  2324.     {
  2325.         DoAlertStrID( kAlertDialogID, true, kGWorldErr );
  2326.         ExitToShell();
  2327.     }
  2328.     else
  2329.         LockPixels( GetGWorldPixMap( maskWorld ) );
  2330.  
  2331.     // Set the current port to the destination window.
  2332.     
  2333.     SetGWorld( (CGrafPtr)destWin, NULL );
  2334.     
  2335.     // Save the port's colors and set them to black/white.
  2336.     
  2337.     GetForeColor( &savedFore );  RGBForeColor( &colors[kBlack] );
  2338.     GetBackColor( &savedBack );  RGBBackColor( &colors[kWhite] );
  2339.     
  2340.     // Save the port's clip region and clip to the destination rect.
  2341.     
  2342.     savedClip = NewRgn();
  2343.     GetClip( savedClip );
  2344.     ClipRect( destRect );
  2345.     
  2346.     // Make sure the speed is within the correct range.
  2347.     
  2348.     if ( speed <= 0 ) speedToUse = 1;
  2349.     else if ( speed > 20 ) speedToUse = 20;
  2350.     else speedToUse = speed;
  2351.     
  2352.     // Determine if the destination rectangle is wider than it
  2353.     // is tall or the other way around and save the bigger number.
  2354.     
  2355.     if ( (destRect->right - destRect->left) >
  2356.                 (destRect->bottom - destRect->top) )
  2357.         destSize = (destRect->right - destRect->left);
  2358.     else
  2359.         destSize = (destRect->bottom - destRect->top);
  2360.     
  2361.     // Make the rectangle that the circle will start in and create
  2362.     // a delta value to determine if the circle gets bigger or
  2363.     // smaller and by how much each time through the loop.
  2364.     // Make sure it's square.
  2365.     
  2366.     maskRect = WINPORTRECT( maskWorld );
  2367.     if ( maskRect.bottom - maskRect.top > maskRect.right - maskRect.left )
  2368.     {
  2369.         x = maskRect.bottom - maskRect.top;
  2370.         InsetRect( &maskRect, -(x - (maskRect.right - maskRect.left))/2, 0 );
  2371.     }
  2372.     else
  2373.     {
  2374.         x = maskRect.right - maskRect.left;
  2375.         InsetRect( &maskRect, 0, -(x - (maskRect.bottom - maskRect.top))/2 );
  2376.     }
  2377.     
  2378.     if ( inOrOut == kIn )
  2379.     {
  2380.         sizeDelta = (destSize / ((21-speedToUse) * 5) + 1);
  2381.         InsetRect( &maskRect, -(destSize*0.1), -(destSize*0.1) );
  2382.         steps = ((destSize*1.2)/(sizeDelta*2));
  2383.     }
  2384.     else
  2385.     {
  2386.         sizeDelta = -((destSize / ((21-speedToUse) * 5) + 1));
  2387.         InsetRect( &maskRect, ((destSize/2)*0.9), ((destSize/2)*0.9) );
  2388.         steps = -((destSize*1.2)/(sizeDelta*2));
  2389.     }
  2390.     
  2391.     // Loop and copy the source image through the mask to the
  2392.     // destination making the mask circle bigger or smaller each
  2393.     // time.
  2394.     
  2395.     for( x=1; x<=steps; x++ )
  2396.     {
  2397.         // Draw the circle in the mask GWorld.
  2398.         
  2399.         SetGWorld( (CGrafPtr)maskWorld, NULL );
  2400.         EraseRect( &WINPORTRECT( maskWorld ) );
  2401.         PaintArc( &maskRect, 0, 360 );
  2402.         
  2403.         // If we're going inward, invert the mask GWorld.
  2404.         
  2405.         if ( inOrOut == kIn )
  2406.             InvertRect( &WINPORTRECT( maskWorld ) );
  2407.         
  2408.         // Copy the source through the mask to the dest.
  2409.         
  2410.         SetGWorld( (CGrafPtr)destWin, NULL );
  2411.         CopyMask( &WINBITMAP( srcWin ), &WINBITMAP( maskWorld ),
  2412.             &WINBITMAP( destWin ), srcRect, &WINPORTRECT( maskWorld ),
  2413.             destRect );
  2414.             
  2415.         // Change the size of the circle.
  2416.         
  2417.         InsetRect( &maskRect, sizeDelta, sizeDelta );
  2418.     }
  2419.     
  2420.     // Copy the source image directly to the destination to make
  2421.     // sure it ends correctly.
  2422.     
  2423.     CopyBits( &WINBITMAP( srcWin ), &WINBITMAP( destWin ),
  2424.         srcRect, destRect, srcCopy, NULL );
  2425.         
  2426.     // Restore the port's colors and clip region.
  2427.     
  2428.     SetClip( savedClip );
  2429.     RGBForeColor( &savedFore );
  2430.     RGBBackColor( &savedBack );
  2431.     
  2432.     // Restore the saved port.
  2433.     
  2434.     SetGWorld( savedPort, savedDevice );
  2435.     
  2436.     // Dispose of the GWorld we used for the mask.
  2437.     
  2438.     UnlockPixels( GetGWorldPixMap( maskWorld ) );
  2439.     DisposeGWorld( maskWorld );
  2440. }
  2441.  
  2442. // DoTechDemo brings up a new dialog that allows you to experiment
  2443. // with all the different ways of using CopyBits, CopyMask, and
  2444. // CopyDeepMask with different source images and masks.
  2445. //
  2446. void DoTechDemo( void )
  2447. {
  2448.     DialogPtr        demoDlg;
  2449.     short            itemHit;
  2450.     EventRecord        myEvent;
  2451.     DialogPtr        aDlg;
  2452.     Rect            sourceRect, destRect, opColorRect, maskRect;
  2453.     RgnHandle        maskRegion;
  2454.     short            copyMode;    // transfer mode
  2455.     short            ditherAdd;
  2456.     short            hiliteAdd;
  2457.     RGBColor        saveColor;
  2458.     Rect            tempRect;
  2459.     Boolean            maskSet;
  2460.     GWorldPtr        maskGWorld;    // to hold a pixel map mask
  2461.     
  2462.     // Load the main (only) dialog and display it on screen. This
  2463.     // automatically displays our two source PICTS. Since there is
  2464.     // a 'dctb' (Dialog Color Table) resource with the same ID
  2465.     // as the dialog, the Dialog Manager uses NewColorDialog to
  2466.     // make the dialog, thus giving us a color drawing port.
  2467.     
  2468.     demoDlg = GetNewDialog( kTechDemoDlgID, NULL, (WindowPtr)(-1L) );
  2469.     if ( !demoDlg )
  2470.     {
  2471.         DoAlertStrID( kAlertDialogID, true, kMemoryOut );
  2472.         ExitToShell();
  2473.     }
  2474.     ShowWindow( demoDlg );
  2475.  
  2476.     // Make sure the demo dialog is the current port.
  2477.     
  2478.     SetGWorld( (CGrafPtr)demoDlg, NULL );
  2479.     
  2480.     // Set controls to defaults.
  2481.     
  2482.     SetRadioButton( demoDlg, kTechDemoSourceFirst,
  2483.         kTechDemoSourceLast, kTechDemoSourceFirst ); // first source image
  2484.     SetRadioButton( demoDlg, kTechDemoMaskFirst,
  2485.         kTechDemoMaskLast, kTechDemoMaskLast );        // no mask image
  2486.     SetRadioButton( demoDlg, kTechDemoModeFirst,
  2487.         kTechDemoModeLast, kTechDemoModeFirst );    // srcCopy xfer mode
  2488.     SetOnOff( demoDlg, kTechDemoDither, false );    // no dither
  2489.     SetOnOff( demoDlg, kTechDemoHilite, false );    // no hilite
  2490.     SetRadioButton( demoDlg, kTechDemoOpColorFirst,
  2491.         kTechDemoOpColorLast, kTechDemoOpColorLast );    // black OpColor
  2492.     SetRadioButton( demoDlg, kTechDemoMaskRFirst,
  2493.         kTechDemoMaskRLast, kTechDemoMaskRLast );    // no mask region
  2494.     
  2495.     // Set default CopyBits parameters.
  2496.     
  2497.     GetItemRect( demoDlg, kTechDemoSourcePict1, &sourceRect );
  2498.     GetItemRect( demoDlg, kTechDemoDestPict, &destRect );
  2499.     GetItemRect( demoDlg, kTechDemoOpColorPict, &opColorRect );
  2500.     maskSet = false;
  2501.     copyMode = srcCopy;
  2502.     hiliteAdd = ditherAdd = 0;
  2503.     maskRegion = NULL;
  2504.     
  2505.     // Create a GWorld to hold the pixel map mask for CopyMask and CopyDeepMask.
  2506.     // Note that I do this because when I just used the image already in the
  2507.     // dialog (without copying it to its own bitmap), things did not work
  2508.     // correctly. Apparently, the mask has to be in a separate bit/pixmap from
  2509.     // the source and destination images.
  2510.     
  2511.     SetRect( &maskRect, 0, 0, 50, 50 );
  2512.     
  2513.     if ( NewGWorld( &maskGWorld, 0, &maskRect, NULL, NULL, 0 ) != noErr )
  2514.     {
  2515.         DoAlertStrID( kAlertDialogID, true, kGWorldErr );
  2516.         ExitToShell();
  2517.     }
  2518.     
  2519.     // Paint the OpColor pict black since that's the default setting.
  2520.     
  2521.     PaintRect( &opColorRect );
  2522.     
  2523.     // Erase the destination rectangle and draw rectangles around the
  2524.     // OpColor, destination, and mask region areas.
  2525.     
  2526.     EraseRect( &destRect );
  2527.     {
  2528.         tempRect = destRect;
  2529.         InsetRect( &tempRect, -1, -1 );
  2530.         FrameRect( &tempRect );
  2531.         GetItemRect( demoDlg, kTechDemoOpColorPict, &tempRect );
  2532.         InsetRect( &tempRect, -1, -1 );
  2533.         FrameRect( &tempRect );
  2534.         GetItemRect( demoDlg, kTechDemoMaskRPict1, &tempRect );
  2535.         InsetRect( &tempRect, -1, -1 );
  2536.         FrameRect( &tempRect );
  2537.         GetItemRect( demoDlg, kTechDemoMaskRPict2, &tempRect );
  2538.         InsetRect( &tempRect, -1, -1 );
  2539.         FrameRect( &tempRect );
  2540.         GetItemRect( demoDlg, kTechDemoMaskRPict3, &tempRect );
  2541.         InsetRect( &tempRect, -1, -1 );
  2542.         FrameRect( &tempRect );
  2543.     }
  2544.     
  2545.     // Draw in the mask regions in the dialog.
  2546.     
  2547.     DrawMaskRegion( demoDlg, kTechDemoMaskRPict1, 1 );
  2548.     DrawMaskRegion( demoDlg, kTechDemoMaskRPict2, 2 );
  2549.     DrawMaskRegion( demoDlg, kTechDemoMaskRPict3, 3 );
  2550.     
  2551.     // Now wait for the user to press a control in the dialog.
  2552.     
  2553.     itemHit = -1;
  2554.     while ( itemHit != kTechDemoDone )
  2555.     {
  2556.         WaitNextEvent( everyEvent, &myEvent, GetCaretTime(), NULL );
  2557.         
  2558.         // Check for disk events (bad disk mount).
  2559.         
  2560.         if ( (myEvent.what == diskEvt) &&
  2561.             (HiWord(myEvent.message) != noErr) )
  2562.         {
  2563.             Point        dlgUpLeftCorner = { 100, 80 };    // ignored in Sys 7
  2564.             
  2565.             DIBadMount( dlgUpLeftCorner, myEvent.message );    // ignore result
  2566.         }
  2567.  
  2568.         // Pass the event to DialogSelect which takes care of tracking
  2569.         // controls and updating everything (except the destination
  2570.         // area) for us.
  2571.         
  2572.         if ( DialogSelect( &myEvent, &aDlg, &itemHit ) )
  2573.         {
  2574.             // What we do here depends on what the user clicked
  2575.             
  2576.             if ( aDlg == demoDlg )
  2577.                 switch( itemHit )
  2578.                 {
  2579.                     // These radio buttons change the source rectangle.
  2580.                     
  2581.                     case kTechDemoSourceFirst:
  2582.                     case kTechDemoSourcePict1:
  2583.                         SetRadioButton( demoDlg, kTechDemoSourceFirst,
  2584.                             kTechDemoSourceLast, kTechDemoSourceFirst );
  2585.                         GetItemRect( demoDlg, kTechDemoSourcePict1, &sourceRect );
  2586.                         break;
  2587.                     case kTechDemoSourceFirst+1:
  2588.                     case kTechDemoSourcePict2:
  2589.                         SetRadioButton( demoDlg, kTechDemoSourceFirst,
  2590.                             kTechDemoSourceLast, kTechDemoSourceFirst+1 );
  2591.                         GetItemRect( demoDlg, kTechDemoSourcePict2, &sourceRect );
  2592.                         break;
  2593.                     case kTechDemoSourceFirst+2:
  2594.                     case kTechDemoSourcePict3:
  2595.                         SetRadioButton( demoDlg, kTechDemoSourceFirst,
  2596.                             kTechDemoSourceLast, kTechDemoSourceFirst+2 );
  2597.                         GetItemRect( demoDlg, kTechDemoSourcePict3, &sourceRect );
  2598.                         break;
  2599.                     case kTechDemoSourceFirst+3:
  2600.                     case kTechDemoSourcePict4:
  2601.                         SetRadioButton( demoDlg, kTechDemoSourceFirst,
  2602.                             kTechDemoSourceLast, kTechDemoSourceFirst+3 );
  2603.                         GetItemRect( demoDlg, kTechDemoSourcePict4, &sourceRect );
  2604.                         break;
  2605.                     case kTechDemoSourceLast:
  2606.                     case kTechDemoSourcePict5:
  2607.                         SetRadioButton( demoDlg, kTechDemoSourceFirst,
  2608.                             kTechDemoSourceLast, kTechDemoSourceLast );
  2609.                         GetItemRect( demoDlg, kTechDemoSourcePict5, &sourceRect );
  2610.                         break;
  2611.                     
  2612.                     // These radio buttons change the mask for CopyMask. Each of
  2613.                     // the first three copy the mask image shown in the dialog
  2614.                     // into an offscreen GWorld (maskGWorld) to be used as the mask.
  2615.                     // The fourth is the setting for no mask.
  2616.                     
  2617.                     case kTechDemoMaskPict1:
  2618.                     case kTechDemoMaskPict2:
  2619.                     case kTechDemoMaskPict3:
  2620.                     
  2621.                         // Translate clicks on mask images themselves
  2622.                         // to the radio buttons.
  2623.                         if ( itemHit == kTechDemoMaskPict1 )
  2624.                             itemHit = kTechDemoMaskFirst;
  2625.                         else if ( itemHit == kTechDemoMaskPict2 )
  2626.                             itemHit = kTechDemoMaskFirst+1;
  2627.                         else
  2628.                             itemHit = kTechDemoMaskFirst+2;
  2629.                             
  2630.                     case kTechDemoMaskFirst:
  2631.                     case kTechDemoMaskFirst+1:
  2632.                     case kTechDemoMaskFirst+2:
  2633.                     
  2634.                         // Set the proper radio button.
  2635.                         SetRadioButton( demoDlg, kTechDemoMaskFirst,
  2636.                             kTechDemoMaskLast, itemHit );
  2637.                             
  2638.                         // Get the rectangle of the selected mask image.
  2639.                         GetItemRect( demoDlg,
  2640.                             kTechDemoMaskPict1 + itemHit - kTechDemoMaskFirst,
  2641.                             &tempRect );
  2642.                         
  2643.                         // Lock the mask GWorld's pixels and make it the current port.
  2644.                         LockPixels( GetGWorldPixMap( maskGWorld ) );
  2645.                         SetGWorld( (CGrafPtr)maskGWorld, NULL );
  2646.                         
  2647.                         // Copy the mask image from the dialog to the GWorld.
  2648.                         CopyBits( &WINBITMAP( demoDlg ), &WINBITMAP( maskGWorld ),
  2649.                             &tempRect, &maskRect, srcCopy, NULL );
  2650.                         
  2651.                         // Make the dialog the current port again.
  2652.                         SetGWorld( (CGrafPtr)demoDlg, NULL );
  2653.                         
  2654.                         // Unlock the GWorld's pixels.
  2655.                         UnlockPixels( GetGWorldPixMap( maskGWorld ) );
  2656.                         
  2657.                         // There is a mask to use.
  2658.                         maskSet = true;
  2659.                         
  2660.                         break;
  2661.  
  2662.                     case kTechDemoMaskLast:    // no mask
  2663.                     case kTechDemoMaskNone:
  2664.                     
  2665.                         SetRadioButton( demoDlg, kTechDemoMaskFirst,
  2666.                             kTechDemoMaskLast, kTechDemoMaskLast );
  2667.                         maskSet = false;
  2668.                         
  2669.                         if ( maskRegion )
  2670.                         {
  2671.                             DisposeRgn( maskRegion );
  2672.                             maskRegion = NULL;
  2673.                         }
  2674.                         break;
  2675.                         
  2676.                     // These radio buttons change the OpColor.
  2677.                     
  2678.                     case kTechDemoOpColorFirst:
  2679.                         SetRadioButton( demoDlg, kTechDemoOpColorFirst,
  2680.                             kTechDemoOpColorLast, kTechDemoOpColorFirst );
  2681.                         OpColor( &colors[kWhite] );
  2682.                         GetForeColor( &saveColor );
  2683.                         RGBForeColor( &colors[kWhite] );
  2684.                         PaintRect( &opColorRect );
  2685.                         RGBForeColor( &saveColor );
  2686.                         break;
  2687.                     case kTechDemoOpColorFirst+1:
  2688.                         SetRadioButton( demoDlg, kTechDemoOpColorFirst,
  2689.                             kTechDemoOpColorLast, kTechDemoOpColorFirst+1 );
  2690.                         OpColor( &colors[kLtGray] );
  2691.                         GetForeColor( &saveColor );
  2692.                         RGBForeColor( &colors[kLtGray] );
  2693.                         PaintRect( &opColorRect );
  2694.                         RGBForeColor( &saveColor );
  2695.                         break;
  2696.                     case kTechDemoOpColorFirst+2:
  2697.                         SetRadioButton( demoDlg, kTechDemoOpColorFirst,
  2698.                             kTechDemoOpColorLast, kTechDemoOpColorFirst+2 );
  2699.                         OpColor( &colors[kGray] );
  2700.                         GetForeColor( &saveColor );
  2701.                         RGBForeColor( &colors[kGray] );
  2702.                         PaintRect( &opColorRect );
  2703.                         RGBForeColor( &saveColor );
  2704.                         break;
  2705.                     case kTechDemoOpColorFirst+3:
  2706.                         SetRadioButton( demoDlg, kTechDemoOpColorFirst,
  2707.                             kTechDemoOpColorLast, kTechDemoOpColorFirst+3 );
  2708.                         OpColor( &colors[kDkGray] );
  2709.                         GetForeColor( &saveColor );
  2710.                         RGBForeColor( &colors[kDkGray] );
  2711.                         PaintRect( &opColorRect );
  2712.                         RGBForeColor( &saveColor );
  2713.                         break;
  2714.                     case kTechDemoOpColorLast:
  2715.                         SetRadioButton( demoDlg, kTechDemoOpColorFirst,
  2716.                             kTechDemoOpColorLast, kTechDemoOpColorLast );
  2717.                         OpColor( &colors[kBlack] );
  2718.                         GetForeColor( &saveColor );
  2719.                         RGBForeColor( &colors[kBlack] );
  2720.                         PaintRect( &opColorRect );
  2721.                         RGBForeColor( &saveColor );
  2722.                         break;
  2723.                         
  2724.                     // These radio buttons change the transfer mode.
  2725.                     
  2726.                     case kTechDemoModeFirst:
  2727.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2728.                             kTechDemoModeLast, kTechDemoModeFirst );
  2729.                         copyMode = srcCopy;
  2730.                         break;
  2731.                     case kTechDemoModeFirst+1:
  2732.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2733.                             kTechDemoModeLast, kTechDemoModeFirst+1 );
  2734.                         copyMode = srcOr;
  2735.                         break;
  2736.                     case kTechDemoModeFirst+2:
  2737.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2738.                             kTechDemoModeLast, kTechDemoModeFirst+2 );
  2739.                         copyMode = srcXor;
  2740.                         break;
  2741.                     case kTechDemoModeFirst+3:
  2742.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2743.                             kTechDemoModeLast, kTechDemoModeFirst+3 );
  2744.                         copyMode = srcBic;
  2745.                         break;
  2746.                     case kTechDemoModeFirst+4:
  2747.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2748.                             kTechDemoModeLast, kTechDemoModeFirst+4 );
  2749.                         copyMode = notSrcCopy;
  2750.                         break;
  2751.                     case kTechDemoModeFirst+5:
  2752.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2753.                             kTechDemoModeLast, kTechDemoModeFirst+5 );
  2754.                         copyMode = notSrcOr;
  2755.                         break;
  2756.                     case kTechDemoModeFirst+6:
  2757.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2758.                             kTechDemoModeLast, kTechDemoModeFirst+6 );
  2759.                         copyMode = notSrcXor;
  2760.                         break;
  2761.                     case kTechDemoModeFirst+7:
  2762.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2763.                             kTechDemoModeLast, kTechDemoModeFirst+7 );
  2764.                         copyMode = notSrcBic;
  2765.                         break;
  2766.                     case kTechDemoModeFirst+8:
  2767.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2768.                             kTechDemoModeLast, kTechDemoModeFirst+8 );
  2769.                         copyMode = blend;
  2770.                         break;
  2771.                     case kTechDemoModeFirst+9:
  2772.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2773.                             kTechDemoModeLast, kTechDemoModeFirst+9 );
  2774.                         copyMode = addPin;
  2775.                         break;
  2776.                     case kTechDemoModeFirst+10:
  2777.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2778.                             kTechDemoModeLast, kTechDemoModeFirst+10 );
  2779.                         copyMode = addOver;
  2780.                         break;
  2781.                     case kTechDemoModeFirst+11:
  2782.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2783.                             kTechDemoModeLast, kTechDemoModeFirst+11 );
  2784.                         copyMode = subPin;
  2785.                         break;
  2786.                     case kTechDemoModeFirst+12:
  2787.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2788.                             kTechDemoModeLast, kTechDemoModeFirst+12 );
  2789.                         copyMode = transparent;
  2790.                         break;
  2791.                     case kTechDemoModeFirst+13:
  2792.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2793.                             kTechDemoModeLast, kTechDemoModeFirst+13 );
  2794.                         copyMode = addMax;
  2795.                         break;
  2796.                     case kTechDemoModeFirst+14:
  2797.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2798.                             kTechDemoModeLast, kTechDemoModeFirst+14 );
  2799.                         copyMode = subOver;
  2800.                         break;
  2801.                     case kTechDemoModeLast:
  2802.                         SetRadioButton( demoDlg, kTechDemoModeFirst,
  2803.                             kTechDemoModeLast, kTechDemoModeLast );
  2804.                         copyMode = adMin;
  2805.                         break;
  2806.                         
  2807.                     // These check boxes change the transfer mode.
  2808.                     
  2809.                     case kTechDemoDither:
  2810.                         Toggle( demoDlg, kTechDemoDither );
  2811.                         if ( GetOnOff( demoDlg, kTechDemoDither ) )
  2812.                             ditherAdd = ditherCopy;
  2813.                         else
  2814.                             ditherAdd = 0;
  2815.                         break;
  2816.                     case kTechDemoHilite:
  2817.                         Toggle( demoDlg, kTechDemoHilite );
  2818.                         if ( GetOnOff( demoDlg, kTechDemoHilite ) )
  2819.                             hiliteAdd = hilite;
  2820.                         else
  2821.                             hiliteAdd = 0;
  2822.                         break;
  2823.                     
  2824.                     // These buttons set the mask region.
  2825.                     
  2826.                     case kTechDemoMaskRPict1:
  2827.                     case kTechDemoMaskRPict2:
  2828.                     case kTechDemoMaskRPict3:
  2829.                     
  2830.                     // Translate clicks on the mask regions to the
  2831.                     // actual radio buttons.
  2832.                     if ( itemHit == kTechDemoMaskRPict1 )
  2833.                         itemHit = kTechDemoMaskRFirst;
  2834.                     else if ( itemHit == kTechDemoMaskRPict2 )
  2835.                         itemHit = kTechDemoMaskRFirst+1;
  2836.                     else
  2837.                         itemHit = kTechDemoMaskRFirst+2;
  2838.                         
  2839.                     case kTechDemoMaskRFirst:
  2840.                     case kTechDemoMaskRFirst+1:
  2841.                     case kTechDemoMaskRFirst+2:
  2842.                         SetRadioButton( demoDlg, kTechDemoMaskRFirst,
  2843.                             kTechDemoMaskRLast, itemHit );
  2844.                         if ( maskRegion )
  2845.                             DisposeRgn( maskRegion );
  2846.                         maskRegion = NewRgn();
  2847.                         OpenRgn();
  2848.                         if ( itemHit == kTechDemoMaskRFirst )
  2849.                             DrawMaskRegion( demoDlg, kTechDemoDestPict, 1 );
  2850.                         else if ( itemHit == kTechDemoMaskRFirst+1 )
  2851.                             DrawMaskRegion( demoDlg, kTechDemoDestPict, 2 );
  2852.                         else
  2853.                             DrawMaskRegion( demoDlg, kTechDemoDestPict, 3 );
  2854.                         CloseRgn( maskRegion );
  2855.  
  2856.                         break;
  2857.                         
  2858.                     case kTechDemoMaskRLast:        // no mask region
  2859.                     case kTechDemoMaskRNone:
  2860.                         SetRadioButton( demoDlg, kTechDemoMaskRFirst,
  2861.                             kTechDemoMaskRLast, kTechDemoMaskRLast );
  2862.                         DisposeRgn( maskRegion );
  2863.                         maskRegion = NULL;
  2864.                         break;
  2865.                         
  2866.                     // These buttons take some action.
  2867.                     
  2868.                     case kTechDemoCopyBits:
  2869.                         
  2870.                         CopyBits( &WINBITMAP( demoDlg ),
  2871.                             &WINBITMAP( demoDlg ),
  2872.                             &sourceRect, &destRect,
  2873.                             copyMode + ditherAdd + hiliteAdd, maskRegion );
  2874.                         break;
  2875.                         
  2876.                     case kTechDemoCopyMask:
  2877.                         
  2878.                         if ( maskSet )
  2879.                         {
  2880.                             // Lock the mask GWorld's pixelMap.
  2881.                             LockPixels( GetGWorldPixMap( maskGWorld ) );
  2882.                             
  2883.                             // CopyMask to the destination.
  2884.                             CopyMask( &WINBITMAP( demoDlg ),
  2885.                                 &WINBITMAP( maskGWorld ),
  2886.                                 &WINBITMAP( demoDlg ),
  2887.                                 &sourceRect, &maskRect,
  2888.                                 &destRect );
  2889.  
  2890.                             // Unlock the mask GWorld's pixel map.
  2891.                             UnlockPixels( GetGWorldPixMap( maskGWorld ) );
  2892.                         }
  2893.                         else
  2894.                         {
  2895.                             CopyMask( &WINBITMAP( demoDlg ),
  2896.                                 NULL,
  2897.                                 &WINBITMAP( demoDlg ),
  2898.                                 &sourceRect, NULL, &destRect );
  2899.                         }
  2900.                         break;
  2901.                     
  2902.                     case kTechDemoCopyDeepMask:
  2903.                     
  2904.                         if ( maskSet )
  2905.                         {
  2906.                             // Lock the mask GWorld's pixelMap.
  2907.                             LockPixels( GetGWorldPixMap( maskGWorld ) );
  2908.                             
  2909.                             // CopyDeepMask to the destination.
  2910.                             CopyDeepMask( &WINBITMAP( demoDlg ),
  2911.                                 &WINBITMAP( maskGWorld ),
  2912.                                 &WINBITMAP( demoDlg ),
  2913.                                 &sourceRect, &maskRect,
  2914.                                 &destRect,
  2915.                                 copyMode + ditherAdd + hiliteAdd,
  2916.                                 maskRegion );
  2917.  
  2918.                             // Unlock the mask GWorld's pixel map.
  2919.                             UnlockPixels( GetGWorldPixMap( maskGWorld ) );
  2920.                         }
  2921.                         else
  2922.                         {
  2923.                             // CopyDeepMask to the destination.
  2924.                             CopyDeepMask( &WINBITMAP( demoDlg ),
  2925.                                 NULL,
  2926.                                 &WINBITMAP( demoDlg ),
  2927.                                 &sourceRect, NULL, &destRect,
  2928.                                 copyMode + ditherAdd + hiliteAdd,
  2929.                                 maskRegion );
  2930.                         }
  2931.                         break;
  2932.                     
  2933.                     case kTechDemoErase:
  2934.                     
  2935.                         EraseRect( &destRect );
  2936.                         break;
  2937.                         
  2938.                     case kTechDemoDone:
  2939.                     
  2940.                         // Close the demo dialog.
  2941.                         DisposeDialog( demoDlg );
  2942.                         
  2943.                         break;
  2944.                 }
  2945.         }
  2946.     }
  2947.     
  2948.     // Reset the OpColor to black
  2949.     
  2950.     OpColor( &colors[kBlack] );
  2951.     
  2952.     // Dispose of the maskGWorld.
  2953.     
  2954.     DisposeGWorld( maskGWorld );
  2955.     
  2956.     // Dispose of the mask region if one was set.
  2957.     
  2958.     if ( maskRegion )
  2959.         DisposeRgn( maskRegion );
  2960. }
  2961.  
  2962. // DrawMaskRegion draws the contents of each of the three mask regions.
  2963. // The drawing takes place in the rectangle of the item sent as the
  2964. // drawWhere parameter. The whichMask parameter determines what is
  2965. // drawn. When creating the actual mask region to use in the CopyBits
  2966. // operation, we have to make sure and draw the region in the coordinates
  2967. // of the destination image.
  2968. //
  2969. void DrawMaskRegion( WindowPtr win, short drawWhere, short whichMask )
  2970. {
  2971.     Rect        tempRect, tempRect2;
  2972.     short        x;
  2973.     
  2974.     GetItemRect( win, drawWhere, &tempRect );
  2975.  
  2976.     switch( whichMask )
  2977.     {
  2978.         case 1:        // Star
  2979.             {
  2980.                 short    vMid, hMid;
  2981.                 
  2982.                 vMid = tempRect.top + (tempRect.bottom - tempRect.top)/2;
  2983.                 hMid = tempRect.left + (tempRect.right - tempRect.left)/2;
  2984.                 
  2985.                 MoveTo( hMid, tempRect.top );
  2986.                 LineTo( hMid+4, vMid-4 );
  2987.                 LineTo( tempRect.right, vMid );
  2988.                 LineTo( hMid+4, vMid+4 );
  2989.                 LineTo( hMid, tempRect.bottom );
  2990.                 LineTo( hMid-4, vMid+4 );
  2991.                 LineTo( tempRect.left, vMid );
  2992.                 LineTo( hMid-4, vMid-4 );
  2993.                 LineTo( hMid, tempRect.top );
  2994.                 
  2995.                 break;
  2996.             }
  2997.         case 2:        // Square in middle
  2998.             InsetRect( &tempRect, 10, 10 );
  2999.             FrameRect( &tempRect );
  3000.             break;
  3001.             
  3002.         case 3:        // Concentric Squares
  3003.             tempRect2 = tempRect;
  3004.             while ( (tempRect2.right - tempRect2.left) > 2 )
  3005.             {
  3006.                 FrameRect( &tempRect2 );
  3007.                 InsetRect( &tempRect2, 2, 2 );
  3008.             }
  3009.             break;
  3010.     }
  3011. }
  3012.  
  3013.