#include "CopyTexture.hpp" namespace libprojectM { namespace Renderer { #ifdef USE_GLES static constexpr char ShaderVersion[] = "#version 300 es\n\n"; #else static constexpr char ShaderVersion[] = "#version 330\n\n"; #endif static constexpr char CopyTextureVertexShader[] = R"( precision mediump float; layout(location = 0) in vec2 position; layout(location = 2) in vec2 tex_coord; out vec2 fragment_tex_coord; uniform mat4 vertex_transformation; void main() { gl_Position = vec4(position, 0.0, 1.0) * vertex_transformation; fragment_tex_coord = tex_coord; } )"; static constexpr char CopyTextureFragmentShader[] = R"( precision mediump float; in vec2 fragment_tex_coord; uniform sampler2D texture_sampler; out vec4 color; void main(){ color = texture(texture_sampler, fragment_tex_coord); } )"; CopyTexture::CopyTexture() : m_mesh(VertexBufferUsage::StaticDraw, false, true) { m_framebuffer.CreateColorAttachment(0, 0); m_mesh.SetRenderPrimitiveType(Mesh::PrimitiveType::TriangleStrip); m_mesh.SetVertexCount(4); m_mesh.Vertices().Set({{-1.0, 1.0}, {1.0, 1.0}, {-1.0, -1.0}, {1.0, -1.0}}); m_mesh.UVs().Set({{0.0, 1.0}, {1.0, 1.0}, {0.0, 0.0}, {1.0, 0.0}}); m_mesh.Indices().Set({0, 1, 2, 3}); m_mesh.Update(); } void CopyTexture::Draw(ShaderCache& shaderCache, const std::shared_ptr& originalTexture, bool flipVertical, bool flipHorizontal) { if (originalTexture == nullptr) { return; } // Just bind the texture and draw it to the currently bound buffer. originalTexture->Bind(0); Copy(shaderCache, flipVertical, flipHorizontal); } void CopyTexture::Draw(ShaderCache& shaderCache, const std::shared_ptr& originalTexture, const std::shared_ptr& targetTexture, bool flipVertical, bool flipHorizontal) { if (originalTexture == nullptr || originalTexture->Empty() || (targetTexture != nullptr && targetTexture->Empty()) || originalTexture == targetTexture) { return; } if (targetTexture == nullptr) { UpdateTextureSize(originalTexture->Width(), originalTexture->Height()); } else { UpdateTextureSize(targetTexture->Width(), targetTexture->Height()); } if (m_width == 0 || m_height == 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); } Copy(shaderCache, flipVertical, flipHorizontal); // Rebind our internal texture. if (targetTexture) { m_framebuffer.GetAttachment(0, TextureAttachment::AttachmentType::Color, 0)->Texture(internalTexture); } Framebuffer::Unbind(); } void CopyTexture::Draw(ShaderCache& shaderCache, const std::shared_ptr& originalTexture, Framebuffer& framebuffer, int framebufferIndex, bool flipVertical, bool flipHorizontal) { if (originalTexture == nullptr // || originalTexture->Empty() // || framebuffer.GetColorAttachmentTexture(framebufferIndex, 0) == nullptr // || framebuffer.GetColorAttachmentTexture(framebufferIndex, 0)->Empty()) { return; } UpdateTextureSize(framebuffer.Width(), framebuffer.Height()); if (m_width == 0 || m_height == 0) { return; } m_framebuffer.Bind(0); // Draw from unflipped texture originalTexture->Bind(0); Copy(shaderCache, flipVertical, flipHorizontal); // 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(); } void CopyTexture::Draw(ShaderCache& shaderCache, const std::shared_ptr& originalTexture, const std::shared_ptr& targetTexture, int left, int top, int width, int height) { if (originalTexture == nullptr || originalTexture->Empty() || targetTexture == nullptr || targetTexture->Empty() || originalTexture == targetTexture) { return; } UpdateTextureSize(targetTexture->Width(), targetTexture->Height()); if (m_width == 0 || m_height == 0) { return; } std::shared_ptr internalTexture; m_framebuffer.Bind(0); // Draw from original texture originalTexture->Bind(0); internalTexture = m_framebuffer.GetColorAttachmentTexture(0, 0); m_framebuffer.GetAttachment(0, TextureAttachment::AttachmentType::Color, 0)->Texture(targetTexture); Copy(shaderCache, left, top, width, height); // Rebind our internal texture. m_framebuffer.GetAttachment(0, TextureAttachment::AttachmentType::Color, 0)->Texture(internalTexture); Framebuffer::Unbind(); } void CopyTexture::Draw(ShaderCache& shaderCache, GLuint originalTexture, int viewportWidth, int viewportHeight, int left, int top, int width, int height) { if (originalTexture == 0) { return; } if (viewportWidth == 0 || viewportHeight == 0) { return; } int oldWidth = m_width; int oldHeight = m_height; m_width = viewportWidth; m_height = viewportHeight; // Draw from original texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, originalTexture); Copy(shaderCache, left, top, width, height); m_width = oldWidth; m_height = oldHeight; } auto CopyTexture::Texture() -> std::shared_ptr { return m_framebuffer.GetColorAttachmentTexture(0, 0); } void CopyTexture::UpdateTextureSize(int width, int height) { if (m_width == width && m_height == height) { return; } m_width = width; m_height = height; m_framebuffer.SetSize(m_width, m_height); } void CopyTexture::Copy(ShaderCache& shaderCache, bool flipVertical, bool flipHorizontal) { glm::mat4x4 flipMatrix(1.0); flipMatrix[0][0] = flipHorizontal ? -1.0 : 1.0; flipMatrix[1][1] = flipVertical ? -1.0 : 1.0; std::shared_ptr shader = BindShader(shaderCache); shader->SetUniformInt("texture_sampler", 0); shader->SetUniformMat4x4("vertex_transformation", flipMatrix); m_sampler.Bind(0); m_mesh.Draw(); glBindTexture(GL_TEXTURE_2D, 0); Mesh::Unbind(); Sampler::Unbind(0); Shader::Unbind(); } void CopyTexture::Copy(ShaderCache& shaderCache, int left, int top, int width, int height) { glm::mat4x4 translationMatrix(1.0); translationMatrix[0][0] = static_cast(width) / static_cast(m_width); translationMatrix[1][1] = static_cast(height) / static_cast(m_height); translationMatrix[3][0] = static_cast(left) / static_cast(m_width); translationMatrix[3][1] = static_cast(top) / static_cast(m_height); std::shared_ptr shader = BindShader(shaderCache); shader->SetUniformInt("texture_sampler", 0); shader->SetUniformMat4x4("vertex_transformation", translationMatrix); m_sampler.Bind(0); m_mesh.Draw(); Mesh::Unbind(); Sampler::Unbind(0); Shader::Unbind(); } std::shared_ptr CopyTexture::BindShader(ShaderCache& shaderCache) { auto shader = m_shader.lock(); if (!shader) { shader = shaderCache.Get("copy_texture"); } if (!shader) { std::string vertexShader(ShaderVersion); std::string fragmentShader(ShaderVersion); vertexShader.append(CopyTextureVertexShader); fragmentShader.append(CopyTextureFragmentShader); shader = std::make_shared(); shader->CompileProgram(vertexShader, fragmentShader); m_shader = shader; shaderCache.Insert("copy_texture", shader); } shader->Bind(); return shader; } } // namespace Renderer } // namespace libprojectM