0

I'm coding a program to learn OpenGL in C++ (based off of The Benny Boxes tutorials) and I've run into a snag where I don't get any errors, but my shaders refuse to apply to the triangle that I'm rendering.

I'm going to give you all the relevant code but its going to be a lot because, after all, it's OpenGL in C++.

display.cpp

#include "display.h"
#include <GL/glew.h>
#include <iostream>

Display::Display(int width, int height, const std::string& title)
{
    SDL_Init(SDL_INIT_EVERYTHING);

    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_DOUBLEBUFFER, 1);

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

    GLenum status = glewInit();

    if (status != GLEW_OK)
    {
        std::cout << "Glew failed to initialize!" << std::endl;
    }
    m_isClosed = false;
};

Display:: ~Display()
{
    SDL_GL_DeleteContext(m_glContext);
    SDL_DestroyWindow(m_window);
    SDL_Quit();
};

bool Display::isClosed()
{
    return m_isClosed;
}

void Display::Clear(float r, float g, float b, float a)
{
    glClearColor(r, g, b, a);
    glClear(GL_COLOR_BUFFER_BIT);
}

void Display::Update()
{
    SDL_GL_SwapWindow(m_window);

    SDL_Event e;

    while (SDL_PollEvent(&e))
    {
        if (e.type == SDL_QUIT)
        {
            m_isClosed = true;
        }
    }

};

display.h

#ifndef DISPLAY_H
#define DISPLAY_H

#include <SDL2/SDL.h>
#include <string>

class Display
{
public:
    Display(int width, int height, const std::string& title);
    void Clear(float r, float g, float b, float a);

    void Update();

    virtual ~Display();
    bool isClosed();
protected:
private:
    Display(const Display& other) {}
    Display& operator=(const Display& other) {}

    SDL_Window* m_window;
    SDL_GLContext m_glContext;
    bool m_isClosed;
};

#endif // Display_H

shader.cpp

#include "shader.h"
#include <fstream>
#include <iostream>

static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string& errorMessage);
static std::string LoadShader(const std::string &fileName);
static GLuint CreateShader(const std::string text, GLenum shaderType);

Shader::Shader(const std::string& fileName)
{
    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[1]);

    glBindAttribLocation(m_program, 0, "position");

    glLinkProgram(m_program);
    CheckShaderError(m_program, GL_LINK_STATUS, true, "Error: Program Linking Failed: ");

    glValidateProgram(m_program);
    CheckShaderError(m_program, GL_VALIDATE_STATUS, true, "Eror: Program is Invalid: ");
}

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

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

static GLuint CreateShader(const std::string text, GLenum shaderType)
{
    GLuint shader = glCreateShader(0);

    if (shader = 0)
        std::cerr << "Error: Shader Creation Failed!" << std::endl;

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

    shaderSourceStrings[0] = text.c_str();
    sourceSourceStringLengths[0] = text.length();

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

    CheckShaderError(shader, GL_COMPILE_STATUS, false, "Error: Shader Compilation Failed: ");

    return shader;
}

static std::string 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");
        }
    }
    else
    {
        std::cerr << "Unable to load shader: " << fileName << std::endl;;
    }

    return output;
}

static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string& 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);
    }
}

shader.h

#ifndef SHADER_H
#define SHADER_H

#include <string>
#include <GL\glew.h>

class Shader
{
public:
    Shader(const std::string& fileName);

    void Bind();

    virtual ~Shader();
protected:
private:
    static const unsigned int NUM_SHADERS = 2;
    Shader(const Shader& other) {}
    void operator=(const Shader& other) {}

    GLuint m_program;
    GLuint m_shaders[NUM_SHADERS];
};
#endif

Mesh.cpp

#include "Mesh.h"

Mesh::Mesh(Vertex* vertices, unsigned int numVertices)
{
    m_drawCount = numVertices;

    glGenVertexArrays(1, &m_vertexArrayObject);
    glBindVertexArray(m_vertexArrayObject);

    glGenBuffers(NUM_BUFFERS, m_vertexArrayBuffers);
    glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[POSITION_VB]);
    glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(vertices[0]), vertices, GL_STATIC_DRAW);

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

    glBindVertexArray(0);
}

Mesh::~Mesh()
{
    glDeleteVertexArrays(1, &m_vertexArrayObject);
}

void Mesh::Draw()
{
    glBindVertexArray(m_vertexArrayObject);

    glDrawArrays(GL_TRIANGLES, 0, m_drawCount);

    glBindVertexArray(0);
}

Mesh.h

#ifndef MESH_H
#define MESH_H

#include <GL/glew.h>
#include <glm/glm.hpp>

class Vertex
{
public:
    Vertex(const glm::vec3& pos)
    {
        this->pos = pos;
    }
protected:
private:
    glm::vec3 pos;
};

class Mesh
{
public:
    Mesh(Vertex* vertices, unsigned int numVertices);

    void Draw();

    virtual ~Mesh();

protected:
private:
    Mesh(const Mesh& other);
    void operator=(const Mesh& other);

    enum
    {
        POSITION_VB,

        NUM_BUFFERS
    };

    GLuint m_vertexArrayObject;
    GLuint m_vertexArrayBuffers[NUM_BUFFERS];
    unsigned int m_drawCount;
};

#endif

main.cpp

#include <iostream>
#include <GL/glew.h>
#include "display.h"
#include "Mesh.h"
#include "shader.h"

using namespace std;

int main(int argc, char** argv)
{
    Display display(800, 600, "Hello World");

    Shader shader("basicShader");

    Vertex vertices[] = { Vertex(glm::vec3(-0.5, -0.5, 0)),
                          Vertex(glm::vec3(0, 0.5, 0)), 
                          Vertex(glm::vec3(0.5, -0.5, 0)) };

    Mesh mesh(vertices, sizeof(vertices) / sizeof(vertices[0]));

    while (!display.isClosed())
    {
        display.Clear(1.0, 0.0, 0.0, 1.0);

        shader.Bind();
        mesh.Draw();

        display.Update();
    }
    return 0;
}

basicShader.fs

#version 120

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

basicShader.vs

#version 120

attribute vec3 position;

void main()
{
    gl_Position = vec4(position, 1.0);
}

I understand that this is a ridiculously long piece of code, but I would be greatful if you could provide any help as to why it's not displaying my shader properly.

Edited by Reverend Jim: Moved to programming forum

3
Contributors
2
Replies
27
Views
2 Months
Discussion Span
Last Post by wrathness
0

First I can't duplicate your app but have worked with coders that burn out on OpenGL issues like this. For example "This worked fine on NVidia cards but bugged out on ATI cards." or vice versa. So be sure to test this on other cards to see if it's a card/driver limitation. Then find working examples before you code from scratch to be sure you are not dealing with card/driver limitations.

1

Hello Nether_1, not sure if you are still having an issue getting your shaders to run but I have found a solution.

In display.cpp the openGL version was not being set. So the following lines have been added in the Display constructor.

    SDL_Init(SDL_INIT_EVERYTHING);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);

Here is the working CreateShader function from shader.cpp

static GLuint CreateShader(const std::string text, GLenum shaderType)
{
    GLuint shader = glCreateShader(shaderType);

    if (shader == 0)
        std::cerr << "Error: Shader Creation Failed!" << std::endl;

    const GLchar* shaderSourceStrings[1];
    GLint sourceSourceStringLengths[1];
    shaderSourceStrings[0] = text.c_str();
    sourceSourceStringLengths[0] = text.length();

    glShaderSource(shader, 1, &shaderSourceStrings[0], &sourceSourceStringLengths[0]);
    glCompileShader(shader);
    CheckShaderError(shader, GL_COMPILE_STATUS, false, "Error: Shader Compilation Failed: ");
    return shader;
}

The shaderType was being passed into the function but not being used by glCreateShader(). This was simply updated to use the shaderType parameter being passed in.
The if statement was '=' instead of '=='.

I have also provided a modified version of the CreateShader function as seen below:

static GLuint CreateShader(const std::string text, GLenum shaderType)
{
    GLuint shader = glCreateShader(shaderType);
    const GLchar* shaderSource = text.c_str();

    glShaderSource(shader, 1, &shaderSource, NULL);
    glCompileShader(shader);
    CheckShaderError(shader, GL_COMPILE_STATUS, false, "Error: Shader Compilation Failed: ");
    return shader;
}

I noticed that the CheckShaderError function has an error message being passed into it, but it is not being used/logged out along with the shader/program compile errors. Logging these out are very handy for debugging.

The vertex and fragment shaders have the following added at the top of the file:

version 330 core

#version 330 core
void main()
{
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

#version 330 core

attribute vec3 position;
void main()
{
    gl_Position = vec4(position, 1.0);
}

I hope this helps :)

Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.