Question

Ok, I think I'm going crazy.

I've been developing a 3D game in OpenGL for a while now - all working well.

Then I decided to redesign it from scratch since it was turning to custard. So I set up a basic framework for rendering with OpenGL, and I can't for the life of me get the thing to render a triangle.

I have gone over every line of code about 60 times, gone through every checklist I can find on the internet, checked it against my old project which worked, and still can't see anything wrong with it.

So here is where it all starts (the main method):

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char* cmdLine, int cmdShow)
{
    try
    {    
        GLContext gl(WINDOW_TITLE, 800, 600);
        TestRenderable test;

        while(true)
        {
            glClearColor(0.0f, 0.15f, 0.3f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);
            test.draw();
            gl.swapBuffers();
        }

    }
    catch(const std::string& err)
    {
        std::string msg = "Error: ";
        msg += err;

        MessageBox(NULL, msg.c_str(), WINDOW_TITLE, MB_OK | MB_ICONERROR);
    }
    catch(...)
    {
        MessageBox(NULL, "Unknown Error", WINDOW_TITLE, MB_OK | MB_ICONERROR);
    }

}

And all class methods are below:

GLContext::GLContext(const std::string& title, int width, int height)
{
    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    m_pWindow = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL);
    m_glContext = SDL_GL_CreateContext(m_pWindow);

    if(glewInit() != GLEW_OK)
        throw(std::string("Failed to initialize GLEW"));
}

GLContext::~GLContext()
{
    SDL_GL_DeleteContext(m_glContext);
    SDL_DestroyWindow(m_pWindow);
}

void GLContext::swapBuffers()
{
    SDL_GL_SwapWindow(m_pWindow);
}


TestRenderable::TestRenderable() : m_pShader(nullptr), m_pMesh(nullptr)
{
    std::vector<std::string> attributes;
    attributes.push_back("position");
    attributes.push_back("color");

    m_pShader = new Shader("shaders\\shader", attributes);
    m_pShader->addUniform("transform");

    glm::vec3 positions[] =
    {
        { 10.0f, 10.0f, 0.0f },
        { 200.0f, 10.0f, 0.0f },
        { 10.0f, 100.0f, 0.0f }
    };

    glm::vec4 colors[] =
    {
        { 0.0f, 1.0f, 0.0f, 1.0f },
        { 1.0f, 0.0f, 0.0f, 1.0f },
        { 0.0f, 0.0f, 1.0f, 1.0f }
    };

    m_pMesh = new Mesh_PC(positions, colors, 3);

    m_projection = glm::ortho<float>(0.0f, 800.0f, 600.0f, 0.0f, 0.0f, 1.0f);
}

TestRenderable::~TestRenderable()
{
    if(m_pShader != nullptr)
        delete m_pShader;

    if(m_pMesh != nullptr)
        delete m_pMesh;
}

void TestRenderable::draw()
{
    m_pShader->bind();
    m_pShader->setUniformMatrix("transform", m_projection);

    m_pMesh->draw();
}


Mesh_PC::Mesh_PC(glm::vec3 positions[], glm::vec4 colors[], unsigned numVertices) : m_vertexCount(numVertices)
{
    glGenVertexArrays(1, m_vertexArray);

    glBindVertexArray(m_vertexArray[0]);

    glGenBuffers(NUM_BUFFERS, m_buffers);

    glBindBuffer(GL_ARRAY_BUFFER, m_buffers[POSITIONS_BUFFER]);
    glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(positions[0]), positions, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, m_buffers[COLORS_BUFFER]);
    glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(colors[0]), colors, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);

    glBindVertexArray(0);
}

Mesh_PC::~Mesh_PC()
{
    glDeleteBuffers(NUM_BUFFERS, m_buffers);
    glDeleteVertexArrays(1, m_vertexArray);
}

void Mesh_PC::draw()
{
    glBindVertexArray(m_vertexArray[0]);
    glDrawArrays(GL_TRIANGLES, 0, m_vertexCount);
    glBindVertexArray(0);
}



Shader::Shader(const std::string& filename, const std::vector<std::string>& attributes)
{
    m_program = glCreateProgram();
    m_shaders[0] = createShader(loadShader(filename + ".vs"), GL_VERTEX_SHADER);
    m_shaders[1] = createShader(loadShader(filename + ".fs"), GL_FRAGMENT_SHADER);

    for(unsigned int i = 0; i < NUM_SHADERS; ++i)
        glAttachShader(m_program, m_shaders[i]);

    for(unsigned int i = 0; i < attributes.size(); ++i)
        glBindAttribLocation(m_program, i, attributes[i].c_str());

    glLinkProgram(m_program);
    checkShaderError(m_program, GL_LINK_STATUS, true, "Program linking failed");

    glValidateProgram(m_program);
    checkShaderError(m_program, GL_VALIDATE_STATUS, true, "Program is invalid");
}

Shader::~Shader()
{
    for(unsigned int i = 0; i < NUM_SHADERS; ++i)
    {
        glDetachShader(m_program, m_shaders[i]);
        glDeleteShader(m_shaders[i]);
    }

    glDeleteProgram(m_program);
}

void Shader::addUniform(const std::string& name)
{
    m_uniforms.insert(std::make_pair(name, glGetUniformLocation(m_program, name.c_str())));
}

void Shader::bind()
{
    glUseProgram(m_program);
}

void Shader::setUniformMatrix(const std::string& name, const glm::mat4& value)
{
    bind();

    auto it = m_uniforms.find(name);

    if(it != m_uniforms.end())
    {
        glUniformMatrix4fv(it->second, 1, GL_FALSE, &value[0][0]);
    }
}

void Shader::setUniformVec4(const std::string& name, const glm::vec4& value)
{
    bind();

    auto it = m_uniforms.find(name);

    if(it != m_uniforms.end())
    {
        glUniform4fv(it->second, 1, &value[0]);
    }
}

std::string Shader::loadShader(const std::string& filename)
{
    std::ifstream file;
    file.open(filename.c_str());

    std::string output;
    std::string line;

    if(file.is_open())
    {
        while(file.good())
        {
            getline(file, line);
            output.append(line + "\n");
        }

        file.close();
    }
    else
    {
        std::string err("Unable to load shader: ");
        err.append(filename);
        throw(err);
    }

    return output;
}

void Shader::checkShaderError(GLuint shader, GLuint flag, bool isProgram, const char* errorMessage)
{
    GLint success = 0;
    GLchar error[1024] = { 0 };

    if(isProgram)
        glGetProgramiv(shader, flag, &success);
    else
        glGetShaderiv(shader, flag, &success);

    if(success == GL_FALSE)
    {
        if(isProgram)
            glGetProgramInfoLog(shader, sizeof(error), NULL, error);
        else
            glGetShaderInfoLog(shader, sizeof(error), NULL, error);

        std::string err(errorMessage);
        err.append(": '");
        err.append(error);
        err.append("'");
        throw(err);
    }
}

GLuint Shader::createShader(const std::string& text, GLenum shaderType)
{
    GLuint shader = glCreateShader(shaderType);

    if(shader == 0)
        throw("Shader creation failed");

    const GLchar *shaderSourceStrings[1];
    GLint shaderSourceStringLengths[1];

    shaderSourceStrings[0] = text.c_str();
    shaderSourceStringLengths[0] = static_cast<GLint>(text.length());

    glShaderSource(shader, 1, shaderSourceStrings, shaderSourceStringLengths);
    glCompileShader(shader);

    checkShaderError(shader, GL_COMPILE_STATUS, false, "Shader compilation failed");

    return shader;
}

And by the way I am initalizing SDL - I have an object of the below type in the GLContext class:

class SDL
{
public:
    SDL() { SDL_Init(SDL_INIT_VIDEO); }
    ~SDL() { SDL_Quit(); }
};

And my shaders:

Vertex Shader:

#version 120

attribute vec3 position;
attribute vec4 color;

varying vec4 color0;

uniform mat4 transform;

void main(void)
{
    gl_Position = transform * vec4(position, 1.0);
    color0 = color;
}

Fragment Shader:

#version 120

varying vec4 color0;

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

I know there is unused stuff in the shaders etc but this is just for testing purposes.

Can anyone help me here?

Was it helpful?

Solution

You need to call glBindBuffer before calling glVertexAttribPointer. At the moment, both attributes will be using the last buffer bound (the one with the color values).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top