这确实是架构问题或“它是如何工作”的问题,而不是要解决的问题。
Apple文档声称CGL是用于管理OpenGL上下文的最低级api,但缺乏允许将上下文连接到窗口的功能。 AGL和Cocoa可以将上下文绑定到窗口而没有问题,所以问题是 - 如果它们是基于CGL构建的,它们如何做到这一点?
显而易见的方式似乎是他们使用CGL渲染到屏幕外的内存,然后能够以某种方式合成它。如果是这样,那会怎么样?
答案 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, ®ion);
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获取所有其他内容然后附加到窗口就可以了,但在此之后)。