mirror of
https://github.com/projectM-visualizer/projectm.git
synced 2026-02-05 12:05:30 +00:00
If anyone else can come up with a solution that doesn't involve up to three vertical flips, please implement.
243 lines
7.9 KiB
C++
243 lines
7.9 KiB
C++
#include "VideoEcho.hpp"
|
|
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
|
|
VideoEcho::VideoEcho(const PresetState& presetState)
|
|
: RenderItem()
|
|
, m_presetState(presetState)
|
|
{
|
|
RenderItem::Init();
|
|
}
|
|
|
|
void VideoEcho::InitVertexAttrib()
|
|
{
|
|
glEnableVertexAttribArray(0);
|
|
glEnableVertexAttribArray(1);
|
|
glEnableVertexAttribArray(2);
|
|
|
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast<void*>(offsetof(TexturedPoint, x))); // Position
|
|
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast<void*>(offsetof(TexturedPoint, r))); // Color
|
|
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedPoint), reinterpret_cast<void*>(offsetof(TexturedPoint, u))); // Texture coordinates
|
|
}
|
|
|
|
void VideoEcho::Draw()
|
|
{
|
|
float const aspect = m_presetState.renderContext.viewportSizeX / static_cast<float>(m_presetState.renderContext.viewportSizeY * m_presetState.renderContext.invAspectY);
|
|
float aspectMultX = 1.0f;
|
|
float aspectMultY = 1.0f;
|
|
|
|
if (aspect > 1)
|
|
{
|
|
aspectMultY = aspect;
|
|
}
|
|
else
|
|
{
|
|
aspectMultX = 1.0f / aspect;
|
|
}
|
|
|
|
float const fOnePlusInvWidth = 1.0f + 1.0f / static_cast<float>(m_presetState.renderContext.viewportSizeX);
|
|
float const fOnePlusInvHeight = 1.0f + 1.0f / static_cast<float>(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;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
auto const indexFloat = static_cast<float>(i);
|
|
m_shade[i][0] = 0.6f + 0.3f * sinf(m_presetState.renderContext.time * 30.0f * 0.0143f + 3 + indexFloat * 21 + m_presetState.hueRandomOffsets[3]);
|
|
m_shade[i][1] = 0.6f + 0.3f * sinf(m_presetState.renderContext.time * 30.0f * 0.0107f + 1 + indexFloat * 13 + m_presetState.hueRandomOffsets[1]);
|
|
m_shade[i][2] = 0.6f + 0.3f * sinf(m_presetState.renderContext.time * 30.0f * 0.0129f + 6 + indexFloat * 9 + m_presetState.hueRandomOffsets[2]);
|
|
|
|
float const max = std::max(m_shade[i][0], std::max(m_shade[i][1], m_shade[i][2]));
|
|
|
|
for (int k = 0; k < 3; k++)
|
|
{
|
|
m_shade[i][k] /= max;
|
|
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;
|
|
}
|
|
|
|
m_presetState.texturedShader.Bind();
|
|
m_presetState.texturedShader.SetUniformMat4x4("vertex_transformation", PresetState::orthogonalProjection);
|
|
m_presetState.texturedShader.SetUniformInt("texture_sampler", 0);
|
|
|
|
auto mainTexture = m_presetState.mainTexture.lock();
|
|
if (mainTexture)
|
|
{
|
|
mainTexture->Bind(0);
|
|
m_sampler.Bind(0);
|
|
}
|
|
|
|
glBindVertexArray(m_vaoID);
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vboID);
|
|
|
|
if (m_presetState.videoEchoAlpha > 0.001f)
|
|
{
|
|
DrawVideoEcho();
|
|
}
|
|
else
|
|
{
|
|
DrawGammaAdjustment();
|
|
}
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindVertexArray(0);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
Shader::Unbind();
|
|
|
|
if (mainTexture)
|
|
{
|
|
mainTexture->Unbind(0);
|
|
Sampler::Unbind(0);
|
|
}
|
|
}
|
|
|
|
void VideoEcho::DrawVideoEcho()
|
|
{
|
|
auto const videoEchoZoom = m_presetState.videoEchoZoom;
|
|
auto const videoEchoAlpha = m_presetState.videoEchoAlpha;
|
|
auto const videoEchoOrientation = m_presetState.videoEchoOrientation % 4;
|
|
auto const gammaAdj = m_presetState.gammaAdj;
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_ONE, GL_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;
|
|
|
|
// Flipping
|
|
if (pass == 1)
|
|
{
|
|
for (int vertex = 0; vertex < 4; vertex++)
|
|
{
|
|
if (videoEchoOrientation % 2 == 1)
|
|
{
|
|
m_vertices[vertex].u = 1.0f - m_vertices[vertex].u;
|
|
}
|
|
if (videoEchoOrientation >= 2)
|
|
{
|
|
m_vertices[vertex].v = 1.0f - m_vertices[vertex].v;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizei>(sizeof(TexturedPoint) * m_vertices.size()), m_vertices.data(), GL_DYNAMIC_DRAW);
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, m_vertices.size());
|
|
|
|
if (pass == 0)
|
|
{
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
|
}
|
|
|
|
if (gammaAdj > 0.001f)
|
|
{
|
|
int const redrawCount = static_cast<int>(gammaAdj - 0.0001f);
|
|
|
|
for (int redraw = 0; redraw < redrawCount; redraw++)
|
|
{
|
|
float gamma;
|
|
if (redraw == redrawCount - 1)
|
|
{
|
|
gamma = gammaAdj - static_cast<float>(static_cast<int>(gammaAdj - 0.0001f));
|
|
}
|
|
else
|
|
{
|
|
gamma = 1.0f;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizei>(sizeof(TexturedPoint) * m_vertices.size()), m_vertices.data(), GL_DYNAMIC_DRAW);
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, static_cast<GLsizei>(m_vertices.size()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
auto const gammaAdj = m_presetState.gammaAdj;
|
|
int const redrawCount = static_cast<int>(gammaAdj - 0.0001f) + 1;
|
|
|
|
for (int redraw = 0; redraw < redrawCount; redraw++)
|
|
{
|
|
float gamma;
|
|
if (redraw == redrawCount - 1)
|
|
{
|
|
gamma = gammaAdj - static_cast<float>(redraw);
|
|
}
|
|
else
|
|
{
|
|
gamma = 1.0f;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizei>(sizeof(TexturedPoint) * m_vertices.size()), m_vertices.data(), GL_DYNAMIC_DRAW);
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, static_cast<GLsizei>(m_vertices.size()));
|
|
|
|
if (redraw == 0)
|
|
{
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
|
}
|
|
}
|
|
}
|