diff --git a/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.cpp b/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.cpp index 4d06dcc..ac1568b 100644 --- a/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.cpp +++ b/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.cpp @@ -38,6 +38,98 @@ void main() fragColor = texture(uInputTexture, clamp(vTexCoord, vec2(0.0), vec2(1.0))); } )GLSL"; + +const char* kPatternFragmentShader = R"GLSL( +#version 430 core +uniform vec2 uResolution; +uniform float uFrameIndex; +in vec2 vTexCoord; +out vec4 fragColor; + +vec3 hexColor(float r, float g, float b) +{ + return vec3(r, g, b) / 255.0; +} + +vec3 smpteTop(float x) +{ + if (x < 240.0) return hexColor(102.0, 102.0, 102.0); + if (x < 445.0) return hexColor(191.0, 191.0, 191.0); + if (x < 651.0) return hexColor(191.0, 191.0, 0.0); + if (x < 857.0) return hexColor(0.0, 191.0, 191.0); + if (x < 1063.0) return hexColor(0.0, 191.0, 0.0); + if (x < 1269.0) return hexColor(191.0, 0.0, 191.0); + if (x < 1475.0) return hexColor(191.0, 0.0, 0.0); + if (x < 1680.0) return hexColor(0.0, 0.0, 191.0); + return hexColor(102.0, 102.0, 102.0); +} + +vec3 smpteMiddleA(float x) +{ + if (x < 240.0) return hexColor(0.0, 255.0, 255.0); + if (x < 445.0) return hexColor(0.0, 63.0, 105.0); + if (x < 1680.0) return hexColor(191.0, 191.0, 191.0); + return hexColor(0.0, 0.0, 255.0); +} + +vec3 smpteMiddleB(float x) +{ + if (x < 240.0) return hexColor(255.0, 255.0, 0.0); + if (x < 445.0) return hexColor(65.0, 0.0, 119.0); + if (x < 1475.0) + { + float ramp = clamp((x - 445.0) / (1475.0 - 445.0), 0.0, 1.0); + return vec3(ramp); + } + if (x < 1680.0) return vec3(1.0); + return hexColor(255.0, 0.0, 0.0); +} + +vec3 smpteBottom(float x) +{ + if (x < 240.0) return hexColor(38.0, 38.0, 38.0); + if (x < 549.0) return vec3(0.0); + if (x < 960.0) return vec3(1.0); + if (x < 1268.0) return vec3(0.0); + if (x < 1337.0) return hexColor(5.0, 5.0, 5.0); + if (x < 1405.0) return vec3(0.0); + if (x < 1474.0) return hexColor(10.0, 10.0, 10.0); + if (x < 1680.0) return vec3(0.0); + return hexColor(38.0, 38.0, 38.0); +} + +vec3 smpteColor(vec2 uv) +{ + vec2 pixel = vec2(clamp(uv.x, 0.0, 1.0), 1.0 - clamp(uv.y, 0.0, 1.0)) * vec2(1920.0, 1080.0); + if (pixel.y < 630.0) return smpteTop(pixel.x); + if (pixel.y < 720.0) return smpteMiddleA(pixel.x); + if (pixel.y < 810.0) return smpteMiddleB(pixel.x); + return smpteBottom(pixel.x); +} + +void main() +{ + vec2 uv = clamp(vTexCoord, vec2(0.0), vec2(1.0)); + vec3 color = smpteColor(uv); + + float t = uFrameIndex / 60.0; + vec2 cubeSize = vec2(0.16, 0.20); + vec2 cubeMin = vec2( + (0.5 + 0.5 * sin(t * 1.7)) * (1.0 - cubeSize.x), + (0.5 + 0.5 * sin(t * 1.1 + 0.8)) * (1.0 - cubeSize.y)); + vec2 cubeMax = cubeMin + cubeSize; + bool insideCube = uv.x >= cubeMin.x && uv.x <= cubeMax.x && uv.y >= cubeMin.y && uv.y <= cubeMax.y; + if (insideCube) + { + vec2 local = (uv - cubeMin) / cubeSize; + vec3 cubeColor = vec3(1.0, 0.74 + 0.18 * sin(t * 2.1), 0.08); + float edge = step(local.x, 0.04) + step(local.y, 0.04) + step(0.96, local.x) + step(0.96, local.y); + color = edge > 0.0 ? vec3(1.0) : cubeColor; + } + + fragColor = vec4(color, 1.0); +} +)GLSL"; } bool SimpleMotionRenderer::InitializeGl(unsigned width, unsigned height) @@ -49,33 +141,30 @@ bool SimpleMotionRenderer::InitializeGl(unsigned width, unsigned height) 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)); + if (!EnsurePatternProgram()) + { + glViewport(0, 0, static_cast(mWidth), static_cast(mHeight)); + glDisable(GL_SCISSOR_TEST); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + return; + } 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); + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + glUseProgram(mPatternProgram); + const GLint resolutionLocation = glGetUniformLocation(mPatternProgram, "uResolution"); + if (resolutionLocation >= 0) + glUniform2f(resolutionLocation, static_cast(mWidth), static_cast(mHeight)); + const GLint frameIndexLocation = glGetUniformLocation(mPatternProgram, "uFrameIndex"); + if (frameIndexLocation >= 0) + glUniform1f(frameIndexLocation, static_cast(frameIndex)); + glBindVertexArray(mPatternVertexArray); + glDrawArrays(GL_TRIANGLES, 0, 3); + glBindVertexArray(0); + glUseProgram(0); } void SimpleMotionRenderer::RenderTexture(GLuint texture) @@ -103,11 +192,42 @@ void SimpleMotionRenderer::RenderTexture(GLuint texture) void SimpleMotionRenderer::ShutdownGl() { + DestroyPatternProgram(); DestroyTextureProgram(); mWidth = 0; mHeight = 0; } +bool SimpleMotionRenderer::EnsurePatternProgram() +{ + if (mPatternProgram != 0) + return true; + + if (!CompileShader(GL_VERTEX_SHADER, kTextureVertexShader, mPatternVertexShader)) + return false; + if (!CompileShader(GL_FRAGMENT_SHADER, kPatternFragmentShader, mPatternFragmentShader)) + { + DestroyPatternProgram(); + return false; + } + + mPatternProgram = glCreateProgram(); + glAttachShader(mPatternProgram, mPatternVertexShader); + glAttachShader(mPatternProgram, mPatternFragmentShader); + glLinkProgram(mPatternProgram); + + GLint linkResult = GL_FALSE; + glGetProgramiv(mPatternProgram, GL_LINK_STATUS, &linkResult); + if (linkResult == GL_FALSE) + { + DestroyPatternProgram(); + return false; + } + + glGenVertexArrays(1, &mPatternVertexArray); + return mPatternVertexArray != 0; +} + bool SimpleMotionRenderer::EnsureTextureProgram() { if (mTextureProgram != 0) @@ -160,6 +280,22 @@ void SimpleMotionRenderer::DestroyTextureProgram() mTextureVertexArray = 0; } +void SimpleMotionRenderer::DestroyPatternProgram() +{ + if (mPatternProgram != 0) + glDeleteProgram(mPatternProgram); + if (mPatternVertexShader != 0) + glDeleteShader(mPatternVertexShader); + if (mPatternFragmentShader != 0) + glDeleteShader(mPatternFragmentShader); + if (mPatternVertexArray != 0) + glDeleteVertexArrays(1, &mPatternVertexArray); + mPatternProgram = 0; + mPatternVertexShader = 0; + mPatternFragmentShader = 0; + mPatternVertexArray = 0; +} + bool SimpleMotionRenderer::CompileShader(GLenum shaderType, const char* source, GLuint& shader) { shader = glCreateShader(shaderType); diff --git a/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.h b/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.h index db00879..992509f 100644 --- a/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.h +++ b/apps/RenderCadenceCompositor/render/SimpleMotionRenderer.h @@ -19,11 +19,17 @@ public: private: bool EnsureTextureProgram(); + bool EnsurePatternProgram(); void DestroyTextureProgram(); + void DestroyPatternProgram(); static bool CompileShader(GLenum shaderType, const char* source, GLuint& shader); unsigned mWidth = 0; unsigned mHeight = 0; + GLuint mPatternProgram = 0; + GLuint mPatternVertexShader = 0; + GLuint mPatternFragmentShader = 0; + GLuint mPatternVertexArray = 0; GLuint mTextureProgram = 0; GLuint mTextureVertexShader = 0; GLuint mTextureFragmentShader = 0;