Compare commits
2 Commits
0a8b335048
...
2c5e925b97
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c5e925b97 | ||
|
|
957c0be05a |
@@ -159,6 +159,8 @@ void RenderThread::ThreadMain()
|
|||||||
if (!readback.RenderAndQueue(frameIndex, [this, &renderer, &runtimeRenderScene, videoInputTexture](uint64_t index) {
|
if (!readback.RenderAndQueue(frameIndex, [this, &renderer, &runtimeRenderScene, videoInputTexture](uint64_t index) {
|
||||||
if (runtimeRenderScene.HasLayers())
|
if (runtimeRenderScene.HasLayers())
|
||||||
runtimeRenderScene.RenderFrame(index, mConfig.width, mConfig.height, videoInputTexture);
|
runtimeRenderScene.RenderFrame(index, mConfig.width, mConfig.height, videoInputTexture);
|
||||||
|
else if (videoInputTexture != 0)
|
||||||
|
renderer.RenderTexture(videoInputTexture);
|
||||||
else
|
else
|
||||||
renderer.RenderFrame(index);
|
renderer.RenderFrame(index);
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -3,8 +3,135 @@
|
|||||||
#include "GLExtensions.h"
|
#include "GLExtensions.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <cmath>
|
#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";
|
||||||
|
|
||||||
|
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)
|
bool SimpleMotionRenderer::InitializeGl(unsigned width, unsigned height)
|
||||||
{
|
{
|
||||||
mWidth = width;
|
mWidth = width;
|
||||||
@@ -14,37 +141,173 @@ bool SimpleMotionRenderer::InitializeGl(unsigned width, unsigned height)
|
|||||||
|
|
||||||
void SimpleMotionRenderer::RenderFrame(uint64_t frameIndex)
|
void SimpleMotionRenderer::RenderFrame(uint64_t frameIndex)
|
||||||
{
|
{
|
||||||
const float t = static_cast<float>(frameIndex) / 60.0f;
|
if (!EnsurePatternProgram())
|
||||||
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));
|
glViewport(0, 0, static_cast<GLsizei>(mWidth), static_cast<GLsizei>(mHeight));
|
||||||
const float blue = 0.15f + 0.3f * (0.5f + 0.5f * std::sin(t * 0.41f + 2.0f));
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
glViewport(0, 0, static_cast<GLsizei>(mWidth), static_cast<GLsizei>(mHeight));
|
glViewport(0, 0, static_cast<GLsizei>(mWidth), static_cast<GLsizei>(mHeight));
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
glClearColor(red, green, blue, 1.0f);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glDisable(GL_BLEND);
|
||||||
|
glUseProgram(mPatternProgram);
|
||||||
|
const GLint resolutionLocation = glGetUniformLocation(mPatternProgram, "uResolution");
|
||||||
|
if (resolutionLocation >= 0)
|
||||||
|
glUniform2f(resolutionLocation, static_cast<float>(mWidth), static_cast<float>(mHeight));
|
||||||
|
const GLint frameIndexLocation = glGetUniformLocation(mPatternProgram, "uFrameIndex");
|
||||||
|
if (frameIndexLocation >= 0)
|
||||||
|
glUniform1f(frameIndexLocation, static_cast<float>(frameIndex));
|
||||||
|
glBindVertexArray(mPatternVertexArray);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glUseProgram(0);
|
||||||
|
}
|
||||||
|
|
||||||
const int boxWidth = (std::max)(1, static_cast<int>(mWidth / 6));
|
void SimpleMotionRenderer::RenderTexture(GLuint texture)
|
||||||
const int boxHeight = (std::max)(1, static_cast<int>(mHeight / 5));
|
{
|
||||||
const float phase = 0.5f + 0.5f * std::sin(t * 1.7f);
|
if (texture == 0 || !EnsureTextureProgram())
|
||||||
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)));
|
RenderFrame(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
glEnable(GL_SCISSOR_TEST);
|
glViewport(0, 0, static_cast<GLsizei>(mWidth), static_cast<GLsizei>(mHeight));
|
||||||
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);
|
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()
|
void SimpleMotionRenderer::ShutdownGl()
|
||||||
{
|
{
|
||||||
|
DestroyPatternProgram();
|
||||||
|
DestroyTextureProgram();
|
||||||
mWidth = 0;
|
mWidth = 0;
|
||||||
mHeight = 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)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "GLExtensions.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
class SimpleMotionRenderer
|
class SimpleMotionRenderer
|
||||||
@@ -9,12 +11,27 @@ public:
|
|||||||
|
|
||||||
bool InitializeGl(unsigned width, unsigned height);
|
bool InitializeGl(unsigned width, unsigned height);
|
||||||
void RenderFrame(uint64_t frameIndex);
|
void RenderFrame(uint64_t frameIndex);
|
||||||
|
void RenderTexture(GLuint texture);
|
||||||
void ShutdownGl();
|
void ShutdownGl();
|
||||||
|
|
||||||
unsigned Width() const { return mWidth; }
|
unsigned Width() const { return mWidth; }
|
||||||
unsigned Height() const { return mHeight; }
|
unsigned Height() const { return mHeight; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool EnsureTextureProgram();
|
||||||
|
bool EnsurePatternProgram();
|
||||||
|
void DestroyTextureProgram();
|
||||||
|
void DestroyPatternProgram();
|
||||||
|
static bool CompileShader(GLenum shaderType, const char* source, GLuint& shader);
|
||||||
|
|
||||||
unsigned mWidth = 0;
|
unsigned mWidth = 0;
|
||||||
unsigned mHeight = 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;
|
||||||
|
GLuint mTextureVertexArray = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user