Tải bản đầy đủ - 0 (trang)
Chapter 8. The Cocoa API for OpenGL Configuration

Chapter 8. The Cocoa API for OpenGL Configuration

Tải bản đầy đủ - 0trang





Figure 8-1 AppKit API and Framework in Overall OpenGL Infrastructure on

the Mac

and relevant images, workflow, and text for Mac OS X 10.5. If you’re looking

for Mac OS X 10.4 content, read on, but if you’re looking for the same version

of this chapter, addressing Leopard-specific changes, and with a Leopard lookand-feel, please read Appendix C.


The AppKit OpenGL API is part of the overall Apple OpenGL infrastructure.

It constitutes a layer above CGL but also has the ability to reach down into

both CGL and lower layers. Figure 8-1 shows where the AppKit (also known as

Cocoa or NSGL) API and framework reside relative to other API layers.

The AppKit framework is typically found at /System/Library/Frameworks

but may also be in a path specific to your SDK installation. As with other APIs,

linking against AppKit requires specification of this framework path (Table 8-1).


In this section, we will create an XCode project showing how to create a custom view to handle OpenGL rendering using a Cocoa UI element. This project

will be a foundation project that we will return to when we create other examples with increased functionality later in the book. We’ll begin with the overall

project setup and creation—so launch XCode, and we’ll get started.

Create a new XCode project of type Cocoa Application. This action will create your project, set it to link properly against the Cocoa frameworks, and create

a sample main program from which we’ll begin. If you do not feel like walking

through the steps or would like to see the finished product first, check out the

sample code from our website (www.macopenglbook.com).

Table 8-1 AppKit Cocoa Headers, Frameworks, and Overview

Framework path

Build flag




-framework AppKit


Chapter 8: The Cocoa API for OpenGL Configuration

Figure 8-2 Subclassing NSOpenGLView in Interface Builder

Open the Resources folder, and double-click on the MainMenu.nib icon. This

will open the nib file for this project in Interface Builder. Now switch to Interface


In the MainMenu.nib window, click on the Classes tab, and navigate through

the three-pane system until you finally click on NSOpenGLView. The panes

should look like Figure 8-2 when selected.

Next click on the Classes menu and Subclass NSOpenGLView item to create a new derived class based on the NSOpenGLView type. A new text entry

field will appear, suggesting the name MyOpenGLView. Accept the default

name by pressing the Enter key or choose something more interesting and type

away. Your results should look similar to Figure 8-3.

So what did we just do? We told Interface Builder that we wanted to subclass NSOpenGLView for our own purposes. NSOpenGLView is derived from

the NSView class. It provides the integration between OpenGL and Cocoa. By

subclassing it, we become able to customize many aspects of its behavior, including pixel format selection and context sharing. But we’re getting ahead of

ourselves. First we’ve got to get MyOpenGLView into a form where we can write

some code.

We’ll now use Interface Builder to instantiate a default object when the nib file

is loaded, create some sample code, and arrange our view in the window.

First, let’s create an instance of our class. Return to the MainMenu.nib window, where you should still have MyOpenGLView selected. If not, navigate

through the hierarchy to re-select it. With MyOpenGLView selected, click on the

Classes menu and Instantiate MyOpenGLView item. This will create an



Figure 8-3 Subclassed NSOpenGLView in Interface Builder

instance of this class in the nib, and the interface will update to return you to

the Instances tab in the MainMenu.nib window. You should see something

like Figure 8-4.

Now let’s create the actual headers and code. In the MainMenu.nib window, click on the Classes tab. If you’re lucky, MyOpenGLView will still be

selected, if not, navigate to it and select it. Click on the Classes menu and

Create Files for MyOpenGLView item. This will prompt you to create

files for both the header and the source for this view. Accept the defaults, and

we’ll begin laying out the view in a window.

Figure 8-4 Instantiated OpenGL View Object in Interface Builder


Chapter 8: The Cocoa API for OpenGL Configuration

Figure 8-5 Custom View Palette in Interface Builder

At this point, we’ve created the necessary infrastructure, but we still have to

place our view in our window. As with most Interface Builder tasks, we accomplish this by dragging and dropping and by applying a little customization. We

begin by dragging a Custom View into the window named Window. Go to the

Cocoa-Interfaces window (if it’s not visible, get there by clicking the menu

Tools, the submenu Palettes, and then the item Show Palettes) and

navigate to the Custom View pane. This palette can be seen in Figure 8-5. Drag

the CustomView icon from the palette into Window and arrange it as shown in

Figure 8-6.

The final step in this setup operation is to change the CustomView to be your

MyOpenGLView object. To do so, open the Inspector (if it’s not open, click

Figure 8-6 Adding a Custom View to a Window in Interface Builder



Figure 8-7 Binding a Custom View to the NSOpenGLView Subclass Object

the Tools menu and Show Info item) and click on the CustomView you

just dragged into place. Choose the Custom Class pop-up menu entry in the

Inspector window, and navigate and choose MyOpenGLView from the list.

You should see results like those shown in Figure 8-7.

We could have handled all of this setup, configuration, and routing

programmatically—but this book isn’t about Cocoa plumbing, so we’ll stay

at this level for now. In a later section, we’ll explore Cocoa configuration of a

generic NSView, which allows us a bit more flexibility. For now, switch back to

XCode and we’ll dig into the code.

In XCode, open the file MyOpenGLView.m. We’ll now begin adding methods to

handle key elements of the OpenGL render cycle. We start by adding a method

to select pixel formats. This code performs pixel format selection in three steps:

1. A structure is created containing a list of pixel format configuration


2. That structure is passed to an NSOpenGLPixelFormat constructor to create

a new pixel format object.

3. That pixel format object is passed on to the base NSOpenGLView method for

finishing the initialization of this view.

Either add the code yourself to your project or grab it from the sample code

provided in Example 8.1. Compile and run the code, and you should have a



Chapter 8: The Cocoa API for OpenGL Configuration

Table 8-2 Selection Policies and Behaviors





Choose only from the set of pixel formats that match exactly.

Choose a match closest to the size specified, but not necessarily an

exact match.

Require a match of at least this size. Can choose larger sizes.

Require a match of at most this size. Prefers larger sizes.



“But wait,” you say, “what about the rest of the key OpenGL configuration pieces: the context and the drawable or surface?” By subclassing

NSOpenGLView, you’re getting the last two pieces configured for you, you

lucky dog—no extra work required. The base NSOpenGLView class creates a

context from the pixel format you passed in, and it creates a drawable such that

it can be visualized in the window we created with our CustomView back in

Interface Builder. Later, however, we’ll go through the process of specializing

an NSView so we can do the fun bits in creating a context and a drawable, too.

This step is necessary if you want to do more advanced context things, such as

share data with another context. More on that in later sections.

Moving along, now that you know how to choose a pixel format, it’s probably an appropriate time to discuss what the various flags mean to an

NSOpenGLPixelFormat. These flags are generally well documented by Apple, but we’re including a list of all the flags in one spot for handy reference

here. Take a look at Tables 8-2 and 8-3, see which values make sense for your

application, and try a few in the code we’ve just developed. Table 8-3 contains

a fair bit of exposition on these flags, including what the various values mean

and how you might use them—it’s worth a quick read.

In particular, pixel format selection can have a profound impact on both the performance of and the video memory usage by your application. Keep in mind

that choosing pixel formats with more capabilities may lead to slower performance than choosing pixel formats with fewer options and smaller buffers. For

example, if you have a choice between a pixel format with a color buffer size

of, say, 8 bits per color component (32 bits total) or one with a color buffer represented as a 32-bit floating-point number per component (128 bits total), it’s

pretty clear that writing to a single pixel in your drawable requires four times

the bandwidth just for color. We’ll get into these performance implications later

and explore issues like this one in more detail. For now, just realize that a good

rule of thumb for choosing pixel formats is to choose the one that most closely

matches your application’s needs.

Example 8-1 Configuration of an OpenGL View in initWithFrame






#import "MyOpenGLView.h"

@implementation MyOpenGLView

- (id) initWithFrame: (NSRect) frame


time = 0;

angle = 0;

GLuint attributes[] =



// choose among pixelformats capable of rendering to windows


// require hardware-accelerated pixelformat


// require double-buffered pixelformat

NSOpenGLPFAColorSize, 24,

// require 24 bits for color-channels

NSOpenGLPFAAlphaSize, 8,

// require an 8-bit alpha channel

NSOpenGLPFADepthSize, 24,

// require a 24-bit depth buffer


// select a pixelformat which meets or exceeds these requirements



NSOpenGLPixelFormat* pixelformat =

[ [ NSOpenGLPixelFormat alloc ] initWithAttributes:

(NSOpenGLPixelFormatAttribute*) attributes ];

if ( pixelformat == nil )


NSLog( @"No valid OpenGL pixel format" );

NSLog( @"matches the attributes specified" );

// at this point, we’d want to try different sets of

// pixelformat attributes until we got a match, or decide

// we couldn’t create a proper graphics environment for our

// application, and exit appropriately


// now init ourself using NSOpenGLViews

// initWithFrame:pixelFormat message

return self = [ super initWithFrame: frame

pixelFormat: [ pixelformat autorelease ] ];


We’ll finish this Cocoa example by adding a few more useful methods to our

code. These will allow two more key tasks—namely, context setup (that is,

things you might do in an OpenGL application, such as, glEnable certain

states and bind textures) and drawing.


Chapter 8: The Cocoa API for OpenGL Configuration

Table 8-3 Common Pixel Format Qualifiers for Use with





Look in entire set of renderers to find a


Type: Boolean

YES: Search entire set of available renderers,

including those that are potentially

non-OpenGL compliant.

Default: YES

Policy: Any

Double buffer requirements.

Type: Boolean

YES: Search only for a double-buffered pixel


NO: Require a single-buffered pixel format.

Default: NO

Policy: Any

Stereo requirements.

Type: Boolean

YES: Require a stereo pixel format.

NO: Require a monoscopic pixel format.

Default: NO

Policy: Any

Auxiliary buffer requirements.

Type: Unsigned integer

Number of auxiliary buffers required by this

pixel format.

Default: NA

Policy: Smallest

Color bits requirements.

Type: Unsigned integer

Number of color buffer bits required by all

color components together.

Default: If this token is not specified, a

ColorSize that matches the screen is


Policy: Closest

Unsigned integer: The value specified is the

number of alpha buffer bits required.

Default: If no value is specified, pixel

formats discovered may or may not have an

alpha buffer.

Selection policy: Pixel formats that most

closely match this size are preferred.









Table 8-3 Common Pixel Format Qualifiers for Use with

NSOpenGLPixelFormat (Continued)




Unsigned integer: The value specified is the

number of depth buffer bits required.

Default: If no value is specified, pixel formats

discovered may or may not have a depth


Selection policy: Pixel formats that most

closely match this size are preferred.

Unsigned integer: The value specified is the

number of stencil planes required.

Selection policy: The smallest stencil buffer of

at least the specified size is preferred.

Unsigned integer: The value specified is the

number of accumulation buffer bits required.

Selection policy: An accumulation buffer that

most closely matches the specified size is


YES: Change to the selection policy


Selection policy: Consider only buffers

greater than or equal to each specified size of

the color, depth, and accumulation buffers.

YES: Change to the selection policy


Selection policy: For non-zero buffer

specifications, prefer the largest available

buffer for each of color, depth, and

accumulation buffers.

YES: Consider only renderers capable of

rendering to an off-screen memory area that

have a buffer depth exactly equal to the

specified buffer depth size. An implicit

change to the selection policy is as described.

Selection policy:


YES: Consider only renderers capable of

rendering to a full-screen drawable.

Implicitly defines the

NSOpenGLPFASingleRenderer attribute.

Unsigned integer: The value specified is the

number of multisample buffers required.









Chapter 8: The Cocoa API for OpenGL Configuration




Unsigned integer: The value specified is the

number of samples for each multisample

buffer required.

YES: Consider only renderers capable of

using floating-point pixels.

NSOpenGLPFAColorSize should also be set

to 64 or 128 for half- or full-precision

floating-point pixels (Mac OS 10.4).

YES: Consider only renderers capable of

using supersample anti-aliasing.

NSOpenGLPFASampleBuffers and

NSOpenGLPFASamples also need to be set

(Mac OS 10.4).

If present, searches for pixel formats for each

AuxBuffer that has its own depth stencil


Unsigned integer: ID of renderer.

Selection policy: Prefer renderers that match

the specified ID. Refer to CGLRenderers.h

for possible values.

YES: Modify the selection policy to search for

pixel formats only among hardwareaccelerated renderers.

NO (default): Search all renderers, but adhere

to the selection policy specified.

Selection policy: Prefer accelerated renderers.

YES: Modify the selection policy for the color

buffer to choose the closest color buffer size

preferentially. This policy will not take into

account the color buffer size of the current

graphics devices.

NO (default): No modification to selection


YES: Constrain the search of pixel formats to

consider only renderers that have a back

color buffer that is both the full size of the

drawable and guaranteed to be valid after a

call to a buffer flush.

NO (default): No modification to the

pixel buffer search.

YES (default): Search only among renderers

that are capable of rendering to a window.

Note: This attribute is implied only if neither

NSOpenGLPFAFullScreen nor

NSOpenGLPFAOffScreen is specified.

YES: Rendering to a pixel buffer is enabled.












Figure 8-8 Teapot Rendered with NSOpenGLView Subclass

The first of these methods, which is named prepareOpenGL, is defined to be

the first opportunity that your class will have to make some OpenGL calls.

prepareOpenGL will be called once a valid pixel format, context, and drawable are all available, so you can go ahead and call anything you’d like there.

Keep in mind that this method will be called only once, so from that point on,

you’ll have to manage your OpenGL state changes on the fly.

The second method to implement is drawRect. This method will be called every time a scene redraw is necessary; you will do the bulk of your OpenGL

work there. As part of the drawRect signature, you will be handed an NSRect

containing the current origin and size of the drawing area, in pixels.

With that introduction out of the way, we’ll simply point you at the code

(Example C-2) to add to your MyOpenGLView.m file, somewhere between the

@implementation and @end tokens. Once you’ve added this code, recompile

and run the code again, and you should see something like Figure 8-8.

Example 8-2 Cocoa drawRect Rendering Method with Sample OpenGL


- (void) drawRect: (NSRect) rect


// adjust viewing parameters

glViewport( 0, 0, (GLsizei) rect.size.width,

(GLsizei) rect.size.height );


Chapter 8: The Cocoa API for OpenGL Configuration

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Chapter 8. The Cocoa API for OpenGL Configuration

Tải bản đầy đủ ngay(0 tr)