From 370196ef7aae3222427e218865aceda11f081eb0 Mon Sep 17 00:00:00 2001 From: Pablo Rodriguez Date: Sun, 27 Jul 2025 16:13:48 -0400 Subject: [PATCH] Implemented ShaderProgramBuilder --- CMakeLists.txt | 1 + source/app/CMakeLists.txt | 1 + source/app/src/App.cpp | 53 +++++--------- source/shader/CMakeLists.txt | 14 ++++ .../shader/include/ShaderProgramBuilder.hpp | 28 +++++++ source/shader/src/ShaderProgramBuilder.cpp | 73 +++++++++++++++++++ 6 files changed, 135 insertions(+), 35 deletions(-) create mode 100644 source/shader/CMakeLists.txt create mode 100644 source/shader/include/ShaderProgramBuilder.hpp create mode 100644 source/shader/src/ShaderProgramBuilder.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 33d0af5..24fd749 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,3 +7,4 @@ find_package(glfw3 CONFIG REQUIRED) find_package(glm CONFIG REQUIRED) add_subdirectory(./source/app) +add_subdirectory(./source/shader) diff --git a/source/app/CMakeLists.txt b/source/app/CMakeLists.txt index 2bedf77..be99367 100644 --- a/source/app/CMakeLists.txt +++ b/source/app/CMakeLists.txt @@ -13,4 +13,5 @@ target_link_libraries(${PROJECT_NAME} GLEW::GLEW glfw glm::glm + UglyShaderLib ) diff --git a/source/app/src/App.cpp b/source/app/src/App.cpp index 73ed021..2b9d3e6 100644 --- a/source/app/src/App.cpp +++ b/source/app/src/App.cpp @@ -6,6 +6,7 @@ #include #include +#include "ShaderProgramBuilder.hpp" int App::main(std::vector &args) { auto app = App{}; @@ -57,9 +58,9 @@ App::~App() { void App::game_loop() { float vertices[] = { - .0f, .5f, - .5f, -.5f, - -.5f, -.5f + .0f, .5f, 1.f, 0.f, 0.f, + .5f, -.5f, 0.f, 1.f, 0.f, + -.5f, -.5f, 0.f, 0.f, 1.f }; GLuint vbo; @@ -70,56 +71,38 @@ void App::game_loop() { auto vertexSource = R"glsl( #version 150 core in vec2 position; - void main() { gl_Position = vec4(position, 0.0, 1.0); } + in vec3 color; + out vec3 _color; + void main() { _color = color; gl_Position = vec4(position, 0.0, 1.0); } )glsl"; - GLint status; - GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertexShader, 1, &vertexSource, NULL); - glCompileShader(vertexShader); - glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status); - if(!status) { - error_callback_s(GLFW_NO_ERROR, "glShaderSource() failed"); - } - auto fragmentSource = R"glsl( #version 150 core - uniform vec3 triangleColor; + in vec3 _color; out vec4 color; - void main() { color = vec4(triangleColor, 1.0); } + void main() { color = vec4(_color, 1.0); } )glsl"; - - GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragmentShader, 1, &fragmentSource, NULL); - glCompileShader(fragmentShader); - glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status); - if(!status) { - error_callback_s(GLFW_NO_ERROR, "glShaderSource() failed"); - } - - GLuint shaderProgram = glCreateProgram(); - glAttachShader(shaderProgram, vertexShader); - glAttachShader(shaderProgram, fragmentShader); - glLinkProgram(shaderProgram); + GLuint shaderProgram = ugly::ShaderProgramBuilder{} + .attachFromMemory(GL_VERTEX_SHADER, vertexSource) + .attachFromMemory(GL_FRAGMENT_SHADER, fragmentSource) + .link(); glUseProgram(shaderProgram); GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); - glEnableVertexAttribArray(0); - - auto start = glfwGetTime(); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), 0); + glEnableVertexAttribArray(0); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void*)(2*sizeof(float))); + glEnableVertexAttribArray(1); while(!glfwWindowShouldClose(mpWindow)) { glfwPollEvents(); + glClear(GL_COLOR_BUFFER_BIT); glDrawArrays(GL_TRIANGLES, 0, 3); - auto now = glfwGetTime(); - glUniform3f(glGetUniformLocation(shaderProgram, "triangleColor"), (sin(now-start) + 1.0f) / 2.0f, 0.0f, 0.0f); - glfwSwapBuffers(mpWindow); } } diff --git a/source/shader/CMakeLists.txt b/source/shader/CMakeLists.txt new file mode 100644 index 0000000..8446c1d --- /dev/null +++ b/source/shader/CMakeLists.txt @@ -0,0 +1,14 @@ +project(UglyShaderLib) + +add_library(${PROJECT_NAME} + ./src/ShaderProgramBuilder.cpp +) + +target_include_directories(${PROJECT_NAME} + PUBLIC ./include + PRIVATE ./src +) + +target_link_libraries(${PROJECT_NAME} + GLEW::GLEW +) diff --git a/source/shader/include/ShaderProgramBuilder.hpp b/source/shader/include/ShaderProgramBuilder.hpp new file mode 100644 index 0000000..90476fd --- /dev/null +++ b/source/shader/include/ShaderProgramBuilder.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include + +namespace ugly{ + +class ShaderProgramBuilder { +public: + class Error: public std::runtime_error{ + public: + using std::runtime_error::runtime_error; + }; + +public: + ShaderProgramBuilder(); + ~ShaderProgramBuilder(); + void reset(); + ShaderProgramBuilder &attachFromMemory(GLenum type, const GLchar *string, GLint length = 0); + ShaderProgramBuilder &attachFromFile(GLenum type, const char *filename); + GLuint link(); + +private: + GLuint mProgram; +}; + +} diff --git a/source/shader/src/ShaderProgramBuilder.cpp b/source/shader/src/ShaderProgramBuilder.cpp new file mode 100644 index 0000000..0c57751 --- /dev/null +++ b/source/shader/src/ShaderProgramBuilder.cpp @@ -0,0 +1,73 @@ +#include "ShaderProgramBuilder.hpp" + +#include +#include +#include +#include + + +ugly::ShaderProgramBuilder::ShaderProgramBuilder(): + mProgram{glCreateProgram()} { +} + + +ugly::ShaderProgramBuilder::~ShaderProgramBuilder() { + if(mProgram != 0) { + glDeleteProgram(mProgram); + } +} + + +void ugly::ShaderProgramBuilder::reset() { + using namespace std; + swap(*this, ShaderProgramBuilder{}); +} + + +ugly::ShaderProgramBuilder &ugly::ShaderProgramBuilder::attachFromMemory(GLenum type, const GLchar *string, GLint length) { + auto shader = glCreateShader(type); + glShaderSource(shader, 1, &string, length != 0 ? &length : NULL); + glCompileShader(shader); + + GLint status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if(status != GL_TRUE) { + char buf[512]; + glGetShaderInfoLog(shader, 512, NULL, buf); + glDeleteShader(shader); + std::cerr << "Failed to compile shader:\n\t" << buf << '\n'; + throw Error{"shader failed to compile"}; + } + + glAttachShader(mProgram, shader); + glDeleteShader(shader); + return *this; +} + + +ugly::ShaderProgramBuilder &ugly::ShaderProgramBuilder::attachFromFile(GLenum type, const char *filename) { + auto file = std::ifstream{filename}; + file.exceptions(std::ios_base::badbit); + std::ostringstream ss; + ss << file.rdbuf(); + return attachFromMemory(type, ss.str().c_str()); +} + + +GLuint ugly::ShaderProgramBuilder::link() { + glLinkProgram(mProgram); + + GLint status; + glGetProgramiv(mProgram, GL_LINK_STATUS, &status); + if(status != GL_TRUE) { + char buf[512]; + glGetProgramInfoLog(mProgram, 512, NULL, buf); + std::cerr << "Failed to link program:\n\t" << buf << '\n'; + throw Error{"program failed to link"}; + } + + auto result = mProgram; + mProgram = 0; + reset(); + return result; +}