Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The simplest, minimalistic, opengl 3.2 cocoa project

I have used the legacy openGL with cocoa for years, but I'm now struggling to make the transition to openGL 3.2. There are several examples in the internet, but they are all too complex (and many don't even compile any more under XCode 5.1). Could someone write an example of the simplest, minimalistic, minimum cocoa code just to draw a read triangle to a NSOpenGLView? (no fancy shaders, no displayCallbacks, the fewer the code lines, the better).

like image 568
roberto Avatar asked Mar 15 '14 18:03

roberto


2 Answers

Here's an answer based on the code in https://github.com/beelsebob/Cocoa-GL-Tutorial I changed these things: (1) The openGL context is created in a custom NSOpenGLView and not directly appended to the window. (2) I all the initialisation in one single function. (3) I deleted all the error verification code. This is not something you should do for a product, but I find it easier to understand the code with less clutter... (look at Cocoa-GL-Tutorial for proper error handling).

The steps (tested with Xcode 5.1):

  1. Make a new cocoa application
  2. Add a Custom View to the app window in the interface builder
  3. Add an Objective-C class, subclassing NSOpenGLView, I called it MyOpenGLView
  4. In the interface builder, select the CustomView, select the Identity Inspector (one of the icons top-right), and in Custom Class select MyOpenGLView
  5. Now, this is the code for MyOpenGLView.h:

    #import <Cocoa/Cocoa.h>
    #import <OpenGL/OpenGL.h>
    #import <OpenGL/gl3.h>

    @interface MyOpenGLView : NSOpenGLView
    {
        GLuint shaderProgram;
        GLuint vertexArrayObject;
        GLuint vertexBuffer;

        GLint positionUniform;
        GLint colourAttribute;
        GLint positionAttribute;
    }
    @end

And this is the code for MyOpenGLView.m:


    #import "MyOpenGLView.h"

    @implementation MyOpenGLView

    - (id)initWithFrame:(NSRect)frame
    {
        // 1. Create a context with opengl pixel format
        NSOpenGLPixelFormatAttribute pixelFormatAttributes[] =
        {
            NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
            NSOpenGLPFAColorSize    , 24                           ,
            NSOpenGLPFAAlphaSize    , 8                            ,
            NSOpenGLPFADoubleBuffer ,
            NSOpenGLPFAAccelerated  ,
            NSOpenGLPFANoRecovery   ,
            0
        };
        NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttributes];
        self = [super initWithFrame:frame pixelFormat:pixelFormat];

        // 2. Make the context current
        [[self openGLContext] makeCurrentContext];

        // 3. Define and compile vertex and fragment shaders
        GLuint  vs;
        GLuint  fs;
        const char    *vss="#version 150\n\
        uniform vec2 p;\
        in vec4 position;\
        in vec4 colour;\
        out vec4 colourV;\
        void main (void)\
        {\
        colourV = colour;\
        gl_Position = vec4(p, 0.0, 0.0) + position;\
        }";
        const char    *fss="#version 150\n\
        in vec4 colourV;\
        out vec4 fragColour;\
        void main(void)\
        {\
        fragColour = colourV;\
        }";
        vs = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vs, 1, &vss, NULL);
        glCompileShader(vs);
        fs = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fs, 1, &fss, NULL);
        glCompileShader(fs);
        printf("vs: %i, fs: %i\n",vs,fs);

        // 4. Attach the shaders
        shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram, vs);
        glAttachShader(shaderProgram, fs);
        glBindFragDataLocation(shaderProgram, 0, "fragColour");
        glLinkProgram(shaderProgram);

        // 5. Get pointers to uniforms and attributes
        positionUniform = glGetUniformLocation(shaderProgram, "p");
        colourAttribute = glGetAttribLocation(shaderProgram, "colour");
        positionAttribute = glGetAttribLocation(shaderProgram, "position");
        glDeleteShader(vs);
        glDeleteShader(fs);
        printf("positionUniform: %i, colourAttribute: %i, positionAttribute: %i\n",positionUniform,colourAttribute,positionAttribute);

        // 6. Upload vertices (1st four values in a row) and colours (following four values)
        GLfloat vertexData[]= { -0.5,-0.5,0.0,1.0,   1.0,0.0,0.0,1.0,
                                -0.5, 0.5,0.0,1.0,   0.0,1.0,0.0,1.0,
                                 0.5, 0.5,0.0,1.0,   0.0,0.0,1.0,1.0,
                                 0.5,-0.5,0.0,1.0,   1.0,1.0,1.0,1.0};
        glGenVertexArrays(1, &vertexArrayObject);
        glBindVertexArray(vertexArrayObject);

        glGenBuffers(1, &vertexBuffer);
        glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
        glBufferData(GL_ARRAY_BUFFER, 4*8*sizeof(GLfloat), vertexData, GL_STATIC_DRAW);

        glEnableVertexAttribArray((GLuint)positionAttribute);
        glEnableVertexAttribArray((GLuint)colourAttribute  );
        glVertexAttribPointer((GLuint)positionAttribute, 4, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), 0);
        glVertexAttribPointer((GLuint)colourAttribute  , 4, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), (char*)0+4*sizeof(GLfloat));

        return self;
    }

    - (void)drawRect:(NSRect)dirtyRect
    {
        [super drawRect:dirtyRect];

        glClearColor(0.0, 0.0, 0.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);
        glUseProgram(shaderProgram);
        GLfloat p[]={0,0};
        glUniform2fv(positionUniform, 1, (const GLfloat *)&p);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

        [[self openGLContext] flushBuffer];
    }

    @end

like image 72
roberto Avatar answered Oct 11 '22 06:10

roberto


https://stackoverflow.com/a/22502999/4946861

In xcode 6.3.2 I got the example running afterreplacement of

(id)initWithFrame:(NSRect)frame
with
(void)awakeFromNib

and replacement of

self = [super initWithFrame:frame pixelFormat:pixelFormat];
with
super.pixelFormat=pixelFormat;

and deletion of
return self;

or written out in detail:

#import "MyOpenGLView.h"

@implementation MyOpenGLView


- (void)awakeFromNib
{
    NSLog(@"...was here");
    // 1. Create a context with opengl pixel format
    NSOpenGLPixelFormatAttribute pixelFormatAttributes[] =
    {
        NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
        NSOpenGLPFAColorSize    , 24                           ,
        NSOpenGLPFAAlphaSize    , 8                            ,
        NSOpenGLPFADoubleBuffer ,
        NSOpenGLPFAAccelerated  ,
        NSOpenGLPFANoRecovery   ,
        0
    };
    NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttributes];

    super.pixelFormat=pixelFormat;

    // 2. Make the context current
    [[self openGLContext] makeCurrentContext];

    // 3. Define and compile vertex and fragment shaders
    GLuint  vs;
    GLuint  fs;
    const char    *vss="#version 150\n\
    uniform vec2 p;\
    in vec4 position;\
    in vec4 colour;\
    out vec4 colourV;\
    void main (void)\
    {\
    colourV = colour;\
    gl_Position = vec4(p, 0.0, 0.0) + position;\
    }";
    const char    *fss="#version 150\n\
    in vec4 colourV;\
    out vec4 fragColour;\
    void main(void)\
    {\
    fragColour = colourV;\
    }";
    vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vs, 1, &vss, NULL);
    glCompileShader(vs);
    fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fs, 1, &fss, NULL);
    glCompileShader(fs);
    printf("vs: %i, fs: %i\n",vs,fs);

    // 4. Attach the shaders
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vs);
    glAttachShader(shaderProgram, fs);
    glBindFragDataLocation(shaderProgram, 0, "fragColour");
    glLinkProgram(shaderProgram);

    // 5. Get pointers to uniforms and attributes
    positionUniform = glGetUniformLocation(shaderProgram, "p");
    colourAttribute = glGetAttribLocation(shaderProgram, "colour");
    positionAttribute = glGetAttribLocation(shaderProgram, "position");
    glDeleteShader(vs);
    glDeleteShader(fs);
    printf("positionUniform: %i, colourAttribute: %i, positionAttribute: %i\n",positionUniform,colourAttribute,positionAttribute);

    // 6. Upload vertices (1st four values in a row) and colours (following four values)
    GLfloat vertexData[]= { -0.5,-0.5,0.0,1.0,   1.0,0.0,0.0,1.0,
        -0.5, 0.5,0.0,1.0,   0.0,1.0,0.0,1.0,
        0.5, 0.5,0.0,1.0,   0.0,0.0,1.0,1.0,
        0.5,-0.5,0.0,1.0,   1.0,1.0,1.0,1.0};
    glGenVertexArrays(1, &vertexArrayObject);
    glBindVertexArray(vertexArrayObject);

    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, 4*8*sizeof(GLfloat), vertexData, GL_STATIC_DRAW);

    glEnableVertexAttribArray((GLuint)positionAttribute);
    glEnableVertexAttribArray((GLuint)colourAttribute  );
    glVertexAttribPointer((GLuint)positionAttribute, 4, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), 0);
    glVertexAttribPointer((GLuint)colourAttribute  , 4, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), (char*)0+4*sizeof(GLfloat));

}


- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];

    // Drawing code here.

    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(shaderProgram);
    GLfloat p[]={0,0};
    glUniform2fv(positionUniform, 1, (const GLfloat *)&p);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

    [[self openGLContext] flushBuffer];
}

@end
like image 7
nik Avatar answered Oct 11 '22 05:10

nik