Problem retrieving shaders stored inside std::map - c++

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.

Related

x.string Unhandled exception at 0x0014A25D

I am using Visual 2019 with Visual C++. I was following the tutorial by The Cherno. I am stuck on the end of the Eight Episode. What is causing this?
main.cpp:
#include <gl/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <fstream>
#include <sstream>
struct ShaderProgramSources
{
std::string VertexSource;
std::string FragmentSource;
};
static ShaderProgramSources ParseShader(const std::string& filepath)
{
std::ifstream stream(filepath);
enum class shaderType {
NONE = -1, VERTEX = 0, FRAGMENT = 1
};
std::string line;
std::stringstream ss[1];;
shaderType type = shaderType::NONE;
while (getline(stream, line))
{
if (line.find("#shader") != std::string::npos)
{
if (line.find("vertex") != std::string::npos)
shaderType type = shaderType::VERTEX;
else if (line.find("fragment") != std::string::npos)
shaderType type = shaderType::FRAGMENT;
}
else
{
ss[(int)type] << line << "\n";
}
}
return { ss[0].str(), ss[1].str() };
}
static unsigned int 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 legnth;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &legnth);
char* message = (char*)alloca(legnth * sizeof(char));
glGetShaderInfoLog(id, legnth, &legnth, message);
std::cout << "Failed to Compile" << (type == GL_VERTEX_SHADER ? "Vertex: Shader:\n" : "Fragment Shader:\n");
glDeleteShader(id);
return 0;
}
return id;
}
static unsigned int 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);
return program;
}
int main(void)
{
GLFWwindow* window;
if (!glewInit())
return -1;
/* Initialize the library */
if (!glfwInit())
return -1;
window = glfwCreateWindow(640, 480, "Cooked Pixel", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK)
{
std::cout << "Error: GLEW is not initialized \n";
}
std::cout << "GL Version: " << glGetString(GL_VERSION) << "\n";
float positions[6] = {
-0.5, -0.5,
0.0, -0.5,
0.5, 0.5
};
unsigned int buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), positions, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
std::string vertexShader = R"glsl(
#version 330 core
layout(location = 0) in vec4 position;
void main()
{
gl_Position = position;
}
)glsl";
std::string fragmentShader = R"glsl(
#version 330 core
layout(location = 0) out vec4 color;
void main()
{
color = vec4(1.0, 0.0, 0.0, 1.0);
}
)glsl";
ShaderProgramSources source = ParseShader("res/shaders/basic.shader");
std::cout << source.FragmentSource << "\n";
std::cout << source.VertexSource << "\n";
unsigned int shader = CreateShader(vertexShader, fragmentShader);
glUseProgram(shader);
glfwMaximizeWindow(window);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
I get the error on x.string line 433 as:
Unhandled exception at 0x00CEA25D in CookedPixel.exe: 0xC0000005: Access violation reading location 0xCCCCCCD0. occurred
You are trying to access memory which hasn't been initialized yet or there is an out-of-bound memory error. For more link1 link2. Anyway, I see there's only 178 line in the referred cpp file, not sure how you got the error on line 433.
You have at least one error. It will become very obvious when you closely look at ParseShader. You declare a variable
std::stringstream ss[1];
That's an array with just one element. Later you access it like this:
ss[(int)type] << line << "\n";
This will cause undefined behavior (that can manifest as crash) when (int)type is anything but 0. At then end you get UB anyway:
return { ss[0].str(), ss[1].str() };
is an obvious out-of-bounds access.
However, that's just from first glance. This seems like a good time to learn What a debugger is and how it can help you. Using a debugger is a very important skill.

Getting runtime error "Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)" whencalling glCreateShader

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.

glUniform4fv results in GL_INVALID_OPERATION

Hey I have a class abstracting everything shader related called Shader.cpp:
#include "Shader.h"
#include "Renderer.h"
#include <iostream>
#include <fstream>
Shader::Shader()
{
GLCALL(m_RenderedID = glCreateProgram());
}
Shader::~Shader()
{
GLCALL(glDeleteProgram(m_RenderedID));
}
void Shader::Bind() const
{
GLCALL(glUseProgram(m_RenderedID));
}
void Shader::Unbind() const
{
GLCALL(glUseProgram(0));
}
std::string ParseShader(const std::string& path)
{
std::ifstream ifs(path);
return std::string((std::istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>()));
}
static unsigned int CompileShader(unsigned int type, const std::string& source)
{
GLCALL(unsigned int id = glCreateShader(type));
const char* src = source.c_str();
GLCALL(glShaderSource(id, 1, &src, nullptr));
GLCALL(glCompileShader(id));
int result;
GLCALL(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));
GLCALL(glGetShaderInfoLog(id, length, &length, message));
std::cout << "Failed to compile shader!" << std::endl;
std::cout << message << std::endl;
glDeleteShader(id);
return 0;
}
return id;
}
void Shader::Attach(const unsigned int type, const std::string& path)
{
unsigned int id = CompileShader(type, ParseShader(path));
if (m_ShaderFiles.find(id) == m_ShaderFiles.end())
m_ShaderFiles[id] = ShaderFile({ type, path });
GLCALL(glAttachShader(m_RenderedID, id));
}
void Shader::Link()
{
int result;
GLCALL(glLinkProgram(m_RenderedID));
GLCALL(glGetProgramiv(m_RenderedID, GL_LINK_STATUS, &result));
if (result == GL_FALSE)
{
std::cout << "Failed to link shader!" << std::endl;
return;
}
GLCALL(glValidateProgram(m_RenderedID));
GLCALL(glGetProgramiv(m_RenderedID, GL_VALIDATE_STATUS, &result));
if (result == GL_FALSE)
{
std::cout << "Failed to validate shader!" << std::endl;
return;
}
for (const auto& shaderFile : m_ShaderFiles) {
GLCALL(glDeleteShader(shaderFile.first));
}
}
// this part is taken from Shader.h because it's templated
template<typename T, unsigned int S>
void SetUniform(Uniform<T, S>& uniform)
{
Bind();
uniform.Set(GetUniformLocation(uniform.GetName()));
}
int Shader::GetUniformLocation(const std::string& name)
{
if (m_UniformLocationCache.find(name) != m_UniformLocationCache.end())
return m_UniformLocationCache[name];
GLCALL(int location = glGetUniformLocation(m_RenderedID, name.c_str()));
m_UniformLocationCache[name] = location;
return location;
}
This is my app.cpp using the Shader class:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <fstream>
#include <string>
#include "core/renderer/Shader.h"
#include "core/renderer/uniform/Uniform4f.cpp"
#include "core/renderer/VertexArray.h"
#include "core/renderer/VertexBufferLayout.h"
#include "core/renderer/VertexBuffer.h"
#include "core/renderer/IndexBuffer.h"
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
if (glewInit() != GLEW_OK)
std::cout << "Error!" << std::endl;
std::cout << glGetString(GL_VERSION) << std::endl;
float vertices[] = {
-0.5f, -0.5f,
0.5f, -0.5f,
0.5f, 0.5f,
-0.5f, 0.5f
};
unsigned int indices[] = {
0, 1, 2,
2, 3, 0
};
VertexArray va;
VertexBufferLayout layout;
layout.Push({ GL_FLOAT, 2, sizeof(float) * 2, GL_FALSE });
VertexBuffer vb(vertices, sizeof(vertices), layout);
IndexBuffer ib(indices, 6);
va.AddVertexBuffer(vb);
Shader shader;
shader.Attach(GL_VERTEX_SHADER, "res/shaders/basic_vs.shader");
shader.Attach(GL_FRAGMENT_SHADER, "res/shaders/basic_fs.shader");
shader.Link();
shader.Bind();
Uniform4f colorUniform("u_Color");
float r = 0.00f;
float increment = 0.05f;
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
colorUniform.SetValues({ r, 0.5f, 0.9f, 1.0f });
shader.SetUniform(colorUniform);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
if (r > 1.0f)
increment = -0.05f;
else if (r < 0.0f)
increment = 0.05f;
r += increment;
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
#include <iostream>
Here's the Uniform4f.cpp I'm trying to set:
#include "Uniform.h"
#include "../Renderer.h"
#include <iostream>
class Uniform4f : public Uniform<float, 4>
{
public:
Uniform4f(const std::string& name, const std::array<float, 4>& values = {})
: Uniform(name, values)
{
}
virtual void Set(int location)
{
GLCALL(glUniform4fv(location, m_Values.size(), reinterpret_cast<const GLfloat*>(m_Values.data())));
}
};
Now I'm getting GL_INVALID_OPERATION on the call to glUniform4fv(location, m_Values.size(), reinterpret_cast<const GLfloat*>(m_Values.data())) inside the call to shader.SetUniform(colorUniform); in the render loop in app.cpp.
The docs states it can either be one of these problems:
GL_INVALID_OPERATION is generated if there is no current program
object.
GL_INVALID_OPERATION is generated if the size of the uniform variable
declared in the shader does not match the size indicated by the
glUniform command.
GL_INVALID_OPERATION is generated if one of the signed or unsigned
integer variants of this function is used to load a uniform variable
of type float, vec2, vec3, vec4, or an array of these, or if one of
the floating-point variants of this function is used to load a
uniform variable of type int, ivec2, ivec3, ivec4, unsigned int,
uvec2, uvec3, uvec4, or an array of these.
GL_INVALID_OPERATION is generated if one of the signed integer
variants of this function is used to load a uniform variable of type
unsigned int, uvec2, uvec3, uvec4, or an array of these.
GL_INVALID_OPERATION is generated if one of the unsigned integer
variants of this function is used to load a uniform variable of type
int, ivec2, ivec3, ivec4, or an array of these.
GL_INVALID_OPERATION is generated if location is an invalid uniform
location for the current program object and location is not equal to
-1.
GL_INVALID_OPERATION is generated if count is greater than 1 and the
indicated uniform variable is not an array variable.
GL_INVALID_OPERATION is generated if a sampler is loaded using a
command other than glUniform1i and glUniform1iv.
I can't really figure which error could cause it, non of the above seems right. While debugging I see that the uniform values, size, and location that are passed to glUniform4fv are all correct, my shader programs in Binded after it was Linked in the app.cpp, so I'm not sure what's causing this.
I would be thankful to get any help on this.
Ok I figured it out.
The docs say:
count
For the vector (glUniform*v) commands, specifies the number of elements that are to be modified. This should be 1 if the targeted uniform variable is not an array, and 1 or more if it is an array.
It's kind confusing but my mistake is that the target uniform variable is only 1 vec4 and not an array of vec4 and that's what count represent.

Badly contained in a string except when I store it in C++ class

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.

g++ can't find txt files in the same directory (OpenGL)

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!