diff --git a/lib/libimhex/include/hex/helpers/opengl.hpp b/lib/libimhex/include/hex/helpers/opengl.hpp index 00588d5fc..b214ddf3c 100644 --- a/lib/libimhex/include/hex/helpers/opengl.hpp +++ b/lib/libimhex/include/hex/helpers/opengl.hpp @@ -27,101 +27,6 @@ namespace hex::gl { } - class Shader { - public: - Shader(const std::string &vertexSource, const std::string &fragmentSource); - ~Shader(); - - void bind() const; - void unbind() const; - - void setUniform(const std::string &name, const float &value); - - private: - void compile(GLuint shader, const std::string &source); - - private: - GLuint m_program; - std::map m_uniforms; - }; - - enum class BufferType { - Vertex = GL_ARRAY_BUFFER, - Index = GL_ELEMENT_ARRAY_BUFFER - }; - - template - class Buffer { - public: - Buffer(BufferType type, std::span data); - ~Buffer(); - - void bind() const; - void unbind() const; - - void draw() const; - - size_t getSize() const; - private: - GLuint m_buffer; - size_t m_size; - GLuint m_type; - }; - - extern template class Buffer; - extern template class Buffer; - - class VertexArray { - public: - VertexArray(); - ~VertexArray(); - - template - void addBuffer(u32 index, const Buffer &buffer) const { - glEnableVertexAttribArray(index); - buffer.bind(); - glVertexAttribPointer(index, 3, getType(), GL_FALSE, 3 * sizeof(T), nullptr); - } - - void bind() const; - void unbind() const; - - private: - GLuint m_array; - }; - - class Texture { - public: - Texture(u32 width, u32 height); - ~Texture(); - - void bind() const; - void unbind() const; - - GLuint getTexture() const; - u32 getWidth() const; - u32 getHeight() const; - - void release(); - private: - GLuint m_texture; - u32 m_width, m_height; - }; - - class FrameBuffer { - public: - FrameBuffer(); - ~FrameBuffer(); - - void bind() const; - void unbind() const; - - void attachTexture(const Texture &texture) const; - - private: - GLuint m_frameBuffer, m_renderBuffer; - }; - template class Vector { public: @@ -134,7 +39,7 @@ namespace hex::gl { T *data() { return this->m_data.data(); } const T *data() const { return this->m_data.data(); } - size_t size() const { return this->m_data.size(); } + [[nodiscard]] size_t size() const { return this->m_data.size(); } auto operator+(const Vector& other) { auto copy = *this; @@ -175,4 +80,129 @@ namespace hex::gl { }; + class Shader { + public: + Shader() = default; + Shader(std::string_view vertexSource, std::string_view fragmentSource); + ~Shader(); + + Shader(const Shader&) = delete; + Shader(Shader&& other) noexcept; + + Shader& operator=(const Shader&) = delete; + Shader& operator=(Shader&& other) noexcept; + + void bind() const; + void unbind() const; + + void setUniform(std::string_view name, const float &value); + void setUniform(std::string_view name, const Vector &value); + + private: + void compile(GLuint shader, std::string_view source); + GLint getUniformLocation(std::string_view name); + + private: + GLuint m_program = 0; + std::map m_uniforms; + }; + + enum class BufferType { + Vertex = GL_ARRAY_BUFFER, + Index = GL_ELEMENT_ARRAY_BUFFER + }; + + template + class Buffer { + public: + Buffer() = default; + Buffer(BufferType type, std::span data); + ~Buffer(); + Buffer(const Buffer&) = delete; + Buffer(Buffer&& other) noexcept; + + Buffer& operator=(const Buffer&) = delete; + Buffer& operator=(Buffer&& other) noexcept; + + void bind() const; + void unbind() const; + + void draw() const; + + size_t getSize() const; + private: + GLuint m_buffer = 0; + size_t m_size = 0; + GLuint m_type = 0; + }; + + extern template class Buffer; + extern template class Buffer; + + class VertexArray { + public: + VertexArray(); + ~VertexArray(); + VertexArray(const VertexArray&) = delete; + VertexArray(VertexArray&& other) noexcept; + + VertexArray& operator=(const VertexArray&) = delete; + VertexArray& operator=(VertexArray&& other) noexcept; + + template + void addBuffer(u32 index, const Buffer &buffer) const { + glEnableVertexAttribArray(index); + buffer.bind(); + glVertexAttribPointer(index, 3, getType(), GL_FALSE, 3 * sizeof(T), nullptr); + } + + void bind() const; + void unbind() const; + + private: + GLuint m_array; + }; + + class Texture { + public: + Texture(u32 width, u32 height); + ~Texture(); + Texture(const Texture&) = delete; + Texture(Texture&& other) noexcept; + + Texture& operator=(const Texture&) = delete; + Texture& operator=(Texture&& other) noexcept; + + void bind() const; + void unbind() const; + + GLuint getTexture() const; + u32 getWidth() const; + u32 getHeight() const; + + GLuint release(); + private: + GLuint m_texture; + u32 m_width, m_height; + }; + + class FrameBuffer { + public: + FrameBuffer(); + ~FrameBuffer(); + FrameBuffer(const FrameBuffer&) = delete; + FrameBuffer(FrameBuffer&& other) noexcept; + + FrameBuffer& operator=(const FrameBuffer&) = delete; + FrameBuffer& operator=(FrameBuffer&& other) noexcept; + + void bind() const; + void unbind() const; + + void attachTexture(const Texture &texture) const; + + private: + GLuint m_frameBuffer, m_renderBuffer; + }; + } \ No newline at end of file diff --git a/lib/libimhex/source/helpers/opengl.cpp b/lib/libimhex/source/helpers/opengl.cpp index 2e2f24d17..5546f0389 100644 --- a/lib/libimhex/source/helpers/opengl.cpp +++ b/lib/libimhex/source/helpers/opengl.cpp @@ -5,7 +5,7 @@ namespace hex::gl { - Shader::Shader(const std::string &vertexSource, const std::string &fragmentSource) { + Shader::Shader(std::string_view vertexSource, std::string_view fragmentSource) { auto vertexShader = glCreateShader(GL_VERTEX_SHADER); this->compile(vertexShader, vertexSource); @@ -30,7 +30,19 @@ namespace hex::gl { } Shader::~Shader() { - glDeleteProgram(this->m_program); + if (this->m_program != 0) + glDeleteProgram(this->m_program); + } + + Shader::Shader(Shader &&other) noexcept { + this->m_program = other.m_program; + other.m_program = 0; + } + + Shader& Shader::operator=(Shader &&other) noexcept { + this->m_program = other.m_program; + other.m_program = 0; + return *this; } void Shader::bind() const { @@ -41,24 +53,32 @@ namespace hex::gl { glUseProgram(0); } - void Shader::setUniform(const std::string &name, const float &value) { - auto uniform = this->m_uniforms.find(name); - if (uniform == this->m_uniforms.end()) { - auto location = glGetUniformLocation(this->m_program, name.c_str()); - if (location == -1) { - log::warn("Uniform '{}' not found in shader", name); - return; - } - - this->m_uniforms[name] = location; - uniform = this->m_uniforms.find(name); - } - - glUniform1f(uniform->second, value); + void Shader::setUniform(std::string_view name, const float &value) { + glUniform1f(getUniformLocation(name), value); } - void Shader::compile(GLuint shader, const std::string &source) { - auto sourcePtr = source.c_str(); + void Shader::setUniform(std::string_view name, const Vector &value) { + glUniform3f(getUniformLocation(name), value[0], value[1], value[2]); + } + + GLint Shader::getUniformLocation(std::string_view name) { + auto uniform = this->m_uniforms.find(name.data()); + if (uniform == this->m_uniforms.end()) { + auto location = glGetUniformLocation(this->m_program, name.data()); + if (location == -1) { + log::warn("Uniform '{}' not found in shader", name); + return -1; + } + + this->m_uniforms[name.data()] = location; + uniform = this->m_uniforms.find(name.data()); + } + + return uniform->second; + } + + void Shader::compile(GLuint shader, std::string_view source) { + auto sourcePtr = source.data(); glShaderSource(shader, 1, &sourcePtr, nullptr); glCompileShader(shader); @@ -85,6 +105,23 @@ namespace hex::gl { glDeleteBuffers(1, &this->m_buffer); } + template + Buffer::Buffer(Buffer &&other) noexcept { + this->m_buffer = other.m_buffer; + this->m_size = other.m_size; + this->m_type = other.m_type; + other.m_buffer = 0; + } + + template + Buffer& Buffer::operator=(Buffer &&other) noexcept { + this->m_buffer = other.m_buffer; + this->m_size = other.m_size; + this->m_type = other.m_type; + other.m_buffer = 0; + return *this; + } + template void Buffer::bind() const { glBindBuffer(this->m_type, this->m_buffer); @@ -124,6 +161,17 @@ namespace hex::gl { glDeleteVertexArrays(1, &this->m_array); } + VertexArray::VertexArray(VertexArray &&other) noexcept { + this->m_array = other.m_array; + other.m_array = 0; + } + + VertexArray& VertexArray::operator=(VertexArray &&other) noexcept { + this->m_array = other.m_array; + other.m_array = 0; + return *this; + } + void VertexArray::bind() const { glBindVertexArray(this->m_array); } @@ -150,6 +198,17 @@ namespace hex::gl { glDeleteTextures(1, &this->m_texture); } + Texture::Texture(Texture &&other) noexcept { + this->m_texture = other.m_texture; + other.m_texture = 0; + } + + Texture& Texture::operator=(Texture &&other) noexcept { + this->m_texture = other.m_texture; + other.m_texture = 0; + return *this; + } + void Texture::bind() const { glBindTexture(GL_TEXTURE_2D, this->m_texture); } @@ -170,8 +229,11 @@ namespace hex::gl { return this->m_height; } - void Texture::release() { + GLuint Texture::release() { + auto copy = this->m_texture; this->m_texture = 0; + + return copy; } @@ -193,6 +255,21 @@ namespace hex::gl { glDeleteRenderbuffers(1, &this->m_renderBuffer); } + FrameBuffer::FrameBuffer(FrameBuffer &&other) noexcept { + this->m_frameBuffer = other.m_frameBuffer; + other.m_frameBuffer = 0; + this->m_renderBuffer = other.m_renderBuffer; + other.m_renderBuffer = 0; + } + + FrameBuffer& FrameBuffer::operator=(FrameBuffer &&other) noexcept { + this->m_frameBuffer = other.m_frameBuffer; + other.m_frameBuffer = 0; + this->m_renderBuffer = other.m_renderBuffer; + other.m_renderBuffer = 0; + return *this; + } + void FrameBuffer::bind() const { glBindFramebuffer(GL_FRAMEBUFFER, this->m_frameBuffer); } diff --git a/plugins/builtin/romfs/shaders/default/fragment.glsl b/plugins/builtin/romfs/shaders/default/fragment.glsl new file mode 100644 index 000000000..adeea15e3 --- /dev/null +++ b/plugins/builtin/romfs/shaders/default/fragment.glsl @@ -0,0 +1,12 @@ +#version 330 core +in vec3 normal; +out vec4 color; + +void main() { + vec3 norm = normalize(normal); + vec3 lightDir = normalize(vec3(0, 0, -1)); + float diff = max(dot(norm, lightDir), 0.0); + vec3 diffuse = diff * vec3(1.0, 1.0, 1.0); + + color = vec4(1.0f, 0.5f, 0.2f, 1.0f) * vec4(diffuse, 1.0) + 0.1; +} \ No newline at end of file diff --git a/plugins/builtin/romfs/shaders/default/vertex.glsl b/plugins/builtin/romfs/shaders/default/vertex.glsl new file mode 100644 index 000000000..38185f0cb --- /dev/null +++ b/plugins/builtin/romfs/shaders/default/vertex.glsl @@ -0,0 +1,36 @@ +#version 330 core +layout (location = 0) in vec3 in_Position; +layout (location = 1) in vec3 in_Normal; + +/*uniform float time;*/ +uniform float scale; +uniform vec3 rotation; + + +out vec3 normal; + +mat4 rotationMatrix(vec3 axis, float angle) { + axis = normalize(axis); + float s = sin(angle); + float c = cos(angle); + float oc = 1.0 - c; + + return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0, + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0, + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0, + 0.0, 0.0, 0.0, 1.0); +} + +mat4 viewMatrix(vec3 rotation) { + mat4 rotationX = rotationMatrix(vec3(1, 0, 0), rotation.x); + mat4 rotationY = rotationMatrix(vec3(0, 1, 0), rotation.y); + mat4 rotationZ = rotationMatrix(vec3(0, 0, 1), rotation.z); + + return rotationX * rotationY * rotationZ; +} + +void main() { + mat4 view = viewMatrix(rotation); + normal = (vec4(in_Normal, 1.0) * view).xyz; + gl_Position = vec4(in_Position * scale, 1.0) * view; +} \ No newline at end of file diff --git a/plugins/builtin/source/content/pl_visualizers.cpp b/plugins/builtin/source/content/pl_visualizers.cpp index 21aea20c7..1f4da6ce8 100644 --- a/plugins/builtin/source/content/pl_visualizers.cpp +++ b/plugins/builtin/source/content/pl_visualizers.cpp @@ -12,6 +12,8 @@ #include +#include + #include namespace hex::plugin::builtin { @@ -121,13 +123,32 @@ namespace hex::plugin::builtin { void draw3DVisualizer(pl::ptrn::Pattern &pattern, pl::ptrn::Iteratable &, bool shouldReset, const std::vector &) { static ImGui::Texture texture; + static float scaling = 0.5F; + static gl::Vector rotation = { { 1.0F, -1.0F, 0.0F } }; + static std::vector vertices, normals; + static gl::Shader shader; + static gl::VertexArray vertexArray; + static gl::Buffer vertexBuffer, normalBuffer; - if (!shouldReset) { - std::vector vertices; + { + auto dragDelta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Middle); + rotation[0] += -dragDelta.y * 0.0075F; + rotation[1] += -dragDelta.x * 0.0075F; + ImGui::ResetMouseDragDelta(ImGuiMouseButton_Middle); + + auto scrollDelta = ImGui::GetIO().MouseWheel; + scaling += scrollDelta * 0.01F; + + if (scaling < 0.01F) + scaling = 0.01F; + } + + if (shouldReset) { + vertices.clear(); vertices.resize(pattern.getSize() / sizeof(float)); pattern.getEvaluator()->readData(pattern.getOffset(), vertices.data(), vertices.size() * sizeof(float), pattern.getSection()); - std::vector normals; + normals.clear(); normals.resize(vertices.size()); for (u32 i = 0; i < normals.size(); i += 9) { auto v1 = gl::Vector({ vertices[i + 0], vertices[i + 1], vertices[i + 2] }); @@ -146,89 +167,47 @@ namespace hex::plugin::builtin { normals[i + 8] = normal[2]; } - { - gl::FrameBuffer frameBuffer; + shader = gl::Shader(romfs::get("shaders/default/vertex.glsl").string(), romfs::get("shaders/default/fragment.glsl").string()); - gl::Texture renderTexture(512, 512); - frameBuffer.attachTexture(renderTexture); + vertexArray = gl::VertexArray(); + vertexArray.bind(); - frameBuffer.bind(); + vertexBuffer = gl::Buffer (gl::BufferType::Vertex, vertices); + normalBuffer = gl::Buffer(gl::BufferType::Vertex, normals); - constexpr static const char *VertexShaderSource = R"glsl( - #version 330 core - layout (location = 0) in vec3 in_Position; - layout (location = 1) in vec3 in_Normal; + vertexArray.addBuffer(0, vertexBuffer); + vertexArray.addBuffer(1, normalBuffer); - uniform float time; - out vec3 normal; + vertexBuffer.unbind(); + vertexArray.unbind(); + } - mat4 rotationMatrix(vec3 axis, float angle) { - axis = normalize(axis); - float s = sin(angle); - float c = cos(angle); - float oc = 1.0 - c; + { + gl::FrameBuffer frameBuffer; - return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0, - oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0, - oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0, - 0.0, 0.0, 0.0, 1.0); - } + gl::Texture renderTexture(512, 512); + frameBuffer.attachTexture(renderTexture); - void main() { - mat4 rotation = rotationMatrix(vec3(1.0, 0.0, 0.0), time / 2) * rotationMatrix(vec3(0.0, 1.0, 0.0), time / 3); - normal = (vec4(in_Normal, 1.0) * rotation).xyz; - gl_Position = vec4(in_Position * 0.5, 1.0) * rotation; - } - )glsl"; + frameBuffer.bind(); - constexpr static const char *FragmentShaderSource = R"glsl( - #version 330 core - in vec3 normal; - out vec4 color; + glEnable(GL_DEPTH_TEST); - void main() { - vec3 norm = normalize(normal); - vec3 lightDir = normalize(vec3(0, 0, -1)); - float diff = max(dot(norm, lightDir), 0.0); - vec3 diffuse = diff * vec3(1.0, 1.0, 1.0); + shader.bind(); + shader.setUniform("scale", scaling); + shader.setUniform("rotation", rotation); - color = vec4(1.0f, 0.5f, 0.2f, 1.0f) * vec4(diffuse, 1.0) + 0.1; - } - )glsl"; + vertexArray.bind(); - glEnable(GL_DEPTH_TEST); + glViewport(0, 0, renderTexture.getWidth(), renderTexture.getHeight()); + glClearColor(0.00F, 0.00F, 0.00F, 0.00f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + vertexBuffer.draw(); - gl::Shader shader(VertexShaderSource, FragmentShaderSource); + vertexArray.unbind(); + shader.unbind(); + frameBuffer.unbind(); - gl::VertexArray vertexArray; - vertexArray.bind(); - - gl::Buffer vertexBuffer(gl::BufferType::Vertex, vertices); - gl::Buffer normalBuffer(gl::BufferType::Vertex, normals); - - vertexArray.addBuffer(0, vertexBuffer); - vertexArray.addBuffer(1, normalBuffer); - - vertexBuffer.unbind(); - vertexArray.unbind(); - - shader.bind(); - shader.setUniform("time", glfwGetTime()); - - vertexArray.bind(); - - glViewport(0, 0, renderTexture.getWidth(), renderTexture.getHeight()); - glClearColor(0.00F, 0.00F, 0.00F, 0.00f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - vertexBuffer.draw(); - - vertexArray.unbind(); - shader.unbind(); - frameBuffer.unbind(); - - texture = ImGui::Texture(renderTexture.getTexture(), renderTexture.getWidth(), renderTexture.getHeight()); - renderTexture.release(); - } + texture = ImGui::Texture(renderTexture.release(), renderTexture.getWidth(), renderTexture.getHeight()); } ImGui::Image(texture, texture.getSize(), ImVec2(0, 1), ImVec2(1, 0));