Obtaining GL Context

Apprentice
Posts: 14
Joined: 2005.12
Post: #1
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.
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #2
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.
Quote this message in a reply
Apprentice
Posts: 14
Joined: 2005.12
Post: #3
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?
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #4
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.
Quote this message in a reply
Apprentice
Posts: 14
Joined: 2005.12
Post: #5
Okay, I guess I may have to rethink my decision to use Carbon vs. Cocoa.
Quote this message in a reply
FUSION
Unregistered
 
Post: #6
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! Smile

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);
}
Quote this message in a reply
Apprentice
Posts: 14
Joined: 2005.12
Post: #7
Thanks for the info. I'm going to go with Cocoa for now.
Quote this message in a reply
alphapo
Unregistered
 
Post: #8
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? Wink

Casey
Quote this message in a reply
alphapo
Unregistered
 
Post: #9
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;
}
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #10
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.

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Moderator
Posts: 133
Joined: 2008.05
Post: #11
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
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);
... 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.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Obtaining GPU deviceID for each window/NSScreen in multi-display/multi-GPU app? dauerbach 1 3,142 Oct 8, 2012 11:58 AM
Last Post: OneSadCookie
  Obtaining Supported Screen Resolutions Volte 4 4,169 Sep 11, 2005 03:05 AM
Last Post: Volte