178 lines
4.9 KiB
C++
178 lines
4.9 KiB
C++
#include "SimpleMotionRenderer.h"
|
|
|
|
#include "GLExtensions.h"
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cmath>
|
|
|
|
namespace
|
|
{
|
|
constexpr GLuint kInputTextureUnit = 0;
|
|
|
|
const char* kTextureVertexShader = R"GLSL(
|
|
#version 430 core
|
|
out vec2 vTexCoord;
|
|
void main()
|
|
{
|
|
vec2 positions[3] = vec2[3](
|
|
vec2(-1.0, -1.0),
|
|
vec2( 3.0, -1.0),
|
|
vec2(-1.0, 3.0));
|
|
vec2 texCoords[3] = vec2[3](
|
|
vec2(0.0, 0.0),
|
|
vec2(2.0, 0.0),
|
|
vec2(0.0, 2.0));
|
|
gl_Position = vec4(positions[gl_VertexID], 0.0, 1.0);
|
|
vTexCoord = texCoords[gl_VertexID];
|
|
}
|
|
)GLSL";
|
|
|
|
const char* kTextureFragmentShader = R"GLSL(
|
|
#version 430 core
|
|
layout(binding = 0) uniform sampler2D uInputTexture;
|
|
in vec2 vTexCoord;
|
|
out vec4 fragColor;
|
|
void main()
|
|
{
|
|
fragColor = texture(uInputTexture, clamp(vTexCoord, vec2(0.0), vec2(1.0)));
|
|
}
|
|
)GLSL";
|
|
}
|
|
|
|
bool SimpleMotionRenderer::InitializeGl(unsigned width, unsigned height)
|
|
{
|
|
mWidth = width;
|
|
mHeight = height;
|
|
return mWidth > 0 && mHeight > 0;
|
|
}
|
|
|
|
void SimpleMotionRenderer::RenderFrame(uint64_t frameIndex)
|
|
{
|
|
const float t = static_cast<float>(frameIndex) / 60.0f;
|
|
const float red = 0.1f + 0.4f * (0.5f + 0.5f * std::sin(t));
|
|
const float green = 0.1f + 0.4f * (0.5f + 0.5f * std::sin(t * 0.73f + 1.0f));
|
|
const float blue = 0.15f + 0.3f * (0.5f + 0.5f * std::sin(t * 0.41f + 2.0f));
|
|
|
|
glViewport(0, 0, static_cast<GLsizei>(mWidth), static_cast<GLsizei>(mHeight));
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glClearColor(red, green, blue, 1.0f);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
const int boxWidth = (std::max)(1, static_cast<int>(mWidth / 6));
|
|
const int boxHeight = (std::max)(1, static_cast<int>(mHeight / 5));
|
|
const float phase = 0.5f + 0.5f * std::sin(t * 1.7f);
|
|
const int x = static_cast<int>(phase * static_cast<float>(mWidth - static_cast<unsigned>(boxWidth)));
|
|
const int y = static_cast<int>((0.5f + 0.5f * std::sin(t * 1.1f + 0.8f)) * static_cast<float>(mHeight - static_cast<unsigned>(boxHeight)));
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
glScissor(x, y, boxWidth, boxHeight);
|
|
glClearColor(1.0f - red, 0.85f, 0.15f + blue, 1.0f);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
const int stripeWidth = (std::max)(1, static_cast<int>(mWidth / 80));
|
|
const int stripeX = static_cast<int>((frameIndex % 120) * (mWidth - static_cast<unsigned>(stripeWidth)) / 119);
|
|
glScissor(stripeX, 0, stripeWidth, static_cast<GLsizei>(mHeight));
|
|
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
glDisable(GL_SCISSOR_TEST);
|
|
}
|
|
|
|
void SimpleMotionRenderer::RenderTexture(GLuint texture)
|
|
{
|
|
if (texture == 0 || !EnsureTextureProgram())
|
|
{
|
|
RenderFrame(0);
|
|
return;
|
|
}
|
|
|
|
glViewport(0, 0, static_cast<GLsizei>(mWidth), static_cast<GLsizei>(mHeight));
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_BLEND);
|
|
glActiveTexture(GL_TEXTURE0 + kInputTextureUnit);
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
|
glUseProgram(mTextureProgram);
|
|
glBindVertexArray(mTextureVertexArray);
|
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
|
glBindVertexArray(0);
|
|
glUseProgram(0);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
}
|
|
|
|
void SimpleMotionRenderer::ShutdownGl()
|
|
{
|
|
DestroyTextureProgram();
|
|
mWidth = 0;
|
|
mHeight = 0;
|
|
}
|
|
|
|
bool SimpleMotionRenderer::EnsureTextureProgram()
|
|
{
|
|
if (mTextureProgram != 0)
|
|
return true;
|
|
|
|
if (!CompileShader(GL_VERTEX_SHADER, kTextureVertexShader, mTextureVertexShader))
|
|
return false;
|
|
if (!CompileShader(GL_FRAGMENT_SHADER, kTextureFragmentShader, mTextureFragmentShader))
|
|
{
|
|
DestroyTextureProgram();
|
|
return false;
|
|
}
|
|
|
|
mTextureProgram = glCreateProgram();
|
|
glAttachShader(mTextureProgram, mTextureVertexShader);
|
|
glAttachShader(mTextureProgram, mTextureFragmentShader);
|
|
glLinkProgram(mTextureProgram);
|
|
|
|
GLint linkResult = GL_FALSE;
|
|
glGetProgramiv(mTextureProgram, GL_LINK_STATUS, &linkResult);
|
|
if (linkResult == GL_FALSE)
|
|
{
|
|
DestroyTextureProgram();
|
|
return false;
|
|
}
|
|
|
|
glUseProgram(mTextureProgram);
|
|
const GLint inputLocation = glGetUniformLocation(mTextureProgram, "uInputTexture");
|
|
if (inputLocation >= 0)
|
|
glUniform1i(inputLocation, static_cast<GLint>(kInputTextureUnit));
|
|
glUseProgram(0);
|
|
|
|
glGenVertexArrays(1, &mTextureVertexArray);
|
|
return mTextureVertexArray != 0;
|
|
}
|
|
|
|
void SimpleMotionRenderer::DestroyTextureProgram()
|
|
{
|
|
if (mTextureProgram != 0)
|
|
glDeleteProgram(mTextureProgram);
|
|
if (mTextureVertexShader != 0)
|
|
glDeleteShader(mTextureVertexShader);
|
|
if (mTextureFragmentShader != 0)
|
|
glDeleteShader(mTextureFragmentShader);
|
|
if (mTextureVertexArray != 0)
|
|
glDeleteVertexArrays(1, &mTextureVertexArray);
|
|
mTextureProgram = 0;
|
|
mTextureVertexShader = 0;
|
|
mTextureFragmentShader = 0;
|
|
mTextureVertexArray = 0;
|
|
}
|
|
|
|
bool SimpleMotionRenderer::CompileShader(GLenum shaderType, const char* source, GLuint& shader)
|
|
{
|
|
shader = glCreateShader(shaderType);
|
|
glShaderSource(shader, 1, &source, nullptr);
|
|
glCompileShader(shader);
|
|
|
|
GLint compileResult = GL_FALSE;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
|
|
if (compileResult != GL_FALSE)
|
|
return true;
|
|
|
|
glDeleteShader(shader);
|
|
shader = 0;
|
|
return false;
|
|
}
|