Obtaining GL Context
I'm just starting with OpenGL & Carbon. I've looked at several books and tutorials on setting up a basic windowed view to draw into. I'd like to know the recommended approach as there seems to be a couple different approaches.
The Pangea book uses AGL. He creates a window (or I assume I can get one from the nib) and then calls GetWindowPort & aglSetDrawable using the pixel format created, agl context & the window created. However, he does use some seemingly deprecated functions like GetMainDevice.
The UltimateGameProgramming website demos create a window from the nib like what Xcode produces from the new Carbon project. Then they use SetPortWindowPort, GetWindowPort & aglSetDrawable. The do the aglChoosePixelFormat passing in 0 for the gdevs, whereas Pangea uses the GetMainDevice for gdevs.
Both of these sources seem a little dated, so I'm not sure this is the right way to go about it.
I'm going to use Carbon and C++ for a bunch of reasons, none of which should impact the above.
The Pangea book uses AGL. He creates a window (or I assume I can get one from the nib) and then calls GetWindowPort & aglSetDrawable using the pixel format created, agl context & the window created. However, he does use some seemingly deprecated functions like GetMainDevice.
The UltimateGameProgramming website demos create a window from the nib like what Xcode produces from the new Carbon project. Then they use SetPortWindowPort, GetWindowPort & aglSetDrawable. The do the aglChoosePixelFormat passing in 0 for the gdevs, whereas Pangea uses the GetMainDevice for gdevs.
Both of these sources seem a little dated, so I'm not sure this is the right way to go about it.
I'm going to use Carbon and C++ for a bunch of reasons, none of which should impact the above.
If you're creating a windowed context, you'll want to pass 0 and NULL for the device parameters. If you're creating a full-screen context, you need to pass a particular GDevice, and that means you'll be calling GetMainDevice or some function like that.
Yeah, but apparently GetMainDevice or the world various in your book are deprecated in 10.4 with no word on what replaces them. I'm guess some sort of CoreGraphics call.
But otherwise the AGL stuff in your book is the most current?
But otherwise the AGL stuff in your book is the most current?
You have to pass a GDevice to AGL. The only way to get a GDevice is through those QuickDraw calls. If you're compiling with MACOSX_DEPLOYMENT_TARGET set to 10.4 or later (as it is for Intel), you will get deprecation warnings.
Use Cocoa if you don't like it.
Use Cocoa if you don't like it.
Okay, I guess I may have to rethink my decision to use Carbon vs. Cocoa.
OneSadCookie Wrote:You have to pass a GDevice to AGL. The only way to get a GDevice is through those QuickDraw calls. If you're compiling with MACOSX_DEPLOYMENT_TARGET set to 10.4 or later (as it is for Intel), you will get deprecation warnings.
Actually, the function DMGetGDeviceByDisplayID() is not deprecated, which is all you will need. A CGDirectDisplayID can be coerced to a DisplayIDType, which the function uses to specify the device. (Although different types, CGDirectDisplayID and DisplayIDType use the exact same values to represent displays.)
It still feels a little nasty having to use a GDHandle, but until AGL accepts a CGDirectDisplayID, or CGL works for windows, this is probably the best approach.
I would not switch to Cocoa simply for this reason alone. Since you don't in fact need to use any deprecated functions, and since this will be the only spot where you will be forced to use a GDHandle, I could live with that. But if you switch to Cocoa for its obvious benifits, then go for it!

nalenb, here is the code I use to great AGLContexts for either windows or displays:
Code:
/*------------------------------------------------------------------------------
Create the AGLContext for a given context. Passing in a display ID means it
will create a context suitable for full screen mode on that display, else it
creates a context suitable for windowed mode. */
static OSStatus /* Error result if any. */
OGLCreateAGLContext (
CGDirectDisplayID
displayID, /* If != NULL, full screen context for this display
is created. */
long
pixelSize, /* Pixel size to render in. */
AGLContext*
pAGLContext) /* New AGLContext returned here. */
{
OSStatus
err;
GLint
attributes[] =
{
AGL_RGBA,
AGL_DOUBLEBUFFER,
/* Should be used whenever packed pixels is used to disable software
back up textures. */
AGL_NO_RECOVERY,
AGL_DEPTH_SIZE,
kOGLDepthBufferSize,
/* The following attributes are used for full screen mode only and
must be at the end of the list so we can remove them when not using
full screen mode. */
AGL_PIXEL_SIZE,
0,
AGL_FULLSCREEN,
AGL_NONE
};
GDHandle
hGDevice;
AGLPixelFormat
pixelFormat;
AGLContext
aglContext;
UInt32
u32Index;
if (pAGLContext == NULL)
return (paramErr);
*pAGLContext = NULL;
if (displayID != NULL)
{
/* The best way to specify the device for an AGLContext to use is by
supplying aglChoosePixelFormat() the device. Unfortunately it requests a
GDHandle to specify the device. Luckily, DMGetGDeviceByDisplayID() is
not deprecated. Perhaps Apple recognized the need to still require the
means to derive a GDHandle for a display ID.
Alternatively, the device can be specified in aglSetFullScreen() by
supplying a device number. Using deprecated Display Manager calls, this
is the Nth zero-based screen device in the list. I'm not sure how this
number can be derived using CoreGraphics.
As another alternative, CGL could be called directly when we go to full
screen mode, instead of using AGL. (CGL only works in full screen mode.) */
err = DMGetGDeviceByDisplayID((DisplayIDType)displayID, &hGDevice, false);
if (err != noErr)
return (err);
}
else
hGDevice = NULL;
if (displayID != NULL)
{
u32Index = 0;
while (attributes[u32Index] != AGL_PIXEL_SIZE)
++u32Index;
attributes[u32Index + 1] = pixelSize;
}
else
{
u32Index = 0;
while (attributes[u32Index] != AGL_PIXEL_SIZE)
++u32Index;
attributes[u32Index] = AGL_NONE;
}
pixelFormat = aglChoosePixelFormat((hGDevice == NULL) ? NULL : &hGDevice,
(hGDevice == NULL) ? 0 : 1, attributes);
if (pixelFormat == NULL)
{
if ((err = aglGetError()) == AGL_NO_ERROR)
err = AGL_BAD_ATTRIBUTE;
return (err);
}
aglContext = aglCreateContext(pixelFormat, NULL);
err = aglGetError();
aglDestroyPixelFormat(pixelFormat);
if (aglContext == NULL)
{
if (err == AGL_NO_ERROR)
err = AGL_BAD_ALLOC;
return (err);
}
*pAGLContext = aglContext;
return (noErr);
}
Thanks for the info. I'm going to go with Cocoa for now.
FUSION, this source code looks pretty nice. I've been trying to find a non-nib based carbon OpenGL setup sample. I'm a long time Win32 OpenGL guy, and I'm used to doing things manually. As a matter of fact a lot of our code depends on not using resources/nibs and other weirdness. I'd also like to not have a lot of Objective-C glue, hence my desire for Carbon.
Your code for getting a context looks nice. Do you have any sample code similar to that which just sets up a single window, a context, an event loop and sits there? Maybe spinning a triangle? Just curious. All of the apple examples tend to use Nibs and lots of other crap which I don't care about. I just want to get a window with a context up. I know I can use SDL or GLUT, but we're working to bring in better mac support, without depending on these other mechanisms.
Thanks for this code.... got any more?
Casey
Your code for getting a context looks nice. Do you have any sample code similar to that which just sets up a single window, a context, an event loop and sits there? Maybe spinning a triangle? Just curious. All of the apple examples tend to use Nibs and lots of other crap which I don't care about. I just want to get a window with a context up. I know I can use SDL or GLUT, but we're working to bring in better mac support, without depending on these other mechanisms.
Thanks for this code.... got any more?

Casey
I don't know if anyone is going to find it useful, but I put together the following little app which creates a GL context and draws to it. No nibs. Just plain old C code. Don't know why this has been such a hard thing to find any sort of documentation on. Didn't turn out to be that difficult.
Code:
//
// main.c
// CarbonGLNoNib
//
// Created by Casey O'Donnell on 5/9/06.
// Copyright Casey O'Donnell 2006. All rights reserved.
//
#include <Carbon/Carbon.h>
#include <OpenGL/Opengl.h>
#include <OpenGL/CGLTypes.h>
#include <AGL/agl.h>
EventTypeSpec clickSpec = {kEventClassMouse, kEventMouseDown};
EventTypeSpec drawSpec = {kEventClassWindow, kEventWindowDrawContent};
static pascal OSStatus DoDraw(EventHandlerCallRef handlerRef, EventRef event, void *userData)
{
#pragma unused(handlerRef, event)
AGLContext* pContext = (AGLContext*)userData;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f,0.0f,0.0f);
glBegin(GL_TRIANGLES);
glColor3f(1.0f,0.0f,0.0f);
glVertex3f( 0.0f, 1.0f, 0.0f);
glColor3f(0.0f,1.0f,0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glColor3f(0.0f,0.0f,1.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();
aglSwapBuffers(*pContext);
return noErr;
}
static pascal OSStatus DoClick(EventHandlerCallRef handlerRef, EventRef event, void *userData)
{
#pragma unused(handlerRef, event, userData)
QuitApplicationEventLoop();
return noErr;
}
int main(int argc, char* argv[])
{
WindowRef window;
AGLContext context;
AGLDrawable drawable;
GLint defaultAttribs[] = {AGL_RGBA, AGL_DOUBLEBUFFER, AGL_DEPTH_SIZE, 16, AGL_NONE};
AGLPixelFormat format;
GLenum glerr;
OSStatus err;
Rect rWin = {70, 70, 300, 400};
InitCursor();
window = NewCWindow(NULL, &rWin, "\pClick to Quit", false, documentProc,(WindowPtr) -1L, false, 0);
drawable = (AGLDrawable) GetWindowPort(window);
format = aglChoosePixelFormat(NULL,0,defaultAttribs);
context = aglCreateContext(format,NULL/*Share context?*/);
aglSetDrawable(context,drawable);
aglSetCurrentContext(context);
err = InstallWindowEventHandler(window, NewEventHandlerUPP(DoClick), 1, &clickSpec, NULL, NULL);
err = InstallWindowEventHandler(window, NewEventHandlerUPP(DoDraw), 1, &drawSpec, (void*)&context, NULL);
ShowWindow(window);
RunApplicationEventLoop();
aglSetCurrentContext(NULL);
aglDestroyContext(context);
return err;
}
Wiked, thanks!
This is perfect because I am just starting to learn C++ and dont want to be having all my C++ functions called by ObjC stuff.
This is perfect because I am just starting to learn C++ and dont want to be having all my C++ functions called by ObjC stuff.
Sir, e^iπ + 1 = 0, hence God exists; reply!
This is what I use to put a carbon GL context onto a window. It is not full screen, that code is much simpler, but I don't feel like looking around for it right now. This code is nice because it uses AGL_BUFFER_RECT, which allows for gluPicking inside the context to work correctly. At least, so I remember... it's been awhile since I've done anything in carbon.
Here is the code you'd put in createGLWindow.cpp
And when you want to use it...
... where totalWindow is the window you want it in, showContext is an aglContext, fmt is an AGLPixelFormat, and glContextRect is a Rect containing the coordinates of the drawable area.
Hopefully this code still works.
Here is the code you'd put in createGLWindow.cpp
Code:
void FindResolution(int* width, int* height)
{
CGDirectDisplayID dID;
dID = CGMainDisplayID();
*height = CGDisplayPixelsHigh(dID);
*width = CGDisplayPixelsWide(dID);
}
void CreateAGLAttributesForBufferRect(GLint* aglAttributes)
{
int i = 0;
aglAttributes[i++] = AGL_RGBA;
aglAttributes[i++] = AGL_DOUBLEBUFFER;
aglAttributes[i++] = AGL_ACCELERATED;
aglAttributes[i++] = AGL_NO_RECOVERY;
aglAttributes[i++] = AGL_DEPTH_SIZE;
aglAttributes[i++] = 16;
aglAttributes[i++] = AGL_NONE;
}
void CreateAGLPixelFormat(WindowRef w, GLint* aglAttributes, AGLPixelFormat & fmt)
{
GDHandle hGD = NULL;
short numDevices;
fmt = 0;
numDevices = FindGDHandleFromWindow(w,&hGD);
fmt = aglChoosePixelFormat(&hGD, 1, aglAttributes);
}
void PutGLOnWindow(WindowRef w, AGLContext* aglContext, AGLPixelFormat fmt, Rect* vPort)
{
Rect windowRect;
Rect sRect;
int height;
int fullHeight;
GrafPtr cgrafSave = NULL;
SetPortWindowPort(w);
GetWindowBounds(w, kWindowStructureRgn, &sRect);
GetWindowBounds(w, kWindowContentRgn, &windowRect);
height = windowRect.bottom - windowRect.top;
fullHeight = sRect.bottom - sRect.top;
GetPort (&cgrafSave);
//Now build GL on it
if(aglGetCurrentContext() != NULL)
*aglContext = aglCreateContext(fmt, aglGetCurrentContext());
else
*aglContext = aglCreateContext(fmt, 0);
aglSetDrawable(*aglContext, GetWindowPort(w));
aglSetCurrentContext (*aglContext);
SetPort (cgrafSave);
//Setup context if it was created properly.
if (!(*aglContext))
{
//destroy contexts... do later
return;
}
else
{
aglSetCurrentContext (*aglContext);
aglUpdateContext (*aglContext);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glEnable(GL_TEXTURE_2D);
glClearColor(0, 0, 0, 1.0f);
glClear (GL_COLOR_BUFFER_BIT);
//aglSwapBuffers (*aglContext);
//left edge == vPort->left
//bottom edge == height - vPort->bottom
//width = vPort->right - vPort->left
//height = vPort->bottom - vPort->left
//alright, so supposedly agl_buffer_rect is based on the structure region
//therefore, that is not only #1 ***, but #2 inconvenient...
//so we need to rework all this ******* bulshit
//GLint aiRect[4] = { contain->left, contain->top, contain->right - contain->left, contain->bottom - contain->top};
GLint aiRect[4];
aiRect[0] = vPort->left;
aiRect[1] = fullHeight - vPort->bottom;
aiRect[2] = vPort->right - vPort->left;
aiRect[3] = vPort->bottom - vPort->top;
aglSetInteger(*aglContext, AGL_BUFFER_RECT, aiRect);
aglEnable (*aglContext, AGL_BUFFER_RECT);
glViewport (0, 0, vPort->right - vPort->left, vPort->bottom - vPort->top);
aglUpdateContext (*aglContext);
}
aglSetCurrentContext(*aglContext);
}
short FindGDHandleFromWindow (WindowPtr pWindow, GDHandle * phgdOnThisDevice)
{
GrafPtr pgpSave;
Rect rectWind, rectSect;
long greatestArea, sectArea;
short numDevices = 0;
GDHandle hgdNthDevice;
if (!pWindow || !phgdOnThisDevice)
return -1;
*phgdOnThisDevice = NULL;
GetPort (&pgpSave);
SetPortWindowPort (pWindow);
GetWindowPortBounds (pWindow, &rectWind);
LocalToGlobal ((Point*)& rectWind.top);
LocalToGlobal ((Point*)& rectWind.bottom);
hgdNthDevice = GetDeviceList();
greatestArea = 0;
while (hgdNthDevice)
{
if (TestDeviceAttribute (hgdNthDevice, screenDevice))
if (TestDeviceAttribute (hgdNthDevice, screenActive))
{
SectRect (&rectWind, &(**hgdNthDevice).gdRect, &rectSect);
sectArea = (long) (rectSect.right - rectSect.left) * (rectSect.bottom - rectSect.top);
if (sectArea > 0)
numDevices++;
if (sectArea > greatestArea)
{
greatestArea = sectArea;
*phgdOnThisDevice = hgdNthDevice;
}
hgdNthDevice = GetNextDevice(hgdNthDevice);
}
}
SetPort (pgpSave);
return numDevices;
}
And when you want to use it...
Code:
GLint aglAttributes[64];
CreateAGLAttributesForBufferRect(aglAttributes);
CreateAGLPixelFormat(totalWindow, aglAttributes, fmt);
PutGLOnWindow(totalWindow, &showContext, fmt, &glContextRect);
Hopefully this code still works.
Possibly Related Threads...
Thread: | Author | Replies: | Views: | Last Post | |
Obtaining GPU deviceID for each window/NSScreen in multi-display/multi-GPU app? | dauerbach | 1 | 4,953 |
Oct 8, 2012 11:58 AM Last Post: OneSadCookie |
|
Obtaining Supported Screen Resolutions | Volte | 4 | 6,163 |
Sep 11, 2005 03:05 AM Last Post: Volte |