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
NewGWorld
function to create an offscreen graphics world- use the
GetGWorld
procedure to save the onscreen graphics port for the active window- use the
SetGWorld
procedure to make the offscreen graphics world the current graphics port- use the
LockPixels
function to prevent the base address for the offscreen pixel image from moving while you draw into it or copy from it- use the
EraseRect
procedure 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
SetGWorld
procedure to restore the active window as the current graphics port- use the
CopyBits
procedure to copy the image from the offscreen graphics world into the active window- use the
UnlockPixels
procedure to allow the Memory Manager to move the base address for the offscreen pixel image- use the
DisposeGWorld
procedure to dispose of all the memory allocated for an offscreen graphics world when you no longer need its offscreen pixel image
CopyMask
orCopyDeepMask
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 thegestaltSystemVersion
selector. Test the low-order word in theresponse
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 thegestaltQuickDrawVersion
selector. If the value returned in theresponse
parameter 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
Gestalt
function with thegestaltQuickDrawVersion
selector to determine whether the user's system supports offscreen color pixel maps. If the bit indicated by thegestaltHasDeepGWorlds
constant is set in theresponse
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 theNewGWorld
function. It creates a new offscreen graphics port, a new offscreen pixel map, and (on computers that support Color QuickDraw) either a new offscreenGDevice
record or a link to an existing one. It returns a data structure of typeGWorldPtr
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 useNewGWorld
, you can specify a pixel depth, a boundary rectangle (which also becomes the port rectangle), a color table, aGDevice
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 andGDevice
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 ofNewGWorld
, and it supports computers running only basic QuickDraw. This also allows QuickDraw to optimize theCopyBits
,CopyMask
, andCopyDeepMask
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
- 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
CopyBits
procedure- uses the color table and
GDevice
record 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
MyPaintRectsThruGWorld
in Listing 6-1, for example, specifies the default behavior forNewGWorld
. TheMyPaintRectsThruGWorld
routine dereferences the window pointer passed in thewp
parameter to obtain a window's port rectangle, whichMyPaintRectsThruGWorld
passes toNewGWorld
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 theGetGWorld
procedure, which saves the current graphics port and itsGDevice
record. ThenMyPaintRectsThruGWorld
makes the offscreen graphics world the current port by calling theSetGWorld
procedure. After drawing into the offscreen graphics world,MyPaintRectsThruGWorld
also usesSetGWorld
to restore the active window as the current graphics port.Instead of using the
GetPort
andSetPort
procedures for saving and restoring offscreen graphics worlds, you must useGetGWorld
andSetGWorld
; you can also useGetGWorld
andSetGWorld
for saving and restoring color and basic graphics ports.Drawing Into an Offscreen Graphics World
You must call theLockPixels
function before drawing to or copying from an offscreen graphics world. TheLockPixels
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
returnsTRUE
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
returnsFALSE
to indicate that you cannot draw into it or copy from it. (At that point, your application should either call theUpdateGWorld
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 theGetGWorldPixMap
function to get a handle to an offscreen pixel map. Passing this handle to theLockPixels
function,MyPaintRectsThruGWorld
locks 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
GetGWorldPixMap
function returns the handle to a 1-bit pixel map that your application can supply as a parameter toLockPixels
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.MyPaintRectsThruGWorld
routine initializes the offscreen pixel image to all white by calling theEraseRect
procedure, which is described in the chapter "Basic QuickDraw." TheMyPaintRectsThruGWorld
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. ThebaseAddr
field of thePixMap
record for an offscreen graphics world contains a handle instead of a pointer, which is what thebaseAddr
field for an onscreen pixel map contains. You must use theGetPixBaseAddr
function (described on page 6-38) to obtain a pointer to thePixMap
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 useSetGWorld
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 forCopyBits
, and specify the window as its destination. When usingCopyBits
, you must coerce the offscreen graphics world'sGWorldPtr
data type to a data structure of typeGrafPtr
. Similarly, whenever a color graphics port is your destination, you must coerce the window'sCGrafPtr
data type to a data structure of typeGrafPtr
. (TheCopyBits
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, theUnlockPixels
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 theUpdateGWorld
function to reflect the user's choices in the offscreen graphics world. TheUpdateGWorld
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 callUpdateGWorld
after every update event.Calling
UpdateGWorld
and thenCopyBits
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 theCopyMask
orCopyDeepMask
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 useCopyMask
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 causeCopyMask
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 causeCopyMask
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;