0
votes

What I want to do is to simply run the first OpenGL program from the Red Book (triangles.cpp) inside a NSOpenGLView, but my app only clears the screen to black and does not draws the required triangles (even though the shaders were compiled successfully).

(One side note: If I use glBegin() and glEnd() I can draw on the screen, but if I use glDrawArrays() nothing got drawn on the screen)

Here's my code:

#import "GLView.h"
#include <OpenGL/gl3.h>
#include <vector>
#include <iostream>

@implementation GLView

static GLuint shaderProgram; // The shader program

static GLuint vPosition; // vPosition is a vertex shader input variable

static GLuint vao1; // Vertex Array Object
static GLuint vbo1; // Vertex Buffer Object

const GLuint num_verts = 6; // The number of vertices to draw

// The vertex data that will be drawn
GLfloat vertices[num_verts][2] = {
    { -0.90, -0.90 },
    { 0.85, -0.90},
    {-0.90, 0.85},
    {0.90,-0.85},
    {0.90,0.90},
    {-0.85, 0.90}
};

- (id)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];

    // 1. Make an OpenGL 4.1 context
    NSOpenGLPixelFormatAttribute attrs[] =
    {
        NSOpenGLPFADoubleBuffer,
        NSOpenGLPFADepthSize, 24,
        // Must specify the 4.1 Core Profile to use OpenGL 4.1
        NSOpenGLPFAOpenGLProfile,
        NSOpenGLProfileVersion4_1Core,
        0
    };

    NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];

    if (!pf)
    {
        NSLog(@"No OpenGL pixel format");
    }

    NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext: nil] ;

    [context makeCurrentContext];

    // 2. Compiling the shaders
    GLuint  vs;
    GLuint  fs;

    // Vertex Shader Source
    const char    *vss=
        "#version 410\n"

        "in vec4 vPosition;"

        "void main(void) {"
            "gl_Position = vPosition;"
        "}";

    // Fragment Shader Source
    const char    *fss=
        "#version 410\n"

        "out vec4 fColor;"

        "void main(void) {"
            "fColor = vec4(1.0,0.0,0.0,1.0);"
        "}";

    vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vs, 1, &vss, NULL);
    glCompileShader(vs);

    // Error handling if shader was not compiled successfully 
    GLint isCompiled;
    glGetShaderiv(vs, GL_COMPILE_STATUS, &isCompiled);
    if(isCompiled == GL_FALSE)
    {
        GLint maxLength = 0;
        glGetShaderiv(vs, GL_INFO_LOG_LENGTH, &maxLength);

        std::vector<GLchar> infoLog(maxLength);
        glGetShaderInfoLog(vs, maxLength, &maxLength, &infoLog[0]);

        //We don't need the shader anymore.
        glDeleteShader(vs);

        // Printing the error to console
        for (int i = 0; i < infoLog.size(); i++)
            putchar(infoLog[i]);
        putchar('\n');
    }

    fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fs, 1, &fss, NULL);
    glCompileShader(fs);

    // Error handling if shader was not compiled successfully 
    glGetShaderiv(fs, GL_COMPILE_STATUS, &isCompiled);
    if(isCompiled == GL_FALSE)
    {
        GLint maxLength = 0;
        glGetShaderiv(fs, GL_INFO_LOG_LENGTH, &maxLength);

        std::vector<GLchar> infoLog(maxLength);
        glGetShaderInfoLog(fs, maxLength, &maxLength, &infoLog[0]);

        //We don't need the shader anymore.
        glDeleteShader(fs);

        // Printing the error to console
        for (int i = 0; i < infoLog.size(); i++)
            putchar(infoLog[i]);
        putchar('\n');
    }

    // 3. Attach the shaders
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vs);
    glAttachShader(shaderProgram, fs);
    glLinkProgram(shaderProgram);

    // Error handling if program wasn't linked successfully 
    GLint isLinked;
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, (int *)&isLinked);
    if(isLinked == GL_FALSE)
    {
        GLint maxLength = 0;

        glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &maxLength);
        std::vector<GLchar> infoLog(maxLength);

        glGetProgramInfoLog(shaderProgram, maxLength, &maxLength, &infoLog[0]);

        // Printing the error to console
        for (int i = 0; i < infoLog.size(); i++)
            putchar(infoLog[i]);
        putchar('\n');
    }

    vPosition = glGetAttribLocation(shaderProgram, "vPosition");
    glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE,
                    0, 0);

    glEnableVertexAttribArray(vPosition);

    glUseProgram(shaderProgram);

    // 4. Creating the vertex data
    glGenVertexArrays(1, &vao1);
    glBindVertexArray(vao1);

    glGenBuffers(1, &vbo1);
    glBindBuffer(GL_ARRAY_BUFFER, vbo1);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    return self;
}

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

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glBindVertexArray(vao1);
    glDrawArrays(GL_TRIANGLES, 0, num_verts);

    glFlush();
}

@end

Can you tell me wether:

Am I creating the OpenGL 4.1 Context correctly (I.e. The NSOpenGLContext object)?

Am I compile/load the shaders correctly?

Am I creating the vertex array object and vertex buffer object correctly?

1
Have you tried placing glGetError next to OpenGL calls to track down any function returning an error?Joshua Waring

1 Answers

0
votes

I have managed to get it working by using code from Apple's GLEssentials sample:

https://developer.apple.com/library/mac/samplecode/GLEssentials/Introduction/Intro.html

After writing a little code to set up the NSOpenGLView (including setting the OpenGL version that the NSOpenGLView will run to 4.1), The triangles.cpp example from the Red Book were running perfectly inside the NSOpenGLView.