#include "SimpleMotionRenderer.h" #include "GLExtensions.h" #include #include #include 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(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(mWidth), static_cast(mHeight)); glDisable(GL_SCISSOR_TEST); glClearColor(red, green, blue, 1.0f); glClear(GL_COLOR_BUFFER_BIT); const int boxWidth = (std::max)(1, static_cast(mWidth / 6)); const int boxHeight = (std::max)(1, static_cast(mHeight / 5)); const float phase = 0.5f + 0.5f * std::sin(t * 1.7f); const int x = static_cast(phase * static_cast(mWidth - static_cast(boxWidth))); const int y = static_cast((0.5f + 0.5f * std::sin(t * 1.1f + 0.8f)) * static_cast(mHeight - static_cast(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(mWidth / 80)); const int stripeX = static_cast((frameIndex % 120) * (mWidth - static_cast(stripeWidth)) / 119); glScissor(stripeX, 0, stripeWidth, static_cast(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(mWidth), static_cast(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(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; }