diff --git a/src/Renderer.cpp b/src/Renderer.cpp index 811b91b..bd0eee4 100644 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -1,6 +1,7 @@ -#include "Renderer.h" +#include #include +#include "Renderer.h" void GLClearError() { diff --git a/src/Renderer.h b/src/Renderer.h index 75a4451..b6a19a8 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -1,9 +1,9 @@ #pragma once -#include "colormod.h" #include - +#include #include +#include "colormod.h" #if defined(_MSC_VER) // Microsoft Visual C++ #include @@ -33,5 +33,8 @@ ASSERT(GLLogCall()) #define INT2VOIDP(i) (void*)(uintptr_t)(i) + +// Declare global functions void GLClearError(); -bool GLLogCall(); \ No newline at end of file +bool GLLogCall(); + diff --git a/src/Shader.cpp b/src/Shader.cpp new file mode 100644 index 0000000..3514cc5 --- /dev/null +++ b/src/Shader.cpp @@ -0,0 +1,157 @@ +#include "Shader.h" +#include +#include +#include +#include +#include "VertexBuffer.h" +#include "VertexArray.h" +#include "IndexBuffer.h" +#include "fstream" +#include "Renderer.h" + +Shader::Shader(const std::string& filepath) + : m_FilePath(filepath), m_RendererID(0) +{ + ShaderProgramSource source = ParseShader(filepath); + + std::cout << "VERTEX" << std::endl << source.VertexSource << std::endl; + std::cout << "FRAGMENT" << std::endl << source.FragmentSource << std::endl; + + m_RendererID = CreateShader(source.VertexSource, source.FragmentSource); + + GLCall( glUseProgram(m_RendererID) ); +} + +Shader::~Shader() +{ + GLCall( glDeleteProgram(m_RendererID) ); +} + +void Shader::Bind() const +{ + GLCall( glUseProgram(m_RendererID) ); +} + +void Shader::Unbind() const +{ + GLCall( glUseProgram(0) ); +} + +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) + std::cout << "No active uniform variable with name " << name << " found" << std::endl; + + m_UniformLocationCache[name] = location; + + return location; +} + +void Shader::SetUniform1f(const std::string& name, float value) +{ + GLCall( glUniform1f(GetUniformLocation(name), value) ); +} + +void Shader::SetUniform4f(const std::string& name, float f0, float f1, float f2, float f3) +{ + GLCall( glUniform4f(GetUniformLocation(name), f0, f1, f2, f3) ); +} + +enum ShaderType +{ + NONE = -1, VERTEX = 0, FRAGMENT = 1 +}; + +struct ShaderProgramSource Shader::ParseShader(const std::string& filepath) +{ + + std::ifstream stream(filepath); + std::string line; + std::stringstream ss[2]; + ShaderType type = NONE; + + while (getline(stream, line)) + { + if (line.find("#shader") != std::string::npos) + { + if (line.find("vertex") != std::string::npos) + type = VERTEX; + else if (line.find("fragment") != std::string::npos) + type = FRAGMENT; + } + else + { + ss[(int)type] << line << '\n'; + } + } + + struct ShaderProgramSource sps = { ss[0].str(), ss[1].str() }; + return sps; +} + +unsigned int Shader::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) ); + + // Error handling + int result; + GLCall( glGetShaderiv(id, GL_COMPILE_STATUS, &result) ); + std::cout << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader compile status: " << result << std::endl; + 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; +} + +unsigned int Shader::CreateShader(const std::string& vertexShader, const std::string& fragmentShader) +{ + // create a shader program + 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) ); + + GLint program_linked; + + GLCall( glGetProgramiv(program, GL_LINK_STATUS, &program_linked) ); + std::cout << "Program link status: " << program_linked << std::endl; + if (program_linked != GL_TRUE) + { + GLsizei log_length = 0; + GLchar message[1024]; + GLCall( glGetProgramInfoLog(program, 1024, &log_length, message) ); + std::cout << "Failed to link program" << std::endl; + std::cout << message << std::endl; + } + + GLCall( glValidateProgram(program) ); + + GLCall( glDeleteShader(vs) ); + GLCall( glDeleteShader(fs) ); + + return program; +} diff --git a/src/Shader.h b/src/Shader.h new file mode 100644 index 0000000..e693d3c --- /dev/null +++ b/src/Shader.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +struct ShaderProgramSource +{ + std::string VertexSource; + std::string FragmentSource; +}; + +class Shader +{ + private: + unsigned int m_RendererID; + std::string m_FilePath; + std::unordered_map m_UniformLocationCache; + + public: + Shader(const std::string& filepath); + ~Shader(); + + void Bind() const; + void Unbind() const; + + // Set uniforms + void SetUniform4f(const std::string& name, float f0, float f1, float f2, float f3); + void SetUniform1f(const std::string& name, float value); + + private: + int GetUniformLocation(const std::string& name); + struct ShaderProgramSource 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); + +}; diff --git a/src/sdl.cpp b/src/sdl.cpp index 4ebb06b..af59376 100644 --- a/src/sdl.cpp +++ b/src/sdl.cpp @@ -1,54 +1,19 @@ #include // Include GLEW before ? #include "sdl.hpp" #include "VertexBufferLayout.h" -#include "colormod.h" #include #include #include #include #include -#include -//#include #include #include -#include #include "Renderer.h" #include "VertexBuffer.h" #include "VertexArray.h" #include "IndexBuffer.h" - -#if defined(_MSC_VER) // Microsoft Visual C++ - #include - #define DEBUG_BREAK() __debugbreak() -#elif defined(__i386__) || defined(__x86_64__) - // Use inline assembly for x86/x86_64 - #define DEBUG_BREAK() __asm__ volatile("int3") -#else - // Fallback on non-x86 platforms - #include - #define DEBUG_BREAK() raise(SIGTRAP) -#endif - -// ASSERT macro that shows file, line, and the failed expression -#define ASSERT(x) \ - do { \ - if (!(x)) { \ - std::cerr << "Assertion Failed: " << #x << '\n' \ - << "File: " << __FILE__ << '\n' \ - << "Line: " << __LINE__ << std::endl; \ - DEBUG_BREAK(); \ - } \ - } while (false) - -#define GLCall(x) GLClearError();\ - x;\ - ASSERT(GLLogCall()) - - -struct ShaderProgramSource { - std::string VertexSource, FragmentSource; -}; +#include "Shader.h" SdlWindow::SdlWindow(const char* title, int width, int height) : m_window(nullptr), @@ -62,7 +27,7 @@ SdlWindow::SdlWindow(const char* title, int width, int height) r(0.5f), m_glContext(nullptr), increment(0.05f), - m_shader(0), + m_Shader(nullptr), m_Location(-1), m_IB(nullptr), m_VB(nullptr), @@ -145,27 +110,11 @@ SdlWindow::SdlWindow(const char* title, int width, int height) layout.Push(2); m_VA->AddBuffer(*m_VB, layout); + + + m_Shader = new Shader("res/shaders/Basic.shader"); + m_Shader->Bind(); - ShaderProgramSource source = parseShader("res/shaders/Basic.shader"); - - std::cout << "VERTEX" << std::endl << source.VertexSource << std::endl; - std::cout << "FRAGMENT" << std::endl << source.FragmentSource << std::endl; - - unsigned int shader = createShader(source.VertexSource, source.FragmentSource); - m_shader = shader; - std::cout << "shader: " << m_shader << std::endl; - std::cout << "shader: " << m_shader << std::endl; - GLCall(glUseProgram(m_shader)); - - GLCall(m_Location = glGetUniformLocation(m_shader, "u_Color")); - ASSERT(m_Location != -1); // -1 is an error - - GLCall(glUniform4f(m_Location, 0.8f, 0.3f, 0.8f, 1.0f)); - - GLCall(glBindVertexArray(0)); - GLCall(glUseProgram(0)); - GLCall(glBindBuffer(GL_ARRAY_BUFFER, 0)); - GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); } @@ -186,11 +135,8 @@ SdlWindow::~SdlWindow() { SDL_DestroyWindow(m_window); m_window = nullptr; } - if (m_shader) { - glDeleteProgram(m_shader); - m_shader = 0; - } - + ////TODO + //some point check everything is being deleted SDL_Quit(); } // @@ -201,7 +147,6 @@ void SdlWindow::run() { update(); render(); } - GLCall(glDeleteProgram(m_shader)); } // void SdlWindow::processEvents() { @@ -266,11 +211,8 @@ void SdlWindow::render() { // GLCall(glClear(GL_COLOR_BUFFER_BIT)); - GLCall(glUseProgram(m_shader)); - std::cout << "m_shader: " << m_shader << std::endl; - std::cout << "location: " << m_Location << std::endl; - std::cout << "R: " << r << std::endl; - GLCall(glUniform4f(m_Location, r, 0.3f, 0.8f, 1.0f)); + m_Shader->Bind(); + m_Shader->SetUniform4f("u_Color", r, 0.3, 0.8, 1.0); m_VA->Bind(); m_IB->Bind(); @@ -304,94 +246,3 @@ void SdlWindow::setFullscreen(bool fullscreen) { } } } -// -unsigned int SdlWindow::compileShader(unsigned int type, const std::string& source) { - GLCall(unsigned int id = glCreateShader(type)); - const char* src = source.c_str(); // <--- this string needs to exist when compiling/running - GLCall(glShaderSource(id, 1, &src, nullptr)); - GLCall(glCompileShader(id)); - //TODO: 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 = (char*)alloca(length * sizeof(char)); //do i need to deallocate this?? - GLCall(glGetShaderInfoLog(id, length, &length, message)); - std::cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "vertex":"fragment") << " shader" << std::endl; // print out what type of shader it is - std::cout << message << std::endl; - GLCall(glDeleteShader(id)); - return 0; - - } - // - return id; - - -} - -unsigned int SdlWindow::createShader(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; - -} -SdlWindow::ShaderProgramSource SdlWindow::parseShader(const std::string& filepath) { - //can be changed to c standard which is a bit faster - std::ifstream stream(filepath); - if (!stream.is_open()) { - std::cerr << "parseShader ERROR: Could not open file " << filepath << std::endl; - // Return empty (or handle however you prefer) - return {"", ""}; - } - - enum class ShaderType { - NONE = -1, VERTEX = 0, FRAGMENT = 1 - }; - std::string line; - std::stringstream ss[2]; //vertex - fragment - 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() }; - -} - -void SdlWindow::GLClearError() { - while (glGetError() != GL_NO_ERROR); - -} - -bool SdlWindow::GLLogCall() { - Color::Modifier red(Color::FG_RED); - Color::Modifier def(Color::FG_DEFAULT); - while (GLenum error = glGetError()) { - std::cout << red << "[OpenGL Error] (" << error << ")" << def << std::endl; //if error, it will return a number, this needs to be converted to hex to then look up that value inn GL docs - return false; - } - return true; -} - diff --git a/src/sdl.hpp b/src/sdl.hpp index dbe6066..34dce14 100644 --- a/src/sdl.hpp +++ b/src/sdl.hpp @@ -13,6 +13,7 @@ #include "IndexBuffer.h" #include "VertexBufferLayout.h" #include "VertexArray.h" +#include "Shader.h" // Forward declaration of classes and structs if needed // class SomethingElse; @@ -27,20 +28,18 @@ public: // Run the main loop void run(); - unsigned int compileShader(unsigned int type, const std::string& source); - unsigned int createShader(const std::string& vetexShader, const std::string& fragmentShader); - // for spliting our shaders - //struct ShaderProgramSource { - // std::string VetexSource, FragmentSource; - struct ShaderProgramSource { - std::string VertexSource; - std::string FragmentSource; - }; - ShaderProgramSource parseShader(const std::string& filepath); + // unsigned int compileShader(unsigned int type, const std::string& source); + // unsigned int createShader(const std::string& vetexShader, const std::string& fragmentShader); + // // for spliting our shaders + // //struct ShaderProgramSource { + // // std::string VetexSource, FragmentSource; + // struct ShaderProgramSource { + // std::string VertexSource; + // std::string FragmentSource; + // }; + // ShaderProgramSource parseShader(const std::string& filepath); void setFullscreen(bool fullscreen); - void GLClearError(); - bool GLLogCall(); private: @@ -57,11 +56,11 @@ private: SDL_GLContext m_glContext; float increment; // // temp shader stuff - unsigned int m_shader; GLint m_Location; VertexArray* m_VA; IndexBuffer* m_IB; VertexBuffer* m_VB; + Shader* m_Shader; // Private methods void processEvents();