使用 C 和 Cocoa 建立 OpenGL 4.1

注意:在這個例子中會有一些 Objective-c。在這個例子中我們將為 C++做一個包裝器,所以不用擔心它。

首先啟動 Xcode 並建立一個專案。

StackOverflow 文件

並選擇一個 Cocoa 應用程式 StackOverflow 文件

刪除除 Info.plist 檔案以外的所有來源。(如果沒有它,你的應用程式將無法執行)

建立 4 個新的原始檔:Objective-c ++檔案和標題(我稱之為我的 MacApp)一個 C++類(我稱之為我的(應用程式)

在左上角(帶有專案名稱),單擊它並新增連結的框架和庫。新增:OpenGL.Framework AppKit.Framework GLKit.Framework

你的專案可能看起來像這樣:

StackOverflow 文件

NSApplication 是你在建立 MacOS 應用程式時使用的主要類。它允許你註冊視窗和捕獲事件。

我們想要將(我們自己的)視窗註冊到 NSApplication。首先在 objective-c ++標頭檔案中建立一個 Objective-c 類,它繼承自 NSWindow 並實現 NSApplicationDelegate NSWindow 需要一個指向 C++應用程式的指標,一個 openGL 檢視和一個用於繪製迴圈的計時器

//Mac_App_H
#import <Cocoa/Cocoa.h>
#import "Application.hpp"
#import <memory>
NSApplication* application;

@interface MacApp : NSWindow <NSApplicationDelegate>{
    std::shared_ptr<Application> appInstance;
}
@property (nonatomic, retain) NSOpenGLView* glView;
-(void) drawLoop:(NSTimer*) timer;
@end

我們稱之為主要的

int main(int argc, const char * argv[]) {
    MacApp* app;
    application = [NSApplication sharedApplication];
    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; 
    //create a window with the size of 600 by 600   
    app = [[MacApp alloc] initWithContentRect:NSMakeRect(0, 0, 600, 600)              styleMask:NSTitledWindowMask | NSClosableWindowMask |  NSMiniaturizableWindowMask   backing:NSBackingStoreBuffered defer:YES];    
    [application setDelegate:app];
    [application run];
}

我們的視窗的實現實際上非常簡單首先我們宣告合成我們的 glview 並在視窗關閉時新增一個全域性的 objective-c 布林值。

#import "MacApp.h"

@implementation MacApp

@synthesize glView;

BOOL shouldStop = NO;

現在為建構函式。我的偏好是使用 initWithContentRect。

-(id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag{
if(self = [super initWithContentRect:contentRect styleMask:aStyle backing:bufferingType defer:flag]){
    //sets the title of the window (Declared in Plist)
    [self setTitle:[[NSProcessInfo processInfo] processName]];
 
    //This is pretty important.. OS X starts always with a context that only supports openGL 2.1
    //This will ditch the classic OpenGL and initialises openGL 4.1
    NSOpenGLPixelFormatAttribute pixelFormatAttributes[] ={
        NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
            NSOpenGLPFAColorSize    , 24                           ,
            NSOpenGLPFAAlphaSize    , 8                            ,
            NSOpenGLPFADoubleBuffer ,
            NSOpenGLPFAAccelerated  ,
            NSOpenGLPFANoRecovery   ,
            0
    };

    NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc]initWithAttributes:pixelFormatAttributes];
    //Initialize the view 
    glView = [[NSOpenGLView alloc]initWithFrame:contentRect pixelFormat:format];
    
    //Set context and attach it to the window
    [[glView openGLContext]makeCurrentContext];
  
    //finishing off
    [self setContentView:glView];
    [glView prepareOpenGL];
    [self makeKeyAndOrderFront:self];
    [self setAcceptsMouseMovedEvents:YES];
    [self makeKeyWindow];
    [self setOpaque:YES];

    //Start the c++ code
    appInstance = std::shared_ptr<Application>(new Application());

}
return self;
}

好吧……現在我們實際上有一個可執行的應用程式..你可能會看到黑屏或閃爍。

讓我們開始繪製一個很棒的三角形。(在 c ++中)

我的應用標題

#ifndef Application_hpp
#define Application_hpp
#include <iostream>
#include <OpenGL/gl3.h>
class Application{
private:
    GLuint          program;
    GLuint          vao;
public:
    Application();
    void update();
    ~Application();

};

#endif /* Application_hpp */

實施:

Application::Application(){
 static const char * vs_source[] =
    {
        "#version 410 core                                                 \n"
        "                                                                  \n"
        "void main(void)                                                   \n"
        "{                                                                 \n"
        "    const vec4 vertices[] = vec4[](vec4( 0.25, -0.25, 0.5, 1.0),  \n"
        "                                   vec4(-0.25, -0.25, 0.5, 1.0),  \n"
        "                                   vec4( 0.25,  0.25, 0.5, 1.0)); \n"
        "                                                                  \n"
        "    gl_Position = vertices[gl_VertexID];                          \n"
        "}                                                                 \n"
    };

    static const char * fs_source[] =
    {
        "#version 410 core                                                 \n"
        "                                                                  \n"
        "out vec4 color;                                                   \n"
        "                                                                  \n"
        "void main(void)                                                   \n"
        "{                                                                 \n"
        "    color = vec4(0.0, 0.8, 1.0, 1.0);                             \n"
        "}                                                                 \n"
    };

    program = glCreateProgram();
    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fs, 1, fs_source, NULL);
    glCompileShader(fs);

    GLuint vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vs, 1, vs_source, NULL);
    glCompileShader(vs);

    glAttachShader(program, vs);
    glAttachShader(program, fs);

    glLinkProgram(program);

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
}

void Application::update(){
    static const GLfloat green[] = { 0.0f, 0.25f, 0.0f, 1.0f };
    glClearBufferfv(GL_COLOR, 0, green);

    glUseProgram(program);
    glDrawArrays(GL_TRIANGLES, 0, 3);
}

Application::~Application(){
    glDeleteVertexArrays(1, &vao);
    glDeleteProgram(program);
}

現在我們只需要反覆呼叫更新(如果你想要移動的東西)在 objective-c 類中實現

-(void) drawLoop:(NSTimer*) timer{

if(shouldStop){
    [self close];
    return;
}
if([self isVisible]){
  
       appInstance->update();
    [glView update];
    [[glView openGLContext] flushBuffer];
}

}

並在你的 objective-c 類的實現中新增此方法:

- (void)applicationDidFinishLaunching:(NSNotification *)notification {
    [NSTimer scheduledTimerWithTimeInterval:0.000001 target:self selector:@selector(drawLoop:) userInfo:nil repeats:YES];
}

這將一遍又一遍地呼叫你的 c ++類的更新函式(準確地說每個 0.000001 秒)

為了完成,我們在按下關閉按鈕時關閉視窗:

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication     *)theApplication{
    return YES;
}

- (void)applicationWillTerminate:(NSNotification *)aNotification{
    shouldStop = YES;
}

恭喜,現在你有一個很棒的視窗,有一個沒有任何第三方框架的 OpenGL 三角形。 StackOverflow 文件