Mac操作上的OpenGL

时间:2011-04-02 14:38:46

标签: cocoa macos opengl

这确实是架构问题或“它是如何工作”的问题,而不是要解决的问题。

Apple文档声称CGL是用于管理OpenGL上下文的最低级api,但缺乏允许将上下文连接到窗口的功能。 AGL和Cocoa可以将上下文绑定到窗口而没有问题,所以问题是 - 如果它们是基于CGL构建的,它们如何做到这一点?

显而易见的方式似乎是他们使用CGL渲染到屏幕外的内存,然后能够以某种方式合成它。如果是这样,那会怎么样?

3 个答案:

答案 0 :(得分:8)

有一个私有函数CGLSetSurface,它将作为窗口一部分的曲面连接到使用CGLCreateContext创建的GL上下文。 AGL和Cocoa都在内部使用此功能。

答案 1 :(得分:1)

完整示例:

/*
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);

}

答案 2 :(得分:0)

此后我没有重新回答这个问题,这是我能够做到的: 在网上漂浮的未记录的api似乎是一个缺失的块 - 我能够CGLSetSurface没有它返回错误,但它最终没有做那么多。显然,还有一些其他的东西需要做,以使一切工作在如此低的水平。

总之,通过CGL似乎没有一种理智的方式来控制一切。处理所有事情的方式就像其他人正在做的那样 - 通过Cocoa classes使用CGL获取所有其他内容然后附加到窗口就可以了,但在此之后)。