diff --git a/src/libprojectM/MilkdropPreset/BlurTexture.cpp b/src/libprojectM/MilkdropPreset/BlurTexture.cpp index 6cc33660a8..219c22ede2 100644 --- a/src/libprojectM/MilkdropPreset/BlurTexture.cpp +++ b/src/libprojectM/MilkdropPreset/BlurTexture.cpp @@ -5,7 +5,9 @@ #include "MilkdropStaticShaders.hpp" -#include "Renderer/ShaderCache.hpp" +#include +#include +#include #include @@ -13,33 +15,25 @@ namespace libprojectM { namespace MilkdropPreset { BlurTexture::BlurTexture() - : m_blurSampler(std::make_shared(GL_CLAMP_TO_EDGE, GL_LINEAR)) + : m_blurMesh(Renderer::VertexBufferUsage::StaticDraw, false, true) + , m_blurSampler(std::make_shared(GL_CLAMP_TO_EDGE, GL_LINEAR)) { m_blurFramebuffer.CreateColorAttachment(0, 0); - // Initialize Blur VAO/VBO with a single fullscreen quad. - static constexpr std::array pointsBlur{ - -1.0, -1.0, 0.0, 0.0, - 1.0, -1.0, 1.0, 0.0, - -1.0, 1.0, 0.0, 1.0, - 1.0, 1.0, 1.0, 1.0}; + // Initialize blur mesh with a single fullscreen quad. + m_blurMesh.SetRenderPrimitiveType(Renderer::Mesh::PrimitiveType::TriangleStrip); - glGenBuffers(1, &m_vboBlur); - glGenVertexArrays(1, &m_vaoBlur); + m_blurMesh.Vertices().Set({{-1.0f, -1.0f}, + {1.0f, -1.0f}, + {-1.0f, 1.0f}, + {1.0f, 1.0f}}); - glBindVertexArray(m_vaoBlur); - glBindBuffer(GL_ARRAY_BUFFER, m_vboBlur); + m_blurMesh.UVs().Set({{0.0, 0.0}, + {1.0, 0.0}, + {0.0, 1.0}, + {1.0, 1.0}}); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * pointsBlur.size(), pointsBlur.data(), GL_STATIC_DRAW); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, nullptr); // Position at index 0 and 1 - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, reinterpret_cast(sizeof(float) * 2)); // Texture coord at index 2 and 3 - - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); + m_blurMesh.Update(); // Initialize with empty textures. for (size_t i = 0; i < m_blurTextures.size(); i++) @@ -54,12 +48,6 @@ BlurTexture::BlurTexture() } } -BlurTexture::~BlurTexture() -{ - glDeleteBuffers(1, &m_vboBlur); - glDeleteVertexArrays(1, &m_vaoBlur); -} - void BlurTexture::Initialize(const Renderer::RenderContext& renderContext) { auto staticShaders = libprojectM::MilkdropPreset::MilkdropStaticShaders::Get(); @@ -163,8 +151,7 @@ void BlurTexture::Update(const Renderer::Texture& sourceTexture, const PerFrameC m_blurFramebuffer.Bind(0); - glBlendFunc(GL_ONE, GL_ZERO); - glBindVertexArray(m_vaoBlur); + Renderer::BlendMode::Set(true, Renderer::BlendMode::Function::One, Renderer::BlendMode::Function::Zero); for (unsigned int pass = 0; pass < passes; pass++) { @@ -268,7 +255,7 @@ void BlurTexture::Update(const Renderer::Texture& sourceTexture, const PerFrameC } // Draw fullscreen quad - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + m_blurMesh.Draw(); // Save to blur texture m_blurTextures[pass]->Bind(0); @@ -276,8 +263,8 @@ void BlurTexture::Update(const Renderer::Texture& sourceTexture, const PerFrameC m_blurTextures[pass]->Unbind(0); } - glBindVertexArray(0); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + Renderer::Mesh::Unbind(); + Renderer::BlendMode::Set(false, Renderer::BlendMode::Function::SourceAlpha, Renderer::BlendMode::Function::OneMinusSourceAlpha); // Bind previous framebuffer and reset viewport size glBindFramebuffer(GL_READ_FRAMEBUFFER, origReadFramebuffer); diff --git a/src/libprojectM/MilkdropPreset/BlurTexture.hpp b/src/libprojectM/MilkdropPreset/BlurTexture.hpp index edf63660ef..04647a5a80 100644 --- a/src/libprojectM/MilkdropPreset/BlurTexture.hpp +++ b/src/libprojectM/MilkdropPreset/BlurTexture.hpp @@ -4,6 +4,9 @@ */ #pragma once +#include "Renderer/Mesh.hpp" + + #include #include #include @@ -48,7 +51,7 @@ class BlurTexture /** * Destructor. */ - ~BlurTexture(); + virtual ~BlurTexture() = default; /** * @brief Initializes the blur texture. @@ -105,8 +108,7 @@ class BlurTexture */ void AllocateTextures(const Renderer::Texture& sourceTexture); - GLuint m_vboBlur; //!< Vertex buffer object for the fullscreen blur quad. - GLuint m_vaoBlur; //!< Vertex array object for the fullscreen blur quad. + Renderer::Mesh m_blurMesh; //!< The blur mesh (a simple quad). std::weak_ptr m_blur1Shader; //!< The shader used on the first blur pass. std::weak_ptr m_blur2Shader; //!< The shader used for subsequent blur passes after the initial pass. diff --git a/src/libprojectM/MilkdropPreset/Border.cpp b/src/libprojectM/MilkdropPreset/Border.cpp index 2cebe2a541..8ed978c138 100644 --- a/src/libprojectM/MilkdropPreset/Border.cpp +++ b/src/libprojectM/MilkdropPreset/Border.cpp @@ -1,23 +1,28 @@ #include "Border.hpp" +#include + namespace libprojectM { namespace MilkdropPreset { Border::Border(PresetState& presetState) - : RenderItem() - , m_presetState(presetState) + : m_presetState(presetState) + , m_borderMesh(Renderer::VertexBufferUsage::StreamDraw) { - RenderItem::Init(); -} + m_borderMesh.SetRenderPrimitiveType(Renderer::Mesh::PrimitiveType::Triangles); + m_borderMesh.SetVertexCount(8); -void Border::InitVertexAttrib() -{ - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr); - glDisableVertexAttribArray(1); - - std::array vertices{}; - glBufferData(GL_ARRAY_BUFFER, sizeof(Point) * 4, vertices.data(), GL_STREAM_DRAW); + m_borderMesh.Indices().Set({ + { + 0, 1, 4, + 1, 4, 5, + 2, 3, 6, + 3, 7, 6, + 2, 0, 6, + 0, 4, 6, + 3, 7, 5, + 1, 3, 5 + }}); } void Border::Draw(const PerFrameContext& presetPerFrameContext) @@ -26,18 +31,15 @@ void Border::Draw(const PerFrameContext& presetPerFrameContext) float const outerBorderSize = static_cast(*presetPerFrameContext.ob_size); float const innerBorderSize = static_cast(*presetPerFrameContext.ib_size); - glBindVertexArray(m_vaoID); - glBindBuffer(GL_ARRAY_BUFFER, m_vboID); - // No additive drawing for borders - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + Renderer::BlendMode::Set(true, Renderer::BlendMode::Function::SourceAlpha, Renderer::BlendMode::Function::OneMinusSourceAlpha); auto shader = m_presetState.untexturedShader.lock(); shader->Bind(); shader->SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection); - std::array vertices{}; + m_borderMesh.Bind(); + for (int border = 0; border < 2; border++) { float r = (border == 0) ? static_cast(*presetPerFrameContext.ob_r) : static_cast(*presetPerFrameContext.ib_r); @@ -52,39 +54,23 @@ void Border::Draw(const PerFrameContext& presetPerFrameContext) float innerRadius = (border == 0) ? 1.0f - outerBorderSize : 1.0f - outerBorderSize - innerBorderSize; float outerRadius = (border == 0) ? 1.0f : 1.0f - outerBorderSize; - vertices[0].x = innerRadius; - vertices[1].x = outerRadius; - vertices[2].x = outerRadius; - vertices[3].x = innerRadius; - vertices[0].y = innerRadius; - vertices[1].y = outerRadius; - vertices[2].y = -outerRadius; - vertices[3].y = -innerRadius; - - for (int rot = 0; rot < 4; rot++) - { - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Point) * 4, vertices.data()); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // Rotate 90 degrees - // Milkdrop code calculates cos(PI/2) and sin(PI/2), which is 0 and 1 respectively. - // Our code here simplifies the expressions accordingly. - for (int vertex = 0; vertex < 4; vertex++) - { - float const x = vertices[vertex].x; - float const y = vertices[vertex].y; - vertices[vertex].x = -y; // x * cos(PI/2) - y * sin(PI/2) == x * 0 - y * 1 - vertices[vertex].y = x; // x * sin(PI/2) + y * cos(PI/2) == x * 1 + y * 0 - } - } + m_borderMesh.Vertices().Set({{outerRadius, outerRadius}, + {outerRadius, -outerRadius}, + {-outerRadius, outerRadius}, + {-outerRadius, -outerRadius}, + {innerRadius, innerRadius}, + {innerRadius, -innerRadius}, + {-innerRadius, innerRadius}, + {-innerRadius, -innerRadius}}); + + m_borderMesh.Update(); + m_borderMesh.Draw(); } } + Renderer::Mesh::Unbind(); Renderer::Shader::Unbind(); - - glDisable(GL_BLEND); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); + Renderer::BlendMode::SetBlendActive(false); } } // namespace MilkdropPreset diff --git a/src/libprojectM/MilkdropPreset/Border.hpp b/src/libprojectM/MilkdropPreset/Border.hpp index 8b258f6d08..b8f8f7eeb8 100644 --- a/src/libprojectM/MilkdropPreset/Border.hpp +++ b/src/libprojectM/MilkdropPreset/Border.hpp @@ -3,7 +3,7 @@ #include "PerFrameContext.hpp" #include "PresetState.hpp" -#include "Renderer/RenderItem.hpp" +#include namespace libprojectM { namespace MilkdropPreset { @@ -12,15 +12,13 @@ namespace MilkdropPreset { /** * @brief Renders a border around the screen. */ -class Border : public Renderer::RenderItem +class Border { public: Border() = delete; explicit Border(PresetState& presetState); - void InitVertexAttrib() override; - /** * Draws the border. * @param presetPerFrameContext The per-frame context variables. @@ -29,6 +27,7 @@ class Border : public Renderer::RenderItem private: PresetState& m_presetState; //!< The global preset state. + Renderer::Mesh m_borderMesh; //!< The border geometry. }; } // namespace MilkdropPreset diff --git a/src/libprojectM/MilkdropPreset/CustomShape.cpp b/src/libprojectM/MilkdropPreset/CustomShape.cpp index 9eaef3784c..ae30b7ea17 100644 --- a/src/libprojectM/MilkdropPreset/CustomShape.cpp +++ b/src/libprojectM/MilkdropPreset/CustomShape.cpp @@ -2,8 +2,8 @@ #include "PresetFileParser.hpp" +#include #include -#include #include @@ -11,67 +11,20 @@ namespace libprojectM { namespace MilkdropPreset { CustomShape::CustomShape(PresetState& presetState) - : m_presetState(presetState) + : m_outlineMesh(Renderer::VertexBufferUsage::StreamDraw) + , m_fillMesh(Renderer::VertexBufferUsage::StreamDraw, true, false) + , m_presetState(presetState) , m_perFrameContext(presetState.globalMemory, &presetState.globalRegisters) { - std::vector vertexData; - vertexData.resize(102); + m_outlineMesh.SetVertexCount(100); + m_outlineMesh.SetRenderPrimitiveType(Renderer::Mesh::PrimitiveType::LineLoop); - glGenVertexArrays(1, &m_vaoIdTextured); - glGenBuffers(1, &m_vboIdTextured); - - glGenVertexArrays(1, &m_vaoIdUntextured); - glGenBuffers(1, &m_vboIdUntextured); - - glBindVertexArray(m_vaoIdTextured); - glBindBuffer(GL_ARRAY_BUFFER, m_vboIdTextured); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast(offsetof(TexturedPoint, x))); // Position - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast(offsetof(TexturedPoint, r))); // Color - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast(offsetof(TexturedPoint, u))); // Texture coordinate - - glBufferData(GL_ARRAY_BUFFER, sizeof(TexturedPoint) * vertexData.size(), vertexData.data(), GL_STREAM_DRAW); - - glBindVertexArray(m_vaoIdUntextured); - glBindBuffer(GL_ARRAY_BUFFER, m_vboIdUntextured); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast(offsetof(TexturedPoint, x))); // Position - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast(offsetof(TexturedPoint, r))); // Color - - glBufferData(GL_ARRAY_BUFFER, sizeof(TexturedPoint) * vertexData.size(), vertexData.data(), GL_STREAM_DRAW); - - RenderItem::Init(); + m_fillMesh.SetVertexCount(102); + m_fillMesh.SetRenderPrimitiveType(Renderer::Mesh::PrimitiveType::TriangleFan); m_perFrameContext.RegisterBuiltinVariables(); } -CustomShape::~CustomShape() -{ - glDeleteBuffers(1, &m_vboIdTextured); - glDeleteVertexArrays(1, &m_vaoIdTextured); - - glDeleteBuffers(1, &m_vboIdUntextured); - glDeleteVertexArrays(1, &m_vaoIdUntextured); -} - -void CustomShape::InitVertexAttrib() -{ - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr); // points - glDisableVertexAttribArray(1); - - std::vector vertexData; - vertexData.resize(100); - glBufferData(GL_ARRAY_BUFFER, sizeof(Point) * vertexData.size(), vertexData.data(), GL_STREAM_DRAW); -} - void CustomShape::Initialize(::libprojectM::PresetFileParser& parsedFile, int index) { std::string const shapecodePrefix = "shapecode_" + std::to_string(index) + "_"; @@ -128,7 +81,7 @@ void CustomShape::Draw() return; } - glEnable(GL_BLEND); + Renderer::BlendMode::SetBlendActive(true); for (int instance = 0; instance < m_instances; instance++) { @@ -146,15 +99,16 @@ void CustomShape::Draw() } // Additive Drawing or Overwrite - glBlendFunc(GL_SRC_ALPHA, static_cast(*m_perFrameContext.additive) != 0 ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA); - - std::vector vertexData(sides + 2); + Renderer::BlendMode::SetBlendFunction(Renderer::BlendMode::Function::SourceAlpha, + static_cast(*m_perFrameContext.additive) != 0 + ? Renderer::BlendMode::Function::One + : Renderer::BlendMode::Function::OneMinusSourceAlpha); - vertexData[0].x = static_cast(*m_perFrameContext.x * 2.0 - 1.0); - vertexData[0].y = static_cast(*m_perFrameContext.y * -2.0 + 1.0); + auto& vertexData = m_fillMesh.Vertices(); + auto& colorData = m_fillMesh.Colors(); - vertexData[0].u = 0.5f; - vertexData[0].v = 0.5f; + vertexData[0] = Renderer::Point(static_cast(*m_perFrameContext.x * 2.0 - 1.0), + static_cast(*m_perFrameContext.y * -2.0 + 1.0)); // x = f*255.0 & 0xFF = (f*255.0) % 256 // f' = x/255.0 = f % (256/255) @@ -162,15 +116,15 @@ void CustomShape::Draw() // 2.0 -> 254 (0xFE) // -1.0 -> 0x01 - vertexData[0].r = Renderer::color_modulo(*m_perFrameContext.r); - vertexData[0].g = Renderer::color_modulo(*m_perFrameContext.g); - vertexData[0].b = Renderer::color_modulo(*m_perFrameContext.b); - vertexData[0].a = Renderer::color_modulo(*m_perFrameContext.a); + colorData[0] = Renderer::Color::Modulo(Renderer::Color(static_cast(*m_perFrameContext.r), + static_cast(*m_perFrameContext.g), + static_cast(*m_perFrameContext.b), + static_cast(*m_perFrameContext.a))); - vertexData[1].r = Renderer::color_modulo(*m_perFrameContext.r2); - vertexData[1].g = Renderer::color_modulo(*m_perFrameContext.g2); - vertexData[1].b = Renderer::color_modulo(*m_perFrameContext.b2); - vertexData[1].a = Renderer::color_modulo(*m_perFrameContext.a2); + colorData[1] = Renderer::Color::Modulo(Renderer::Color(static_cast(*m_perFrameContext.r2), + static_cast(*m_perFrameContext.g2), + static_cast(*m_perFrameContext.b2), + static_cast(*m_perFrameContext.a2))); for (int i = 1; i < sides + 1; i++) { @@ -178,19 +132,19 @@ void CustomShape::Draw() const float angle = cornerProgress * pi * 2.0f + static_cast(*m_perFrameContext.ang) + pi * 0.25f; // Todo: There's still some issue with aspect ratio here, as everything gets squashed horizontally if Y > x. - vertexData[i].x = vertexData[0].x + static_cast(*m_perFrameContext.rad) * cosf(angle) * m_presetState.renderContext.aspectY; - vertexData[i].y = vertexData[0].y + static_cast(*m_perFrameContext.rad) * sinf(angle); + vertexData[i] = Renderer::Point(vertexData[0].X() + static_cast(*m_perFrameContext.rad) * cosf(angle) * m_presetState.renderContext.aspectY, + vertexData[0].Y() + static_cast(*m_perFrameContext.rad) * sinf(angle)); - vertexData[i].r = vertexData[1].r; - vertexData[i].g = vertexData[1].g; - vertexData[i].b = vertexData[1].b; - vertexData[i].a = vertexData[1].a; + colorData[i] = colorData[1]; } // Duplicate last vertex. vertexData[sides + 1] = vertexData[1]; + colorData[sides + 1] = colorData[1]; - if (static_cast(*m_perFrameContext.textured) != 0) + m_fillMesh.SetUseUV(static_cast(*m_perFrameContext.textured) != 0); + + if (m_fillMesh.UseUV()) { auto shader = m_presetState.texturedShader.lock(); shader->Bind(); @@ -223,58 +177,55 @@ void CustomShape::Draw() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + auto& uvs = m_fillMesh.UVs(); + + uvs[0] = Renderer::TextureUV(0.5f, 0.5f); + for (int i = 1; i < sides + 1; i++) { const float cornerProgress = static_cast(i - 1) / static_cast(sides); const float angle = cornerProgress * pi * 2.0f + static_cast(*m_perFrameContext.tex_ang) + pi * 0.25f; - vertexData[i].u = 0.5f + 0.5f * cosf(angle) / static_cast(*m_perFrameContext.tex_zoom) * textureAspectY; - vertexData[i].v = 1.0f - (0.5f - 0.5f * sinf(angle) / static_cast(*m_perFrameContext.tex_zoom)); // Vertical flip required! + uvs[i] = Renderer::TextureUV(0.5f + 0.5f * cosf(angle) / static_cast(*m_perFrameContext.tex_zoom) * textureAspectY, + 1.0f - (0.5f - 0.5f * sinf(angle) / static_cast(*m_perFrameContext.tex_zoom))); // Vertical flip required! } - vertexData[sides + 1] = vertexData[1]; - - glBindBuffer(GL_ARRAY_BUFFER, m_vboIdTextured); - - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(TexturedPoint) * (sides + 2), vertexData.data()); - - glBindVertexArray(m_vaoIdTextured); - glDrawArrays(GL_TRIANGLE_FAN, 0, sides + 2); - glBindVertexArray(0); - - glBindTexture(GL_TEXTURE_2D, 0); - Renderer::Sampler::Unbind(0); + uvs[sides + 1] = uvs[1]; } else { // Untextured (creates a color gradient: center=r/g/b/a to border=r2/b2/g2/a2) - glBindBuffer(GL_ARRAY_BUFFER, m_vboIdUntextured); - - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(TexturedPoint) * (sides + 2), vertexData.data()); - auto shader = m_presetState.untexturedShader.lock(); shader->Bind(); shader->SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection); - - glBindVertexArray(m_vaoIdUntextured); - glDrawArrays(GL_TRIANGLE_FAN, 0, sides + 2); - glBindVertexArray(0); } + m_fillMesh.Indices().Resize(sides + 2); + m_fillMesh.Indices().MakeContinuous(); + m_fillMesh.Update(); + m_fillMesh.Draw(); + + glBindTexture(GL_TEXTURE_2D, 0); + Renderer::Sampler::Unbind(0); + if (*m_perFrameContext.border_a > 0.0001f) { - std::vector points(sides); + m_outlineMesh.Indices().Resize(sides); + m_outlineMesh.Indices().MakeContinuous(); + + auto& points = m_outlineMesh.Vertices(); for (int i = 0; i < sides; i++) { - points[i].x = vertexData[i + 1].x; - points[i].y = vertexData[i + 1].y; + points[i] = m_fillMesh.Vertex(i + 1); } auto shader = m_presetState.untexturedShader.lock(); shader->Bind(); shader->SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection); + m_outlineMesh.Bind(); + glVertexAttrib4f(1, static_cast(*m_perFrameContext.border_r), static_cast(*m_perFrameContext.border_g), @@ -285,9 +236,6 @@ void CustomShape::Draw() glEnable(GL_LINE_SMOOTH); #endif - glBindVertexArray(m_vaoID); - glBindBuffer(GL_ARRAY_BUFFER, m_vboID); - const auto iterations = m_thickOutline ? 4 : 1; // Need to use +/- 1.0 here instead of 2.0 used in Milkdrop to achieve the same rendering result. @@ -306,40 +254,38 @@ void CustomShape::Draw() case 1: for (auto j = 0; j < sides; j++) { - points[j].x += incrementX; + points[j].SetX(points[j].X() + incrementX); } break; case 2: for (auto j = 0; j < sides; j++) { - points[j].y += incrementY; + points[j].SetY(points[j].Y() + incrementY); } break; case 3: for (auto j = 0; j < sides; j++) { - points[j].x -= incrementX; + points[j].SetX(points[j].X() - incrementX); } break; } - glBufferSubData(GL_ARRAY_BUFFER, 0, static_cast(sizeof(Point) * sides), points.data()); - glDrawArrays(GL_LINE_LOOP, 0, sides); + m_outlineMesh.Update(); + m_outlineMesh.Draw(); } } } - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); + Renderer::Mesh::Unbind(); + Renderer::Shader::Unbind(); #ifndef USE_GLES glDisable(GL_LINE_SMOOTH); #endif - glDisable(GL_BLEND); - - Renderer::Shader::Unbind(); + Renderer::BlendMode::SetBlendActive(false); } } // namespace MilkdropPreset diff --git a/src/libprojectM/MilkdropPreset/CustomShape.hpp b/src/libprojectM/MilkdropPreset/CustomShape.hpp index ea59d34e48..326790b2af 100644 --- a/src/libprojectM/MilkdropPreset/CustomShape.hpp +++ b/src/libprojectM/MilkdropPreset/CustomShape.hpp @@ -4,7 +4,7 @@ #include "PresetState.hpp" #include "ShapePerFrameContext.hpp" -#include +#include #include @@ -19,14 +19,12 @@ class PresetFileParser; * The class creates two sets of VBO/VAO as it's only known later (in the Draw() call) whether the shape is textured * or not. */ -class CustomShape : public Renderer::RenderItem +class CustomShape { public: CustomShape(PresetState& presetState); - ~CustomShape() override; - - void InitVertexAttrib() override; + virtual ~CustomShape() = default; /** * @brief Loads the initial values and code from the preset file. @@ -47,12 +45,10 @@ class CustomShape : public Renderer::RenderItem void Draw(); private: - struct ShapeVertex { - float x{.0f}; //!< The vertex X coordinate. - float y{.0f}; //!< The vertex Y coordinate. - }; + Renderer::Mesh m_outlineMesh; //!< The shape's border/outline mesh. + Renderer::Mesh m_fillMesh; //!< The shape's color/texture mesh. - std::string m_image; //!< Texture filename to be rendered on this shape + std::string m_image; //!< Texture filename to be rendered on this shape. int m_index{0}; //!< The custom shape index in the preset. bool m_enabled{false}; //!< If false, the shape isn't drawn. @@ -93,12 +89,6 @@ class CustomShape : public Renderer::RenderItem PresetState& m_presetState; //!< The global preset state. ShapePerFrameContext m_perFrameContext; - GLuint m_vboIdTextured{0}; //!< Vertex buffer object ID for a textured shape. - GLuint m_vaoIdTextured{0}; //!< Vertex array object ID for a textured shape. - - GLuint m_vboIdUntextured{0}; //!< Vertex buffer object ID for an untextured shape. - GLuint m_vaoIdUntextured{0}; //!< Vertex array object ID for an untextured shape. - friend class ShapePerFrameContext; }; diff --git a/src/libprojectM/MilkdropPreset/CustomWaveform.cpp b/src/libprojectM/MilkdropPreset/CustomWaveform.cpp index 9f046d5335..0b62ec28fa 100644 --- a/src/libprojectM/MilkdropPreset/CustomWaveform.cpp +++ b/src/libprojectM/MilkdropPreset/CustomWaveform.cpp @@ -3,46 +3,37 @@ #include "PerFrameContext.hpp" #include "PresetFileParser.hpp" +#include + #include #include namespace libprojectM { namespace MilkdropPreset { -static constexpr int CustomWaveformMaxSamples = std::max(libprojectM::Audio::WaveformSamples, libprojectM::Audio::SpectrumSamples); +static constexpr int CustomWaveformMaxSamples = std::max(Audio::WaveformSamples, Audio::SpectrumSamples); CustomWaveform::CustomWaveform(PresetState& presetState) - : RenderItem() - , m_presetState(presetState) + : m_presetState(presetState) , m_perFrameContext(presetState.globalMemory, &presetState.globalRegisters) , m_perPointContext(presetState.globalMemory, &presetState.globalRegisters) + , m_mesh(Renderer::VertexBufferUsage::StreamDraw, true, false) { - RenderItem::Init(); - m_perFrameContext.RegisterBuiltinVariables(); m_perPointContext.RegisterBuiltinVariables(); -} - -void CustomWaveform::InitVertexAttrib() -{ - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(ColoredPoint), nullptr); // points - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(ColoredPoint), reinterpret_cast(sizeof(float) * 2)); // colors - - std::vector vertexData; - vertexData.resize(std::max(libprojectM::Audio::SpectrumSamples, libprojectM::Audio::WaveformSamples) * 2 + 2); - glBufferData(GL_ARRAY_BUFFER, sizeof(ColoredPoint) * vertexData.size(), vertexData.data(), GL_STREAM_DRAW); + // Allocate space for max number of vertices possible, so we won't have to resize the vertex + // buffers, which may change on each frame. + m_mesh.SetVertexCount(std::max(Audio::SpectrumSamples, Audio::WaveformSamples) * 2 + 2); } -void CustomWaveform::Initialize(::libprojectM::PresetFileParser& parsedFile, int index) +void CustomWaveform::Initialize(PresetFileParser& parsedFile, int index) { std::string const wavecodePrefix = "wavecode_" + std::to_string(index) + "_"; std::string const wavePrefix = "wave_" + std::to_string(index) + "_"; m_index = index; - m_enabled = parsedFile.GetInt(wavecodePrefix + "enabled", m_enabled); + m_enabled = parsedFile.GetBool(wavecodePrefix + "enabled", m_enabled); m_samples = parsedFile.GetInt(wavecodePrefix + "samples", m_samples); m_sep = parsedFile.GetInt(wavecodePrefix + "sep", m_sep); m_spectrum = parsedFile.GetBool(wavecodePrefix + "bSpectrum", m_spectrum); @@ -56,6 +47,7 @@ void CustomWaveform::Initialize(::libprojectM::PresetFileParser& parsedFile, int m_b = parsedFile.GetFloat(wavecodePrefix + "b", m_b); m_a = parsedFile.GetFloat(wavecodePrefix + "a", m_a); + m_mesh.SetRenderPrimitiveType(m_useDots ? Renderer::Mesh::PrimitiveType::Points : Renderer::Mesh::PrimitiveType::LineStrip); } void CustomWaveform::CompileCodeAndRunInitExpressions(const PerFrameContext& presetPerFrameContext) @@ -74,15 +66,15 @@ void CustomWaveform::CompileCodeAndRunInitExpressions(const PerFrameContext& pre void CustomWaveform::Draw(const PerFrameContext& presetPerFrameContext) { - static_assert(libprojectM::Audio::WaveformSamples <= WaveformMaxPoints, "WaveformMaxPoints is larger than WaveformSamples"); - static_assert(libprojectM::Audio::SpectrumSamples <= WaveformMaxPoints, "WaveformMaxPoints is larger than SpectrumSamples"); + static_assert(Audio::WaveformSamples <= WaveformMaxPoints, "WaveformMaxPoints is larger than WaveformSamples"); + static_assert(Audio::SpectrumSamples <= WaveformMaxPoints, "WaveformMaxPoints is larger than SpectrumSamples"); if (!m_enabled) { return; } - int const maxSampleCount{m_spectrum ? libprojectM::Audio::SpectrumSamples : libprojectM::Audio::WaveformSamples}; + int const maxSampleCount{m_spectrum ? Audio::SpectrumSamples : Audio::WaveformSamples}; // Initialize and execute per-frame code LoadPerFrameEvaluationVariables(presetPerFrameContext); @@ -108,7 +100,6 @@ void CustomWaveform::Draw(const PerFrameContext& presetPerFrameContext) : m_presetState.audioData.waveformRight.data(); const float mult = m_scaling * m_presetState.waveScale * (m_spectrum ? 0.15f : 0.004f); - //const float mult = m_scaling * m_presetState.waveScale * (m_spectrum ? 0.05f : 1.0f); // PCM data smoothing const int offset1 = m_spectrum ? 0 : (maxSampleCount - sampleCount) / 2 - m_sep / 2; @@ -144,7 +135,8 @@ void CustomWaveform::Draw(const PerFrameContext& presetPerFrameContext) sampleDataR[sample] *= mult; } - std::vector pointsTransformed(sampleCount); + std::vector points(sampleCount); + std::vector colors(sampleCount); float const sampleMultiplicator = sampleCount > 1 ? 1.0f / static_cast(sampleCount - 1) : 0.0f; for (int sample = 0; sample < sampleCount; sample++) @@ -154,17 +146,16 @@ void CustomWaveform::Draw(const PerFrameContext& presetPerFrameContext) m_perPointContext.ExecutePerPointCode(); - pointsTransformed[sample].x = static_cast((*m_perPointContext.x * 2.0 - 1.0) * m_presetState.renderContext.invAspectX); - pointsTransformed[sample].y = static_cast((*m_perPointContext.y * -2.0 + 1.0) * m_presetState.renderContext.invAspectY); + points[sample] = Renderer::Point(static_cast((*m_perPointContext.x * 2.0 - 1.0) * m_presetState.renderContext.invAspectX), + static_cast((*m_perPointContext.y * -2.0 + 1.0) * m_presetState.renderContext.invAspectY)); - pointsTransformed[sample].r = Renderer::color_modulo(*m_perPointContext.r); - pointsTransformed[sample].g = Renderer::color_modulo(*m_perPointContext.g); - pointsTransformed[sample].b = Renderer::color_modulo(*m_perPointContext.b); - pointsTransformed[sample].a = Renderer::color_modulo(*m_perPointContext.a); + colors[sample] = Renderer::Color::Modulo(Renderer::Color(static_cast(*m_perPointContext.r), + static_cast(*m_perPointContext.g), + static_cast(*m_perPointContext.b), + static_cast(*m_perPointContext.a))); } - std::vector pointsSmoothed(sampleCount * 2); - auto smoothedVertexCount = SmoothWave(pointsTransformed.data(), sampleCount, pointsSmoothed.data()); + SmoothWave(points, colors); #ifndef USE_GLES glDisable(GL_LINE_SMOOTH); @@ -172,14 +163,13 @@ void CustomWaveform::Draw(const PerFrameContext& presetPerFrameContext) glLineWidth(1); // Additive wave drawing (vice overwrite) - glEnable(GL_BLEND); if (m_additive) { - glBlendFunc(GL_SRC_ALPHA, GL_ONE); + Renderer::BlendMode::Set(true, Renderer::BlendMode::Function::SourceAlpha, Renderer::BlendMode::Function::One); } else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + Renderer::BlendMode::Set(true, Renderer::BlendMode::Function::SourceAlpha, Renderer::BlendMode::Function::OneMinusSourceAlpha); } auto shader = m_presetState.untexturedShader.lock(); @@ -192,10 +182,9 @@ void CustomWaveform::Draw(const PerFrameContext& presetPerFrameContext) auto incrementX = 1.0f / static_cast(m_presetState.renderContext.viewportSizeX); auto incrementY = 1.0f / static_cast(m_presetState.renderContext.viewportSizeX); - GLuint drawType = m_useDots ? GL_POINTS : GL_LINE_STRIP; + size_t smoothedVertexCount = m_mesh.Indices().Size(); - glBindVertexArray(m_vaoID); - glBindBuffer(GL_ARRAY_BUFFER, m_vboID); + auto& vertices = m_mesh.Vertices(); // If thick outline is used, draw the shape four times with slight offsets // (top left, top right, bottom right, bottom left). @@ -208,37 +197,34 @@ void CustomWaveform::Draw(const PerFrameContext& presetPerFrameContext) break; case 1: - for (auto j = 0; j < smoothedVertexCount; j++) + for (size_t j = 0; j < smoothedVertexCount; j++) { - pointsSmoothed[j].x += incrementX; + vertices[j].SetX(vertices[j].X() + incrementX); } break; case 2: - for (auto j = 0; j < smoothedVertexCount; j++) + for (size_t j = 0; j < smoothedVertexCount; j++) { - pointsSmoothed[j].y += incrementY; + vertices[j].SetY(vertices[j].Y() + incrementY); } break; case 3: - for (auto j = 0; j < smoothedVertexCount; j++) + for (size_t j = 0; j < smoothedVertexCount; j++) { - pointsSmoothed[j].x -= incrementX; + vertices[j].SetX(vertices[j].X() - incrementX); } break; } - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(ColoredPoint) * smoothedVertexCount, pointsSmoothed.data()); - glDrawArrays(drawType, 0, smoothedVertexCount); + m_mesh.Update(); + m_mesh.Draw(); } - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - + m_mesh.Unbind(); Renderer::Shader::Unbind(); - - glDisable(GL_BLEND); + Renderer::BlendMode::SetBlendActive(false); } void CustomWaveform::LoadPerFrameEvaluationVariables(const PerFrameContext& presetPerFrameContext) @@ -272,9 +258,7 @@ void CustomWaveform::LoadPerPointEvaluationVariables(float sample, float value1, *m_perPointContext.a = *m_perFrameContext.a; } -int CustomWaveform::SmoothWave(const CustomWaveform::ColoredPoint* inputVertices, - int vertexCount, - CustomWaveform::ColoredPoint* outputVertices) +void CustomWaveform::SmoothWave(const std::vector& points, const std::vector& colors) { constexpr float c1{-0.15f}; constexpr float c2{1.15f}; @@ -282,25 +266,36 @@ int CustomWaveform::SmoothWave(const CustomWaveform::ColoredPoint* inputVertices constexpr float c4{-0.15f}; constexpr float inverseSum{1.0f / (c1 + c2 + c3 + c4)}; - int outputIndex = 0; - int iBelow = 0; - int iAbove2 = 1; + size_t outputIndex = 0; + size_t iBelow = 0; + size_t iAbove2 = 1; + + size_t vertexCount = points.size(); + + auto& outVertices = m_mesh.Vertices(); + auto& outColors = m_mesh.Colors(); - for (auto inputIndex = 0; inputIndex < vertexCount - 1; inputIndex++) + for (size_t inputIndex = 0; inputIndex < vertexCount - 1; inputIndex++) { - int const iAbove = iAbove2; + size_t const iAbove = iAbove2; iAbove2 = std::min(vertexCount - 1, inputIndex + 2); - outputVertices[outputIndex] = inputVertices[inputIndex]; - outputVertices[outputIndex + 1] = inputVertices[inputIndex]; - outputVertices[outputIndex + 1].x = (c1 * inputVertices[iBelow].x + c2 * inputVertices[inputIndex].x + c3 * inputVertices[iAbove].x + c4 * inputVertices[iAbove2].x) * inverseSum; - outputVertices[outputIndex + 1].y = (c1 * inputVertices[iBelow].y + c2 * inputVertices[inputIndex].y + c3 * inputVertices[iAbove].y + c4 * inputVertices[iAbove2].y) * inverseSum; + outVertices[outputIndex] = points[inputIndex]; + outColors[outputIndex] = colors[inputIndex]; + outColors[outputIndex + 1] = colors[inputIndex]; + auto& smoothedPoint = outVertices[outputIndex + 1]; + smoothedPoint = points[inputIndex]; + smoothedPoint.SetX((c1 * points[iBelow].X() + c2 * points[inputIndex].X() + c3 * points[iAbove].X() + c4 * points[iAbove2].X()) * inverseSum); + smoothedPoint.SetY((c1 * points[iBelow].Y() + c2 * points[inputIndex].Y() + c3 * points[iAbove].Y() + c4 * points[iAbove2].Y()) * inverseSum); iBelow = inputIndex; outputIndex += 2; } - outputVertices[outputIndex] = inputVertices[vertexCount - 1]; + outVertices[outputIndex] = points[vertexCount - 1]; + outColors[outputIndex] = colors[vertexCount - 1]; - return outputIndex + 1; + auto& indices = m_mesh.Indices(); + indices.Resize(outputIndex + 1); + indices.MakeContinuous(); } } // namespace MilkdropPreset diff --git a/src/libprojectM/MilkdropPreset/CustomWaveform.hpp b/src/libprojectM/MilkdropPreset/CustomWaveform.hpp index 31d2bfae0c..e82687ae91 100644 --- a/src/libprojectM/MilkdropPreset/CustomWaveform.hpp +++ b/src/libprojectM/MilkdropPreset/CustomWaveform.hpp @@ -3,7 +3,9 @@ #include "WaveformPerFrameContext.hpp" #include "WaveformPerPointContext.hpp" -#include +#include +#include +#include "Renderer/Point.hpp" #include @@ -13,7 +15,7 @@ class PresetFileParser; namespace MilkdropPreset { -class CustomWaveform : public Renderer::RenderItem +class CustomWaveform { public: @@ -23,11 +25,6 @@ class CustomWaveform : public Renderer::RenderItem */ explicit CustomWaveform(PresetState& presetState); - /** - * @brief Initializes the waveform's vertex buffer and attribute data. - */ - void InitVertexAttrib() override; - /** * @brief Loads the initial values and code from the preset file. * @param parsedFile The file parser with the preset data. @@ -73,15 +70,13 @@ class CustomWaveform : public Renderer::RenderItem * * Roughly doubles the number of points. * - * @param inputVertices Pointer to an array of vertices to be smoothed. - * @param vertexCount Number of vertices/points in the input data. - * @param outputVertices Pointer to a buffer that will receive the smoothed data. Must be able to hold 2 * vertexCount vertices. - * @return The number of vertices in outputVertices after smoothing. + * @param points A vector of points to be smoothed. + * @param colors A vector of colors for the points. */ - static int SmoothWave(const ColoredPoint* inputVertices, int vertexCount, ColoredPoint* outputVertices); + void SmoothWave(const std::vector& points, const std::vector& colors); int m_index{0}; //!< Custom waveform index in the preset. - int m_enabled{0}; //!< Render waveform if non-zero. + bool m_enabled{false}; //!< Render waveform if non-zero. int m_samples{WaveformMaxPoints}; //!< Number of samples/vertices in the waveform. int m_sep{0}; //!< Separation distance of dual waveforms. float m_scaling{1.0f}; //!< Scale factor of waveform. @@ -103,7 +98,7 @@ class CustomWaveform : public Renderer::RenderItem WaveformPerFrameContext m_perFrameContext; //!< Holds the code execution context for per-frame expressions WaveformPerPointContext m_perPointContext; //!< Holds the code execution context for per-point expressions - std::vector m_points; //!< Points in this waveform. + Renderer::Mesh m_mesh; //!< Points in this waveform. friend class WaveformPerFrameContext; friend class WaveformPerPointContext; diff --git a/src/libprojectM/MilkdropPreset/DarkenCenter.cpp b/src/libprojectM/MilkdropPreset/DarkenCenter.cpp index 64899b3242..c550afc3ea 100644 --- a/src/libprojectM/MilkdropPreset/DarkenCenter.cpp +++ b/src/libprojectM/MilkdropPreset/DarkenCenter.cpp @@ -1,57 +1,52 @@ #include "DarkenCenter.hpp" +#include + namespace libprojectM { namespace MilkdropPreset { DarkenCenter::DarkenCenter(PresetState& presetState) - : RenderItem() - , m_presetState(presetState) -{ - RenderItem::Init(); -} - -void DarkenCenter::InitVertexAttrib() + : m_presetState(presetState) + , m_mesh(Renderer::VertexBufferUsage::StaticDraw, true, false) { - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(ColoredPoint), nullptr); // points - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(ColoredPoint), reinterpret_cast(offsetof(ColoredPoint, r))); // colors + m_mesh.SetRenderPrimitiveType(Renderer::Mesh::PrimitiveType::TriangleFan); + m_mesh.SetVertexCount(6); + m_mesh.Colors().Set({{0.0f, 0.0f, 0.0f, 3.0f / 32.0f}, + {0.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 0.0f}}); + m_mesh.Update(); } void DarkenCenter::Draw() { - glBindVertexArray(m_vaoID); - if (m_presetState.renderContext.aspectY != m_aspectY) { m_aspectY = m_presetState.renderContext.aspectY; // Update mesh with new aspect ratio if needed - float const halfSize = 0.05f; - std::array vertices = {{{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 3.0f / 32.0f}, - {0.0f - halfSize * m_aspectY, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 0.0f - halfSize, 0.0f, 0.0f, 0.0f, 0.0f}, - {0.0f + halfSize * m_aspectY, 0.0, 0.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 0.0f + halfSize, 0.0f, 0.0f, 0.0f, 0.0f}, - {0.0f - halfSize * m_aspectY, 0.0, 0.0f, 0.0f, 0.0f, 0.0f}}}; - - glBindBuffer(GL_ARRAY_BUFFER, m_vboID); - glBufferData(GL_ARRAY_BUFFER, sizeof(ColoredPoint) * vertices.size(), vertices.data(), GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); + constexpr float halfSize = 0.05f; + m_mesh.Vertices().Set({{0.0f, 0.0f}, + {0.0f - halfSize * m_aspectY, 0.0f}, + {0.0f, 0.0f - halfSize}, + {0.0f + halfSize * m_aspectY, 0.0f}, + {0.0f, 0.0f + halfSize}, + {0.0f - halfSize * m_aspectY, 0.0f}}); + m_mesh.Update(); } - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + Renderer::BlendMode::Set(true, Renderer::BlendMode::Function::SourceAlpha, Renderer::BlendMode::Function::OneMinusSourceAlpha); auto shader = m_presetState.untexturedShader.lock(); shader->Bind(); shader->SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection); - glDrawArrays(GL_TRIANGLE_FAN, 0, 6); + m_mesh.Draw(); - glDisable(GL_BLEND); - glBindVertexArray(0); + Renderer::BlendMode::SetBlendActive(false); + Renderer::Mesh::Unbind(); Renderer::Shader::Unbind(); } diff --git a/src/libprojectM/MilkdropPreset/DarkenCenter.hpp b/src/libprojectM/MilkdropPreset/DarkenCenter.hpp index 3f04012f7b..b6921d1a07 100644 --- a/src/libprojectM/MilkdropPreset/DarkenCenter.hpp +++ b/src/libprojectM/MilkdropPreset/DarkenCenter.hpp @@ -2,7 +2,7 @@ #include "PresetState.hpp" -#include +#include namespace libprojectM { namespace MilkdropPreset { @@ -10,15 +10,13 @@ namespace MilkdropPreset { /** * @brief Darkens the screen center a bit on each frame. */ -class DarkenCenter : public Renderer::RenderItem +class DarkenCenter { public: DarkenCenter() = delete; explicit DarkenCenter(PresetState& presetState); - void InitVertexAttrib(); - /** * Applies the darkening area. */ @@ -26,7 +24,8 @@ class DarkenCenter : public Renderer::RenderItem private: PresetState& m_presetState; //!< The global preset state. - float m_aspectY{}; //!< Previous Y aspect ration. + Renderer::Mesh m_mesh; //!< The "diamond" mesh. + float m_aspectY{}; //!< Previous Y aspect ratio. }; } // namespace MilkdropPreset diff --git a/src/libprojectM/MilkdropPreset/Filters.cpp b/src/libprojectM/MilkdropPreset/Filters.cpp index 472a0e70b5..c84d9784be 100644 --- a/src/libprojectM/MilkdropPreset/Filters.cpp +++ b/src/libprojectM/MilkdropPreset/Filters.cpp @@ -1,21 +1,18 @@ #include "Filters.hpp" +#include + +using libprojectM::Renderer::BlendMode; + namespace libprojectM { namespace MilkdropPreset { Filters::Filters(const PresetState& presetState) - : RenderItem() - , m_presetState(presetState) + : m_presetState(presetState) + , m_filterMesh(Renderer::VertexBufferUsage::StaticDraw) { - RenderItem::Init(); -} - -void Filters::InitVertexAttrib() -{ - glEnableVertexAttribArray(0); - glDisableVertexAttribArray(1); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Point), reinterpret_cast(offsetof(Point, x))); + m_filterMesh.SetRenderPrimitiveType(Renderer::Mesh::PrimitiveType::TriangleStrip); + m_filterMesh.SetVertexCount(4); } void Filters::Draw() @@ -27,13 +24,12 @@ void Filters::Draw() return; } - glEnable(GL_BLEND); + BlendMode::SetBlendActive(true); auto shader = m_presetState.untexturedShader.lock(); shader->Bind(); shader->SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection); - glBindVertexArray(m_vaoID); glVertexAttrib4f(1, 1.0, 1.0, 1.0, 1.0); if (m_presetState.brighten) @@ -53,42 +49,41 @@ void Filters::Draw() Invert(); } - glBindVertexArray(0); - + Renderer::Mesh::Unbind(); Renderer::Shader::Unbind(); - glDisable(GL_BLEND); + BlendMode::SetBlendActive(false); } void Filters::Brighten() { - glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glBlendFunc(GL_ZERO, GL_DST_COLOR); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + BlendMode::SetBlendFunction(BlendMode::Function::OneMinusDestinationColor, BlendMode::Function::Zero); + m_filterMesh.Draw(); + BlendMode::SetBlendFunction(BlendMode::Function::Zero, BlendMode::Function::DestinationColor); + m_filterMesh.Draw(); + BlendMode::SetBlendFunction(BlendMode::Function::OneMinusDestinationColor, BlendMode::Function::Zero); + m_filterMesh.Draw(); } void Filters::Darken() { - glBlendFunc(GL_ZERO, GL_DST_COLOR); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + BlendMode::SetBlendFunction(BlendMode::Function::Zero, BlendMode::Function::DestinationColor); + m_filterMesh.Draw(); } void Filters::Solarize() { - glBlendFunc(GL_ZERO, GL_ONE_MINUS_DST_COLOR); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glBlendFunc(GL_DST_COLOR, GL_ONE); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + BlendMode::SetBlendFunction(BlendMode::Function::Zero, BlendMode::Function::OneMinusDestinationColor); + m_filterMesh.Draw(); + BlendMode::SetBlendFunction(BlendMode::Function::DestinationColor, BlendMode::Function::One); + m_filterMesh.Draw(); } void Filters::Invert() { - glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + BlendMode::SetBlendFunction(BlendMode::Function::OneMinusDestinationColor, BlendMode::Function::Zero); + m_filterMesh.Draw(); } void Filters::UpdateMesh() @@ -102,24 +97,14 @@ void Filters::UpdateMesh() m_viewportWidth = m_presetState.renderContext.viewportSizeX; m_viewportHeight = m_presetState.renderContext.viewportSizeY; - std::array points; - float const fOnePlusInvWidth = 1.0f + 1.0f / static_cast(m_viewportWidth); float const fOnePlusInvHeight = 1.0f + 1.0f / static_cast(m_viewportHeight); - points[0].x = -fOnePlusInvWidth; - points[1].x = fOnePlusInvWidth; - points[2].x = -fOnePlusInvWidth; - points[3].x = fOnePlusInvWidth; - points[0].y = fOnePlusInvHeight; - points[1].y = fOnePlusInvHeight; - points[2].y = -fOnePlusInvHeight; - points[3].y = -fOnePlusInvHeight; - - glBindVertexArray(m_vaoID); - glBindBuffer(GL_ARRAY_BUFFER, m_vboID); - glBufferData(GL_ARRAY_BUFFER, sizeof(points), points.data(), GL_STATIC_DRAW); - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); + m_filterMesh.Vertices().Set({{-fOnePlusInvWidth, fOnePlusInvHeight}, + {fOnePlusInvWidth, fOnePlusInvHeight}, + {-fOnePlusInvWidth, -fOnePlusInvHeight}, + {fOnePlusInvWidth, -fOnePlusInvHeight}}); + + m_filterMesh.Update(); } } // namespace MilkdropPreset diff --git a/src/libprojectM/MilkdropPreset/Filters.hpp b/src/libprojectM/MilkdropPreset/Filters.hpp index c00084654d..1decfcafb8 100644 --- a/src/libprojectM/MilkdropPreset/Filters.hpp +++ b/src/libprojectM/MilkdropPreset/Filters.hpp @@ -2,7 +2,7 @@ #include "PresetState.hpp" -#include +#include namespace libprojectM { namespace MilkdropPreset { @@ -10,14 +10,12 @@ namespace MilkdropPreset { /** * @brief Classic Milkdrop 1 postprocessing effects. */ -class Filters : public Renderer::RenderItem +class Filters { public: Filters() = delete; explicit Filters(const PresetState& presetState); - void InitVertexAttrib(); - /** * @brief Applies the configured filters to the current output. */ @@ -48,6 +46,8 @@ class Filters : public Renderer::RenderItem const PresetState& m_presetState; //!< The global preset state. + Renderer::Mesh m_filterMesh; + int m_viewportWidth{}; //!< Last known viewport width int m_viewportHeight{}; //!< Last known viewport height }; diff --git a/src/libprojectM/MilkdropPreset/FinalComposite.cpp b/src/libprojectM/MilkdropPreset/FinalComposite.cpp index 549c950437..bb58992b38 100644 --- a/src/libprojectM/MilkdropPreset/FinalComposite.cpp +++ b/src/libprojectM/MilkdropPreset/FinalComposite.cpp @@ -2,6 +2,8 @@ #include "PresetState.hpp" +#include + #include #ifdef MILKDROP_PRESET_DEBUG @@ -14,28 +16,23 @@ namespace MilkdropPreset { static std::string const defaultCompositeShader = "shader_body\n{\nret = tex2D(sampler_main, uv).xyz;\n}"; FinalComposite::FinalComposite() + : m_compositeMesh(Renderer::VertexBufferUsage::StreamDraw, true, true) { - RenderItem::Init(); -} - -void FinalComposite::InitVertexAttrib() -{ - glGenBuffers(1, &m_elementBuffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuffer); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - glEnableVertexAttribArray(3); + m_compositeMesh.SetRenderPrimitiveType(Renderer::Mesh::PrimitiveType::Triangles); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), nullptr); // Positions - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast(offsetof(MeshVertex, r))); // Colors - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast(offsetof(MeshVertex, u))); // Textures - glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast(offsetof(MeshVertex, radius))); // Radius/Angle + // Add attribute array for radius and angle information to the mesh. + m_compositeMesh.Bind(); + m_radiusAngle.Bind(); + m_radiusAngle.Resize(vertexCount); + m_radiusAngle.InitializeAttributePointer(3); + Renderer::VertexBuffer::SetEnableAttributeArray(3, true); // Pre-allocate vertex and index buffers - glBufferData(GL_ARRAY_BUFFER, sizeof(MeshVertex) * vertexCount, m_vertices.data(), GL_STREAM_DRAW); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * m_indices.size(), m_indices.data(), GL_STREAM_DRAW); + m_compositeMesh.SetVertexCount(vertexCount); + m_compositeMesh.Indices().Resize(indexCount); + m_compositeMesh.Update(); + + Renderer::Mesh::Unbind(); } void FinalComposite::LoadCompositeShader(const PresetState& presetState) @@ -58,7 +55,7 @@ void FinalComposite::LoadCompositeShader(const PresetState& presetState) std::cerr << "[Composite Shader] Error loading composite warp shader code:" << ex.message() << std::endl; std::cerr << "[Composite Shader] Using fallback shader." << std::endl; #else - (void)ex; // silence unused parameter warning + (void) ex; // silence unused parameter warning #endif // Fall back to default shader m_compositeShader = std::make_unique(MilkdropShader::ShaderType::CompositeShader); @@ -104,7 +101,7 @@ void FinalComposite::CompileCompositeShader(PresetState& presetState) std::cerr << "[Composite Shader] Error compiling composite warp shader code:" << ex.message() << std::endl; std::cerr << "[Composite Shader] Using fallback shader." << std::endl; #else - (void)ex; // silence unused parameter warning + (void) ex; // silence unused parameter warning #endif // Fall back to default shader m_compositeShader = std::make_unique(MilkdropShader::ShaderType::CompositeShader); @@ -122,15 +119,11 @@ void FinalComposite::Draw(const PresetState& presetState, const PerFrameContext& ApplyHueShaderColors(presetState); // Render the grid - glDisable(GL_BLEND); - glBindVertexArray(m_vaoID); - glBindBuffer(GL_ARRAY_BUFFER, m_vboID); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(MeshVertex) * vertexCount, m_vertices.data()); - glBindBuffer(GL_ARRAY_BUFFER, 0); - + Renderer::BlendMode::SetBlendActive(false); m_compositeShader->LoadVariables(presetState, perFrameContext); - glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, nullptr); + m_compositeMesh.Draw(); + Renderer::Mesh::Unbind(); } else { @@ -142,7 +135,6 @@ void FinalComposite::Draw(const PresetState& presetState, const PerFrameContext& } } - glBindVertexArray(0); Renderer::Shader::Unbind(); } @@ -167,6 +159,9 @@ void FinalComposite::InitializeMesh(const PresetState& presetState) constexpr float PI = 3.1415926535898f; + auto& vertices = m_compositeMesh.Vertices(); + auto& uvs = m_compositeMesh.UVs(); + for (int gridY = 0; gridY < compositeGridHeight; gridY++) { int const gridY2 = gridY - gridY / (compositeGridHeight / 2); @@ -179,13 +174,12 @@ void FinalComposite::InitializeMesh(const PresetState& presetState) float const u = SquishToCenter(gridX2 * dividedByX, 3.0f); float const sx = u * 2.0f - 1.0f; - auto& vertex = m_vertices.at(gridX + gridY * compositeGridWidth); + const size_t vertexIndex = gridX + gridY * compositeGridWidth; - vertex.x = sx; - vertex.y = sy; + vertices[vertexIndex] = {sx, sy}; - float rad; - float ang; + float rad{}; + float ang{}; UvToMathSpace(presetState.renderContext.aspectX, presetState.renderContext.aspectY, u, v, rad, ang); @@ -251,16 +245,16 @@ void FinalComposite::InitializeMesh(const PresetState& presetState) ang = PI * 0.0f; } } - vertex.u = u + halfTexelWidth; - vertex.v = v + halfTexelHeight; + uvs[vertexIndex] = {u + halfTexelWidth, + v + halfTexelHeight}; - vertex.radius = rad; - vertex.angle = ang; + m_radiusAngle[vertexIndex] = {rad, ang}; } } // build index list for final composite blit - // order should be friendly for interpolation of 'ang' value! + auto& indices = m_compositeMesh.Indices(); int currentIndex = 0; for (int gridY = 0; gridY < compositeGridHeight - 1; gridY++) { @@ -283,32 +277,30 @@ void FinalComposite::InitializeMesh(const PresetState& presetState) if ((static_cast(leftHalf) + static_cast(topHalf) + static_cast(center4)) % 2 == 1) { - m_indices[currentIndex + 0] = gridY * compositeGridWidth + gridX; - m_indices[currentIndex + 1] = gridY * compositeGridWidth + gridX + 1; - m_indices[currentIndex + 2] = (gridY + 1) * compositeGridWidth + gridX + 1; - m_indices[currentIndex + 3] = (gridY + 1) * compositeGridWidth + gridX + 1; - m_indices[currentIndex + 4] = (gridY + 1) * compositeGridWidth + gridX; - m_indices[currentIndex + 5] = gridY * compositeGridWidth + gridX; + indices[currentIndex + 0] = gridY * compositeGridWidth + gridX; + indices[currentIndex + 1] = gridY * compositeGridWidth + gridX + 1; + indices[currentIndex + 2] = (gridY + 1) * compositeGridWidth + gridX + 1; + indices[currentIndex + 3] = (gridY + 1) * compositeGridWidth + gridX + 1; + indices[currentIndex + 4] = (gridY + 1) * compositeGridWidth + gridX; + indices[currentIndex + 5] = gridY * compositeGridWidth + gridX; } else { - m_indices[currentIndex + 0] = (gridY + 1) * compositeGridWidth + (gridX); - m_indices[currentIndex + 1] = (gridY) *compositeGridWidth + (gridX); - m_indices[currentIndex + 2] = (gridY) *compositeGridWidth + (gridX + 1); - m_indices[currentIndex + 3] = (gridY) *compositeGridWidth + (gridX + 1); - m_indices[currentIndex + 4] = (gridY + 1) * compositeGridWidth + (gridX + 1); - m_indices[currentIndex + 5] = (gridY + 1) * compositeGridWidth + (gridX); + indices[currentIndex + 0] = (gridY + 1) * compositeGridWidth + (gridX); + indices[currentIndex + 1] = (gridY) *compositeGridWidth + (gridX); + indices[currentIndex + 2] = (gridY) *compositeGridWidth + (gridX + 1); + indices[currentIndex + 3] = (gridY) *compositeGridWidth + (gridX + 1); + indices[currentIndex + 4] = (gridY + 1) * compositeGridWidth + (gridX + 1); + indices[currentIndex + 5] = (gridY + 1) * compositeGridWidth + (gridX); } currentIndex += 6; } } - // Store indices. - // ToDo: Probably don't need to store m_indices - glBindVertexArray(m_vaoID); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * m_indices.size(), m_indices.data()); - glBindVertexArray(0); + // Update mesh geometry and indices. + m_compositeMesh.Update(); + m_radiusAngle.Update(); } float FinalComposite::SquishToCenter(float x, float exponent) @@ -366,13 +358,16 @@ void FinalComposite::ApplyHueShaderColors(const PresetState& presetState) } // Interpolate and apply to all grid vertices. + auto& vertices = m_compositeMesh.Vertices(); + auto& colors = m_compositeMesh.Colors(); + for (int gridY = 0; gridY < compositeGridHeight; gridY++) { for (int gridX = 0; gridX < compositeGridWidth; gridX++) { - auto& vertex = m_vertices[gridX + gridY * compositeGridWidth]; - float x = vertex.x * 0.5f + 0.5f; - float y = vertex.y * 0.5f + 0.5f; + auto vertexIndex = gridX + gridY * compositeGridWidth; + float x = vertices[vertexIndex].X() * 0.5f + 0.5f; + float y = vertices[vertexIndex].Y() * 0.5f + 0.5f; std::array color{{1.0f, 1.0f, 1.0f}}; for (int col = 0; col < 3; col++) @@ -383,12 +378,16 @@ void FinalComposite::ApplyHueShaderColors(const PresetState& presetState) shade[3][col] * (1 - x) * (1 - y); } - vertex.r = color[0]; - vertex.g = color[1]; - vertex.b = color[2]; - vertex.a = 1.0f; + colors[vertexIndex] = {color[0], + color[1], + color[2], + 1.0f}; } } + + // Only update color buffer. + m_compositeMesh.Bind(); + m_compositeMesh.Colors().Update(); } } // namespace MilkdropPreset diff --git a/src/libprojectM/MilkdropPreset/FinalComposite.hpp b/src/libprojectM/MilkdropPreset/FinalComposite.hpp index b9cf50b400..9701447706 100644 --- a/src/libprojectM/MilkdropPreset/FinalComposite.hpp +++ b/src/libprojectM/MilkdropPreset/FinalComposite.hpp @@ -4,9 +4,8 @@ #include "MilkdropShader.hpp" #include "VideoEcho.hpp" -#include +#include -#include #include namespace libprojectM { @@ -15,13 +14,11 @@ namespace MilkdropPreset { /** * @brief Draws the final composite effect, either a shader or Milkdrop 1 effects. */ -class FinalComposite : public Renderer::RenderItem +class FinalComposite { public: FinalComposite(); - void InitVertexAttrib() override; - /** * @brief Loads the composite shader, if the preset uses one. * @param presetState The preset state to retrieve the shader from. @@ -90,16 +87,15 @@ class FinalComposite : public Renderer::RenderItem static constexpr int vertexCount{compositeGridWidth * compositeGridHeight}; static constexpr int indexCount{(compositeGridWidth - 2) * (compositeGridHeight - 2) * 6}; - GLuint m_elementBuffer{}; //!< Element buffer holding the draw indices. - std::array m_vertices{}; //!< Composite grid vertices - std::array m_indices{}; //!< Composite grid draw indices + Renderer::Mesh m_compositeMesh; //!< The composite shader mesh. + Renderer::VertexBuffer m_radiusAngle{Renderer::VertexBufferUsage::StreamDraw}; //!< Additional vertex attribute array for radius and angle. int m_viewportWidth{}; //!< Last known viewport width. int m_viewportHeight{}; //!< Last known viewport height. std::unique_ptr m_compositeShader; //!< The composite shader. Either preset-defined or empty. - std::unique_ptr m_videoEcho; //!< Video echo effect. Used if no composite shader is loaded and video echo is enabled. - std::unique_ptr m_filters; //!< Color post-processing filters. Used if no composite shader is loaded. + std::unique_ptr m_videoEcho; //!< Video echo effect. Used if no composite shader is loaded and video echo is enabled. + std::unique_ptr m_filters; //!< Color post-processing filters. Used if no composite shader is loaded. }; } // namespace MilkdropPreset diff --git a/src/libprojectM/MilkdropPreset/MotionVectors.cpp b/src/libprojectM/MilkdropPreset/MotionVectors.cpp index 3ec34e17e6..5cd31b111b 100644 --- a/src/libprojectM/MilkdropPreset/MotionVectors.cpp +++ b/src/libprojectM/MilkdropPreset/MotionVectors.cpp @@ -2,27 +2,20 @@ #include "MilkdropStaticShaders.hpp" +#include #include #include +#include + namespace libprojectM { namespace MilkdropPreset { MotionVectors::MotionVectors(PresetState& presetState) - : RenderItem() - , m_presetState(presetState) + : m_presetState(presetState) + , m_motionVectorMesh(Renderer::VertexBufferUsage::StreamDraw) { - RenderItem::Init(); -} - -void MotionVectors::InitVertexAttrib() -{ - glEnableVertexAttribArray(0); - glDisableVertexAttribArray(1); - glEnableVertexAttribArray(2); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(MotionVectorVertex), reinterpret_cast(offsetof(MotionVectorVertex, x))); - glVertexAttribIPointer(2, 1, GL_INT, sizeof(MotionVectorVertex), reinterpret_cast(offsetof(MotionVectorVertex, index))); + m_motionVectorMesh.SetRenderPrimitiveType(Renderer::Mesh::PrimitiveType::Lines); } void MotionVectors::Draw(const PerFrameContext& presetPerFrameContext, std::shared_ptr motionTexture) @@ -59,22 +52,8 @@ void MotionVectors::Draw(const PerFrameContext& presetPerFrameContext, std::shar auto const divertY2 = static_cast(*presetPerFrameContext.mv_dy); // Clamp X/Y diversions to 0..1 - if (divertX < 0.0f) - { - divertX = 0.0f; - } - if (divertX > 1.0f) - { - divertX = 1.0f; - } - if (divertY < 0.0f) - { - divertY = 0.0f; - } - if (divertY > 1.0f) - { - divertY = 1.0f; - } + divertX = std::min(1.0f, std::max(0.0f, divertX)); + divertY = std::min(1.0f, std::max(0.0f, divertY)); // Tweaked this a bit to ensure lines are always at least a bit more than 1px long. // Line smoothing makes some of them disappear otherwise. @@ -82,10 +61,9 @@ void MotionVectors::Draw(const PerFrameContext& presetPerFrameContext, std::shar float const inverseHeight = 1.25f / static_cast(m_presetState.renderContext.viewportSizeY); float const minimumLength = sqrtf(inverseWidth * inverseWidth + inverseHeight * inverseHeight); - std::vector lineVertices(static_cast(countX + 1) * 2); // countX + 1 lines for each grid row, 2 vertices each. + m_motionVectorMesh.SetVertexCount(static_cast(countX + 1) * 2); // countX + 1 lines for each grid row, 2 vertices each. - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + Renderer::BlendMode::Set(true, Renderer::BlendMode::Function::SourceAlpha, Renderer::BlendMode::Function::OneMinusSourceAlpha); auto shader = GetShader(); shader->Bind(); @@ -103,14 +81,13 @@ void MotionVectors::Draw(const PerFrameContext& presetPerFrameContext, std::shar static_cast(*presetPerFrameContext.mv_b), static_cast(*presetPerFrameContext.mv_a)); - glBindVertexArray(m_vaoID); - glBindBuffer(GL_ARRAY_BUFFER, m_vboID); - glLineWidth(1); #ifndef USE_GLES glEnable(GL_LINE_SMOOTH); #endif + auto& lineVertices = m_motionVectorMesh.Vertices(); + for (int y = 0; y < countY; y++) { float const posY = (static_cast(y) + 0.25f) / (static_cast(countY) + divertY + 0.25f - 1.0f) - divertY2; @@ -124,41 +101,26 @@ void MotionVectors::Draw(const PerFrameContext& presetPerFrameContext, std::shar if (posX > 0.0001f && posX < 0.9999f) { - lineVertices[vertex].x = posX; - lineVertices[vertex].y = posY; - lineVertices[vertex].index = vertex; - - lineVertices[vertex + 1] = lineVertices[vertex]; - lineVertices[vertex + 1].index++; + lineVertices[vertex + 1] = lineVertices[vertex] = {posX, posY}; vertex += 2; } } // Draw a row of lines. - if (m_lastVertexCount >= vertex) - { - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(MotionVectorVertex) * vertex, lineVertices.data()); - } - else - { - glBufferData(GL_ARRAY_BUFFER, sizeof(MotionVectorVertex) * vertex, lineVertices.data(), GL_STREAM_DRAW); - m_lastVertexCount = vertex; - } - glDrawArrays(GL_LINES, 0, static_cast(vertex)); + m_motionVectorMesh.Update(); + m_motionVectorMesh.Draw(); } } - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); + Renderer::Mesh::Unbind(); + Renderer::Shader::Unbind(); #ifndef USE_GLES glDisable(GL_LINE_SMOOTH); #endif - Renderer::Shader::Unbind(); - - glDisable(GL_BLEND); + Renderer::BlendMode::SetBlendActive(false); } std::shared_ptr MotionVectors::GetShader() diff --git a/src/libprojectM/MilkdropPreset/MotionVectors.hpp b/src/libprojectM/MilkdropPreset/MotionVectors.hpp index 4782e03ade..93e44124b2 100644 --- a/src/libprojectM/MilkdropPreset/MotionVectors.hpp +++ b/src/libprojectM/MilkdropPreset/MotionVectors.hpp @@ -3,7 +3,7 @@ #include "PerFrameContext.hpp" #include "PresetState.hpp" -#include +#include #include @@ -13,21 +13,18 @@ namespace MilkdropPreset { /** * @brief Draws a flexible motion vector field. * - * This is broken right now, as it only renders a relatively static 1px point grid, with no apparent motion trails. - * Milkdrop renders this as lines with trails. - * - * @todo Reverse-engineer the original Milkdrop code and reimplement it properly. - * https://github.com/projectM-visualizer/milkdrop2/blob/f05b0d811a87a17c4624170c26c93bac39b05bde/src/vis_milk2/milkdropfs.cpp#L1239 + * Uses the same drawing logic as Milkdrop, but instead of reverse-propagating the motion data + * on the CPU, projectM does this within the Motion Vector vertex shader. The Warp effect draws the + * final U/V coordinates to a float texture, which is then used in the next frame to calculate the + * vector length at the location of the line origin. */ -class MotionVectors : public Renderer::RenderItem +class MotionVectors { public: MotionVectors() = delete; explicit MotionVectors(PresetState& presetState); - void InitVertexAttrib(); - /** * Renders the motion vectors. * @param presetPerFrameContext The per-frame context variables. @@ -36,20 +33,14 @@ class MotionVectors : public Renderer::RenderItem void Draw(const PerFrameContext& presetPerFrameContext, std::shared_ptr motionTexture); private: - struct MotionVectorVertex { - float x{}; - float y{}; - int32_t index{}; - }; - std::shared_ptr GetShader(); PresetState& m_presetState; //!< The global preset state. + Renderer::Mesh m_motionVectorMesh; //!< The Motion Vector geometry. + std::weak_ptr m_motionVectorShader; //!< The motion vector shader, calculates the trace positions in the GPU. std::shared_ptr m_sampler{std::make_shared(GL_CLAMP_TO_EDGE, GL_LINEAR)}; //!< The texture sampler. - - int m_lastVertexCount{}; //!< Number of vertices drawn in the previous draw call. }; } // namespace MilkdropPreset diff --git a/src/libprojectM/MilkdropPreset/PerPixelMesh.cpp b/src/libprojectM/MilkdropPreset/PerPixelMesh.cpp index 5ad57c28d6..54b5d1c26d 100644 --- a/src/libprojectM/MilkdropPreset/PerPixelMesh.cpp +++ b/src/libprojectM/MilkdropPreset/PerPixelMesh.cpp @@ -6,7 +6,8 @@ #include "PerPixelContext.hpp" #include "PresetState.hpp" -#include "Renderer/ShaderCache.hpp" +#include +#include #include #include @@ -18,44 +19,31 @@ namespace libprojectM { namespace MilkdropPreset { -static constexpr uint32_t VerticesPerDrawCall = 1024 * 3; - PerPixelMesh::PerPixelMesh() - : RenderItem() -{ - RenderItem::Init(); -} - -void PerPixelMesh::InitVertexAttrib() + : m_warpMesh(Renderer::VertexBufferUsage::StreamDraw) { - m_drawVertices.resize(VerticesPerDrawCall); // Fixed size, may scale it later depending on GPU caps. - - glGenVertexArrays(1, &m_vaoID); - glGenBuffers(1, &m_vboID); - - glBindVertexArray(m_vaoID); - glBindBuffer(GL_ARRAY_BUFFER, m_vboID); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - glEnableVertexAttribArray(3); - glEnableVertexAttribArray(4); - glEnableVertexAttribArray(5); - - // Only position & texture coordinates are per-vertex, colors are equal all over the grid (used for decay). - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast(offsetof(MeshVertex, x))); // Position, radius & angle - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast(offsetof(MeshVertex, radius))); // Position, radius & angle - glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast(offsetof(MeshVertex, zoom))); // zoom, zoom exponent, rotation & warp - glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast(offsetof(MeshVertex, centerX))); // Center coord - glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast(offsetof(MeshVertex, distanceX))); // Distance - glVertexAttribPointer(5, 2, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), reinterpret_cast(offsetof(MeshVertex, stretchX))); // Stretch - - // Pre-allocate vertex buffer - glBufferData(GL_ARRAY_BUFFER, sizeof(MeshVertex) * m_drawVertices.size(), m_drawVertices.data(), GL_STREAM_DRAW); - - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); + m_warpMesh.SetRenderPrimitiveType(Renderer::Mesh::PrimitiveType::Triangles); + + m_warpMesh.Bind(); + m_radiusAngleBuffer.Bind(); + m_zoomRotWarpBuffer.Bind(); + m_centerBuffer.Bind(); + m_distanceBuffer.Bind(); + m_stretchBuffer.Bind(); + + m_radiusAngleBuffer.InitializeAttributePointer(3); + m_zoomRotWarpBuffer.InitializeAttributePointer(4); + m_centerBuffer.InitializeAttributePointer(5); + m_distanceBuffer.InitializeAttributePointer(6); + m_stretchBuffer.InitializeAttributePointer(7); + + Renderer::VertexBuffer::SetEnableAttributeArray(3, true); + Renderer::VertexBuffer::SetEnableAttributeArray(4, true); + Renderer::VertexBuffer::SetEnableAttributeArray(5, true); + Renderer::VertexBuffer::SetEnableAttributeArray(6, true); + Renderer::VertexBuffer::SetEnableAttributeArray(7, true); + + Renderer::Mesh::Unbind(); } void PerPixelMesh::LoadWarpShader(const PresetState& presetState) @@ -139,9 +127,17 @@ void PerPixelMesh::InitializeMesh(const PresetState& presetState) m_gridSizeX = presetState.renderContext.perPixelMeshX; m_gridSizeY = presetState.renderContext.perPixelMeshY; - // Grid size has changed, reallocate vertex buffers - m_vertices.resize((m_gridSizeX + 1) * (m_gridSizeY + 1)); - m_listIndices.resize(m_gridSizeX * m_gridSizeY * 6); + // Grid size has changed, resize buffers accordingly + const size_t vertexCount = (m_gridSizeX + 1) * (m_gridSizeY + 1); + + m_warpMesh.SetVertexCount(vertexCount); + m_radiusAngleBuffer.Resize(vertexCount); + m_zoomRotWarpBuffer.Resize(vertexCount); + m_centerBuffer.Resize(vertexCount); + m_distanceBuffer.Resize(vertexCount); + m_stretchBuffer.Resize(vertexCount); + + m_warpMesh.Indices().Resize(m_gridSizeX * m_gridSizeY * 6); } else if (m_viewportWidth == presetState.renderContext.viewportSizeX && m_viewportHeight == presetState.renderContext.viewportSizeY) @@ -150,29 +146,29 @@ void PerPixelMesh::InitializeMesh(const PresetState& presetState) return; } - float aspectX = static_cast(presetState.renderContext.aspectX); - float aspectY = static_cast(presetState.renderContext.aspectY); + const float aspectX = presetState.renderContext.aspectX; + const float aspectY = presetState.renderContext.aspectY; // Either viewport size or mesh size changed, reinitialize the vertices. + auto& vertices = m_warpMesh.Vertices(); int vertexIndex{0}; for (int gridY = 0; gridY <= m_gridSizeY; gridY++) { for (int gridX = 0; gridX <= m_gridSizeX; gridX++) { - auto& vertex = m_vertices.at(vertexIndex); - - vertex.x = static_cast(gridX) / static_cast(m_gridSizeX) * 2.0f - 1.0f; - vertex.y = static_cast(gridY) / static_cast(m_gridSizeY) * 2.0f - 1.0f; + const float x = static_cast(gridX) / static_cast(m_gridSizeX) * 2.0f - 1.0f; + const float y = static_cast(gridY) / static_cast(m_gridSizeY) * 2.0f - 1.0f; + vertices[vertexIndex] = {x, y}; // Milkdrop uses sqrtf, but hypotf is probably safer. - vertex.radius = hypotf(vertex.x * aspectX, vertex.y * aspectY); + m_radiusAngleBuffer[vertexIndex].radius = hypotf(x * aspectX, y * aspectY); if (gridY == m_gridSizeY / 2 && gridX == m_gridSizeX / 2) { - vertex.angle = 0.0f; + m_radiusAngleBuffer[vertexIndex].angle = 0.0f; } else { - vertex.angle = atan2f(vertex.y * aspectY, vertex.x * aspectX); + m_radiusAngleBuffer[vertexIndex].angle = atan2f(y * aspectY, x * aspectX); } vertexIndex++; @@ -204,12 +200,12 @@ void PerPixelMesh::InitializeMesh(const PresetState& presetState) // 0 - 1 3 // / / // 2 4 - 5 - m_listIndices.at(vertexListIndex++) = vertex; - m_listIndices.at(vertexListIndex++) = vertex + 1; - m_listIndices.at(vertexListIndex++) = vertex + m_gridSizeX + 1; - m_listIndices.at(vertexListIndex++) = vertex + 1; - m_listIndices.at(vertexListIndex++) = vertex + m_gridSizeX + 1; - m_listIndices.at(vertexListIndex++) = vertex + m_gridSizeX + 2; + m_warpMesh.Indices()[vertexListIndex++] = vertex; + m_warpMesh.Indices()[vertexListIndex++] = vertex + 1; + m_warpMesh.Indices()[vertexListIndex++] = vertex + m_gridSizeX + 1; + m_warpMesh.Indices()[vertexListIndex++] = vertex + 1; + m_warpMesh.Indices()[vertexListIndex++] = vertex + m_gridSizeX + 1; + m_warpMesh.Indices()[vertexListIndex++] = vertex + m_gridSizeX + 2; } } } @@ -232,19 +228,25 @@ void PerPixelMesh::CalculateMesh(const PresetState& presetState, const PerFrameC int vertex = 0; // Can't make this multithreaded as per-pixel code may use gmegabuf or regXX vars. + auto& vertices = m_warpMesh.Vertices(); for (int y = 0; y <= m_gridSizeY; y++) { for (int x = 0; x <= m_gridSizeX; x++) { - auto& curVertex = m_vertices[vertex]; + auto& curVertex = vertices[vertex]; + auto& curRadiusAngle = m_radiusAngleBuffer[vertex]; + auto& curZoomRotWarp = m_zoomRotWarpBuffer[vertex]; + auto& curCenter = m_centerBuffer[vertex]; + auto& curDistance = m_distanceBuffer[vertex]; + auto& curStretch = m_stretchBuffer[vertex]; // Execute per-vertex/per-pixel code if the preset uses it. if (perPixelContext.perPixelCodeHandle) { - *perPixelContext.x = static_cast(curVertex.x * 0.5f * presetState.renderContext.aspectX + 0.5f); - *perPixelContext.y = static_cast(curVertex.y * -0.5f * presetState.renderContext.aspectY + 0.5f); - *perPixelContext.rad = static_cast(curVertex.radius); - *perPixelContext.ang = static_cast(curVertex.angle); + *perPixelContext.x = static_cast(curVertex.X() * 0.5f * presetState.renderContext.aspectX + 0.5f); + *perPixelContext.y = static_cast(curVertex.Y() * -0.5f * presetState.renderContext.aspectY + 0.5f); + *perPixelContext.rad = static_cast(curRadiusAngle.radius); + *perPixelContext.ang = static_cast(curRadiusAngle.angle); *perPixelContext.zoom = static_cast(*perFrameContext.zoom); *perPixelContext.zoomexp = static_cast(*perFrameContext.zoomexp); *perPixelContext.rot = static_cast(*perFrameContext.rot); @@ -258,34 +260,38 @@ void PerPixelMesh::CalculateMesh(const PresetState& presetState, const PerFrameC perPixelContext.ExecutePerPixelCode(); - curVertex.zoom = static_cast(*perPixelContext.zoom); - curVertex.zoomExp = static_cast(*perPixelContext.zoomexp); - curVertex.rot = static_cast(*perPixelContext.rot); - curVertex.warp = static_cast(*perPixelContext.warp); - curVertex.centerX = static_cast(*perPixelContext.cx); - curVertex.centerY = static_cast(*perPixelContext.cy); - curVertex.distanceX = static_cast(*perPixelContext.dx); - curVertex.distanceY = static_cast(*perPixelContext.dy); - curVertex.stretchX = static_cast(*perPixelContext.sx); - curVertex.stretchY = static_cast(*perPixelContext.sy); + curZoomRotWarp.zoom = static_cast(*perPixelContext.zoom); + curZoomRotWarp.zoomExp = static_cast(*perPixelContext.zoomexp); + curZoomRotWarp.rot = static_cast(*perPixelContext.rot); + curZoomRotWarp.warp = static_cast(*perPixelContext.warp); + curCenter = {static_cast(*perPixelContext.cx), + static_cast(*perPixelContext.cy)}; + curDistance = {static_cast(*perPixelContext.dx), + static_cast(*perPixelContext.dy)}; + curStretch = {static_cast(*perPixelContext.sx), + static_cast(*perPixelContext.sy)}; } else { - curVertex.zoom = zoom; - curVertex.zoomExp = zoomExp; - curVertex.rot = rot; - curVertex.warp = warp; - curVertex.centerX = cx; - curVertex.centerY = cy; - curVertex.distanceX = dx; - curVertex.distanceY = dy; - curVertex.stretchX = sx; - curVertex.stretchY = sy; + curZoomRotWarp.zoom = zoom; + curZoomRotWarp.zoomExp = zoomExp; + curZoomRotWarp.rot = rot; + curZoomRotWarp.warp = warp; + curCenter = { cx, cy}; + curDistance = {dx, dy}; + curStretch = {sx, sy}; } vertex++; } } + + m_warpMesh.Update(); + m_radiusAngleBuffer.Update(); + m_zoomRotWarpBuffer.Update(); + m_centerBuffer.Update(); + m_distanceBuffer.Update(); + m_stretchBuffer.Update(); } void PerPixelMesh::WarpedBlit(const PresetState& presetState, @@ -315,7 +321,7 @@ void PerPixelMesh::WarpedBlit(const PresetState& presetState, } // No blending between presets here, so we make sure blending is disabled. - glDisable(GL_BLEND); + Renderer::BlendMode::SetBlendActive(false); if (!m_warpShader) { @@ -362,38 +368,9 @@ void PerPixelMesh::WarpedBlit(const PresetState& presetState, } m_perPixelSampler.Bind(0); - glBindVertexArray(m_vaoID); - glBindBuffer(GL_ARRAY_BUFFER, m_vboID); - - int trianglesPerBatch = static_cast(m_drawVertices.size() / 3 - 4); - int triangleCount = m_gridSizeX * m_gridSizeY * 2; // Two triangles per quad/grid cell. - int sourceIndex = 0; - - while (sourceIndex < triangleCount * 3) - { - int trianglesQueued = 0; - int vertex = 0; - while (trianglesQueued < trianglesPerBatch && sourceIndex < triangleCount * 3) - { - // Copy one triangle/3 vertices - for (int i = 0; i < 3; i++) - { - m_drawVertices[vertex++] = m_vertices[m_listIndices[sourceIndex++]]; - } - - trianglesQueued++; - } - - if (trianglesQueued > 0) - { - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(MeshVertex) * trianglesQueued * 3, m_drawVertices.data()); - glDrawArrays(GL_TRIANGLES, 0, trianglesQueued * 3); - } - } - - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); + m_warpMesh.Draw(); + Renderer::Mesh::Unbind(); Renderer::Sampler::Unbind(0); Renderer::Shader::Unbind(); } diff --git a/src/libprojectM/MilkdropPreset/PerPixelMesh.hpp b/src/libprojectM/MilkdropPreset/PerPixelMesh.hpp index 98576d30a3..f9a51c02b8 100644 --- a/src/libprojectM/MilkdropPreset/PerPixelMesh.hpp +++ b/src/libprojectM/MilkdropPreset/PerPixelMesh.hpp @@ -1,10 +1,8 @@ #pragma once -#include -#include +#include "Renderer/Mesh.hpp" -#include -#include +#include namespace libprojectM { namespace MilkdropPreset { @@ -27,13 +25,11 @@ class MilkdropShader; * * The mesh size can be changed between frames, the class will reallocate the buffers if needed. */ -class PerPixelMesh : public Renderer::RenderItem +class PerPixelMesh { public: PerPixelMesh(); - void InitVertexAttrib() override; - /** * @brief Loads the warp shader, if the preset uses one. * @param presetState The preset state to retrieve the shader from. @@ -59,31 +55,33 @@ class PerPixelMesh : public Renderer::RenderItem private: /** - * Warp mesh vertex with all required attributes. + * Vertex attributes for radius and angle. */ - struct MeshVertex { - float x{}; - float y{}; + struct RadiusAngle { float radius{}; float angle{}; + static void InitializeAttributePointer(uint32_t attributeIndex) + { + glVertexAttribPointer(attributeIndex, sizeof(RadiusAngle) / sizeof(float), GL_FLOAT, GL_FALSE, sizeof(RadiusAngle), nullptr); + } + }; + + /** + * Vertex attributes for zoom, zoom exponent, rotation and warp strength. + */ + struct ZoomRotWarp { float zoom{}; float zoomExp{}; float rot{}; float warp{}; - float centerX{}; - float centerY{}; - - float distanceX{}; - float distanceY{}; - - float stretchX{}; - float stretchY{}; + static void InitializeAttributePointer(uint32_t attributeIndex) + { + glVertexAttribPointer(attributeIndex, sizeof(ZoomRotWarp) / sizeof(float), GL_FLOAT, GL_FALSE, sizeof(ZoomRotWarp), nullptr); + } }; - using VertexList = std::vector; - /** * @brief Initializes the vertex array and fills in static data if needed. * @@ -124,10 +122,12 @@ class PerPixelMesh : public Renderer::RenderItem int m_viewportWidth{}; //!< Last known viewport width. int m_viewportHeight{}; //!< Last known viewport height. - VertexList m_vertices; //!< The calculated mesh vertices. - - std::vector m_listIndices; //!< List of vertex indices to render. - VertexList m_drawVertices; //!< Temp data buffer for the vertices to be drawn. + Renderer::Mesh m_warpMesh; //!< The Warp effect mesh + Renderer::VertexBuffer m_radiusAngleBuffer{Renderer::VertexBufferUsage::StreamDraw}; //!< Vertex attribute buffer for radius and angle values. + Renderer::VertexBuffer m_zoomRotWarpBuffer{Renderer::VertexBufferUsage::StreamDraw}; //!< Vertex attribute buffer for zoom, roation and warp values. + Renderer::VertexBuffer m_centerBuffer{Renderer::VertexBufferUsage::StreamDraw}; //!< Vertex attribute buffer for center coordinate values. + Renderer::VertexBuffer m_distanceBuffer{Renderer::VertexBufferUsage::StreamDraw}; //!< Vertex attribute buffer for distance values. + Renderer::VertexBuffer m_stretchBuffer{Renderer::VertexBufferUsage::StreamDraw}; //!< Vertex attribute buffer for stretch values. std::weak_ptr m_perPixelMeshShader; //!< Special shader which calculates the per-pixel UV coordinates. std::unique_ptr m_warpShader; //!< The warp shader. Either preset-defined or a default shader. diff --git a/src/libprojectM/MilkdropPreset/Shaders/BlurVertexShaderGlsl330.vert b/src/libprojectM/MilkdropPreset/Shaders/BlurVertexShaderGlsl330.vert index 38bdeacc20..e31d4253e5 100644 --- a/src/libprojectM/MilkdropPreset/Shaders/BlurVertexShaderGlsl330.vert +++ b/src/libprojectM/MilkdropPreset/Shaders/BlurVertexShaderGlsl330.vert @@ -1,7 +1,7 @@ precision mediump float; layout(location = 0) in vec2 vertex_position; -layout(location = 1) in vec2 vertex_texture; +layout(location = 2) in vec2 vertex_texture; uniform int flipVertical; diff --git a/src/libprojectM/MilkdropPreset/Shaders/PresetMotionVectorsVertexShaderGlsl330.vert b/src/libprojectM/MilkdropPreset/Shaders/PresetMotionVectorsVertexShaderGlsl330.vert index 9de4ec60aa..c61d462b75 100644 --- a/src/libprojectM/MilkdropPreset/Shaders/PresetMotionVectorsVertexShaderGlsl330.vert +++ b/src/libprojectM/MilkdropPreset/Shaders/PresetMotionVectorsVertexShaderGlsl330.vert @@ -2,7 +2,6 @@ precision mediump float; layout(location = 0) in vec2 vertex_position; layout(location = 1) in vec4 vertex_color; -layout(location = 2) in int vertex_index; uniform mat4 vertex_transformation; uniform float length_multiplier; @@ -17,7 +16,7 @@ void main() { // screen coordinates. vec2 pos = vertex_position; - if (vertex_index % 2 == 1) + if (gl_VertexID % 2 == 1) { // Reverse propagation using the u/v texture written in the previous frame. // Milkdrop's original code did a simple bilinear interpolation, but here it was already diff --git a/src/libprojectM/MilkdropPreset/Shaders/PresetWarpVertexShaderGlsl330.vert b/src/libprojectM/MilkdropPreset/Shaders/PresetWarpVertexShaderGlsl330.vert index c52ff6089d..5012604650 100644 --- a/src/libprojectM/MilkdropPreset/Shaders/PresetWarpVertexShaderGlsl330.vert +++ b/src/libprojectM/MilkdropPreset/Shaders/PresetWarpVertexShaderGlsl330.vert @@ -14,11 +14,11 @@ precision mediump float; #define invAspectY aspect.w layout(location = 0) in vec2 vertex_position; -layout(location = 1) in vec2 rad_ang; -layout(location = 2) in vec4 transforms; -layout(location = 3) in vec2 warp_center; -layout(location = 4) in vec2 warp_distance; -layout(location = 5) in vec2 stretch; +layout(location = 3) in vec2 rad_ang; +layout(location = 4) in vec4 transforms; +layout(location = 5) in vec2 warp_center; +layout(location = 6) in vec2 warp_distance; +layout(location = 7) in vec2 stretch; uniform mat4 vertex_transformation; uniform vec4 aspect; diff --git a/src/libprojectM/MilkdropPreset/VideoEcho.cpp b/src/libprojectM/MilkdropPreset/VideoEcho.cpp index 9bf9ae4f26..21b7399d89 100644 --- a/src/libprojectM/MilkdropPreset/VideoEcho.cpp +++ b/src/libprojectM/MilkdropPreset/VideoEcho.cpp @@ -1,24 +1,16 @@ #include "VideoEcho.hpp" +#include + namespace libprojectM { namespace MilkdropPreset { VideoEcho::VideoEcho(const PresetState& presetState) - : RenderItem() - , m_presetState(presetState) + : m_presetState(presetState) + , m_echoMesh(Renderer::VertexBufferUsage::DynamicDraw, true, true) { - RenderItem::Init(); -} - -void VideoEcho::InitVertexAttrib() -{ - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast(offsetof(TexturedPoint, x))); // Position - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast(offsetof(TexturedPoint, r))); // Color - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast(offsetof(TexturedPoint, u))); // Texture coordinates + m_echoMesh.SetRenderPrimitiveType(Renderer::Mesh::PrimitiveType::TriangleStrip); + m_echoMesh.SetVertexCount(4); } void VideoEcho::Draw() @@ -38,15 +30,12 @@ void VideoEcho::Draw() float const fOnePlusInvWidth = 1.0f + 1.0f / static_cast(m_presetState.renderContext.viewportSizeX); float const fOnePlusInvHeight = 1.0f + 1.0f / static_cast(m_presetState.renderContext.viewportSizeY); - m_vertices[0].x = -fOnePlusInvWidth * aspectMultX; - m_vertices[1].x = fOnePlusInvWidth * aspectMultX; - m_vertices[2].x = -fOnePlusInvWidth * aspectMultX; - m_vertices[3].x = fOnePlusInvWidth * aspectMultX; - m_vertices[0].y = fOnePlusInvHeight * aspectMultY; - m_vertices[1].y = fOnePlusInvHeight * aspectMultY; - m_vertices[2].y = -fOnePlusInvHeight * aspectMultY; - m_vertices[3].y = -fOnePlusInvHeight * aspectMultY; + m_echoMesh.Vertices().Set({{-fOnePlusInvWidth * aspectMultX, fOnePlusInvHeight * aspectMultY}, + {fOnePlusInvWidth * aspectMultX, fOnePlusInvHeight * aspectMultY}, + {-fOnePlusInvWidth * aspectMultX, -fOnePlusInvHeight * aspectMultY}, + {fOnePlusInvWidth * aspectMultX, -fOnePlusInvHeight * aspectMultY}}); + auto& colors = m_echoMesh.Colors(); for (int i = 0; i < 4; i++) { auto const indexFloat = static_cast(i); @@ -62,10 +51,10 @@ void VideoEcho::Draw() m_shade[i][k] = 0.5f + 0.5f * m_shade[i][k]; } - m_vertices[i].r = m_shade[i][0]; - m_vertices[i].g = m_shade[i][1]; - m_vertices[i].b = m_shade[i][2]; - m_vertices[i].a = 1.0f; + colors[i] = {m_shade[i][0], + m_shade[i][1], + m_shade[i][2], + 1.0f}; } auto shader = m_presetState.texturedShader.lock(); @@ -80,9 +69,6 @@ void VideoEcho::Draw() m_sampler.Bind(0); } - glBindVertexArray(m_vaoID); - glBindBuffer(GL_ARRAY_BUFFER, m_vboID); - if (m_presetState.videoEchoAlpha > 0.001f) { DrawVideoEcho(); @@ -92,11 +78,8 @@ void VideoEcho::Draw() DrawGammaAdjustment(); } - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - - glDisable(GL_BLEND); - + Renderer::BlendMode::SetBlendActive(false); + Renderer::Mesh::Unbind(); Renderer::Shader::Unbind(); if (mainTexture) @@ -113,23 +96,19 @@ void VideoEcho::DrawVideoEcho() auto const videoEchoOrientation = m_presetState.videoEchoOrientation % 4; auto const gammaAdj = m_presetState.gammaAdj; - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ZERO); + Renderer::BlendMode::Set(true, Renderer::BlendMode::Function::One, Renderer::BlendMode::Function::Zero); for (int pass = 0; pass < 2; pass++) { float const zoom = (pass == 0) ? 1.0f : videoEchoZoom; float const tempLow = 0.5f - 0.5f / zoom; - float const temphigh = 0.5f + 0.5f / zoom; - m_vertices[0].u = tempLow; - m_vertices[0].v = tempLow; - m_vertices[1].u = temphigh; - m_vertices[1].v = tempLow; - m_vertices[2].u = tempLow; - m_vertices[2].v = temphigh; - m_vertices[3].u = temphigh; - m_vertices[3].v = temphigh; + float const tempHigh = 0.5f + 0.5f / zoom; + + m_echoMesh.UVs().Set({{tempLow, tempLow}, + {tempHigh, tempLow}, + {tempLow, tempHigh}, + {tempHigh, tempHigh}}); // Flipping if (pass == 1) @@ -138,11 +117,11 @@ void VideoEcho::DrawVideoEcho() { if (videoEchoOrientation % 2 == 1) { - m_vertices[vertex].u = 1.0f - m_vertices[vertex].u; + m_echoMesh.UVs()[vertex].SetU(1.0f - m_echoMesh.UVs()[vertex].U()); } if (videoEchoOrientation >= 2) { - m_vertices[vertex].v = 1.0f - m_vertices[vertex].v; + m_echoMesh.UVs()[vertex].SetV(1.0f - m_echoMesh.UVs()[vertex].V()); } } } @@ -150,18 +129,19 @@ void VideoEcho::DrawVideoEcho() float const mix = (pass == 1) ? videoEchoAlpha : 1.0f - videoEchoAlpha; for (int vertex = 0; vertex < 4; vertex++) { - m_vertices[vertex].r = mix * m_shade[vertex][0]; - m_vertices[vertex].g = mix * m_shade[vertex][1]; - m_vertices[vertex].b = mix * m_shade[vertex][2]; - m_vertices[vertex].a = 1.0f; + m_echoMesh.Colors()[vertex] = { + mix * m_shade[vertex][0], + mix * m_shade[vertex][1], + mix * m_shade[vertex][2], + 1.0f}; } - glBufferData(GL_ARRAY_BUFFER, static_cast(sizeof(TexturedPoint) * m_vertices.size()), m_vertices.data(), GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLE_STRIP, 0, static_cast(m_vertices.size())); + m_echoMesh.Update(); + m_echoMesh.Draw(); if (pass == 0) { - glBlendFunc(GL_ONE, GL_ONE); + Renderer::BlendMode::SetBlendFunction(Renderer::BlendMode::Function::One, Renderer::BlendMode::Function::One); } if (gammaAdj > 0.001f) @@ -182,14 +162,15 @@ void VideoEcho::DrawVideoEcho() for (int vertex = 0; vertex < 4; vertex++) { - m_vertices[vertex].r = gamma * mix * m_shade[vertex][0]; - m_vertices[vertex].g = gamma * mix * m_shade[vertex][1]; - m_vertices[vertex].b = gamma * mix * m_shade[vertex][2]; - m_vertices[vertex].a = 1.0f; + m_echoMesh.Colors()[vertex] = { + gamma * mix * m_shade[vertex][0], + gamma * mix * m_shade[vertex][1], + gamma * mix * m_shade[vertex][2], + 1.0f}; } - glBufferData(GL_ARRAY_BUFFER, static_cast(sizeof(TexturedPoint) * m_vertices.size()), m_vertices.data(), GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLE_STRIP, 0, static_cast(m_vertices.size())); + m_echoMesh.Colors().Update(); + m_echoMesh.Draw(); } } } @@ -197,17 +178,12 @@ void VideoEcho::DrawVideoEcho() void VideoEcho::DrawGammaAdjustment() { - m_vertices[0].u = 0.0f; - m_vertices[0].v = 0.0f; - m_vertices[1].u = 1.0f; - m_vertices[1].v = 0.0f; - m_vertices[2].u = 0.0f; - m_vertices[2].v = 1.0f; - m_vertices[3].u = 1.0f; - m_vertices[3].v = 1.0f; - - glDisable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ZERO); + m_echoMesh.UVs().Set({{0.0f, 0.0f}, + {1.0f, 0.0f}, + {0.0f, 1.0f}, + {1.0f, 1.0f}}); + + Renderer::BlendMode::Set(true, Renderer::BlendMode::Function::One, Renderer::BlendMode::Function::Zero); auto const gammaAdj = m_presetState.gammaAdj; int const redrawCount = static_cast(gammaAdj - 0.0001f) + 1; @@ -226,19 +202,19 @@ void VideoEcho::DrawGammaAdjustment() for (int vertex = 0; vertex < 4; vertex++) { - m_vertices[vertex].r = gamma * m_shade[vertex][0]; - m_vertices[vertex].g = gamma * m_shade[vertex][1]; - m_vertices[vertex].b = gamma * m_shade[vertex][2]; - m_vertices[vertex].a = 1.0f; + m_echoMesh.Colors()[vertex] = { + gamma * m_shade[vertex][0], + gamma * m_shade[vertex][1], + gamma * m_shade[vertex][2], + 1.0f}; } - glBufferData(GL_ARRAY_BUFFER, static_cast(sizeof(TexturedPoint) * m_vertices.size()), m_vertices.data(), GL_DYNAMIC_DRAW); - glDrawArrays(GL_TRIANGLE_STRIP, 0, static_cast(m_vertices.size())); + m_echoMesh.Update(); + m_echoMesh.Draw(); if (redraw == 0) { - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); + Renderer::BlendMode::Set(true, Renderer::BlendMode::Function::One, Renderer::BlendMode::Function::One); } } } diff --git a/src/libprojectM/MilkdropPreset/VideoEcho.hpp b/src/libprojectM/MilkdropPreset/VideoEcho.hpp index dce3cace9f..1077ba4f66 100644 --- a/src/libprojectM/MilkdropPreset/VideoEcho.hpp +++ b/src/libprojectM/MilkdropPreset/VideoEcho.hpp @@ -3,9 +3,7 @@ #include "PerFrameContext.hpp" #include "PresetState.hpp" -#include - -#include +#include namespace libprojectM { namespace MilkdropPreset { @@ -13,14 +11,12 @@ namespace MilkdropPreset { /** * @brief Renders a video "echo" (ghost image) effect and gamma adjustments. */ -class VideoEcho: public Renderer::RenderItem +class VideoEcho { public: VideoEcho() = delete; explicit VideoEcho(const PresetState& presetState); - void InitVertexAttrib() override; - void Draw(); private: @@ -31,7 +27,7 @@ class VideoEcho: public Renderer::RenderItem const PresetState& m_presetState; //!< The global preset state. std::array, 4> m_shade; // !< Random, changing color values for the four corners - std::array m_vertices; //!< The video echo/gamma adj mesh + Renderer::Mesh m_echoMesh; //!< The video echo/gamma adj mesh Renderer::Sampler m_sampler{GL_CLAMP_TO_EDGE, GL_LINEAR}; }; diff --git a/src/libprojectM/MilkdropPreset/Waveform.cpp b/src/libprojectM/MilkdropPreset/Waveform.cpp index ce4351784c..caaca5987a 100644 --- a/src/libprojectM/MilkdropPreset/Waveform.cpp +++ b/src/libprojectM/MilkdropPreset/Waveform.cpp @@ -5,35 +5,20 @@ #include "Waveforms/Factory.hpp" -#include +#include -#include