Documentation Archive Developer
Search

ADC Home > Reference Library > Technical Q&As > Graphics & Imaging > OpenGL >

Using Clip Region and Buffer Rectangles with OpenGL Carbon


Q: How are AGL buffer rectangles and clip regions used?

A: Using AGL buffer rectangles and clip regions are very similar operations. aglSetInteger is used to setup the rectangle or region then aglEnable or aglDisable is used to turn the feature on or off for both buffer rectangles and clip regions. Client applications need to use these per context, for both the enable and the setting of rectangle or region data. Note, while applications are the usual OpenGL client code, the techniques presented here work for other Carbon OpenGL clients which have a drawable and an associated context.

To use a buffer rectangle with a specific context both the buffer rectangle must be enabled and the size must be set. Listing 1 shows an example.


#include <AGL/agl.h>

// aglContext must be a valid pre-existing context
short left = 10, bottom = 10, width = 300, height = 300;
GLint bufferRect[4];

bufferRect[0] = left; // 0 = left edge
bufferRect[1] = bottom; // 0 = bottom edge
bufferRect[2] = width; // width of buffer rect
bufferRect[3] = height; // height of buffer rect
aglSetInteger (aglContext, AGL_BUFFER_RECT, bufferRect);
aglEnable (aglContext, AGL_BUFFER_RECT);

Listing 1. Buffer Rect Setup


If the buffer rectangle is window size relative, the area should also be reset whenever the window size changes, usually along with the glViewport. It is recommended this be done in response to kEventWindowShown, kEventWindowBoundsChanged, kEventWindowZoomed and kEventWindowResizeCompleted Carbon window events. Additionally, window content should normally be drawn on kEventWindowActivated, kEventWindowDrawContent, and kEventWindowBoundsChanged Carbon window events to ensure it is always up to date.

Using a clip region with AGL is very similar to using buffer rectangles. Specifically, a clip region has the same update requirements as buffer rectangles. To set a clip region, construct a QuickDraw region which will constrain the OpenGL update that is the region should only include the parts of the window in which OpenGL should draw. The code in Listing 2 is an example of this which uses some random geometry and excludes the bounds rectangles of four predefined controls to construct the clip region.


#include <AGL/agl.h>
#include <Carbon/Carbon.h>


 static void SetClipRegion (WindowRef win)
{
    RgnHandle       clipRgn = NewRgn();
    RgnHandle       maskRgn = NewRgn();
    Rectangle       rectPort, bounds = { -32767, -32767, 32767, 32767 };
    ControlID       idControl;
    ControlRef      control;

    GetWindowPortBounds(win, &rectPort);
    // set up some random region
    SetEmptyRgn (clipRgn);
    OpenRgn ();
    MoveTo (rectPort.left + 10, rectPort.top + 30);
    LineTo (rectPort.right - 20, rectPort.top + 50);
    LineTo (rectPort.right - 50, rectPort.bottom - 25);
    LineTo (rectPort.left + 10, rectPort.top + 50);
    CloseRgn (clipRgn);
    // cutouts for existing controls (assuming there are 4 in the window)
    idControl.signature = 'cbrt'; // app can use any sig that is used in nib
    for (idControl.id = 0; idControl.id < 4; idControl.id++) {
        GetControlByID (win, &idControl, &control);
        GetControlBounds (control, &bounds);
        RectRgn(maskRgn, &bounds);
        DiffRgn(clipRgn, maskRgn, clipRgn);
    }
    // set clip region for AGL
    //   aglContext is a valid pre-existing context for this window
    aglSetInteger (aglContext, AGL_CLIP_REGION, (const GLint *)clipRgn);
    DisposeRgn(clipRgn);
    DisposeRgn(maskRgn);
}

Listing 2. Clip Region Setup


It is important to understand the region supplied to AGL via aglSetInteger is created manually and is not associated with the window's clip or vis region. The window's clip region could be supplied to AGL but AGL's copy would need to be updated manually for any clip changes, that is there is no native clip region tracking in the AGL Framework. This was done because the QuickDraw clip region for drawing will likely be an inverse, or close to an inverse, of the region used for OpenGL drawing since OpenGL will likely draw in the places where QuickDraw 2D is not drawing. Keeping AGL's region synced with an inverse of QuickDraw's clip region would be difficult at best, especially with OpenGL possibly receiving asynchronous updates without application interaction. This AGL API is designed for the client application to provide a region directly with no specific ties to existing window regions such as the visRgn or clipRgn.

As alluded to above, AGL makes a copy of the region at the time of the aglSetInteger with AGL_CLIP_REGION call, so the application is free to dispose of the region anytime after aglSetInteger returns. The region copy operation can be quite costly for complicated regions thus developers should limit the use of aglSetinteger with AGL_CLIP_REGION in performance critical code sections.

Remember, clip regions still need to be enabled just as buffer rectangles do and listing 3 shows an example.


#include <AGL/agl.h>

// aglContext is a valid pre-existing context
aglEnable (aglContext, AGL_CLIP_REGION);

Listing 3. Enabling a Clip Region


This enable could have been wrapped into the above SetClipRegion code if desired. In this example, a separate code section was chosen since the region itself does not need to be reset every time the clip region is enabled. A final note, if a region is created relative to the window size, it has the same resize update requirements as buffer rectangles.

Both clip regions and buffer rectangles provide AGL applications with two convenient ways to limit the size and shape of accelerated surface drawing within a window. This allows the application to draw 2D content in areas not covered by the accelerated surface. Buffer rectangles are available in all versions of Mac OS X while clip regions are available in Mac OS X v10.2 and later.


[Dec 3 2002]