summaryrefslogtreecommitdiffstats
path: root/Project/Shader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Project/Shader.cpp')
-rw-r--r--Project/Shader.cpp139
1 files changed, 139 insertions, 0 deletions
diff --git a/Project/Shader.cpp b/Project/Shader.cpp
new file mode 100644
index 0000000..7835fec
--- /dev/null
+++ b/Project/Shader.cpp
@@ -0,0 +1,139 @@
+#include "Shader.h"
+#include "Renderer.h"
+
+#include <wx/msgdlg.h>
+
+#include <fstream>
+#include <sstream>
+#include <string>
+
+
+Shader::Shader(const std::string& filepath)
+ : m_filepath(filepath), m_rendererID(0)
+{
+ ShaderSource source = ParseShader(filepath);
+ m_rendererID = CreateShader(source.vertexShader, source.fragmentShader);
+}
+
+Shader::~Shader()
+{
+ GLCall(glDeleteProgram(m_rendererID));
+}
+
+
+unsigned int Shader::CompileShader(unsigned int type, const wxString& source) const
+{
+ unsigned int id = glCreateShader(type);
+ const char* src = source.c_str();
+ GLCall(glShaderSource(id, 1, &src, nullptr));
+ GLCall(glCompileShader(id));
+
+ // Error handling
+ 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 = static_cast<char*>(alloca(length * sizeof(char))); // Heap allocation dynamically! =)
+ GLCall(glGetShaderInfoLog(id, length, &length, message));
+
+ wxMessageBox(wxString::Format("Erro ao compilar o \"%s shader\" ='(\n%s", type == GL_VERTEX_SHADER ? "vertex" : "fragment", message));
+
+ GLCall(glDeleteShader(id));
+ return 0;
+ }
+ return id;
+}
+
+ShaderSource Shader::ParseShader(const wxString& filepath) const
+{
+ enum class ShaderType
+ {
+ NONE = -1, VERTEX = 0, FRAGMENT = 1
+ };
+
+ ShaderType type = ShaderType::NONE;
+
+ std::ifstream stream(filepath.ToStdString());
+ std::string line;
+ std::stringstream ss[2];
+
+ 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[static_cast<int>(type)] << line + std::string("\n");
+ }
+ }
+
+ return { ss[0].str(), ss[1].str() };
+}
+
+unsigned int Shader::CreateShader(std::string& vertexShader, std::string& fragmentShader) const
+{
+ 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;
+}
+
+void Shader::Bind() const
+{
+ GLCall(glUseProgram(m_rendererID));
+}
+
+void Shader::Unbind() const
+{
+ GLCall(glUseProgram(0));
+}
+
+void Shader::SetUniform4f(const std::string& name, float v0, float v1, float v2, float v3)
+{
+ GLCall(glUniform4f(GetUniformLocation(name), v0, v1, v2, v3));
+}
+
+void Shader::SetUniform2f(const std::string& name, float v0, float v1)
+{
+ GLCall(glUniform2f(GetUniformLocation(name), v0, v1));
+}
+
+void Shader::SetUniformMatrix4fv(const std::string& name, const glm::mat4& matrix)
+{
+ GLCall(glUniformMatrix4fv(GetUniformLocation(name), 1, GL_FALSE, &matrix[0][0]));
+}
+
+void Shader::SetUniform1f(const std::string& name, const float& value)
+{
+ GLCall(glUniform1f(GetUniformLocation(name), value));
+}
+
+unsigned int Shader::GetUniformLocation(const std::string& name)
+{
+ if (m_uniformLocationCache.find(name) != m_uniformLocationCache.end())
+ return m_uniformLocationCache[name];
+
+ GLCall(int location = glGetUniformLocation(m_rendererID, name.c_str()));
+ if (location == -1) {
+ wxMessageBox(wxString::Format("Atenção! uniform \"%s\" não encontrado", name));
+ }
+
+ m_uniformLocationCache[name] = location;
+ return location;
+}