So the problem is that my code is not running the right glUseProgram function.
I've tested what value it should need and it works, but I obviously don't want to hardcode it.
Shader.cpp (I declared the programID in the header file)
#include "Shader.h"
#include <GL/glew.h>
#include <iostream>
#include <fstream>
GLuint vertexShaderID, fragmentShaderID;
Shader::Shader() {
}
Shader::Shader(const GLchar* vertexFile, const GLchar* fragmentFile) {
GLint success;
GLchar infoLog[512];
vertexShaderID = loadShader(vertexFile, GL_VERTEX_SHADER);
fragmentShaderID = loadShader(fragmentFile, GL_FRAGMENT_SHADER);
programID = glCreateProgram();
glAttachShader(programID, vertexShaderID);
glAttachShader(programID, fragmentShaderID);
glLinkProgram(programID);
//glValidateProgram(programID);
glGetProgramiv(programID, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(programID, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
//bindAttributes();
std::cout << "SHADER::LOADED\n" << std::endl;
glDeleteShader(vertexShaderID);
glDeleteShader(fragmentShaderID);
std::cout << "PROGRAM::" << programID << std::endl;
}
void Shader::Start() const
{
glUseProgram(programID);
std::cout << "p:" << programID << std::endl;
}
void Shader::cleanUp() {
glUseProgram(0);
glDetachShader(programID, vertexShaderID);
glDetachShader(programID, fragmentShaderID);
glDeleteShader(vertexShaderID);
glDeleteShader(fragmentShaderID);
glDeleteProgram(programID);
}
TestShader.cpp
#include "TestShader.h"
#include "Shader.h"
const GLchar* VERTEX_FILE = "shaders/shader.vs";
const GLchar* FRAGMENT_FILE = "shaders/shader.frag";
TestShader::TestShader() {
Shader::Shader(VERTEX_FILE, FRAGMENT_FILE);
}
main.cpp
#include <iostream>
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
// SOIL
#include <SOIL2/SOIL2.h>
// GLM
#include <GLM/glm.hpp>
// Other includes
#include "TestShader.h"
// GameEngine
#include "Display.h"
#include "Mesh.h"
const GLuint WIDTH = 800, HEIGHT = 600;
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
Display display(WIDTH, HEIGHT, "GameEngine");
glewExperimental = GL_TRUE;
glewInit();
TestShader s;
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())
{
glfwPollEvents();
display.Clear(0.0f, 0.0f, 0.3f, 0.0f);
s.Start();
mesh.Draw();
s.cleanUp();
display.Update();
}
glfwTerminate();
return 0;
}
TestShader.h
#ifndef TESTSHADER_H
#define TESTSHADER_H
#include "Shader.h"
#include <GL/glew.h>
#include <iostream>
class TestShader : public Shader {
public:
TestShader();
private:
protected:
void bindAttributes() override;
};
#endif // TESTSHADER_H
Shader.h
#ifndef SHADER_H
#define SHADER_H
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <GL/glew.h>
class Shader
{
private:
GLuint programID;
protected:
int getUniformLocation(GLchar * uniformName);
public:
Shader();
Shader(const GLchar* vertexFile, const GLchar* fragmentFile);
~Shader();
GLuint loadShader(const GLchar * shaderSourcePath, GLuint type);
virtual void bindAttributes();
void bindAttribute(int attribute, GLchar* variableName);
void Start() const;
void cleanUp();
};
#endif // !SHADER_H
If I cout the programID in the constructor I get the value 3 but if I cout it in the Start function I get a 3435973836 (always.. I think).
There is probably a problem with the inheritance I guess. But why does it work if I hardcode a 3 in the Start function instead of the programID?
The issue is in the constructor of the object TestShader
:
TestShader::TestShader() { Shader::Shader(VERTEX_FILE, FRAGMENT_FILE); }
The statement Shader::Shader(VERTEX_FILE, FRAGMENT_FILE);
doesn't do what you expect it to do. It doesn't "construct" respectively initialize the base class, it generates a completely new object in scope of the body of the constructor.
You've to specify the constructor of the base class in the initializer-list of the constructor (see Constructors and member initializer lists):
TestShader::TestShader()
: Shader(VERTEX_FILE, FRAGMENT_FILE) {
}
Note, in your code actually the attribute programID
of the object TestShader s
is never set, because the default constructor is used to construct the base class.
But another object is generated in the body of the constructor of TestShader
. This object successfully generates the shader program and sets it's own the attribute programID
(that is what is printed in the first line of the output).
Of course this object is destructed immediately, but that doesn't matter, since the OpenGL shader program object still exists on the GPU.
So the ("hardcoded") call glUsePrgram(3)
installs the shader program.