From 0d2ac563bc965ed7c02f1fde2a503906f877af7d Mon Sep 17 00:00:00 2001 From: Kai Blaschke Date: Sat, 30 Sep 2023 14:06:54 +0200 Subject: [PATCH] Fix upside-down and vertical effect misalignment issues. If anyone else can come up with a solution that doesn't involve up to three vertical flips, please implement. --- src/libprojectM/MilkdropPreset/CMakeLists.txt | 2 + .../MilkdropPreset/CustomWaveform.cpp | 2 +- src/libprojectM/MilkdropPreset/Filters.cpp | 3 +- .../MilkdropPreset/FinalComposite.cpp | 5 + .../MilkdropPreset/FinalComposite.hpp | 6 + .../MilkdropPreset/FlipTexture.cpp | 148 ++++++++++++++++++ .../MilkdropPreset/FlipTexture.hpp | 67 ++++++++ .../MilkdropPreset/MilkdropPreset.cpp | 20 ++- .../MilkdropPreset/MilkdropPreset.hpp | 2 + .../MilkdropPreset/MilkdropShader.cpp | 2 +- .../MilkdropPreset/PerPixelMesh.cpp | 2 +- .../MilkdropPreset/PresetState.cpp | 8 +- ...resetMotionVectorsVertexShaderGlsl330.vert | 3 +- .../PresetWarpVertexShaderGlsl330.vert | 4 +- src/libprojectM/MilkdropPreset/VideoEcho.cpp | 2 +- src/libprojectM/Renderer/Framebuffer.cpp | 33 ++++ src/libprojectM/Renderer/Framebuffer.hpp | 10 ++ .../Renderer/TextureAttachment.cpp | 11 ++ .../Renderer/TextureAttachment.hpp | 7 + 19 files changed, 321 insertions(+), 16 deletions(-) create mode 100644 src/libprojectM/MilkdropPreset/FlipTexture.cpp create mode 100644 src/libprojectM/MilkdropPreset/FlipTexture.hpp diff --git a/src/libprojectM/MilkdropPreset/CMakeLists.txt b/src/libprojectM/MilkdropPreset/CMakeLists.txt index 2b436192d8..3db4a5c75d 100644 --- a/src/libprojectM/MilkdropPreset/CMakeLists.txt +++ b/src/libprojectM/MilkdropPreset/CMakeLists.txt @@ -56,6 +56,8 @@ add_library(MilkdropPreset OBJECT Filters.hpp FinalComposite.cpp FinalComposite.hpp + FlipTexture.cpp + FlipTexture.hpp IdlePreset.cpp IdlePreset.hpp MilkdropNoise.cpp diff --git a/src/libprojectM/MilkdropPreset/CustomWaveform.cpp b/src/libprojectM/MilkdropPreset/CustomWaveform.cpp index 80c0d66bd3..c34d09638d 100644 --- a/src/libprojectM/MilkdropPreset/CustomWaveform.cpp +++ b/src/libprojectM/MilkdropPreset/CustomWaveform.cpp @@ -183,7 +183,7 @@ void CustomWaveform::Draw(const PerFrameContext& presetPerFrameContext) } m_presetState.untexturedShader.Bind(); - m_presetState.untexturedShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjectionFlipped); + m_presetState.untexturedShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection); auto iterations = (m_drawThick && !m_useDots) ? 4 : 1; diff --git a/src/libprojectM/MilkdropPreset/Filters.cpp b/src/libprojectM/MilkdropPreset/Filters.cpp index 9f86d4b2e5..875e071203 100644 --- a/src/libprojectM/MilkdropPreset/Filters.cpp +++ b/src/libprojectM/MilkdropPreset/Filters.cpp @@ -29,7 +29,7 @@ void Filters::Draw() glEnable(GL_BLEND); m_presetState.untexturedShader.Bind(); - m_presetState.untexturedShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjectionFlipped); + m_presetState.untexturedShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection); glBindVertexArray(m_vaoID); glVertexAttrib4f(1, 1.0, 1.0, 1.0, 1.0); @@ -88,6 +88,7 @@ void Filters::Invert() glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } + void Filters::UpdateMesh() { if (m_viewportWidth == m_presetState.renderContext.viewportSizeX && diff --git a/src/libprojectM/MilkdropPreset/FinalComposite.cpp b/src/libprojectM/MilkdropPreset/FinalComposite.cpp index 6c172c8a98..77c25a9573 100644 --- a/src/libprojectM/MilkdropPreset/FinalComposite.cpp +++ b/src/libprojectM/MilkdropPreset/FinalComposite.cpp @@ -131,6 +131,11 @@ void FinalComposite::Draw(const PresetState& presetState, const PerFrameContext& Shader::Unbind(); } +auto FinalComposite::HasCompositeShader() const -> bool +{ + return m_compositeShader != nullptr; +} + void FinalComposite::InitializeMesh(const PresetState& presetState) { if (m_viewportWidth == presetState.renderContext.viewportSizeX && diff --git a/src/libprojectM/MilkdropPreset/FinalComposite.hpp b/src/libprojectM/MilkdropPreset/FinalComposite.hpp index 988c8e8c42..a5dba3b841 100644 --- a/src/libprojectM/MilkdropPreset/FinalComposite.hpp +++ b/src/libprojectM/MilkdropPreset/FinalComposite.hpp @@ -39,6 +39,12 @@ class FinalComposite : public RenderItem void Draw(const PresetState& presetState, const PerFrameContext& perFrameContext); + /** + * @brief Returns if the final composite is using a shader or classic filters. + * @return true if the final composite is done via a shader, false if not. + */ + auto HasCompositeShader() const -> bool; + private: /** * Composite mesh vertex with all required attributes. diff --git a/src/libprojectM/MilkdropPreset/FlipTexture.cpp b/src/libprojectM/MilkdropPreset/FlipTexture.cpp new file mode 100644 index 0000000000..14a42d8cbc --- /dev/null +++ b/src/libprojectM/MilkdropPreset/FlipTexture.cpp @@ -0,0 +1,148 @@ +#include "FlipTexture.hpp" + +FlipTexture::FlipTexture(const PresetState& presetState) + : RenderItem() + , m_presetState(presetState) +{ + RenderItem::Init(); + + m_framebuffer.CreateColorAttachment(0, 0); +} + +void FlipTexture::InitVertexAttrib() +{ + glEnableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glEnableVertexAttribArray(2); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast(offsetof(TexturedPoint, x))); // Position + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast(offsetof(TexturedPoint, u))); // Texture coordinate + + std::array points; + + points[0].x = -1.0; + points[0].y = 1.0; + points[1].x = 1.0; + points[1].y = 1.0; + points[2].x = -1.0; + points[2].y = -1.0; + points[3].x = 1.0; + points[3].y = -1.0; + + points[0].u = 0.0; + points[0].v = 1.0; + points[1].u = 1.0; + points[1].v = 1.0; + points[2].u = 0.0; + points[2].v = 0.0; + points[3].u = 1.0; + points[3].v = 0.0; + + glBufferData(GL_ARRAY_BUFFER, sizeof(points), points.data(), GL_STATIC_DRAW); +} + +void FlipTexture::Draw(const std::shared_ptr& originalTexture, const std::shared_ptr& targetTexture) +{ + if (originalTexture == nullptr || originalTexture == targetTexture) + { + return; + } + + UpdateTextureSize(); + + if (m_viewportWidth == 0 || m_viewportHeight == 0) + { + return; + } + + std::shared_ptr internalTexture; + + m_framebuffer.Bind(0); + + // Draw from unflipped texture + originalTexture->Bind(0); + + if (targetTexture) + { + internalTexture = m_framebuffer.GetColorAttachmentTexture(0, 0); + m_framebuffer.GetAttachment(0, TextureAttachment::AttachmentType::Color, 0)->Texture(targetTexture); + } + + Flip(); + + // Rebind our internal texture. + if (targetTexture) + { + m_framebuffer.GetAttachment(0, TextureAttachment::AttachmentType::Color, 0)->Texture(internalTexture); + } + + Framebuffer::Unbind(); +} + +void FlipTexture::Draw(const std::shared_ptr& originalTexture, Framebuffer& framebuffer, int framebufferIndex) +{ + if (originalTexture == nullptr || framebuffer.GetColorAttachmentTexture(framebufferIndex, 0) == nullptr) + { + return; + } + + UpdateTextureSize(); + + if (m_viewportWidth == 0 || m_viewportHeight == 0) + { + return; + } + + m_framebuffer.Bind(0); + + // Draw from unflipped texture + originalTexture->Bind(0); + + Flip(); + + // Swap texture attachments + auto tempAttachment = framebuffer.GetAttachment(framebufferIndex, TextureAttachment::AttachmentType::Color, 0); + framebuffer.RemoveColorAttachment(framebufferIndex, 0); + framebuffer.SetAttachment(framebufferIndex, 0, m_framebuffer.GetAttachment(0, TextureAttachment::AttachmentType::Color, 0)); + m_framebuffer.RemoveColorAttachment(0, 0); + m_framebuffer.SetAttachment(0, 0, tempAttachment); + + Framebuffer::Unbind(); +} + +auto FlipTexture::FlippedTexture() -> std::shared_ptr +{ + return m_framebuffer.GetColorAttachmentTexture(0, 0); +} + +void FlipTexture::UpdateTextureSize() +{ + if (m_viewportWidth == m_presetState.renderContext.viewportSizeX && + m_viewportHeight == m_presetState.renderContext.viewportSizeY) + { + return; + } + + m_viewportWidth = m_presetState.renderContext.viewportSizeX; + m_viewportHeight = m_presetState.renderContext.viewportSizeY; + + m_framebuffer.SetSize(m_viewportWidth, m_viewportHeight); +} + +void FlipTexture::Flip() const +{ + m_presetState.texturedShader.Bind(); + m_presetState.texturedShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection); + m_presetState.texturedShader.SetUniformInt("texture_sampler", 0); + + m_sampler.Bind(0); + + glBindVertexArray(m_vaoID); + glVertexAttrib4f(1, 1.0, 1.0, 1.0, 1.0); // Color + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); + + glBindTexture(GL_TEXTURE_2D, 0); + Sampler::Unbind(0); + Shader::Unbind(); +} \ No newline at end of file diff --git a/src/libprojectM/MilkdropPreset/FlipTexture.hpp b/src/libprojectM/MilkdropPreset/FlipTexture.hpp new file mode 100644 index 0000000000..7030976780 --- /dev/null +++ b/src/libprojectM/MilkdropPreset/FlipTexture.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include "PresetState.hpp" + +#include +#include + +/** + * @class FlipTexture + * @brief Flips the given input texture upside-down. + * + * Milkdrop uses HLSL, so the input and output UV coordinates in the draw call are upside-down because + * DirectX has the origin at the top-left while OpenGL/Vulkan use the bottom-left. + * + * Some presets need the input, the calculated UVs and the output to be properly aligned, so at some + * point, input textures must be flipped for the next rendering step. This class uses a simple draw + * call with a pass-through shader to draw the same image 1:1, but vertically flipped. + */ +class FlipTexture : public RenderItem +{ +public: + FlipTexture() = delete; + explicit FlipTexture(const PresetState& presetState); + + void InitVertexAttrib(); + + /** + * @brief Flips the original texture either into the object's internal framebuffer or a given target texture. + * The original and target textures must not be the same. + * @param originalTexture The texture to be flipped. + * @param targetTexture Optional target texture to draw onto. + */ + void Draw(const std::shared_ptr& originalTexture, const std::shared_ptr& targetTexture = {}); + + /** + * @brief Flips the texture bound the given framebuffer's first color attachment. + * This is done by drawing into a second framebuffer, then swapping the textures, so the original texture + * can be the current color attachment of targetFramebuffer. + * @param originalTexture The texture to be flipped. + * @param targetFramebuffer Optional target texture to draw onto. + * @param framebufferIndex The index of the framebuffer to use. + */ + void Draw(const std::shared_ptr& originalTexture, Framebuffer& framebuffer, int framebufferIndex); + + /** + * @brief Returns the flipped texture. + * + * @return The flipped texture. + */ + auto FlippedTexture() -> std::shared_ptr; + +private: + /** + * Updates the mesh + */ + void UpdateTextureSize(); + + void Flip() const; + + const PresetState& m_presetState; //!< The global preset state. + + Framebuffer m_framebuffer{1}; //!< Framebuffer for drawing the flipped texture + Sampler m_sampler{GL_CLAMP_TO_EDGE, GL_NEAREST}; //!< Texture sampler settings + + int m_viewportWidth{}; //!< Last known viewport width + int m_viewportHeight{}; //!< Last known viewport height +}; diff --git a/src/libprojectM/MilkdropPreset/MilkdropPreset.cpp b/src/libprojectM/MilkdropPreset/MilkdropPreset.cpp index 5aeb57b815..fa0fd5d0a1 100755 --- a/src/libprojectM/MilkdropPreset/MilkdropPreset.cpp +++ b/src/libprojectM/MilkdropPreset/MilkdropPreset.cpp @@ -99,9 +99,12 @@ void MilkdropPreset::RenderFrame(const libprojectM::Audio::FrameAudioData& audio m_motionVectors.Draw(m_perFrameContext, m_motionVectorUVMap->Texture()); } - // We now draw to the first framebuffer, but read from the second one for warping and textured shapes. - m_framebuffer.BindRead(m_previousFrameBuffer); - m_framebuffer.BindDraw(m_currentFrameBuffer); + // y-flip the previous frame and assign the flipped texture as "main" + m_flipTexture.Draw(m_framebuffer.GetColorAttachmentTexture(m_previousFrameBuffer, 0)); + m_state.mainTexture = m_flipTexture.FlippedTexture(); + + // We now draw to the current framebuffer. + m_framebuffer.Bind(m_currentFrameBuffer); // Add motion vector u/v texture for the warp mesh draw and clean both buffers. m_framebuffer.SetAttachment(m_currentFrameBuffer, 1, m_motionVectorUVMap); @@ -135,15 +138,24 @@ void MilkdropPreset::RenderFrame(const libprojectM::Audio::FrameAudioData& audio // Todo: Song title anim would go here + // y-flip the image for final compositing again + m_flipTexture.Draw(m_framebuffer.GetColorAttachmentTexture(m_currentFrameBuffer, 0)); + m_state.mainTexture = m_flipTexture.FlippedTexture(); + // We no longer need the previous frame image, use it to render the final composite. m_framebuffer.BindRead(m_currentFrameBuffer); m_framebuffer.BindDraw(m_previousFrameBuffer); - m_state.mainTexture = m_framebuffer.GetColorAttachmentTexture(m_currentFrameBuffer, 0); m_finalComposite.Draw(m_state, m_perFrameContext); // ToDo: Draw user sprites (can have evaluated code) + if (!m_finalComposite.HasCompositeShader()) + { + // Flip texture again in "previous" framebuffer as old-school effects are still upside down. + m_flipTexture.Draw(m_framebuffer.GetColorAttachmentTexture(m_previousFrameBuffer, 0), m_framebuffer, m_previousFrameBuffer); + } + // TEST: Copy result to default framebuffer m_framebuffer.BindRead(m_previousFrameBuffer); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); diff --git a/src/libprojectM/MilkdropPreset/MilkdropPreset.hpp b/src/libprojectM/MilkdropPreset/MilkdropPreset.hpp index d42a60c3df..3ccf052e72 100644 --- a/src/libprojectM/MilkdropPreset/MilkdropPreset.hpp +++ b/src/libprojectM/MilkdropPreset/MilkdropPreset.hpp @@ -29,6 +29,7 @@ #include "DarkenCenter.hpp" #include "Filters.hpp" #include "FinalComposite.hpp" +#include "FlipTexture.hpp" #include "MotionVectors.hpp" #include "PerFrameContext.hpp" #include "PerPixelContext.hpp" @@ -116,6 +117,7 @@ class MilkdropPreset : public Preset std::array, CustomShapeCount> m_customShapes; //!< Custom shapes in this preset. DarkenCenter m_darkenCenter; //!< Center darkening effect. Border m_border; //!< Inner/outer borders. + FlipTexture m_flipTexture{ m_state }; //!< Texture flip filter FinalComposite m_finalComposite; //!< Final composite shader or filters. diff --git a/src/libprojectM/MilkdropPreset/MilkdropShader.cpp b/src/libprojectM/MilkdropPreset/MilkdropShader.cpp index 49603054db..2d34463e70 100644 --- a/src/libprojectM/MilkdropPreset/MilkdropShader.cpp +++ b/src/libprojectM/MilkdropPreset/MilkdropShader.cpp @@ -122,7 +122,7 @@ void MilkdropShader::LoadVariables(const PresetState& presetState, const PerFram m_shader.Bind(); - m_shader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjectionFlipped); + m_shader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection); m_shader.SetUniformFloat4("rand_frame", {floatRand(), floatRand(), diff --git a/src/libprojectM/MilkdropPreset/PerPixelMesh.cpp b/src/libprojectM/MilkdropPreset/PerPixelMesh.cpp index 64b2a2706e..3aef868567 100644 --- a/src/libprojectM/MilkdropPreset/PerPixelMesh.cpp +++ b/src/libprojectM/MilkdropPreset/PerPixelMesh.cpp @@ -306,7 +306,7 @@ void PerPixelMesh::WarpedBlit(const PresetState& presetState, if (!m_warpShader) { m_perPixelMeshShader.Bind(); - m_perPixelMeshShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjectionFlipped); + m_perPixelMeshShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection); m_perPixelMeshShader.SetUniformInt("texture_sampler", 0); m_perPixelMeshShader.SetUniformFloat4("aspect", {presetState.renderContext.aspectX, presetState.renderContext.aspectY, diff --git a/src/libprojectM/MilkdropPreset/PresetState.cpp b/src/libprojectM/MilkdropPreset/PresetState.cpp index 74266a88fd..d21148fc90 100644 --- a/src/libprojectM/MilkdropPreset/PresetState.cpp +++ b/src/libprojectM/MilkdropPreset/PresetState.cpp @@ -6,17 +6,17 @@ #include -const glm::mat4 PresetState::orthogonalProjection = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -40.0f, 40.0f); -const glm::mat4 PresetState::orthogonalProjectionFlipped = glm::ortho(-1.0f, 1.0f, 1.0f, -1.0f, -40.0f, 40.0f); +const glm::mat4 PresetState::orthogonalProjection = glm::ortho(-1.0f, 1.0f, 1.0f, -1.0f, -40.0f, 40.0f); +const glm::mat4 PresetState::orthogonalProjectionFlipped = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -40.0f, 40.0f); PresetState::PresetState() : globalMemory(projectm_eval_memory_buffer_create()) { auto staticShaders = libprojectM::MilkdropPreset::MilkdropStaticShaders::Get(); untexturedShader.CompileProgram(staticShaders->GetUntexturedDrawVertexShader(), - staticShaders->GetUntexturedDrawFragmentShader()); + staticShaders->GetUntexturedDrawFragmentShader()); texturedShader.CompileProgram(staticShaders->GetTexturedDrawVertexShader(), - staticShaders->GetTexturedDrawFragmentShader()); + staticShaders->GetTexturedDrawFragmentShader()); std::random_device randomDevice; std::mt19937 randomGenerator(randomDevice()); diff --git a/src/libprojectM/MilkdropPreset/Shaders/PresetMotionVectorsVertexShaderGlsl330.vert b/src/libprojectM/MilkdropPreset/Shaders/PresetMotionVectorsVertexShaderGlsl330.vert index 70de3751cd..9de4ec60aa 100644 --- a/src/libprojectM/MilkdropPreset/Shaders/PresetMotionVectorsVertexShaderGlsl330.vert +++ b/src/libprojectM/MilkdropPreset/Shaders/PresetMotionVectorsVertexShaderGlsl330.vert @@ -23,7 +23,8 @@ void main() { // Milkdrop's original code did a simple bilinear interpolation, but here it was already // done by the fragment shader during the warp mesh drawing. We just need to look up the // motion vector coordinate. - vec2 oldUV = texture(warp_coordinates, pos.xy).xy; + // We simply invert the y coordinate because it's easier than flipping the u/v texture. + vec2 oldUV = texture(warp_coordinates, vec2(pos.x, 1.0 - pos.y)).xy; // Enforce minimum trail length vec2 dist = oldUV - pos; diff --git a/src/libprojectM/MilkdropPreset/Shaders/PresetWarpVertexShaderGlsl330.vert b/src/libprojectM/MilkdropPreset/Shaders/PresetWarpVertexShaderGlsl330.vert index 4e8d58a35e..b73da90160 100644 --- a/src/libprojectM/MilkdropPreset/Shaders/PresetWarpVertexShaderGlsl330.vert +++ b/src/libprojectM/MilkdropPreset/Shaders/PresetWarpVertexShaderGlsl330.vert @@ -40,11 +40,11 @@ void main() { // Initial texture coordinates, with built-in zoom factor float u = pos.x * aspectX * 0.5 * zoom2Inverse + 0.5; - float v = -pos.y * aspectY * 0.5 * zoom2Inverse + 0.5; + float v = pos.y * aspectY * 0.5 * zoom2Inverse + 0.5; // original UV coordinates vec2 uv_original = vec2(pos.x * 0.5 + 0.5 + texelOffset.x, - -pos.y * 0.5 + 0.5 + texelOffset.y); + pos.y * 0.5 + 0.5 + texelOffset.y); // Stretch on X, Y u = (u - center.x) / stretch.x + center.x; diff --git a/src/libprojectM/MilkdropPreset/VideoEcho.cpp b/src/libprojectM/MilkdropPreset/VideoEcho.cpp index 17763986a5..aeb63c7d65 100644 --- a/src/libprojectM/MilkdropPreset/VideoEcho.cpp +++ b/src/libprojectM/MilkdropPreset/VideoEcho.cpp @@ -68,7 +68,7 @@ void VideoEcho::Draw() } m_presetState.texturedShader.Bind(); - m_presetState.texturedShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjectionFlipped); + m_presetState.texturedShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection); m_presetState.texturedShader.SetUniformInt("texture_sampler", 0); auto mainTexture = m_presetState.mainTexture.lock(); diff --git a/src/libprojectM/Renderer/Framebuffer.cpp b/src/libprojectM/Renderer/Framebuffer.cpp index b4b9775020..1a71f2565b 100644 --- a/src/libprojectM/Renderer/Framebuffer.cpp +++ b/src/libprojectM/Renderer/Framebuffer.cpp @@ -102,6 +102,39 @@ bool Framebuffer::SetSize(int width, int height) return true; } +auto Framebuffer::GetAttachment(int framebufferIndex, TextureAttachment::AttachmentType type, int attachmentIndex) const -> std::shared_ptr +{ + if (framebufferIndex < 0 || framebufferIndex >= static_cast(m_framebufferIds.size())) + { + return {}; + } + + const auto& framebufferAttachments = m_attachments.at(framebufferIndex); + GLenum textureType; + + switch (type) + { + case TextureAttachment::AttachmentType::Color: + textureType = GL_COLOR_ATTACHMENT0 + attachmentIndex; + break; + case TextureAttachment::AttachmentType::Depth: + textureType = GL_DEPTH_ATTACHMENT; + break; + case TextureAttachment::AttachmentType::Stencil: + textureType = GL_STENCIL_ATTACHMENT; + break; + case TextureAttachment::AttachmentType::DepthStencil: + textureType = GL_DEPTH_STENCIL_ATTACHMENT; + break; + } + + if (framebufferAttachments.find(textureType) == framebufferAttachments.end()) { + return {}; + } + + return framebufferAttachments.at(textureType); +} + void Framebuffer::SetAttachment(int framebufferIndex, int attachmentIndex, const std::shared_ptr& attachment) { if (!attachment) diff --git a/src/libprojectM/Renderer/Framebuffer.hpp b/src/libprojectM/Renderer/Framebuffer.hpp index 558595693a..984166c0b4 100644 --- a/src/libprojectM/Renderer/Framebuffer.hpp +++ b/src/libprojectM/Renderer/Framebuffer.hpp @@ -93,6 +93,16 @@ class Framebuffer */ bool SetSize(int width, int height); + /** + * @brief Returns a texture attachment object. + * @param framebufferIndex The framebuffer index. + * @param type The attachment type to retrieve. + * @param attachmentIndex The index of the color attachment, at least indices 0-7 are guaranteed + * to be available. Ignored for non-color attachments. + * @return The requested attachment or nullptr if there is no attachment in the requested slot. + */ + auto GetAttachment(int framebufferIndex, TextureAttachment::AttachmentType type, int attachmentIndex = 0) const -> std::shared_ptr; + /** * @brief Sets a texture attachment slot to the given object. * Sets the read/write FBOs to the previously used ones in this instance. If a different diff --git a/src/libprojectM/Renderer/TextureAttachment.cpp b/src/libprojectM/Renderer/TextureAttachment.cpp index f39b69432e..4863289ee2 100644 --- a/src/libprojectM/Renderer/TextureAttachment.cpp +++ b/src/libprojectM/Renderer/TextureAttachment.cpp @@ -36,6 +36,11 @@ auto TextureAttachment::Texture() const -> std::shared_ptr return m_texture; } +void TextureAttachment::Texture(const std::shared_ptr& texture) +{ + m_texture = texture; +} + void TextureAttachment::SetSize(int width, int height) { if (width > 0 && height > 0) @@ -54,6 +59,12 @@ void TextureAttachment::ReplaceTexture(int width, int height) GLint textureFormat; GLenum pixelFormat; + // Don't replace if size hasn't changed + if (m_texture->Width() == width && m_texture->Height() == height) + { + return; + } + switch(m_attachmentType) { case AttachmentType::Color: diff --git a/src/libprojectM/Renderer/TextureAttachment.hpp b/src/libprojectM/Renderer/TextureAttachment.hpp index 7044badff4..845c74ea02 100644 --- a/src/libprojectM/Renderer/TextureAttachment.hpp +++ b/src/libprojectM/Renderer/TextureAttachment.hpp @@ -67,6 +67,13 @@ class TextureAttachment */ auto Texture() const -> std::shared_ptr; + /** + * @brief Replaces the current internal texture with the given one. + * Texture size is not changed. + * @param texture + */ + void Texture(const std::shared_ptr& texture); + /** * @brief Sets a new texture size. * Effectively reallocates the texture.