diff --git a/src/libprojectM/UserSprites/MilkdropSprite.cpp b/src/libprojectM/UserSprites/MilkdropSprite.cpp index 4fbfbf239..0d0595b90 100644 --- a/src/libprojectM/UserSprites/MilkdropSprite.cpp +++ b/src/libprojectM/UserSprites/MilkdropSprite.cpp @@ -1,5 +1,6 @@ #include "UserSprites/MilkdropSprite.hpp" +#include "SpriteException.hpp" #include "SpriteShaders.hpp" #include @@ -24,19 +25,9 @@ namespace libprojectM { namespace UserSprites { MilkdropSprite::MilkdropSprite() + : m_mesh(Renderer::VertexBufferUsage::DynamicDraw, false, true) { - RenderItem::Init(); -} - -void MilkdropSprite::InitVertexAttrib() -{ - glEnableVertexAttribArray(0); - glDisableVertexAttribArray(1); - glEnableVertexAttribArray(2); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast(offsetof(TexturedPoint, x))); // Position - // Color (index 1) is passed as a 4-float constant vertex attribute. - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast(offsetof(TexturedPoint, u))); // Texture coordinate + m_mesh.SetVertexCount(4); } void MilkdropSprite::Init(const std::string& spriteData, const Renderer::RenderContext& renderContext) @@ -119,7 +110,7 @@ void MilkdropSprite::Draw(const Audio::FrameAudioData& audioData, m_spriteDone = *m_codeContext.done != 0.0; bool burnIn = *m_codeContext.burn != 0.0; - Quad vertices{}; + auto& vertices = m_mesh.Vertices().Get(); // Get values from expression code and clamp them where necessary. float x = std::min(1000.0f, std::max(-1000.0f, static_cast(*m_codeContext.x) * 2.0f - 1.0f)); @@ -139,14 +130,14 @@ void MilkdropSprite::Draw(const Audio::FrameAudioData& audioData, float a = std::min(1.0f, std::max(0.0f, (static_cast(*m_codeContext.a)))); // ToDo: Move all translations to vertex shader - vertices[0 + flipx].x = -sx; - vertices[1 - flipx].x = sx; - vertices[2 + flipx].x = -sx; - vertices[3 - flipx].x = sx; - vertices[0 + flipy * 2].y = -sy; - vertices[1 + flipy * 2].y = -sy; - vertices[2 - flipy * 2].y = sy; - vertices[3 - flipy * 2].y = sy; + vertices[0 + flipx].SetX(-sx); + vertices[1 - flipx].SetX(sx); + vertices[2 + flipx].SetX(-sx); + vertices[3 - flipx].SetX(sx); + vertices[0 + flipy * 2].SetY(-sy); + vertices[1 + flipy * 2].SetY(-sy); + vertices[2 - flipy * 2].SetY(sy); + vertices[3 - flipy * 2].SetY(sy); // First aspect ratio: adjust for non-1:1 images { @@ -157,7 +148,7 @@ void MilkdropSprite::Draw(const Audio::FrameAudioData& audioData, // Landscape image for (auto& vertex : vertices) { - vertex.y *= aspect; + vertex.SetY(vertex.Y() * aspect); } } else @@ -165,7 +156,7 @@ void MilkdropSprite::Draw(const Audio::FrameAudioData& audioData, // Portrait image for (auto& vertex : vertices) { - vertex.x /= aspect; + vertex.SetX(vertex.X() / aspect); } } } @@ -177,18 +168,17 @@ void MilkdropSprite::Draw(const Audio::FrameAudioData& audioData, for (auto& vertex : vertices) { - float rotX = vertex.x * cos_rot - vertex.y * sin_rot; - float rotY = vertex.x * sin_rot + vertex.y * cos_rot; - vertex.x = rotX; - vertex.y = rotY; + float rotX = vertex.X() * cos_rot - vertex.Y() * sin_rot; + float rotY = vertex.X() * sin_rot + vertex.Y() * cos_rot; + vertex = {rotX, rotY}; } } // Translation for (auto& vertex : vertices) { - vertex.x += x; - vertex.y += y; + vertex.SetX(vertex.X() + x); + vertex.SetY(vertex.Y() + y); } // Second aspect ratio: normalize to width of screen @@ -199,14 +189,14 @@ void MilkdropSprite::Draw(const Audio::FrameAudioData& audioData, { for (auto& vertex : vertices) { - vertex.y *= aspect; + vertex.SetY(vertex.Y() * aspect); } } else { for (auto& vertex : vertices) { - vertex.x /= aspect; + vertex.SetX(vertex.X() / aspect); } } } @@ -219,19 +209,15 @@ void MilkdropSprite::Draw(const Audio::FrameAudioData& audioData, float dtu = 0.5f; float dtv = 0.5f; - vertices[0].u = -dtu; - vertices[1].u = dtu; - vertices[2].u = -dtu; - vertices[3].u = dtu; - vertices[0].v = -dtv; - vertices[1].v = -dtv; - vertices[2].v = dtv; - vertices[3].v = dtv; + m_mesh.UVs().Set({{-dtu, -dtv}, + {dtu, -dtv}, + {-dtu, dtv}, + {dtu, dtv}}); - for (auto& vertex : vertices) + for (auto& uv : m_mesh.UVs().Get()) { - vertex.u = (vertex.u - 0.0f) * repeatx + 0.5f; - vertex.v = (vertex.v - 0.0f) * repeaty + 0.5f; + uv = {(uv.U() - 0.0f) * repeatx + 0.5f, + (uv.V() - 0.0f) * repeaty + 0.5f}; } } @@ -243,9 +229,7 @@ void MilkdropSprite::Draw(const Audio::FrameAudioData& audioData, m_texture->Bind(0); m_sampler.Bind(0); - glBindVertexArray(m_vaoID); - glBindBuffer(GL_ARRAY_BUFFER, m_vboID); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(), GL_DYNAMIC_DRAW); + m_mesh.Update(); glVertexAttrib4f(1, r, g, b, a); @@ -275,7 +259,7 @@ void MilkdropSprite::Draw(const Audio::FrameAudioData& audioData, } // Draw to current output buffer - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + m_mesh.Draw(); if (burnIn) { @@ -288,7 +272,7 @@ void MilkdropSprite::Draw(const Audio::FrameAudioData& audioData, } preset.get()->BindFramebuffer(); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + m_mesh.Draw(); } // Reset to original FBO @@ -300,6 +284,7 @@ void MilkdropSprite::Draw(const Audio::FrameAudioData& audioData, glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); m_texture->Unbind(0); + Renderer::Mesh::Unbind(); Renderer::Shader::Unbind(); } diff --git a/src/libprojectM/UserSprites/MilkdropSprite.hpp b/src/libprojectM/UserSprites/MilkdropSprite.hpp index 21cd14e91..d19139012 100644 --- a/src/libprojectM/UserSprites/MilkdropSprite.hpp +++ b/src/libprojectM/UserSprites/MilkdropSprite.hpp @@ -2,6 +2,7 @@ #include "UserSprites/Sprite.hpp" +#include #include #include @@ -17,8 +18,6 @@ public: ~MilkdropSprite() override = default; - void InitVertexAttrib() override; - void Init(const std::string& spriteData, const Renderer::RenderContext& renderContext) override; void Draw(const Audio::FrameAudioData& audioData, @@ -26,16 +25,13 @@ public: uint32_t outputFramebufferObject, PresetList presets) override; - auto Done() const-> bool override; + auto Done() const -> bool override; private: - using Quad = std::array; - /** * @brief Context for the init and per-frame code. */ - struct CodeContext - { + struct CodeContext { CodeContext(); ~CodeContext(); @@ -61,46 +57,45 @@ private: const Renderer::RenderContext& renderContext); projectm_eval_context* spriteCodeContext{nullptr}; //!< The code runtime context, holds memory buffers and variables. - projectm_eval_code* perFrameCodeHandle{nullptr}; //!< The compiled per-frame code handle. + projectm_eval_code* perFrameCodeHandle{nullptr}; //!< The compiled per-frame code handle. // Input variables - PRJM_EVAL_F* time{}; //!< Time passed since program start. Also available in init code. - PRJM_EVAL_F* frame{}; //!< Total frames rendered so far. Also available in init code. - PRJM_EVAL_F* fps{}; //!< Current (or, if not available, target) frames per second value. + PRJM_EVAL_F* time{}; //!< Time passed since program start. Also available in init code. + PRJM_EVAL_F* frame{}; //!< Total frames rendered so far. Also available in init code. + PRJM_EVAL_F* fps{}; //!< Current (or, if not available, target) frames per second value. PRJM_EVAL_F* progress{}; //!< Preset blending progress (only if blending). - PRJM_EVAL_F* bass{}; //!< Bass frequency loudness, median of 1.0, range of ~0.7 to ~1.3 in most cases. - PRJM_EVAL_F* mid{}; //!< Middle frequency loudness, median of 1.0, range of ~0.7 to ~1.3 in most cases. - PRJM_EVAL_F* treb{}; //!< Treble frequency loudness, median of 1.0, range of ~0.7 to ~1.3 in most cases. + PRJM_EVAL_F* bass{}; //!< Bass frequency loudness, median of 1.0, range of ~0.7 to ~1.3 in most cases. + PRJM_EVAL_F* mid{}; //!< Middle frequency loudness, median of 1.0, range of ~0.7 to ~1.3 in most cases. + PRJM_EVAL_F* treb{}; //!< Treble frequency loudness, median of 1.0, range of ~0.7 to ~1.3 in most cases. PRJM_EVAL_F* bass_att{}; //!< More attenuated/smoothed value of bass. - PRJM_EVAL_F* mid_att{}; //!< More attenuated/smoothed value of mid. + PRJM_EVAL_F* mid_att{}; //!< More attenuated/smoothed value of mid. PRJM_EVAL_F* treb_att{}; //!< More attenuated/smoothed value of treb. // Output variables - PRJM_EVAL_F* done{}; //!< If this becomes non-zero, the sprite is deleted. Default: 0.0 - PRJM_EVAL_F* burn{}; //!< If non-zero, the sprite will be "burned" into currently rendered presets when done is also true, effectively "dissolving" the sprite in the preset. Default: 1.0 - PRJM_EVAL_F* x{}; //!< Sprite x position (position of the image center). Range from -1000 to 1000. Default: 0.5 - PRJM_EVAL_F* y{}; //!< Sprite y position (position of the image center). Range from -1000 to 1000. Default: 0.5 - PRJM_EVAL_F* sx{}; //!< Sprite x scaling factor. Range from -1000 to 1000. Default: 1.0 - PRJM_EVAL_F* sy{}; //!< Sprite y scaling factor. Range from -1000 to 1000. Default: 1.0 - PRJM_EVAL_F* rot{}; //!< Sprite rotation in radians (2*PI equals one full rotation). Default: 0.0 - PRJM_EVAL_F* flipx{}; //!< If flag is non-zero, the sprite is flipped on the x axis. Default: 0.0 - PRJM_EVAL_F* flipy{}; //!< If flag is non-zero, the sprite is flipped on the y axis. Default: 0.0 - PRJM_EVAL_F* repeatx{}; //!< Repeat count of the image on the sprite quad on the x axis. Fractional values allowed. Range from 0.01 to 100.0. Default: 1.0 - PRJM_EVAL_F* repeaty{}; //!< Repeat count of the image on the sprite quad on the y axis. Fractional values allowed. Range from 0.01 to 100.0. Default: 1.0 + PRJM_EVAL_F* done{}; //!< If this becomes non-zero, the sprite is deleted. Default: 0.0 + PRJM_EVAL_F* burn{}; //!< If non-zero, the sprite will be "burned" into currently rendered presets when done is also true, effectively "dissolving" the sprite in the preset. Default: 1.0 + PRJM_EVAL_F* x{}; //!< Sprite x position (position of the image center). Range from -1000 to 1000. Default: 0.5 + PRJM_EVAL_F* y{}; //!< Sprite y position (position of the image center). Range from -1000 to 1000. Default: 0.5 + PRJM_EVAL_F* sx{}; //!< Sprite x scaling factor. Range from -1000 to 1000. Default: 1.0 + PRJM_EVAL_F* sy{}; //!< Sprite y scaling factor. Range from -1000 to 1000. Default: 1.0 + PRJM_EVAL_F* rot{}; //!< Sprite rotation in radians (2*PI equals one full rotation). Default: 0.0 + PRJM_EVAL_F* flipx{}; //!< If flag is non-zero, the sprite is flipped on the x axis. Default: 0.0 + PRJM_EVAL_F* flipy{}; //!< If flag is non-zero, the sprite is flipped on the y axis. Default: 0.0 + PRJM_EVAL_F* repeatx{}; //!< Repeat count of the image on the sprite quad on the x axis. Fractional values allowed. Range from 0.01 to 100.0. Default: 1.0 + PRJM_EVAL_F* repeaty{}; //!< Repeat count of the image on the sprite quad on the y axis. Fractional values allowed. Range from 0.01 to 100.0. Default: 1.0 PRJM_EVAL_F* blendmode{}; //!< Image blending mode. 0 = Alpha blending (default), 1 = Decal mode (no transparency), 2 = Additive blending, 3 = Source color blending, 4 = Color key blending. Default: 0 - PRJM_EVAL_F* r{}; //!< Modulation color used in some blending modes. Default: 1.0 - PRJM_EVAL_F* g{}; //!< Modulation color used in some blending modes. Default: 1.0 - PRJM_EVAL_F* b{}; //!< Modulation color used in some blending modes. Default: 1.0 - PRJM_EVAL_F* a{}; //!< Modulation color used in some blending modes. Default: 1.0 - + PRJM_EVAL_F* r{}; //!< Modulation color used in some blending modes. Default: 1.0 + PRJM_EVAL_F* g{}; //!< Modulation color used in some blending modes. Default: 1.0 + PRJM_EVAL_F* b{}; //!< Modulation color used in some blending modes. Default: 1.0 + PRJM_EVAL_F* a{}; //!< Modulation color used in some blending modes. Default: 1.0 }; - CodeContext m_codeContext; //!< Sprite init and per-frame code. - std::shared_ptr m_texture; //!< The sprite image, loaded via a name like other textures in Milkdrop presets. + CodeContext m_codeContext; //!< Sprite init and per-frame code. + std::shared_ptr m_texture; //!< The sprite image, loaded via a name like other textures in Milkdrop presets. Renderer::Sampler m_sampler{GL_REPEAT, GL_LINEAR}; //!< Texture sampler settings - std::weak_ptr m_spriteShader; //!< The shader used to draw the user sprite. - bool m_spriteDone{false}; //!< If true, the sprite will be removed from the list. - + std::weak_ptr m_spriteShader; //!< The shader used to draw the user sprite. + Renderer::Mesh m_mesh; //!< A simple quad. + bool m_spriteDone{false}; //!< If true, the sprite will be removed from the list. }; } // namespace UserSprites diff --git a/src/libprojectM/UserSprites/Sprite.hpp b/src/libprojectM/UserSprites/Sprite.hpp index e70e1a7a2..629426af5 100644 --- a/src/libprojectM/UserSprites/Sprite.hpp +++ b/src/libprojectM/UserSprites/Sprite.hpp @@ -1,13 +1,10 @@ #pragma once -#include "UserSprites/SpriteException.hpp" - #include #include