Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Imaging With QuickDraw /
Chapter 6 - Offscreen Graphics Worlds


Using Offscreen Graphics Worlds

To use an offscreen graphics world, you generally

If you want to use the CopyMask or CopyDeepMask procedure, you can create another offscreen graphics world and draw your mask into that offscreen world.

These tasks are explained in greater detail in the rest of this chapter.

Before using the routines described in this chapter, you must use the InitGraf procedure, described in the chapter "Basic QuickDraw," to initialize QuickDraw. You should also ensure the availability of these routines by checking for the existence of System 7 or Color QuickDraw.

You can make sure that offscreen graphics world routines are available on any computer--including one supporting only basic QuickDraw--by using the Gestalt function with the gestaltSystemVersion selector. Test the low-order word in the response parameter; if the value is $0700 or greater, then offscreen graphics worlds are supported.

You can also test for offscreen graphics world support by using the Gestalt function with the gestaltQuickDrawVersion selector. If the value returned in the response parameter is equal to or greater than the value of the constant gestalt32BitQD, then the system supports both Color QuickDraw and offscreen graphics worlds.

You can use the Gestalt function with the gestaltQuickDrawVersion selector to determine whether the user's system supports offscreen color pixel maps. If the bit indicated by the gestaltHasDeepGWorlds constant is set in the response parameter, then offscreen color pixel maps are available.

For more information about the Gestalt function, see the chapter "Gestalt Manager" in Inside Macintosh: Operating System Utilities.

Creating an Offscreen Graphics World

You create an offscreen graphics world with the NewGWorld function. It creates a new offscreen graphics port, a new offscreen pixel map, and (on computers that support Color QuickDraw) either a new offscreen GDevice record or a link to an existing one. It returns a data structure of type GWorldPtr by which your application refers to your new offscreen graphics world. Listing 6-1 illustrates how to create an offscreen graphics world.

Listing 6-1 Using a single offscreen graphics world and the CopyBits procedure

PROCEDURE MyPaintRectsThruGWorld (wp: WindowPtr);
   VAR
      origPort:               GrafPtr;
      origDev:                GDHandle;
      myErr:                  QDErr;
      myOffGWorld:            GWorldPtr;
      offPixMapHandle:        PixMapHandle;
      good:                   Boolean;
      sourceRect, destRect:   Rect;
BEGIN
   GetGWorld(origPort, origDev);          {save window's graphics port}
   myErr := NewGWorld(myOffGWorld, 0,     {create offscreen graphics world, }
                     wp^.portRect,        { using window's port rectangle}
                     NIL, NIL, []);
   IF (myOffGWorld = NIL) OR (myErr <> noErr) THEN
      ; {handle error here}
   SetGWorld(myOffGWorld, NIL);  {make offscreen world the current port}
   offPixMapHandle := GetGWorldPixMap(myOffGWorld);   {get handle to }
   good := LockPixels(offPixMapHandle); { offscreen pixel image and lock it}
   IF NOT good THEN
      ; {handle error here}
   EraseRect(myOffGWorld^.portRect);         {initialize its pixel image}
   MyPaintAndFillColorRects; {paint a blue rectangle, fill a green rectangle}
   SetGWorld(origPort, origDev);          {make window the current port}
      {next, for CopyBits, create source and destination rectangles that }
      { exclude scroll bar areas}
   sourceRect := myOffGWorld^.portRect;   {use offscreen portRect for source}
   sourceRect.bottom := myOffGWorld^.portRect.bottom - 15;
   sourceRect.right := myOffGWorld^.portRect.right - 15;
   destRect := wp^.portRect;        {use window portRect for destination}
   destRect.bottom := wp^.portRect.bottom - 15;
   destRect.right := wp^.portRect.right - 15;
      {next, use CopyBits to transfer the offscreen image to the window}
   CopyBits(GrafPtr(myOffGWorld)^.portBits,  {coerce graphics world's }
                                             { PixMap to a BitMap}
            GrafPtr(wp)^.portBits,     {coerce window's PixMap to a BitMap}
            sourceRect, destRect, srcCopy, NIL);
   IF QDError <> noErr THEN
      ; {likely error is that there is insufficient memory}
   UnlockPixels(offPixMapHandle);         {unlock the pixel image}
   DisposeGWorld(myOffGWorld);            {dispose of offscreen world}
END;
When you use NewGWorld, you can specify a pixel depth, a boundary rectangle (which also becomes the port rectangle), a color table, a GDevice record, and option flags for memory allocation for the offscreen graphics world. Typically, however, you pass 0 as the pixel depth, a window's port rectangle as the offscreen world's boundary rectangle, NIL for both the color table and GDevice record, and an empty set ([ ]) in your Pascal code or 0 in your C code for the option flags. This provides your application with the default behavior of NewGWorld, and it supports computers running only basic QuickDraw. This also allows QuickDraw to optimize the CopyBits, CopyMask, and CopyDeepMask procedures when your application copies the image you create in an offscreen graphics world into the window's port rectangle.

When creating an offscreen graphics world, if you specify 0 as the pixel depth, the port rectangle for a window as the boundary rectangle, and no option flags, the NewGWorld function

The application-defined routine MyPaintRectsThruGWorld in Listing 6-1, for example, specifies the default behavior for NewGWorld. The MyPaintRectsThruGWorld routine dereferences the window pointer passed in the wp parameter to obtain a window's port rectangle, which MyPaintRectsThruGWorld passes to NewGWorld as the boundary and port rectangle for the offscreen graphics world.

Setting the Graphics Port for an Offscreen Graphics World

Before drawing into the offscreen graphics port created in Listing 6-1 on page 6-5, MyPaintRectsThruGWorld saves the graphics port for the front window by calling the GetGWorld procedure, which saves the current graphics port and its GDevice record. Then MyPaintRectsThruGWorld makes the offscreen graphics world the current port by calling the SetGWorld procedure. After drawing into the offscreen graphics world, MyPaintRectsThruGWorld also uses SetGWorld to restore the active window as the current graphics port.

Instead of using the GetPort and SetPort procedures for saving and restoring offscreen graphics worlds, you must use GetGWorld and SetGWorld; you can also use GetGWorld and SetGWorld for saving and restoring color and basic graphics ports.

Drawing Into an Offscreen Graphics World

You must call the LockPixels function before drawing to or copying from an offscreen graphics world. The LockPixels function prevents the base address for an offscreen pixel image from being moved while you draw into it or copy from it.

If the base address for an offscreen pixel image hasn't been purged by the Memory Manager or if its base address is not purgeable, LockPixels returns TRUE as its function result, and your application can draw into or copy from the offscreen pixel image. However, if the base address for an offscreen pixel image has been purged, LockPixels returns FALSE to indicate that you cannot draw into it or copy from it. (At that point, your application should either call the UpdateGWorld function to reallocate the offscreen pixel image and then reconstruct it, or draw directly into an onscreen graphics port.)

After setting the offscreen graphics world to the current graphics port, MyPaintRectsThruGWorld in Listing 6-1 on page 6-5 uses the GetGWorldPixMap function to get a handle to an offscreen pixel map. Passing this handle to the LockPixels function, MyPaintRectsThruGWorld locks the memory for the offscreen pixel image in preparation for drawing into its pixel map.

IMPORTANT
On a system running only basic QuickDraw, the GetGWorldPixMap function returns the handle to a 1-bit pixel map that your application can supply as a parameter to LockPixels and the other routines related to offscreen graphics worlds that are described in this chapter. On a basic QuickDraw system, however, your application should not supply this handle to Color QuickDraw routines.
The MyPaintRectsThruGWorld routine initializes the offscreen pixel image to all white by calling the EraseRect procedure, which is described in the chapter "Basic QuickDraw." The MyPaintRectsThruGWorld routine then calls another application-defined routine, MyPaintAndFillColorRects, to draw color rectangles into the pixel map for the offscreen graphics world.

IMPORTANT
You cannot dereference the GWorldPtr data structure to get to the pixel map. The baseAddr field of the PixMap record for an offscreen graphics world contains a handle instead of a pointer, which is what the baseAddr field for an onscreen pixel map contains. You must use the GetPixBaseAddr function (described on page 6-38) to obtain a pointer to the PixMap record for an offscreen graphics world.

Copying an Offscreen Image Into a Window

After preparing an image in the offscreen graphics world, your application must use SetGWorld to restore the active window as the current graphics port, as illustrated in Listing 6-1 on page 6-5.

To copy the image from an offscreen graphics world into a window, use the CopyBits procedure. Specify the offscreen graphics world as the source image for CopyBits, and specify the window as its destination. When using CopyBits, you must coerce the offscreen graphics world's GWorldPtr data type to a data structure of type GrafPtr. Similarly, whenever a color graphics port is your destination, you must coerce the window's CGrafPtr data type to a data structure of type GrafPtr. (The CopyBits procedure is described in the chapter "QuickDraw Drawing.")

As long as you're drawing into an offscreen graphics world or copying the image out of it, you must leave its pixel image locked. When you are finished drawing into and copying from an offscreen graphics world, use the UnlockPixels procedure. To help prevent heap fragmentation, the UnlockPixels procedure allows the Memory Manager to move the base address for the offscreen pixel image. (For more information about Macintosh memory management, see Inside Macintosh: Memory.)

Finally, call the DisposeGWorld procedure when your application no longer needs the pixel image associated with this offscreen graphics world, as illustrated in Listing 6-1.

Updating an Offscreen Graphics World

When the user resizes or moves a window, changes the pixel depth of a screen that a window intersects, or modifies a color table, you can use the UpdateGWorld function to reflect the user's choices in the offscreen graphics world. The UpdateGWorld function, described on page 6-23, allows you to change the pixel depth, boundary rectangle, or color table for an existing offscreen graphics world without recreating it and redrawing its contents. You should also call UpdateGWorld after every update event.

Calling UpdateGWorld and then CopyBits when the user makes these changes helps your application get the maximum refresh speed when updating the window. See the chapters "Event Manager" and "Window Manager" in Inside Macintosh: Macintosh Toolbox Essentials for more information about handling update events in windows and about resizing windows.

Creating a Mask and a Source Image in Offscreen Graphics Worlds

When you use the CopyMask or CopyDeepMask procedure (described in the chapter "QuickDraw Drawing"), you can create the source image and its mask in separate offscreen graphics worlds. Plates 3 and 4 at the front of this book illustrate how to use CopyMask in this way. The source image in Plate 3 consists of graduated gray stripes; this image is created in an offscreen graphics world. The mask in Plate 3 consists of a black rectangle alongside a red rectangle; this mask is created in a separate graphics world that shares the same coordinates as the source image.

When the CopyMask procedure copies the grayscale image through this mask, the result is the untitled window illustrated in the bottom half of Plate 3. The black pixels in the mask cause CopyMask to copy directly into the window those pixels from the source image that are masked by the black rectangle. The red pixels in the mask cause CopyMask to alter most of the source pixels masked by the red rectangle when copying them. That is, the source pixels that are completely black are changed to the mask's red when copied into the window. The source pixels that are completely white are left unaltered when copied into the window. The source pixels that are between black and white are given a graduated amount of the mask's red.

Listing 6-2 shows the code that produces the window shown in Plate 3.

Listing 6-2 Using two offscreen graphics worlds and the CopyMask procedure

PROCEDURE MyCopyBlackAndRedMasks (wp: WindowPtr);
   VAR
      origPort:                           GrafPtr;
      origDevice:                         GDHandle;
      myErr:                              QDErr;
      myOffScreen1, myOffScreen2:         GWorldPtr;
      theColor:                           RGBColor;
      i:                                  Integer;
      offPixMapHandle1, offPixMapHandle2: PixMapHandle;
      good:                               Boolean;
      myRect:                             Rect;
BEGIN
   GetGWorld(origPort, origDevice);       {save window's graphics port}
                        {create an offscreen world for building an image}
   myErr := NewGWorld(myOffScreen1, 0, wp^.portRect, NIL, NIL, []);
   IF (myOffScreen1 = NIL) OR (myErr <> noErr) THEN
      ; {handle error here}
                        {create another offscreen world for building a mask}
   myErr := NewGWorld(myOffScreen2, 0, wp^.portRect, NIL, NIL, []);
   IF (myOffScreen2 = NIL) OR (myErr <> noErr) THEN
      ; {handle error here}
   SetGWorld(myOffScreen1, NIL); {make first offscreen world the }
                                 { current port}
   offPixMapHandle1 := GetGWorldPixMap(myOffScreen1);
   good := LockPixels(offPixMapHandle1);  {lock its pixel image}
   IF NOT good THEN
      ; {handle error here}
   EraseRect(myOffScreen1^.portRect);     {initialize its pixel image}
   FOR i := 0 TO 9 DO      {draw graduated grayscale stripes for the image}
      BEGIN
         theColor.red := i * 7168; 
         theColor.green := i * 7168; 
         theColor.blue := i * 7168;
         RGBForeColor(theColor);
         SetRect(myRect, myOffScreen1^.portRect.left, i * 10,
                 myOffScreen1^.portRect.right, i * 10 + 10);
         PaintRect(myRect);
      END;
   SetGWorld(myOffScreen2, NIL); {make second offscreen world the }
                                 { current port}
   offPixMapHandle2 := GetGWorldPixMap(myOffScreen2);
   good := LockPixels(offPixMapHandle2);  {lock its pixel image}
   IF NOT good THEN
      ; {handle error here}
   EraseRect(myOffScreen2^.portRect);     {initialize its pixel image}
   SetRect(myRect, 20, 20, 80, 80);
   PaintRect(myRect);   {paint a black rectangle in the mask}
   SetRect(myRect, 100, 20, 160, 80);
   theColor.red := $FFFF;  theColor.green := $0000; theColor.blue := $0000;
   RGBForeColor(theColor);
   PaintRect(myRect);   {paint a red rectangle in the mask}
   SetGWorld(wp, GetMainDevice); {make window the current port}
   EraseRect(wp^.portRect);      {erase the window before using CopyMask}
   CopyMask(GrafPtr(myOffScreen1)^.portBits, {use gray image as source}
            GrafPtr(myOffScreen2)^.portBits, {use 2-rectangle image as mask}
            GrafPtr(wp)^.portBits,           {use window as destination}
            myOffScreen1^.portRect, 
            myOffScreen2^.portRect, 
            wp^.portRect);
   UnlockPixels(offPixMapHandle1);  UnlockPixels(offPixMapHandle2);
   DisposeGWorld(myOffScreen1);  DisposeGWorld(myOffScreen2);
   SetGWorld(origPort, origDevice);    {restore original graphics port}
END;

Previous Book Contents Book Index Next

© Apple Computer, Inc.
7 JUL 1996