In Xcode or Visual Studio, I was able to compile and run my codes successfully when I put my txt files within the same directory where the codes were located. These txt files had glsl codes in it for shading. However, now I want to run my files in the command line with g++. Just like in XCode, I put all my files(including the txt files) in the same directory, and ran the command
g++ -o Animation glad.c Animation.cpp -lglfw.3
The executable file 'Animation' is made in the same directory where all the other files were, but when I run it, I get the following error messages.
ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ
ERROR::PROGRAM_LINKING_ERROR of type: PROGRAM
ERROR: Compiled vertex shader was corrupt.
ERROR: Compiled fragment shader was corrupt.
The render window does appear, but nothing is drawn since the program could not read my txt files.
Here are parts of the codes that can help you understand my problem. This is my Animation.cpp code
#include "Camera.h"
#include "Shader.h"
#include <GLFW/glfw3.h>
#include <glm/gtc/type_ptr.hpp>
int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
#endif
if(!glfwInit())
return -1;
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
// tell GLFW to capture our mouse
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
//Where the error happens
Shader shader("AnimationVertexShader.txt", "AnimationFragmentShader.txt");
shader.use();
......
}
This is the Shader.h code
#ifndef SHADER_H
#define SHADER_H
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
class Shader
{
public:
unsigned int ID;
// constructor generates the shader on the fly
// ------------------------------------------------------------------------
Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr)
{
// 1. retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::string geometryCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
std::ifstream gShaderFile;
// ensure ifstream objects can throw exceptions:
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
gShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
// open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
// if geometry shader path is present, also load a geometry shader
if (geometryPath != nullptr)
{
gShaderFile.open(geometryPath);
std::stringstream gShaderStream;
gShaderStream << gShaderFile.rdbuf();
gShaderFile.close();
geometryCode = gShaderStream.str();
}
}
catch (std::ifstream::failure e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const char* vShaderCode = vertexCode.c_str();
const char * fShaderCode = fragmentCode.c_str();
// 2. compile shaders
unsigned int vertex, fragment;
int success;
char infoLog[512];
// vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// if geometry shader is given, compile geometry shader
unsigned int geometry;
if (geometryPath != nullptr)
{
const char * gShaderCode = geometryCode.c_str();
geometry = glCreateShader(GL_GEOMETRY_SHADER);
glShaderSource(geometry, 1, &gShaderCode, NULL);
glCompileShader(geometry);
checkCompileErrors(geometry, "GEOMETRY");
}
// shader Program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
if (geometryPath != nullptr)
glAttachShader(ID, geometry);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
// delete the shaders as they're linked into our program now and no longer necessery
glDeleteShader(vertex);
glDeleteShader(fragment);
if (geometryPath != nullptr)
glDeleteShader(geometry);
}
// activate the shader
// ------------------------------------------------------------------------
void use()
{
glUseProgram(ID);
}
// utility uniform functions
// ------------------------------------------------------------------------
void setBool(const std::string &name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
// ------------------------------------------------------------------------
void setInt(const std::string &name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
// ------------------------------------------------------------------------
void setFloat(const std::string &name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
// ------------------------------------------------------------------------
void setVec2(const std::string &name, const glm::vec2 &value) const
{
glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec2(const std::string &name, float x, float y) const
{
glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
}
// ------------------------------------------------------------------------
void setVec3(const std::string &name, const glm::vec3 &value) const
{
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec3(const std::string &name, float x, float y, float z) const
{
glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
}
// ------------------------------------------------------------------------
void setVec4(const std::string &name, const glm::vec4 &value) const
{
glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec4(const std::string &name, float x, float y, float z, float w)
{
glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
}
// ------------------------------------------------------------------------
void setMat2(const std::string &name, const glm::mat2 &mat) const
{
glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
// ------------------------------------------------------------------------
void setMat3(const std::string &name, const glm::mat3 &mat) const
{
glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
// ------------------------------------------------------------------------
void setMat4(const std::string &name, const glm::mat4 &mat) const
{
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
private:
// utility function for checking shader compilation/linking errors.
// ------------------------------------------------------------------------
void checkCompileErrors(GLuint shader, std::string type)
{
GLint success;
GLchar infoLog[1024];
if (type != "PROGRAM")
{
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
else
{
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
}
};
#endif
What would be the reason why g++ cannot read the txt files from the same directory? Any help would be appreciated. Thanks in advance!
Related
So I've been learning OpenGL for sometimes now and today I come up with an idea to put multiple
shaders in one std::map, like this
std::map<std::string, Shader> Shaders;
the key holds the name of the shader and the value is the Shader class I created.
Then I worte both add and get shader function
void AddShader(std::string filepath, std::string name)
{
Shader shader(filepath);
Shaders[name] = shader;
if (glIsProgram(Shaders[name].m_RendererID) != GL_TRUE)
{
std::cout << "invalid program" << std::endl;
__debugbreak();
}
}
Shader GetShader(std::string name)
{
//added for debug purposes.
if (glIsProgram(Shaders[name].m_RendererID) != GL_TRUE)
{
std::cout << "invalid program" << std::endl;
__debugbreak();
}
return Shaders[name];
}
Now here comes the problem. Whenever I tried to call GetShader function I would recieve
invalid program error and bind shader wouldn't work either as it would return GL_INVALID_VALUE
here is shader class I abstracted:
Shader.h
#pragma once
#include <string>
#include "glm/glm.hpp"
#include <glad/glad.h>
struct ShaderProgramSources
{
std::string VertexSource;
std::string FragmentSource;
};
class Shader
{
private:
std::string m_FilePath;
int GetUniformLocation(const std::string& name);
public:
unsigned int m_RendererID;
Shader(const std::string& filepath);
Shader(void) {}
~Shader();
void Bind() const;
void Unbind() const;
ShaderProgramSources ParseShader(const std::string& filepath);
unsigned int CompileShader(unsigned int type, const std::string& source);
unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader);
Shader.cpp
#include "Shader.h"
#include <iostream>
#include <string>
#include <fstream>
#include <string>
#include <sstream>
Shader::Shader(const std::string& filepath)
: m_FilePath(filepath), m_RendererID(0)
{
ShaderProgramSources source = ParseShader(filepath);
m_RendererID = CreateShader(source.VertexSource, source.FragmentSource);
}
Shader::~Shader()
{
glDeleteProgram(m_RendererID);
}
void Shader::Bind() const
{
glUseProgram(m_RendererID);
}
void Shader::Unbind() const
{
glUseProgram(0);
}
unsigned int Shader::CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
{
unsigned int program = glCreateProgram();
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
unsigned int Shader::CompileShader(unsigned int type, const std::string& source)
{
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));
glGetShaderInfoLog(id, length, &length, message);
std::cout << "Failed to compile " << std::endl;
if (type == GL_VERTEX_SHADER)
std::cout << "vertex " << std::endl;
else
std::cout << "fragment " << std::endl;
std::cout << message << std::endl;
glDeleteShader(id);
return 0;
}
return id;
}
ShaderProgramSources Shader::ParseShader(const std::string& filepath)
{
std::ifstream stream(filepath);
enum class ShaderType
{
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
std::string line;
std::stringstream ss[2];
ShaderType type = ShaderType::NONE;
while (getline(stream, line))
{
if (line.find("#shader") != std::string::npos)
{
if (line.find("vertex") != std::string::npos)
{
type = ShaderType::VERTEX;
}
if (line.find("fragment") != std::string::npos)
{
type = ShaderType::FRAGMENT;
}
}
else
{
ss[(int)type] << line << '\n';
}
}
ShaderProgramSources sources;
sources.VertexSource = ss[0].str();
sources.FragmentSource = ss[1].str();
return sources;
}
both vertex and fragment shader are put in one single file identified by "#shader vertex"
and "#shader fragment" at the beginning of each shader. Like this:
#shader vertex
#version 330 core
...
#shader fragment
#version 330 core
...
Main file
int main(int argc, char* argv[])
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
GLFWwindow* window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "TITLE", nullptr, nullptr);
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum serverity,
GLsizei length, const GLchar* message, const void* userParam)
{
std::cout << source << message << std::endl;
__debugbreak();
}, NULL);
AddShader("Shader/test1.shader", "shader1");
AddShader("Shader/test2.shader", "shader2");
Shader shader = GetShader("shader1");
Shader shader2 = GetShader("shader2");
shader.Bind();
float deltaTime = 0.0f;
float lastFrame = 0.0f;
while (!glfwWindowShouldClose(window))
{
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
glfwPollEvents();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
Can somebody please tell me where the problems are? Thanks
Look at your AddShader code:
Shader shader(filepath);
So you have a Shader object local to this function.
Shaders[name] = shader;
Now this copies the Shader object into the container, using the implicit copy constructor. You have now two Shader objects, both referencing the same GL object ID, one in the map, and one in your local variable.
When the function is left, the local variable gets out of scope, and the destructor is called, which destroys the GL object. What's left is the copy in the map, which still references the now-destroyed GL object ID.
Naively wrapping GL objects in C++ objects isn't going to work. You will need a more elaborate scheme for proper OpenGL object management.
if (glIsProgram(Shaders[name].m_RendererID) != GL_TRUE)
Shaders is a std::map. Its operator[] default-constructs the object if the key does not exist in the map.
Your Shader class's default constructor fails to initialize m_RendererID. As such, this results in undefined behavior, whenever the name that gets passed in does not exist.
You can use your debugger to set a breakpoint here, when that happens, then work your way up the call stack and determine the reason for the logical error. You will discover that m_RendererID gets set to the return value of glCreateProgram, and based on its description, a comparison against GL_TRUE appears to be meaningless.
My issue begins with my shader, specifically the Vertex Shader not being linked, I am currently following the LearnOpenGL guide for the code.
ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ
ERROR::PROGRAM_LINKING_ERROR of type: PROGRAM
Vertex info
-----------
(0) : error C5145: must write to gl_Position
So this is my shader.vert file-
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
A very simple, vert file I was able to achieve this working with the strings method, but when reading from file is where the issues begin.
Here is the shader.frag file -
#version 330 core
out vec4 FragColor;
in vec4 vertexColor; // the input variable from the vertex shader (same
name and same type)
void main()
{
FragColor = vertexColor;
}
This is the .h file which reads the files from LearnOpenGL, and to my knowledge this file isn't the problem.
#include <GL/glew.h>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
class Shader
{
public:
unsigned int ID;
// constructor generates the shader on the fly
// ------------------------------------------------------------------------
Shader(const char* vertexPath, const char* fragmentPath)
{
// 1. retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// ensure ifstream objects can throw exceptions:
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
// open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure& e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
// 2. compile shaders
unsigned int vertex, fragment;
// vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// shader Program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
// delete the shaders as they're linked into our program now and no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
}
// activate the shader
// ------------------------------------------------------------------------
void use()
{
glUseProgram(ID);
}
// utility uniform functions
// ------------------------------------------------------------------------
void setBool(const std::string& name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
// ------------------------------------------------------------------------
void setInt(const std::string& name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
// ------------------------------------------------------------------------
void setFloat(const std::string& name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
private:
// utility function for checking shader compilation/linking errors.
// ------------------------------------------------------------------------
void checkCompileErrors(unsigned int shader, std::string type)
{
int success;
char infoLog[1024];
if (type != "PROGRAM")
{
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
else
{
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -
- --------------------------------------------------- -- " << std::endl;
}
}
}
};
I am unsure how many different ways I tried linking the files, renaming them with different names, using Full Paths, and relative Paths, and still wasn't able to find the solution.
Shader ourShader("Shaders/shader.vert","Shaders/shader.frag");
Alright, so after testing so many things I have found the solution:
So for linking files always have the right folder path,
Shader ourShader("Source/Shaders/Shader.vert", "Source/Shaders/Shader.frag");
Also I found that my GLEW wasn't initialized before I used this function which also led to errors, hope my solution will help to those who has the same problem.
I'm trying to compile a shader program, but I'm getting the runtime error message specified above. I've tried for a while to figure out why this is occurring and what it means, but I'm pretty stuck.
Here is the relevant source code:
Main.cpp:
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "shader.hpp"
void initGLFW() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
}
GLFWwindow* createWindow(int width, int height) {
GLFWwindow* window = glfwCreateWindow(width, height, "LearnOpenGL", NULL, NULL);
if (window == NULL) {
throw runtime_error("Failed to create GLFW window");
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
return window;
}
int main() {
initGLFW();
GLFWwindow* window = createWindow(WIDTH, HEIGHT);
initGLAD();
Shader sh {"vertex-shader.txt", "fragment-shader.txt"};
}
Shader.cpp
unsigned int Shader::compileShader(ShaderType shaderType, const char* srcShader) {
unsigned int shader {};
string shaderStr {};
if (shaderType == ShaderType::vertex) {
shader = glCreateShader(GL_VERTEX_SHADER); // THIS IS WHERE THE RUNTIME ERROR COMES UP
shaderStr = "Vertex";
}
else if (shaderType == ShaderType::fragment) {
shader = glCreateShader(GL_FRAGMENT_SHADER);
shaderStr = "Fragment";
}
glShaderSource(shader, 1, &srcShader, nullptr);
glCompileShader(shader);
// Check for compilation failure
int success;
char infoLog[512];
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 512, nullptr, infoLog);
ostringstream oss {};
oss << shaderStr << " shader compilation failed.\n" << infoLog << endl;
throw runtime_error(oss.str());
}
return shader;
}
Shader::Shader(const string& vertexShaderFilepath,
const string& fragmentShaderFilepath)
{
string srcVertexShader {shaderFromFile(vertexShaderFilepath)};
string srcFragmentShader {shaderFromFile(fragmentShaderFilepath)};
const char* srcVS_cstr = srcVertexShader.c_str();
const char* srcFS_cstr = srcFragmentShader.c_str();
unsigned int vertexShader = compileShader(ShaderType::vertex, srcVS_cstr);
unsigned int fragmentShader = compileShader(ShaderType::fragment, srcFS_cstr);
shaderProgram = linkShaders(vertexShader, fragmentShader);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
// More stuff in shader.cpp, I only included relevant bits of code.
Shader.hpp (mostly irrelevant):
#include <string>
using namespace std;
class Shader {
public:
Shader(const string& vertexShaderFilepath,
const string& fragmentShaderFilepath);
void activate();
void activateWithUniform(const string& uniformName, float uniformVal);
void activateWithUniform(const string& uniformName, int uniformVal);
private:
enum class ShaderType { vertex, fragment };
static string shaderFromFile(const string& filepath);
static unsigned int compileShader(ShaderType shaderType, const char* srcShader);
static unsigned int linkShaders(unsigned int shader1, unsigned int shader2);
unsigned int shaderProgram {};
};
Heres a screenshot showing what libraries I have linked.
I should mention that the shaders are the only thing thats not working in the program - if I comment out the shader, the remainder of the program will output a window with a greenish background. Here is the full source code, but I hope the pieces of code above is enough to provide the required information.
You should choose between GLAD and GLEW, but not use both: GLEW ships with its own set of symbols for OpenGL, but you're not calling glewInit so they remain at 0x0. Either drop the libGLEW library or the GLAD code.
I'm training in openGL programmation and I want to create my own classes to make me life easier. However, I'm faced to a problem in my Shader class.
My Shader class is composed of one C++ string (the name of the shader) and two others C strings (which contain the code of the fragment and vertex shaders).
Then, during initialization, I read my files to stock every character into my both C string. At this moment, these two variable are correctly filled, but if I try to read them by my getVertex() method, it does not show me at all what must be in it.
Fragment and Vertex shaders code must be stock in a const GLchar * because of glShaderSource() which is used to load shaders. Here is the prototype of this function: void glShaderSource(GLuint shader, GLsizei count, const GLchar **string, const GLint *length);.
I have already tried to use basic const char * as const GLchar *, but it is even.
I also tried to stock shaders code into C++ strings and convert them into C string in the main but it it does not change anything.
Here is my code with the debug print:
-main.cpp
#include "head.h"
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
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_OPENGL_FORWARD_COMPAT, GL_TRUE); //For MacOS
/*Window initialization*/
GLFWwindow* window = glfwCreateWindow(800, 600, "Hello Window!", NULL, NULL);
if (window == NULL){
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
/*GLAD initialization*/
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
/*Initialize shaders*/
Shader myShaders("Hello");
std::cout << "Main Print\n" << myShaders.getVertex() << std::endl;
/*Triangle Vertices*/
/*float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};*/
/*Rectangle Vertices*/
float vertices[] = {
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
unsigned int VBO;
glGenBuffers(1, &VBO);
/*Define the type of the VBO*/
glBindBuffer(GL_ARRAY_BUFFER, VBO);
/*Copy vertices into the GL_ARRAY_BUFFER object (VBO)*/
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
/*Creating a VS object*/
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
/*Link the VS code to the VS object*/
glShaderSource(vertexShader, 1, &myShaders.getVertex(), NULL);
glCompileShader(vertexShader);
/*Testing the VS compilation*/
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success){
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
/*As the VS, same for FS*/
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &myShaders.getFragment(), NULL);
glCompileShader(fragmentShader);
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
/*Creating the program Shader*/
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
/*Testing PS compilation*/
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::COMPILATION_FAILED\n" << infoLog << std::endl;
}
/*Deleting shaders already used*/
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
/*Activating our shader*/
glUseProgram(shaderProgram);
/*How to interprets data*/
/*(layout (location = 0),vec3,type of the vec,for [-1.0;1.0],stride worked with 0 too, offset to begin*/
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
/*Creating Vertex Array Object*/
unsigned int VAO;
glGenVertexArrays(1, &VAO);
// 1. Lier le Vertex Array Object (VAO)
glBindVertexArray(VAO);
// 2. Copier les sommets dans un tampon pour qu’OpenGL les utilise
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 3. Initialiser les pointeurs d’attributs de sommets
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
/*Creating an EBO for tell the order of vertices to being draw*/
unsigned int EBO;
glGenBuffers(1, &EBO);
/*GL_ELEMENT_ARRAY_BUFFER for EBO*/
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
/*Setting the view*/
glViewport(0, 0, 800, 600);
/*To get a thread style*/
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
/*Render Loop*/
while (!glfwWindowShouldClose(window)){
glClearColor(0.5f, 0.3f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
processInput(window);
glUseProgram(shaderProgram);
//glBindVertexArray(VAO);
/*(Kind of primitive to use, begin of vertices tab, end of vertices tab)*/
//glDrawArrays(GL_TRIANGLES, 0, 3);
/*6 for length of EBO*/
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwPollEvents();
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
/*Resize*/
void framebuffer_size_callback(GLFWwindow* window, int width, int height){
glViewport(0, 0, width, height);
}
/*Handle inputs*/
void processInput(GLFWwindow* window){
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
-shader.hpp:
#pragma once
class Shader {
public:
Shader(std::string const& name) : name_(name){
std::string tmp;
std::ifstream stream("./shaders/" + name_ + ".fs");
if(stream) {
while (stream.good()) {
tmp += stream.get();
}
}
fragment_ = tmp.c_str();
stream.close();
tmp = "";
stream.open("./shaders/" + name_ + ".vs");
if(stream) {
while (stream.good()) {
tmp += stream.get();
}
}
vertex_ = tmp.c_str();
stream.close();
std::cout << "Shader Initialization Print\n" << vertex_ << "\n\n";
}
void initialize(){
if (name_.size() > 0) {
std::string tmp;
std::ifstream stream("./shaders/" + name_ + ".fs");
if (stream) {
while (stream.good()) {
tmp += stream.get();
}
}
fragment_ = tmp.c_str();
stream.close();
tmp = "";
stream.open("./shaders/" + name_ + ".vs");
if (stream) {
while (stream.good()) {
tmp += stream.get();
}
}
vertex_ = tmp.c_str();
stream.close();
}
}
void setName(std::string const& name) {
name_ = name;
}
std::string getName() {
return name_;
}
void setFragment(std::string const& fragment) {
fragment_ = fragment.c_str();
}
const GLchar* & getFragment() {
return fragment_;
}
void setVertex(std::string const& vertex) {
vertex_ = vertex.c_str();
}
const GLchar* & getVertex() {
std::cout << "getVertex() Print\n" << vertex_ << "\n\n";
return vertex_;
}
private:
std::string name_;
const GLchar * vertex_;
const GLchar * fragment_;
};
-head.h:
#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "shader.hpp"
-Trace of execution
Shader Initialization Print
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
getVertex() Print
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
Main Print
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
getVertex() Print
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
ERROR::SHADER::VERTEX::COMPILATION_FAILED
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
ERROR::SHADER::FRAGMENT::COMPILATION_FAILED
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
ERROR::SHADER::PROGRAM::COMPILATION_FAILED
Vertex info
-----------
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
(0) : error C2003: incompatible options for link
Fragment info
-------------
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
(0) : error C2003: incompatible options for link
Actually, I expect to get what shader initialization print everywhere I call my getVertex()/getFragment() methods.
First of all there is an issue when you read the file you've to evaluate stream.good() after the character is read but befor the cahrater is add to the string. Note, .get sets the eofbit when it fails to read a character, but not when th kast charater was read:
std::string tmp;
std::ifstream stream("./shaders/" + name_ + ".fs");
while (true) {
char c = stream.get();
if (!stream)
break;
tmp += c;
}
Anyway i recmmend to use std::istreambuf_iterator:
std::ifstream stream("./shaders/" + name_ + ".fs");
std::string tmp = std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
getVertex and getFragment. Should return a reference to a pointer to the shader code characters (const GLchar*&). So you've to store the shader code in an attribute. I recommend to stroe the code in a std::string. Further you need an attribute of type const GLchar*, which holds a pointer to the code and can be returned by reference:
class Shader {
public:
// ...
void setVertex(std::string const& vertex) {
vertex_ = vertex;
vs_ptr_ = vertex_.c_str();
}
const GLchar*& getVertex() {
return vs_ptr_;
}
private:
// ...
std::string vertex_;
const GLchar *vs_ptr_;
};
The entire class my look as follows:
class Shader {
public:
Shader(std::string const& name)
: name_(name){
initialize();
}
void initialize(){
if (name_.empty())
return;
std::ifstream stream("./shaders/" + name_ + ".fs");
std::string tmp = std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
stream.close();
setFragment(tmp);
stream.open("./shaders/" + name_ + ".vs");
tmp = std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
stream.close();
setVertex(tmp);
}
void setName(std::string const& name) {
name_ = name;
}
std::string getName() {
return name_;
}
void setFragment(std::string const& fragment) {
fragment_ = fragment;
fs_ptr_ = fragment_.c_str();
}
const GLchar*& getFragment() {
return fs_ptr_;
}
void setVertex(std::string const& vertex) {
vertex_ = vertex;
vs_ptr_ = vertex_.c_str();
}
const GLchar*& getVertex() {
return vs_ptr_;
}
private:
std::string name_;
std::string vertex_;
std::string fragment_;
const GLchar *vs_ptr_;
const GLchar *fs_ptr_;
};
Here's one way to handle this. It uses a string and also stores the result of c_str() on that string. The point is that by storing the pointer as well as the string it is based on you make sure that the pointer remains valid for as long as the string is valid.
class Shader
{
public:
void setVertex(std::string const& vertex) {
vertex_ = vertex;
vertexPtr_ = vertex_.c_str(); // this must be vertex_ not vertex, otherwise we have exactly the same problem as before
}
const GLchar* & getVertex() {
std::cout << "getVertex() Print\n" << vertex_ << "\n\n";
return vertexPtr_;
}
private:
string vertex_;
const GLchar* vertexPtr_;
};
This is untested code.
C++ is not a language where data remains valid as long as it is accessible (unlike Java for instance). You cannot program C++ without understanding the lifetime of the objects you create. Your program got the types correct but failed to understand that the pointer was invalid by the time you used it. This version keeps the string and the pointer to it together so that both have the same lifetime.
I am trying to just render a triangle in one file so I can understand how openGL works so I can use that as an example when creating an engine. The program worked correctly before I created the shaders and the VAO stuff. The exception said: "Access violation at memory location: 0x000000" when the glDrawArrays() function was called. My guess is that i messed up the VAO. It could be the shader too. Thanks in advance for your time!
here is my code
#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include <iostream>
#include <string>
#include <fstream>
const std::string FILENAME = "src\\shaders\\basic";
static void error_callback(int error, const char* description);
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
static void resize_callback(GLFWwindow* window, int width, int height);
static std::string LoadShader(const std::string& filename);
static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string& errorMessage);
static GLuint CreateShader(const std::string& text, GLenum shaderType);
int main()
{
//Initalize GLFW
if (!glfwInit())
{
//TODO: Failed to initialize GLFW
}
//Create window and store it to a handler
GLFWwindow* window = glfwCreateWindow(1024, 768, "GL Noob Project", NULL, NULL);
if (!window)
{
//TODO: Failed to create window
}
glfwMakeContextCurrent(window); //Set the OpenGL context to our window
glfwSwapInterval(1); //Set the buffer swap interval to 1
//Initialize GLEW
if (glewInit() != GLEW_OK) {
//TODO Failed to initialize glew
}
//Set callbacks
glfwSetErrorCallback(error_callback);
glfwSetKeyCallback(window, key_callback);
glfwSetFramebufferSizeCallback(window, resize_callback);
//Shaders
GLuint program;
GLuint v_shader;
GLuint f_shader;
program = glCreateProgram();
v_shader = CreateShader(LoadShader(FILENAME + ".vs"), GL_VERTEX_SHADER);
f_shader = CreateShader(LoadShader(FILENAME + ".fs"), GL_FRAGMENT_SHADER);
glBindAttribLocation(program, 0, "position");
glAttachShader(program, v_shader);
glAttachShader(program, f_shader);
glLinkProgram(program);
CheckShaderError(program, GL_LINK_STATUS, true, "Shader Error");
glValidateProgram(program);
CheckShaderError(program, GL_VALIDATE_STATUS, true, "Shader Error");
glUseProgram(program);
//CREATE VAO
static const GLfloat data[] = { 0.0, 0.0, 0.0,
0.0, 0.0, 0.0,
0.0, 0.0, 0.0 };
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, sizeof(data), GL_FLOAT, GL_FALSE, 0, 0);
while (!glfwWindowShouldClose(window)) //While there is no close flag
{
//DRAW
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glfwSwapBuffers(window); //Swap front and back buffer
glfwPollEvents(); //Get events
}
glDetachShader(program, v_shader);
glDeleteShader(v_shader);
glDetachShader(program, f_shader);
glDeleteShader(f_shader);
glDeleteProgram(program);
glfwDestroyWindow(window); //Destroy window
glfwTerminate(); //Terminate GLFW
return 0;
}
//CALLBACK FUNCTIONS
//Error callback
static void error_callback(int error, const char* description) {
std::cerr << "Error: " << description << std::endl;
}
//Key callback
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
static void resize_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
//SHADER FUNCTIONS
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 from file: "<< 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);
std::cerr << errorMessage << ": " << error << std::endl;
}
}
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* shaderSourceString = text.c_str();
const GLint shaderSourceStringLength = text.length();
glShaderSource(shader, 1, &shaderSourceString, &shaderSourceStringLength);
glCompileShader(shader);
CheckShaderError(shader, GL_COMPILE_STATUS, false, "Error: shader compilation Failed");
return shader;
}
here are the shader files (My guess is that i have propably messed up something here)
Vertex Shader:
#version 330 core
layout(location = 0) in vec3 position;
void main()
{
gl_Position = vec4(position, 1.0);
}
Fragment Shader:
#version 330 core
out vec4 color;
void main() {
color = vec4(1.0, 0.0, 0.0, 1.0);
}