Search code examples
c++openglsdlglew

Triangle not being drawn. C++/GLEW/SDL


I am trying to create a program that will draw a red triangle to the screen, I successfully did this with GLFW instead of SDL and without using classes. However, when doing this in SDL and using classes, it doesn't seem to draw the Triangle but the build is successful and returns 0 as it should.

I've scanned my code carefully but still can't find the solution.

Is it because I simply just can't use classes in this kind of programming (which I doubt)?

main.cpp

#include <iostream>
#include <GL/glew.h>
#define SDL_MAIN_HANDLED
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>

#include "Shader.h"
#include "Shape.h"

using namespace std;

const GLint WIDTH = 800;
const GLint HEIGHT = 600;

GLuint VAO, VBO, shader;

int main() {
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        cout << "Error: Failed to initialize SDL!" << endl;
        return 1;
    }
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
    SDL_Window* mainWindow = SDL_CreateWindow("My Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WIDTH, HEIGHT, SDL_WINDOW_OPENGL);
    if (mainWindow == nullptr) {
        cout << "Error: Failed to create window [mainWindow]" << endl;
        return 1;
    }
    SDL_GLContext context = SDL_GL_CreateContext(mainWindow);
    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK) {
        cout << "Error: Failed to initialize GLEW, OpenGL error." << endl;
        return 1;
    }
    Shader cShader;
    Shape shape;

    glViewport(0, 0, WIDTH, HEIGHT);
    shape.CreateTriangle(VAO, VBO);
    cShader.CompileShader(shader);

    SDL_Event windowEvent;
    while (true) {
        if (SDL_PollEvent(&windowEvent)) {
            if (windowEvent.type == SDL_QUIT) {
                break;
            }
        }
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(shader);

        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glBindVertexArray(0);

        glUseProgram(0);
        SDL_GL_SwapWindow(mainWindow);
    }
    SDL_GL_DeleteContext(context);
    SDL_DestroyWindow(mainWindow);
    SDL_Quit();
    return 0;
}

Shape.h

#pragma once
#include <GL/glew.h>
class Shape
{
public:
    void CreateTriangle(GLuint VAO, GLuint VBO);
};

Shape.cpp

#include "Shape.h"
#include <GL/glew.h>

void Shape::CreateTriangle(GLuint VAO, GLuint VBO) {
    GLfloat triVertices[] = {
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        0.0f, 1.0f, 0.0f
    };
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    glBufferData(GL_ARRAY_BUFFER, sizeof(triVertices), triVertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

Shader.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
class Shader
{
public:
    static const char* vShader;
    static const char* fShader;
    void AddShader(const char* shaderCode, GLenum shaderType, GLuint shader);
    void CompileShader(GLuint shader);
};

Shader.cpp

#include "Shader.h"
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <GL/glew.h>

const char* Shader::vShader = "                                    \n\
#version 330                       ck                                \n\
                                                                   \n\
layout (location = 0) in vec3 pos;                                 \n\
                                                                   \n\
void main()                                                        \n\
{                                                                  \n\
     gl_Position = vec4(0.4 * pos.x, 0.4 * pos.y, pos.z, 1.0);     \n\
}";

const char* Shader::fShader = "              \n\
#version 330                                 \n\
                                             \n\
out vec4 colour;                             \n\
                                             \n\
void main()                                  \n\
{                                            \n\
     colour = vec4(1.0, 0.0, 0.0, 1.0);      \n\
}";

void Shader::AddShader(const char* shaderCode, GLenum shaderType, GLuint theProgram) {
    GLuint theShader = glCreateShader(shaderType);

    const GLchar* theCode[1];
    theCode[0] = shaderCode;

    GLint codeLength[1];
    codeLength[0] = strlen(shaderCode);

    glShaderSource(theShader, 1, theCode, codeLength);
    glCompileShader(theShader);

    GLint result = 0;
    GLchar eLog[1024] = { 0 };

    glGetShaderiv(theShader, GL_COMPILE_STATUS, &result);
    if (!result) {
        glGetShaderInfoLog(theShader, sizeof(eLog), NULL, eLog);
        printf("Error compiling the %d shader: %s\n", shaderType, eLog);
        return;
    }
    glAttachShader(theProgram, theShader);
}

void Shader::CompileShader(GLuint shader) {
    shader = glCreateProgram();

    if (!shader) {
        printf("Error creating shader!\n");
        return;
    }

    AddShader(vShader, GL_VERTEX_SHADER, shader);
    AddShader(fShader, GL_FRAGMENT_SHADER, shader);

    GLint result = 0;
    GLchar eLog[1024] = { 0 };

    glLinkProgram(shader);
    glGetProgramiv(shader, GL_LINK_STATUS, &result);
    if (!result) {
        glGetProgramInfoLog(shader, sizeof(eLog), NULL, eLog);
        printf("Error linking program: %s\n", eLog);
        return;
    }

    glValidateProgram(shader);
    glGetProgramiv(shader, GL_VALIDATE_STATUS, &result);
    if (!result) {
        glGetProgramInfoLog(shader, sizeof(eLog), NULL, eLog);
        printf("Error validating program: %s\n", eLog);
        return;
    }
}

Solution

  • The parameters to the methods

    void CreateTriangle(GLuint VAO, GLuint VBO);
    
    void CompileShader(GLuint shader);
    

    are passed by value.

    If you want to "get back" the created objects (values) from the methods, then you've to pass the parameters by reference:

    class Shape
    {
    public:
        void CreateTriangle(GLuint &VAO, GLuint &VBO);
    };
    
    class Shader
    {
    public:
    
        // ...    
    
        void CompileShader(GLuint &shader);
    };