Carlo Bonandrini
Carlo Bonandrini

Reputation: 19

OpenGL basic triangle render with c++ not working

I have a basic OpenGL program using GLFW and GLEW to render a triangle.

I'm using a Mac with Xcode with GLFW 3.3 and GLEW 2.1.

I was encountering a problem with glfwCreateWindow() that would return null if I set the OpenGL profile to core profile (because for what I understand Mac needs it) and I solved it by putting the forward compatibility to true.

Can somebody explain to me if this solution is right or not?

One other thing is that now the windows gets created without problems but now I'm not seeing anything on the screen.

This is the code:

#include <GL/glew.h> 
#include <GLFW/glfw3.h>

#include <iostream>

static unsigned int CompileShader(unsigned int type, const std::string& source)
{
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
// Compiles the actual shader
glCompileShader(id);

// Error handeling of the compilation
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
    int length;
    // Gets the lenght of the message
    glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
    // This is used to allocate memory on the stack dynamically
    char* message = (char*)alloca(length * sizeof(char));
    // Gets the log
    glGetShaderInfoLog(id, length, &length, message);
    std::cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << std::endl;
    std::cout << message << std::endl;
    glDeleteShader(id);
    return 0;
}

return id;
}
static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
unsigned int program = glCreateProgram();
// Creating the two shader
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
// Attaches the two shaders to the program and validate everything
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program); // This links the shader executable to the actual processor
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
int main(void)
{
// to initialize glew go to c++ preprocessor and add GLEW_STATIC

GLFWwindow* window;

/* Initialize the library */
if (!glfwInit())
    return -1;

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

/* Create a window and its OpenGl context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);

if (!window)
{
    glfwTerminate();
    return -1;
}

/* Make the window's context current */
glfwMakeContextCurrent(window);
// Glew init HAS to be put after making the context
if (glewInit() != GLEW_OK)
    std::cout << "GlewInit Error" << std::endl;


std::cout << "VERSION:" << std::endl;
std::cout << glGetString(GL_VERSION) << std::endl;
std::cout << "GL Version: " << (char *)glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;

// Defining the position of the vertices
float positions[6] = {
    -0.5f, -0.5f,
    0.0f,  0.5f,
    0.5f, -0.5f
};


unsigned int buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), positions, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);

std::string vertexShader =
"#version 330 core\n"
"\n"
// here we are saying that the attribute at the position 0 (see attribPointer)
// which is the position itself is a input value put in a vec4 because
// glPosition needs a vec4
"layout(location = 0) in vec4 position;\n"
"\n"
"void main()\n"
"{\n"
"    gl_Position = position;\n"
"}\n";

std::string fragmentShader =
"#version 330 core\n"
"\n"
"layout(location = 0) out vec4 color;\n"
"\n"
"void main()\n"
"{\n"
"    color = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";

unsigned int shader = CreateShader(vertexShader, fragmentShader);
glUseProgram(shader);

/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
    /* Render here */
    glClear(GL_COLOR_BUFFER_BIT);

    // second parameter is the starting index and the third is the number of indexes
    glDrawArrays(GL_TRIANGLES, 0, 3);

    /* Swap front and back buffers */
    glfwSwapBuffers(window);

    /* Poll for and process events */
    glfwPollEvents();
}

glDeleteProgram(shader);

glfwTerminate();
return 0;
}

Upvotes: 0

Views: 352

Answers (1)

genpfault
genpfault

Reputation: 52162

Vertex Array Objects (VAOs) aren't optional in Core contexts like they are in Compatibility. You have to have one bound to draw anything.

Create one and bind it before setting up your vertex layout and drawing:

GLuint vao = 0;
glCreateVertexArrays( 1, &vao );
glBindVertexArray( vao );
...
glEnableVertexAttribArray( ... );
glVertexAttribPointer( ... );
...
glDrawArrays( ... );

All together:

#include <GL/glew.h> 
#include <GLFW/glfw3.h>
#include <iostream>
#include <cstdarg>

struct Program
{
    static GLuint Load( const char* shader, ... )
    {
        GLuint prog = glCreateProgram();
        va_list args;
        va_start( args, shader );
        while( shader )
        {
            const GLenum type = va_arg( args, GLenum );
            AttachShader( prog, type, shader );
            shader = va_arg( args, const char* );
        }
        va_end( args );
        glLinkProgram( prog );
        CheckStatus( prog );
        return prog;
    }

private:
    static void CheckStatus( GLuint obj )
    {
        GLint status = GL_FALSE;
        if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
        if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
        if( status == GL_TRUE ) return;
        GLchar log[ 1 << 15 ] = { 0 };
        if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
        if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
        std::cerr << log << std::endl;
        std::exit( EXIT_FAILURE );
    }

    static void AttachShader( GLuint program, GLenum type, const char* src )
    {
        GLuint shader = glCreateShader( type );
        glShaderSource( shader, 1, &src, NULL );
        glCompileShader( shader );
        CheckStatus( shader );
        glAttachShader( program, shader );
        glDeleteShader( shader );
    }
};

const char* vert = 1 + R"GLSL(
#version 330 core
// here we are saying that the attribute at the position 0 (see attribPointer)
// which is the position itself is a input value put in a vec4 because
// glPosition needs a vec4
layout(location = 0) in vec4 position;
void main()
{
    gl_Position = position;
};
)GLSL";

const char* frag = 1 + R"GLSL(
#version 330 core
layout(location = 0) out vec4 color;
void main()
{
    color = vec4(1.0, 0.0, 0.0, 1.0);
};
)GLSL";

int main( void )
{
    if( !glfwInit() )
        return -1;

    glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
    glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
    glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE );
    glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
    GLFWwindow* window = glfwCreateWindow( 640, 480, "Hello World", NULL, NULL );
    if( !window )
    {
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent( window );

    // Glew init HAS to be put after making the context
    if( glewInit() != GLEW_OK )
        std::cout << "GlewInit Error" << std::endl;

    GLuint vao = 0;
    glCreateVertexArrays( 1, &vao );
    glBindVertexArray( vao );

    // Defining the position of the vertices
    float positions[ 6 ] = {
        -0.5f, -0.5f,
        0.0f,  0.5f,
        0.5f, -0.5f
    };

    unsigned int buffer;
    glGenBuffers( 1, &buffer );
    glBindBuffer( GL_ARRAY_BUFFER, buffer );
    glBufferData( GL_ARRAY_BUFFER, 6 * sizeof( float ), positions, GL_STATIC_DRAW );
    glEnableVertexAttribArray( 0 );
    glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, sizeof( float ) * 2, 0 );

    GLuint shader = Program::Load( vert, GL_VERTEX_SHADER, frag, GL_FRAGMENT_SHADER, NULL );
    glUseProgram( shader );

    while( !glfwWindowShouldClose( window ) )
    {
        glClear( GL_COLOR_BUFFER_BIT );
        glDrawArrays( GL_TRIANGLES, 0, 3 );
        glfwSwapBuffers( window );
        glfwPollEvents();
    }

    glDeleteProgram( shader );

    glfwTerminate();
    return 0;
}

Upvotes: 1

Related Questions