macoscocoaopenglglslnsopenglview

GLSL example not working on mac


I am trying to create a GLSL example on Mac. I am trying to set up one color attribute per vertex. However, when the program runs, I just get a purple screen (the purple comes from glClearColor). I post the relevant code snippets.

-(void)drawRect:(NSRect)dirtyRect
{    
    // get program ID for shader program
    GLuint programID = [self loadShaders];

    // get new dimensions
    NSSize dim = [self frame].size;

    // clear the background with color
    glClearColor(0.4f, 0.1f, 0.7f, 1.0f);
    glDepthRange(1.0, -1.0);
    glViewport(0, 0, dim.width, dim.height);
    glClear(GL_COLOR_BUFFER_BIT);

    // generate a buffer for our triangle
    glGenBuffers(2, vertexBuffer);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);

    glUseProgram(programID);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(VERTEX_POS_INDEX, VERTEX_POS_SIZE, GL_FLOAT, GL_FALSE, VERTEX_POS_SIZE*sizeof(vertices), vertices);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(VERTEX_COLOR_INDEX, VERTEX_COLOR_SIZE, GL_FLOAT, GL_FALSE, VERTEX_POS_SIZE*sizeof(colors), colors);

    glDrawArrays(GL_TRIANGLES, 0, 3);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glUseProgram(0);

    // flush buffer
    glFlush();
    [[self openGLContext] flushBuffer];
}

And then the loading shadings code:

-(GLuint)loadShaders
{
    printf("GLSL version %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
    printf("GL Version: %s", glGetString(GL_VERSION));

    // Create the shaders
    GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
    GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

    // get handle for app bundle
    NSBundle *appBundle = [NSBundle mainBundle];

    // get the path for the vertex shader file
    NSString *vertexFilePath = [appBundle pathForResource:vertexShaderFile ofType:nil];
    // get the path for the fragment shader file
    NSString *fragmentFilePath = [appBundle pathForResource:fragmentShaderFile ofType:nil];

    // get the contents of the vertex shader file into a string
    NSString *vertexFileContents = [NSString stringWithContentsOfFile:vertexFilePath encoding:NSUTF8StringEncoding error:NULL];
    NSLog(@"%@", vertexFileContents);
    // get the contents of the fragment shader file into a string
    NSString *fragmentFileContents = [NSString stringWithContentsOfFile:fragmentFilePath encoding:NSUTF8StringEncoding error:NULL];
    NSLog(@"%@", fragmentFileContents);

    GLint Result = GL_FALSE;
    int infoLogLength;

    // get a pointer the vertex shader program source, compile shader program
    const char *vertexSourcePointer = [vertexFileContents UTF8String];
    glShaderSource(vertexShaderID, 1, &vertexSourcePointer, NULL);
    glCompileShader(vertexShaderID);
    // check the vertex shader
    glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(vertexShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
    char vertexShaderErrorMessage[infoLogLength];
    glGetShaderInfoLog(vertexShaderID, infoLogLength, NULL, vertexShaderErrorMessage);
    // print error message
    NSLog(@"%@", [NSString stringWithUTF8String:vertexShaderErrorMessage]);

    // get a pointer to the fragment shader program source, compile shader program
    const char *fragmentSourcePointer = [fragmentFileContents UTF8String];
    glShaderSource(fragmentShaderID, 1, &fragmentSourcePointer, NULL);
    glCompileShader(fragmentShaderID);
    // check the fragment shader
    glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(fragmentShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
    char fragmentShaderErrorMessage[infoLogLength];
    glGetShaderInfoLog(fragmentShaderID, infoLogLength, NULL, fragmentShaderErrorMessage);
    // print error message
    NSLog(@"%@", [NSString stringWithUTF8String:fragmentShaderErrorMessage]);

    // link the program
    NSLog(@"Linking program...");
    GLuint programID = glCreateProgram();
    glAttachShader(programID, vertexShaderID);
    glAttachShader(programID, fragmentShaderID);

    glBindAttribLocation(programID, 0, "position");
    glBindAttribLocation(programID, 1, "inColor");

    glLinkProgram(programID);

    // check the program
    glGetProgramiv(programID, GL_LINK_STATUS, &Result);
    glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &infoLogLength);
    char shaderProgramErrorMessage[max(infoLogLength, (int)1)];
    glGetProgramInfoLog(programID, infoLogLength, NULL, shaderProgramErrorMessage);
    // pring error message
    NSLog(@"%@", [NSString stringWithUTF8String:shaderProgramErrorMessage]);

    // delete shaders
    glDeleteShader(vertexShaderID);
    glDeleteShader(fragmentShaderID);

    return programID;

}

And finally the shaders:

#version 120

attribute vec4 position;
attribute vec4 inColor;
varying vec4 outColor;
void main()
{
    gl_Position = position;
    outColor = inColor;
}

And

#version 120

varying vec4 outColor;
void main()
{
    gl_FragColor = outColor;
}

Solution

  • Looks fairly good, though I do see one mistake.

    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(VERTEX_POS_INDEX, 
                          VERTEX_POS_SIZE, 
                          GL_FLOAT, 
                          GL_FALSE, 
                          VERTEX_POS_SIZE*sizeof(vertices), 
                          vertices);
    

    If you are using VBO, then the final attribute to glVertexAttribPointer should be the offset from the start of the currently bound buffer.

    If you were using vertex arrays (no glBindBuffer), then you would point to vertices with the final argument of glVertexAttribPointer.

    However, since you've already uploaded vertices to a buffer and bound it, the final value of glVertexAttribPointer should be the offset from the start of the vertices buffer, which in your case, should be 0.

    Same mistake for the colors buffer as well.