Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL on Mac operation

This is really architecture question or 'how does it work' question than a problem to solve.

Apple documentation claims that CGL is lowest level api for managing OpenGL contexts, yet is lacks functionality that allows to connect a context to a window. AGL and Cocoa can bind a context to a window without a problem though, so the question is - how do they do that if they are built upon CGL?

The obvious way appears to be that they use CGL to render to offscreen memory and are then capable of compositing this somehow. If this is so, how does that happen?

like image 266
Steve Avatar asked Apr 02 '11 14:04

Steve


2 Answers

There is a private function CGLSetSurface that connects a surface that is part of a window to a GL context created with CGLCreateContext. Both AGL and Cocoa use this function internally.

like image 197
nschmidt Avatar answered Nov 05 '22 04:11

nschmidt


Complete example:

/*
mkdir -p build/test.app/Contents/MacOS
clang++ --std=c++11 
 -fno-exceptions
 -fno-rtti
 -mmacosx-version-min=10.9
 -Wno-writable-strings
 -Wno-deprecated-declarations
 -framework OpenGL
 -framework Carbon
 -g gui8.cpp
 -o build/test.app/Contents/MacOS/test


 */


#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#include <ApplicationServices/ApplicationServices.h>
#include <Carbon/Carbon.h>
#include <OpenGL/CGLTypes.h>
#include <OpenGL/CGLCurrent.h>
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>

typedef int CGSConnectionID;
typedef int CGSWindowID;
typedef int CGSSurfaceID;

typedef uint32_t _CGWindowID;

extern "C" {

typedef int CGSConnection;
typedef int CGSWindow;
typedef int CGSValue;

typedef enum _CGSWindowOrderingMode {
   kCGSOrderAbove                =  1, // Window is ordered above target.
   kCGSOrderBelow                = -1, // Window is ordered below target.
   kCGSOrderOut                  =  0  // Window is removed from the on-screen window list.
} CGSWindowOrderingMode;

typedef void *CGSRegion;
typedef CGSRegion *CGSRegionRef;
typedef CGSWindow *CGSWindowRef;

extern CGError CGSNewWindow( CGSConnection cid, int, float, float, const CGSRegion, CGSWindowRef);
extern CGError CGSNewRegionWithRect( const CGRect * rect, CGSRegionRef newRegion );
extern OSStatus CGSOrderWindow(CGSConnection cid, CGSWindow win, CGSWindowOrderingMode place, CGSWindow relativeToWindow /* nullable */);
extern OSStatus CGSSetWindowProperty(const CGSConnection cid, CGSWindow wid, CGSValue key, CGSValue value);
extern CGSConnectionID CGSMainConnectionID(void);
extern CGError CGSAddSurface(CGSConnectionID cid, _CGWindowID wid, CGSSurfaceID *sid);
extern CGError CGSSetSurfaceBounds(CGSConnectionID cid, _CGWindowID wid, CGSSurfaceID sid, CGRect rect);
extern CGError CGSOrderSurface(CGSConnectionID cid, _CGWindowID wid, CGSSurfaceID sid, int a, int b);
extern OSStatus CGSMoveWindow(const CGSConnection cid, const CGSWindow wid, CGPoint *point);
extern CGLError CGLSetSurface(CGLContextObj gl, CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID sid);

}
#define kCGSBufferedBackingType 2


int main () {

    CGLContextObj cgl_context = NULL;
    CGSWindow window = 0;

    int width = 500, height = 500;
    CGPoint window_pos = { .x = 200, .y = 200 };
    bool quit = false;

    CGSConnectionID connection_id = CGSMainConnectionID();
    assert(connection_id);

    {

        CGSRegion region = NULL;
        CGRect r = CGRectMake(0,0, width, height);
        auto err1 = CGSNewRegionWithRect(&r, &region);
        assert(region);
        auto err2 = CGSNewWindow(connection_id, kCGSBufferedBackingType, window_pos.x, window_pos.y, region, &window);
        assert(window);
        auto err3 = CGSOrderWindow(connection_id, window, kCGSOrderAbove, 0);
        assert (err3 == kCGErrorSuccess);


        CGLPixelFormatAttribute attributes[] = {
            kCGLPFADoubleBuffer,
            kCGLPFAAccelerated, // Hardware rendering
            // kCGLPFARendererID, (CGLPixelFormatAttribute) kCGLRendererGenericFloatID, // Software rendering
            (CGLPixelFormatAttribute)0
        };

        CGLPixelFormatObj pix;
        GLint num;
        auto err4 = CGLChoosePixelFormat(attributes, &pix, &num);
        assert(err4 == kCGLNoError); // CGLErrorString(err1)
        assert(pix);

        CGLCreateContext(pix, NULL, &cgl_context);
        assert(cgl_context);
        CGLDestroyPixelFormat(pix);
        CGLSetCurrentContext(cgl_context);

        GLint v_sync_enabled = 1;
        CGLSetParameter(cgl_context, kCGLCPSwapInterval, &v_sync_enabled);

        CGSSurfaceID surface_id = 0;
        auto err5 = CGSAddSurface(connection_id, window, &surface_id);
        assert(err5 == kCGErrorSuccess);
        auto err6 = CGSSetSurfaceBounds(connection_id, window, surface_id, CGRectMake(0, 0, width, height));
        assert(err6 == kCGErrorSuccess);
        auto err7 = CGSOrderSurface(connection_id, window, surface_id, 1, 0);
        assert(err7 == kCGErrorSuccess);

        auto err8 = CGLSetSurface(cgl_context, connection_id, window, surface_id);
        assert(err8 == kCGLNoError);

        GLint drawable = 0;
        CGLGetParameter(cgl_context, kCGLCPHasDrawable, &drawable);
        assert(drawable == 1);




    }

    assert(glGetError() == GL_NO_ERROR);

    CGPoint drag_starting_position;
    bool drag_started = false;
    while (!quit) {

        glClearColor(1,1,0,1);
        glClear(GL_COLOR_BUFFER_BIT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        static float a = 0;
        glRotatef(a * 1000, 0, 0, 1);
        // printf("a: %f\n", a);
        a= a + .001;
        glBegin(GL_QUADS);
        if (a>1.5) a=0;
        glColor4f(0,a,1,1);
        glVertex2f(0.25, 0.25);
        glVertex2f(0.75, 0.25);
        glVertex2f(0.75, 0.75);
        glVertex2f(0.25, 0.75);
        glEnd();

        auto err1 = CGLFlushDrawable(cgl_context);
        assert(err1 == kCGLNoError);

        assert(glGetError() == GL_NO_ERROR);

    }

    CGLSetCurrentContext(NULL);
    CGLDestroyContext(cgl_context);

}
like image 2
Dave Butler Avatar answered Nov 05 '22 06:11

Dave Butler