Important: The information in this document is obsolete and should not be used for new development.
Using Offscreen Graphics Worlds
To use an offscreen graphics world, you generally
If you want to use the
- use the
NewGWorldfunction to create an offscreen graphics world- use the
GetGWorldprocedure to save the onscreen graphics port for the active window- use the
SetGWorldprocedure to make the offscreen graphics world the current graphics port- use the
LockPixelsfunction to prevent the base address for the offscreen pixel image from moving while you draw into it or copy from it- use the
EraseRectprocedure to initialize the offscreen pixel image- use the basic QuickDraw and Color QuickDraw routines described elsewhere in this book to draw into the offscreen graphics world
- use the
SetGWorldprocedure to restore the active window as the current graphics port- use the
CopyBitsprocedure to copy the image from the offscreen graphics world into the active window- use the
UnlockPixelsprocedure to allow the Memory Manager to move the base address for the offscreen pixel image- use the
DisposeGWorldprocedure to dispose of all the memory allocated for an offscreen graphics world when you no longer need its offscreen pixel image
CopyMaskorCopyDeepMaskprocedure, 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
InitGrafprocedure, 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
Gestaltfunction with thegestaltSystemVersionselector. Test the low-order word in theresponseparameter; 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
Gestaltfunction with thegestaltQuickDrawVersionselector. If the value returned in theresponseparameter is equal to or greater than the value of the constantgestalt32BitQD, then the system supports both Color QuickDraw and offscreen graphics worlds.You can use the
Gestaltfunction with thegestaltQuickDrawVersionselector to determine whether the user's system supports offscreen color pixel maps. If the bit indicated by thegestaltHasDeepGWorldsconstant is set in theresponseparameter, then offscreen color pixel maps are available.For more information about the
Gestaltfunction, see the chapter "Gestalt Manager" in Inside Macintosh: Operating System Utilities.Creating an Offscreen Graphics World
You create an offscreen graphics world with theNewGWorldfunction. It creates a new offscreen graphics port, a new offscreen pixel map, and (on computers that support Color QuickDraw) either a new offscreenGDevicerecord or a link to an existing one. It returns a data structure of typeGWorldPtrby 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
CopyBitsprocedure
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 useNewGWorld, you can specify a pixel depth, a boundary rectangle (which also becomes the port rectangle), a color table, aGDevicerecord, 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,NILfor both the color table andGDevicerecord, 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 ofNewGWorld, and it supports computers running only basic QuickDraw. This also allows QuickDraw to optimize theCopyBits,CopyMask, andCopyDeepMaskprocedures 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
NewGWorldfunction
The application-defined routine
- uses the pixel depth of the screen with the greatest pixel depth from among all screens intersected by the window
- aligns the pixel image to the screen for optimum performance for the
CopyBitsprocedure- uses the color table and
GDevicerecord for the screen with the greatest pixel depth from among all screens intersected by the window- allocates an unpurgeable base address for the offscreen pixel image in your application heap
- allows graphics accelerators to cache the offscreen pixel image
MyPaintRectsThruGWorldin Listing 6-1, for example, specifies the default behavior forNewGWorld. TheMyPaintRectsThruGWorldroutine dereferences the window pointer passed in thewpparameter to obtain a window's port rectangle, whichMyPaintRectsThruGWorldpasses toNewGWorldas 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,MyPaintRectsThruGWorldsaves the graphics port for the front window by calling theGetGWorldprocedure, which saves the current graphics port and itsGDevicerecord. ThenMyPaintRectsThruGWorldmakes the offscreen graphics world the current port by calling theSetGWorldprocedure. After drawing into the offscreen graphics world,MyPaintRectsThruGWorldalso usesSetGWorldto restore the active window as the current graphics port.Instead of using the
GetPortandSetPortprocedures for saving and restoring offscreen graphics worlds, you must useGetGWorldandSetGWorld; you can also useGetGWorldandSetGWorldfor saving and restoring color and basic graphics ports.Drawing Into an Offscreen Graphics World
You must call theLockPixelsfunction before drawing to or copying from an offscreen graphics world. TheLockPixelsfunction 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,
LockPixelsreturnsTRUEas 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,LockPixelsreturnsFALSEto indicate that you cannot draw into it or copy from it. (At that point, your application should either call theUpdateGWorldfunction 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,
MyPaintRectsThruGWorldin Listing 6-1 on page 6-5 uses theGetGWorldPixMapfunction to get a handle to an offscreen pixel map. Passing this handle to theLockPixelsfunction,MyPaintRectsThruGWorldlocks the memory for the offscreen pixel image in preparation for drawing into its pixel map.
The
- IMPORTANT
- On a system running only basic QuickDraw, the
GetGWorldPixMapfunction returns the handle to a 1-bit pixel map that your application can supply as a parameter toLockPixelsand 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.![]()
MyPaintRectsThruGWorldroutine initializes the offscreen pixel image to all white by calling theEraseRectprocedure, which is described in the chapter "Basic QuickDraw." TheMyPaintRectsThruGWorldroutine 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
GWorldPtrdata structure to get to the pixel map. ThebaseAddrfield of thePixMaprecord for an offscreen graphics world contains a handle instead of a pointer, which is what thebaseAddrfield for an onscreen pixel map contains. You must use theGetPixBaseAddrfunction (described on page 6-38) to obtain a pointer to thePixMaprecord for an offscreen graphics world.![]()
Copying an Offscreen Image Into a Window
After preparing an image in the offscreen graphics world, your application must useSetGWorldto 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
CopyBitsprocedure. Specify the offscreen graphics world as the source image forCopyBits, and specify the window as its destination. When usingCopyBits, you must coerce the offscreen graphics world'sGWorldPtrdata type to a data structure of typeGrafPtr. Similarly, whenever a color graphics port is your destination, you must coerce the window'sCGrafPtrdata type to a data structure of typeGrafPtr. (TheCopyBitsprocedure 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
UnlockPixelsprocedure. To help prevent heap fragmentation, theUnlockPixelsprocedure 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
DisposeGWorldprocedure 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 theUpdateGWorldfunction to reflect the user's choices in the offscreen graphics world. TheUpdateGWorldfunction, 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 callUpdateGWorldafter every update event.Calling
UpdateGWorldand thenCopyBitswhen 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 theCopyMaskorCopyDeepMaskprocedure (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 useCopyMaskin 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
CopyMaskprocedure 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 causeCopyMaskto copy directly into the window those pixels from the source image that are masked by the black rectangle. The red pixels in the mask causeCopyMaskto 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
CopyMaskprocedure
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;