glUniform4fv results in GL_INVALID_OPERATION - c++

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.

Related

Problem retrieving shaders stored inside std::map

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.

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.

glDrawElements GL_OUT_OF_MEMORY [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I try to launch next code, but it gives error with code 1285 on line glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr) (Application.cpp).
If I replace preceding line of code with glDrawArrays(GL_TRIANGLES, 0, 3) it draws a triangle, so shader, vertex buffer, vertex array binding works fine. The problem should be in IndexBuffer, but I can't find it.
Renderer.h
#pragma once
#include <GL/glew.h>
#define ASSERT(x) if (!(x)) __debugbreak();
#define GLCall(x) GLClearError();\
x;\
ASSERT(GLLogCall(#x, __FILE__, __LINE__))
void GLClearError();
bool GLLogCall(const char* function, const char* file, int line);
Renderer.cpp
#include "Renderer.h"
#include <iostream>
void GLClearError()
{
while (glGetError() != GL_NO_ERROR);
}
bool GLLogCall(const char* function, const char* file, int line)
{
while (GLenum error = glGetError())
{
std::cout << "[OpenGL Error] (" << error << "): " << function <<
" " << file << ": " << line << std::endl;
return false;
}
return true;
}
VertexBuffer.h
#pragma once
class VertexBuffer
{
private:
unsigned int m_RendererID;
public:
VertexBuffer(const void* data, unsigned int size);
~VertexBuffer();
void Bind() const;
void Unbind() const;
};
VertexBuffer.cpp
#include "VertexBuffer.h"
#include "Renderer.h"
VertexBuffer::VertexBuffer(const void* data, unsigned int size)
{
GLCall(glGenBuffers(1, &m_RendererID));
GLCall(glBindBuffer(GL_ARRAY_BUFFER, m_RendererID));
GLCall(glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW));
}
VertexBuffer::~VertexBuffer()
{
GLCall(glDeleteBuffers(1, &m_RendererID));
}
void VertexBuffer::Bind() const
{
GLCall(glBindBuffer(GL_ARRAY_BUFFER, m_RendererID));
}
void VertexBuffer::Unbind() const
{
GLCall(glBindBuffer(GL_ARRAY_BUFFER, 0));
}
IndexBuffer.h
#pragma once
class IndexBuffer
{
private:
unsigned int m_RendererID;
unsigned int m_Count;
public:
IndexBuffer(const unsigned int* data, unsigned int count);
~IndexBuffer();
void Bind() const;
void Unbind() const;
inline unsigned int GetCount() const { return m_Count; }
};
IndexBuffer.cpp
#include "IndexBuffer.h"
#include "Renderer.h"
IndexBuffer::IndexBuffer(const unsigned int* data, unsigned int count)
: m_Count(count)
{
ASSERT(sizeof(unsigned int) == sizeof(GLuint));
GLCall(glGenBuffers(1, &m_RendererID));
GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID));
GLCall(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(unsigned int), data, GL_STATIC_DRAW);
}
IndexBuffer::~IndexBuffer()
{
GLCall(glDeleteBuffers(1, &m_RendererID));
}
void IndexBuffer::Bind() const
{
GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID));
}
void IndexBuffer::Unbind() const
{
GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
Application.cpp
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include "Renderer.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
struct ShaderProgramSource
{
std::string VertexSource;
std::string FragmentSource;
};
static ShaderProgramSource ParseShader(const std::string& filepath)
{
std::fstream 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;
}
else if (line.find("fragment") != std::string::npos)
{
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)
{
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;
GLCall(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 " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader!" << std::endl;
std::cout << message << std::endl;
GLCall(glDeleteShader(id));
return 0;
}
return id;
}
static unsigned int CreateProgram(const std::string& vertexShader, const std::string& fragmentShader)
{
GLCall(unsigned int program = glCreateProgram());
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
GLCall(glAttachShader(program, vs));
GLCall(glAttachShader(program, fs));
GLCall(glLinkProgram(program));
GLCall(glValidateProgram(program));
GLCall(glDeleteShader(vs));
GLCall(glDeleteShader(fs));
return program;
}
int main()
{
GLFWwindow* window;
if (!glfwInit())
{
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(640, 400, "Hello world", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
if (glewInit() != GLEW_OK)
{
std::cout << "Error while GLEW init!" << std::endl;
}
std::cout << glGetString(GL_VERSION) << std::endl;
{
float positions[] = {
-0.5f, -0.5f, // 0
0.5f, -0.5f, // 1
0.5f, 0.5f, // 2
-0.5f, 0.5f // 3
};
unsigned int indices[] = {
0, 1, 2,
2, 3, 0
};
unsigned int vao;
GLCall(glGenVertexArrays(1, &vao));
GLCall(glBindVertexArray(vao));
VertexBuffer vb(positions, 4 * 2 * sizeof(float));
GLCall(glEnableVertexAttribArray(0));
GLCall(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0));
IndexBuffer ib(indices, 6);
ShaderProgramSource source = ParseShader("res/shaders/Basic.shader");
unsigned int program = CreateProgram(source.VertexSource, source.FragmentSource);
GLCall(glUseProgram(program));
GLCall(int location = glGetUniformLocation(program, "u_Color"));
ASSERT(location != -1);
GLCall(glUniform4f(location, 0.8f, 0.3f, 0.8f, 1.0f));
GLCall(glBindVertexArray(0));
GLCall(glUseProgram(0));
vb.Unbind();
ib.Unbind();
float r = 0;
float increment = 0.05f;
while (!glfwWindowShouldClose(window))
{
GLCall(glClear(GL_COLOR_BUFFER_BIT));
glClearColor(1, 0, 0, 1);
GLCall(glUseProgram(program));
GLCall(glUniform4f(location, r, 0.3f, 0.8f, 1.0f));
GLCall(glBindVertexArray(vao));
ib.Bind();
// glDrawArrays(GL_TRIANGLES, 0, 3);
GLCall(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;
glfwSwapBuffers(window);
glfwPollEvents();
}
GLCall(glDeleteProgram(program));
}
glfwTerminate();
return 0;
}
Basic.shader
#shader vertex
#version 330 core
layout(location = 0) in vec4 position;
void main()
{
gl_Position = position;
}
#shader fragment
#version 330 core
layout(location = 0) out vec4 color;
uniform vec4 u_Color;
void main()
{
color = u_Color;
}
This does not look right. Missing a glBufferData?
GLCall(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(unsigned int), data, GL_STATIC_DRAW);

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.

OpenGL Program Shader Linking Error

I have been working to create a circle based on a shader that changes color periodically. My code prints out a blank window. I decided to set-up some methods to check for errors using GL_LINK_STATUS and it seems that my code is encountering an issue linking the program and the shader.
I did some research into similar issues that people have had but they don't seem to have similar causes.
I have posted my shader code, the driver program(named Priomary) and the Shader Program below.
Vertex Shader
#version 330 core
layout (location = 0) in vec3 pos;
uniform vec2 posOffset;
void main()
{
gl_Position = vec4(pos.x + posOffset.x, pos.y + posOffset.y, pos.z, 1.0);
}
Fragment Shader
#version 330 core
uniform vec4 vertColor;
out vec4 frag_color;
void main()
{
frag_color = vertColor;
}
Shader Program
#include "ShaderProgram.h"
#include <fstream>
#include <iostream>
#include <sstream>
ShaderProgram::ShaderProgram()
: mProgram(0){
}
ShaderProgram::~ShaderProgram()
{
glDeleteProgram(mProgram);
}
bool ShaderProgram::assignShaders(const char* vertFileName, const char* fragFileName)
{
//Shaders output objects called programs that define their relationship and lead to .exe functionality
//assigning pointer to the shader
string vsString = readFile(vertFileName);
string fsString = readFile(fragFileName);
// c_str returns a const char* that points to a null-terminated string (i.e. a C-style string). It is useful when you want to pass the "contents"¹ of an std::string to a function that expects to work with a C-style string.
const GLchar* vsSourcePtr = vsString.c_str();
const GLchar* fsSourcePtr = fsString.c_str();
//creating vertex shader(vs) shader object
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
//assigning shader source using address. Replaces the source code in a shader object //#arg (shader, count Strings, pointer to const File ,size)
glShaderSource(vs, 1, &vsSourcePtr, NULL);
glShaderSource(fs, 1, &fsSourcePtr, NULL);
glCompileShader(vs);
testShaderCompile(vs);
glCompileShader(fs);
testShaderCompile(fs);
//createProgram returns GLUint which is basically an unsigned int... we will use This Handler to create a program object
mProgram = glCreateProgram();
if (mProgram == 0)
{
std::cerr << "Shader cannot be created" << std::endl;
return false;
}
//assign the program object(mProgram) to the Shader
glAttachShader(mProgram, vs);
glAttachShader(mProgram, fs);
//this method accepts a GLuint "program" . If its an object of type GL_VERTEX_SHADER,
//itll create a .exe that runs on the programmable vertex processor. same goes for geometric and fragment shaders if they were included
//it will also bind all user defined uniform variables and attributes to the program
//The program can then be made part of a defined state by calling useProgram
glLinkProgram(mProgram);
testProgramCompile();
//cleaning up the elements we already used
glDeleteShader(vs);
glDeleteShader(fs);
//clear the identifier lookup map(in this case, there's only one)
mUniformIdentifiers.clear();
return true;
}//end main
//Read the shaderFile. strngstream for reading multiple lines
string ShaderProgram:: readFile(const string& filename) {
std::stringstream strgstream;
std::ifstream file;
try
{
file.open(filename, std::ios::in);
if (!file.fail())
{
strgstream << file.rdbuf();
}
file.close();
}
catch (std::exception ex)
{
std::cerr << "Error: File or File Name Issues" << std::endl;
}
return strgstream.str();
}
//use the Program Object we created in this current state(color)
void ShaderProgram::use()
{
//check if it is not null
if (mProgram > 0)
glUseProgram(mProgram);
}
void ShaderProgram::dumpShaderLog(bool is_shader, GLuint obj)
{
int maxlen = 0;
if (is_shader) glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &maxlen);
else glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &maxlen);
if (maxlen > 0)
{
char *log = new char[maxlen];
int len;
if (is_shader) glGetShaderInfoLog(obj, maxlen, &len, log);
else glGetProgramInfoLog(obj, maxlen, &len, log);
if (len > 0 && log[0] != '\0')
fprintf(stderr, "%s\n", log);
delete[] log;
}
}
void ShaderProgram::testProgramCompile() {
int status = 0;
GLuint program = mProgram;
// ///CHECKING GL_LINK_STATUS to see if Program Link was successul. Link Status will return GL_TRUE if it was
glGetProgramiv( mProgram, GL_LINK_STATUS, &status); //requesting the status
if (status == GL_FALSE)
{
GLint length = 0;
glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &length);
string errorLog(length, ' '); // Resize and fill with space character
glGetProgramInfoLog(mProgram, length, &length, &errorLog[0]);
dumpShaderLog(false, mProgram);
std::cerr << "Linking Error with Program and Shader" << std::endl;
}
}
void ShaderProgram :: testShaderCompile(GLuint shader) {
int status = 0;
// ///CHECKING GL_LINK_STATUS to see if Program Link was successul. Link Status will return GL_TRUE if it was
glGetShaderiv (shader, GL_COMPILE_STATUS, &status);//requesting the status
if (status == GL_FALSE)
{
GLint length = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
string errorLog(length, ' '); // Resize and fill with space character
glGetShaderInfoLog(shader, length, &length, &errorLog[0]);
std::cerr << "SHADER COMPILE TEST ERROR " << std::endl;
}
}
////GETTERS AND SETTERS
GLuint ShaderProgram::getProgram() const
{
return mProgram;
}
void ShaderProgram::setUniform(const GLchar* name, const glm::vec2& v)
{
GLint address = getUniformIdentifier(name);
glUniform2f(address, v.x, v.y);
}
void ShaderProgram::setUniform(const GLchar* name, const glm::vec3& v)
{
GLint address = getUniformIdentifier(name);
glUniform3f(address, v.x, v.y, v.z);
}
void ShaderProgram:: setUniform(const GLchar* name, const glm::vec4& v) {
GLint address = getUniformIdentifier(name);
glUniform4f(address, v.x, v.y, v.z, v.w);
}
//Maybe need to switch places with setUniform
GLint ShaderProgram :: getUniformIdentifier(const GLchar* name) {
std::map<std::string, GLint>::iterator it;
it = mUniformIdentifiers.find(name);
//std::map<std::string, GLint>
// Only need to query the shader program IF it doesn't already exist.
if (it == mUniformIdentifiers.end())
{
// Find it and add it to the map
mUniformIdentifiers[name] = glGetUniformLocation(mProgram, name);
}
// Return it
return mUniformIdentifiers[name];
}
Primary Program
#include <iostream>
#include <vector>
#include <sstream>
#define GLEW_STATIC
//always GLEW before GLFW
#include "GL/glew.h"
#include "GLFW/glfw3.h"
#include "glm/glm.hpp"
#include "ShaderProgram.h"
#ifndef M_PI
# define M_PI 3.141592653
#endif
/////gLOBAL
GLFWwindow* w = NULL;
const int wWidth = 800;
const int wHeight = 600;
std::vector<glm::vec3> vertices;
std::vector<unsigned int> indices;
GLfloat Radius = 6;
GLfloat Stacks = 5;
GLfloat Slices = 5;
void key_callback(GLFWwindow *w, int key, int scancode, int action, int mode);
//update colors based on average framerate
void averageFPS(GLFWwindow* window);
//screen resizing
void glfw_onFramebufferSize(GLFWwindow* window, int width, int height);
bool initOpenGL();
static void error(int error, const char *desc)
{
fputs(desc, stderr);
}
//setting up values for keys
int main() {
//pointing to GLFW window
//GLFWwindow *w; //may want to initialize as null outside before main
if (!initOpenGL()) ///5IMPR
{
// An error occured
std::cerr << "GLFW not initialized" << std::endl;
return -1;
}
glfwSetErrorCallback(error);
///TEMP CIRCLE VERTICES
// Calc The Vertices
for (int i = 0; i <= Stacks; ++i) {
float V = i / (float)Stacks;
float phi = V * M_PI; //change to glm:: pi
// Loop Through Slices
for (int j = 0; j <= Slices; ++j) {
float U = j / (float)Slices;
float theta = U * (M_PI * 2);
// Calc The Vertex Positions
float x = cosf(theta) * sinf(phi);
float y = cosf(phi);
float z = sinf(theta) * sinf(phi);
// Push Back Vertex Data //push_back is a standard vector function which adds a parameter to the end of the vector
//std::vector<glm::vec3> vertices; //moved to global variables at top
vertices.push_back(glm::vec3(x, y, z) * Radius);
}
}
// Calc The Index Positions
for (int i = 0; i < Slices * Stacks + Slices; ++i) {
indices.push_back(i);
indices.push_back(i + Slices + 1);
indices.push_back(i + Slices);
indices.push_back(i + Slices + 1);
indices.push_back(i);
indices.push_back(i + 1);
}
////TEMP CIRCLE VERTICES END
// 2. Set up buffers on the GPU
GLuint vbo, ibo, vao; ///5IMPROVEdown
glGenBuffers(1, &vbo); // Generate an empty vertex buffer on the GPU
glBindBuffer(GL_ARRAY_BUFFER, vbo); // "bind" or set as the current buffer we are working with
//3rd argument of glBufferData needs a pointer to the std:vector data...A pointer to the data can be obtained by vertices.data() accrding to std: ector docs...
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);// copy the data from CPU to GPU
glGenVertexArrays(1, &vao); // Tell OpenGL to create new Vertex Array Object
glBindVertexArray(vao); // Make it the current one
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); // Define a layout for the first vertex buffer "0"
glEnableVertexAttribArray(0); // Enable the first attribute or attribute "0"
// Set up index buffer
glGenBuffers(1, &ibo); // Create buffer space on the GPU for the index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
// glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); - REPLACED
glBindVertexArray(0); // unbind to make sure other code doesn't change it
ShaderProgram shaderProgram; ///5ADD
shaderProgram.assignShaders("shaders\\ColorShader.vert", "shaders\\ColorShader.frag"); ///5ADD
////////SETUP RENDERING
while (!glfwWindowShouldClose(w))
{
averageFPS(w);
//process events
glfwPollEvents();
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT);
shaderProgram.use(); ///5ADD
GLfloat time = (GLfloat)glfwGetTime(); ///5ADD
GLfloat blueSetting = (sin(time) / 2) + 0.5f; ///5ADD
glm::vec2 pos;
pos.x = sin(time) / 2;
pos.y = cos(time) / 2;
shaderProgram.setUniform("vertColor", glm::vec4(0.0f, 0.0f, blueSetting, 1.0f)); ///5ADD
shaderProgram.setUniform("posOffset", pos);
glBindVertexArray(vao);
//og for quad
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//glDrawElements(GL_LINE_LOOP, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
// Swap buffers and look for events
glfwSwapBuffers(w);
}
//clean up
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &ibo);
//glfwDestroyWindow(w);
glfwTerminate();
return 0;
}
///////START Initializing glfw glew etc
bool initOpenGL(){
//this method will exit on these conditions
GLuint error = glfwInit();
if (!error)
return false;
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);
w = glfwCreateWindow(wWidth, wHeight, "Exercise", NULL, NULL);
if (w== NULL)
{
std::cerr << "glfw window not created" << std::endl;
glfwTerminate();
return false;
}
//update context
glfwMakeContextCurrent(w);
// Initialize GLEWunifor
glewExperimental = GL_TRUE;
GLuint err = glewInit();
if (err != GLEW_OK)
{
std::cerr << "initialize GLEW Failed" << std::endl;
return false;
}
//setup key callbacks
glfwSetKeyCallback(w, key_callback);
glfwSetFramebufferSizeCallback(w, glfw_onFramebufferSize);
glClearColor(0.23f, 0.38f, 0.47f, 1.0f); ///5ADD
// Define the viewport dimensions
glViewport(0, 0, wWidth, wHeight); //necessary?
return true;
}
void key_callback(GLFWwindow *w, int key, int scancode, int action, int mode)
{
// See http://www.glfw.org/docs/latest/group__keys.html
if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_PRESS)
glfwSetWindowShouldClose(w, GL_TRUE);
if (key == GLFW_KEY_W && action == GLFW_PRESS)
{
bool showWires = false;
if (showWires)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
else
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
}
//whever window resizes, do this
void glfw_onFramebufferSize(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void averageFPS(GLFWwindow* window) ///5ADDdown
{
static double previousSeconds = 0.0;
static int frameCount = 0;
double passedSeconds;
double currentSeconds = glfwGetTime(); //seconds since GLFW started
passedSeconds = currentSeconds - previousSeconds;
// Limit time updates to 4 times per second
if (passedSeconds > 0.25)
{
previousSeconds = currentSeconds;
double fps = (double)frameCount / passedSeconds;
// double frameInMilSecs = 1000.0 / fps;
frameCount = 0;}
frameCount++;
}
While glGetShaderiv returns a parameter from a shader object, glGetProgramiv returns a parameter from a program object.
This means you have to change your code like this:
// glGetProgramiv(shader, GL_COMPILE_STATUS, &status); <--- delete
glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
Ensure that the shader files are correctly loaded and trace them for debug reasons:
glShaderSource(vs, 1, &vsSourcePtr, NULL);
glShaderSource(fs, 1, &fsSourcePtr, NULL);
std::cout << "VERTEX SHADER:" << std::endl << vsSourcePtr << std::endl << std::endl;
glCompileShader(vs);
testShaderCompile(vs);
std::cout << "FRAGMENT SHADER:" << std::endl << fsSourcePtr << std::endl << std::endl;
glCompileShader(fs);
testShaderCompile(fs);
Since you don't set any matrices, you have to set up all the vertex coordinates in normalized device space, which is in [-1.0, 1.0].
To make the mesh proper "visible" on the viewport set the radius of the sphere to 0.5:
GLfloat Radius = 0.5f;
and draw all the primitives:
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);