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]
|