mirror of
https://github.com/projectM-visualizer/projectm.git
synced 2026-02-04 19:15:28 +00:00
Also use shader cache in texture copier and a transformation matrix for flipping instead of flags.
332 lines
8.8 KiB
C++
332 lines
8.8 KiB
C++
#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<class Texture>& 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<class Texture>& originalTexture,
|
|
const std::shared_ptr<class Texture>& 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<class Texture> 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<class Texture>& 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<struct Texture>& originalTexture,
|
|
const std::shared_ptr<struct Texture>& 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<class Texture> 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<class Texture>
|
|
{
|
|
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> 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<float>(width) / static_cast<float>(m_width);
|
|
translationMatrix[1][1] = static_cast<float>(height) / static_cast<float>(m_height);
|
|
|
|
translationMatrix[3][0] = static_cast<float>(left) / static_cast<float>(m_width);
|
|
translationMatrix[3][1] = static_cast<float>(top) / static_cast<float>(m_height);
|
|
|
|
std::shared_ptr<Shader> 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<Shader> 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>();
|
|
shader->CompileProgram(vertexShader, fragmentShader);
|
|
|
|
m_shader = shader;
|
|
shaderCache.Insert("copy_texture", shader);
|
|
}
|
|
|
|
shader->Bind();
|
|
|
|
return shader;
|
|
}
|
|
|
|
} // namespace Renderer
|
|
} // namespace libprojectM
|