/* * * Copyright (C) 2023 Brett Terpstra * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BLT_WITH_GRAPHICS_SHADER_H #define BLT_WITH_GRAPHICS_SHADER_H #include #include #include #include #include #include #include namespace blt::gfx { class uniform_buffer { private: GLuint uboID = 0; size_t size_; GLuint location_; public: explicit uniform_buffer(size_t size, GLuint location = 0); uniform_buffer(void* data, size_t size, GLuint location = 0); /** * Resizes the internal UBO * @param newSize new size for the UBO */ uniform_buffer& resize(size_t newSize); /** * Uploads data to the UBO. This can be an arbitrary locations and does not need to be the whole UBO. */ uniform_buffer& upload(void* data, size_t size, size_t offset = 0); uniform_buffer& bind(); inline uniform_buffer& unbind() { glBindBuffer(GL_UNIFORM_BUFFER, 0); return *this; } ~uniform_buffer(); [[nodiscard]] inline size_t size() const { return size_; } [[nodiscard]] inline GLuint location() const { return location_; } }; class shader_base_t { friend uniform_buffer; protected: struct IntDefaultedToMinusOne { GLint i = -1; inline explicit operator bool() const { return i != -1; } }; std::unordered_map uniformVars; GLuint programID = 0; IntDefaultedToMinusOne getUniformLocation(const std::string& name); public: const shader_base_t& bind() const { glUseProgram(programID); return *this; } shader_base_t& bind() { glUseProgram(programID); return *this; } shader_base_t& unbind() { glUseProgram(0); return *this; } shader_base_t& setBool(const std::string& name, bool value); shader_base_t& setInt(const std::string& name, int value); shader_base_t& setFloat(const std::string& name, float value); shader_base_t& setMatrix(const std::string& name, blt::mat4x4& matrix); // poor solution: TODO shader_base_t& setMatrix(const std::string& name, blt::mat4x4&& matrix); shader_base_t& setVec2(const std::string& name, const blt::vec2& vec); shader_base_t& setVec3(const std::string& name, const blt::vec3& vec); shader_base_t& setVec4(const std::string& name, const blt::vec4& vec); shader_base_t& setVec4i(const std::string& name, const blt::vec4i& vec); shader_base_t& setVec2(const std::string& name, float x, float y); shader_base_t& setVec3(const std::string& name, float x, float y, float z); shader_base_t& setVec4(const std::string& name, float x, float y, float z, float w); }; /** * a basic computer shader class, contains the functions and resources required to use compute shaders! */ class compute_shader_t : public shader_base_t { private: GLuint shaderID = 0; public: explicit compute_shader_t(const std::string& shader_source, bool loadAsString = true); void execute(const int x, const int y, const int z) const { bind(); glDispatchCompute(x, y, z); } ~compute_shader_t(); }; class shader_t : public shader_base_t { private: GLuint vertexShaderID = 0; GLuint fragmentShaderID = 0; static unsigned int createShader(const std::string& source, int type); static std::string loadShader(std::string_view file); shader_t(std::string_view vertex, std::string_view fragment); static std::pair process_templates(template_engine_t& engine, std::string_view vertex, std::string_view fragment); public: /** * Creates a shader from source file * @param vertex vertex shader source * @param fragment fragment shader source */ static shader_t* make(std::optional> engine, std::string_view vertex, std::string_view fragment); static shader_t* make(std::string_view vertex, std::string_view fragment) { return make({}, vertex, fragment); } static std::unique_ptr make_unique(std::optional> engine, std::string_view vertex, std::string_view fragment); static std::unique_ptr make_unique(std::string_view vertex, std::string_view fragment) { return make_unique({}, vertex, fragment); } /** * Creates a shader by loading lines of source from the file. * @param vertex vertex shader file path * @param fragment fragment shader file path */ static shader_t* load(std::optional> engine, std::string_view vertex, std::string_view fragment); static shader_t* load(std::string_view vertex, std::string_view fragment) { return load({}, vertex, fragment); } static std::unique_ptr load_unique(std::optional> engine, std::string_view vertex, std::string_view fragment); static std::unique_ptr load_unique(std::string_view vertex, std::string_view fragment) { return load_unique({}, vertex, fragment); } shader_t(shader_t&& move) noexcept; shader_t(const shader_t& copy) = delete; // used to set the location of VAOs to the in variables in opengl shaders. void bindAttribute(int attribute, const std::string& name) const; // used to set location of shared UBOs like the perspective and view matrix void setUniformBlockLocation(const std::string& name, int location) const; ~shader_t(); }; } #endif //BLT_WITH_GRAPHICS_SHADER_H