mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-25 07:35:38 +00:00
Added rounded corner support to the image, video, animation, carousel and grid elements
This commit is contained in:
parent
ed22fc7aa5
commit
170d8e3791
|
@ -118,6 +118,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
||||||
{"itemAxisRotation", FLOAT},
|
{"itemAxisRotation", FLOAT},
|
||||||
{"imageFit", STRING},
|
{"imageFit", STRING},
|
||||||
{"imageInterpolation", STRING},
|
{"imageInterpolation", STRING},
|
||||||
|
{"imageCornerRadius", FLOAT},
|
||||||
{"imageColor", COLOR},
|
{"imageColor", COLOR},
|
||||||
{"imageColorEnd", COLOR},
|
{"imageColorEnd", COLOR},
|
||||||
{"imageGradientType", STRING},
|
{"imageGradientType", STRING},
|
||||||
|
@ -184,6 +185,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
||||||
{"unfocusedItemDimming", FLOAT},
|
{"unfocusedItemDimming", FLOAT},
|
||||||
{"imageFit", STRING},
|
{"imageFit", STRING},
|
||||||
{"imageRelativeScale", FLOAT},
|
{"imageRelativeScale", FLOAT},
|
||||||
|
{"imageCornerRadius", FLOAT},
|
||||||
{"imageColor", COLOR},
|
{"imageColor", COLOR},
|
||||||
{"imageColorEnd", COLOR},
|
{"imageColorEnd", COLOR},
|
||||||
{"imageGradientType", STRING},
|
{"imageGradientType", STRING},
|
||||||
|
@ -194,11 +196,13 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
||||||
{"imageSaturation", FLOAT},
|
{"imageSaturation", FLOAT},
|
||||||
{"backgroundImage", PATH},
|
{"backgroundImage", PATH},
|
||||||
{"backgroundRelativeScale", FLOAT},
|
{"backgroundRelativeScale", FLOAT},
|
||||||
|
{"backgroundCornerRadius", FLOAT},
|
||||||
{"backgroundColor", COLOR},
|
{"backgroundColor", COLOR},
|
||||||
{"backgroundColorEnd", COLOR},
|
{"backgroundColorEnd", COLOR},
|
||||||
{"backgroundGradientType", STRING},
|
{"backgroundGradientType", STRING},
|
||||||
{"selectorImage", PATH},
|
{"selectorImage", PATH},
|
||||||
{"selectorRelativeScale", FLOAT},
|
{"selectorRelativeScale", FLOAT},
|
||||||
|
{"selectorCornerRadius", FLOAT},
|
||||||
{"selectorLayer", STRING},
|
{"selectorLayer", STRING},
|
||||||
{"selectorColor", COLOR},
|
{"selectorColor", COLOR},
|
||||||
{"selectorColorEnd", COLOR},
|
{"selectorColorEnd", COLOR},
|
||||||
|
@ -282,6 +286,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
||||||
{"tileHorizontalAlignment", STRING},
|
{"tileHorizontalAlignment", STRING},
|
||||||
{"tileVerticalAlignment", STRING},
|
{"tileVerticalAlignment", STRING},
|
||||||
{"interpolation", STRING},
|
{"interpolation", STRING},
|
||||||
|
{"cornerRadius", FLOAT},
|
||||||
{"color", COLOR},
|
{"color", COLOR},
|
||||||
{"colorEnd", COLOR},
|
{"colorEnd", COLOR},
|
||||||
{"gradientType", STRING},
|
{"gradientType", STRING},
|
||||||
|
@ -309,6 +314,8 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
||||||
{"onIterationsDone", STRING},
|
{"onIterationsDone", STRING},
|
||||||
{"audio", BOOLEAN},
|
{"audio", BOOLEAN},
|
||||||
{"interpolation", STRING},
|
{"interpolation", STRING},
|
||||||
|
{"imageCornerRadius", FLOAT},
|
||||||
|
{"videoCornerRadius", FLOAT},
|
||||||
{"color", COLOR},
|
{"color", COLOR},
|
||||||
{"colorEnd", COLOR},
|
{"colorEnd", COLOR},
|
||||||
{"gradientType", STRING},
|
{"gradientType", STRING},
|
||||||
|
@ -337,6 +344,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
||||||
{"direction", STRING},
|
{"direction", STRING},
|
||||||
{"iterationCount", UNSIGNED_INTEGER},
|
{"iterationCount", UNSIGNED_INTEGER},
|
||||||
{"interpolation", STRING},
|
{"interpolation", STRING},
|
||||||
|
{"cornerRadius", FLOAT},
|
||||||
{"color", COLOR},
|
{"color", COLOR},
|
||||||
{"colorEnd", COLOR},
|
{"colorEnd", COLOR},
|
||||||
{"gradientType", STRING},
|
{"gradientType", STRING},
|
||||||
|
|
|
@ -45,6 +45,7 @@ GIFAnimComponent::GIFAnimComponent()
|
||||||
, mIterationCount {0}
|
, mIterationCount {0}
|
||||||
, mPlayCount {0}
|
, mPlayCount {0}
|
||||||
, mTargetIsMax {false}
|
, mTargetIsMax {false}
|
||||||
|
, mCornerRadius {0.0f}
|
||||||
, mColorShift {0xFFFFFFFF}
|
, mColorShift {0xFFFFFFFF}
|
||||||
, mColorShiftEnd {0xFFFFFFFF}
|
, mColorShiftEnd {0xFFFFFFFF}
|
||||||
, mColorGradientHorizontal {true}
|
, mColorGradientHorizontal {true}
|
||||||
|
@ -372,6 +373,10 @@ void GIFAnimComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
mIterationCount *= 2;
|
mIterationCount *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (elem->has("cornerRadius"))
|
||||||
|
mCornerRadius =
|
||||||
|
glm::clamp(elem->get<float>("cornerRadius"), 0.0f, 0.5f) * mRenderer->getScreenWidth();
|
||||||
|
|
||||||
if (elem->has("interpolation")) {
|
if (elem->has("interpolation")) {
|
||||||
const std::string& interpolation {elem->get<std::string>("interpolation")};
|
const std::string& interpolation {elem->get<std::string>("interpolation")};
|
||||||
if (interpolation == "linear") {
|
if (interpolation == "linear") {
|
||||||
|
@ -588,6 +593,11 @@ void GIFAnimComponent::render(const glm::mat4& parentTrans)
|
||||||
vertices->dimming = mDimming;
|
vertices->dimming = mDimming;
|
||||||
vertices->shaderFlags = Renderer::ShaderFlags::PREMULTIPLIED;
|
vertices->shaderFlags = Renderer::ShaderFlags::PREMULTIPLIED;
|
||||||
|
|
||||||
|
if (mCornerRadius > 0.0f) {
|
||||||
|
vertices->cornerRadius = mCornerRadius;
|
||||||
|
vertices->shaderFlags = vertices->shaderFlags | Renderer::ShaderFlags::ROUNDED_CORNERS;
|
||||||
|
}
|
||||||
|
|
||||||
// Render it.
|
// Render it.
|
||||||
mRenderer->drawTriangleStrips(&vertices[0], 4);
|
mRenderer->drawTriangleStrips(&vertices[0], 4);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,7 @@ private:
|
||||||
int mPlayCount;
|
int mPlayCount;
|
||||||
bool mTargetIsMax;
|
bool mTargetIsMax;
|
||||||
|
|
||||||
|
float mCornerRadius;
|
||||||
unsigned int mColorShift;
|
unsigned int mColorShift;
|
||||||
unsigned int mColorShiftEnd;
|
unsigned int mColorShiftEnd;
|
||||||
bool mColorGradientHorizontal;
|
bool mColorGradientHorizontal;
|
||||||
|
|
|
@ -29,7 +29,9 @@ ImageComponent::ImageComponent(bool forceLoad, bool dynamic)
|
||||||
, mColorShiftEnd {0xFFFFFFFF}
|
, mColorShiftEnd {0xFFFFFFFF}
|
||||||
, mColorGradientHorizontal {true}
|
, mColorGradientHorizontal {true}
|
||||||
, mFadeOpacity {0.0f}
|
, mFadeOpacity {0.0f}
|
||||||
|
, mCornerRadius {0.0f}
|
||||||
, mReflectionsFalloff {0.0f}
|
, mReflectionsFalloff {0.0f}
|
||||||
|
, mCornerAntiAliasing {true}
|
||||||
, mFading {false}
|
, mFading {false}
|
||||||
, mForceLoad {forceLoad}
|
, mForceLoad {forceLoad}
|
||||||
, mDynamic {dynamic}
|
, mDynamic {dynamic}
|
||||||
|
@ -332,7 +334,6 @@ void ImageComponent::setSaturation(float saturation)
|
||||||
|
|
||||||
void ImageComponent::setDimming(float dimming)
|
void ImageComponent::setDimming(float dimming)
|
||||||
{
|
{
|
||||||
// Set dimming value.
|
|
||||||
mDimming = dimming;
|
mDimming = dimming;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,6 +433,18 @@ void ImageComponent::render(const glm::mat4& parentTrans)
|
||||||
mVertices->dimming = mDimming;
|
mVertices->dimming = mDimming;
|
||||||
mVertices->reflectionsFalloff = mReflectionsFalloff;
|
mVertices->reflectionsFalloff = mReflectionsFalloff;
|
||||||
|
|
||||||
|
if (mCornerRadius > 0.0f) {
|
||||||
|
mVertices->cornerRadius = mCornerRadius;
|
||||||
|
if (mCornerAntiAliasing) {
|
||||||
|
mVertices->shaderFlags =
|
||||||
|
mVertices->shaderFlags | Renderer::ShaderFlags::ROUNDED_CORNERS;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mVertices->shaderFlags =
|
||||||
|
mVertices->shaderFlags | Renderer::ShaderFlags::ROUNDED_CORNERS_NO_AA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mVertices->shaderFlags = mVertices->shaderFlags | Renderer::ShaderFlags::PREMULTIPLIED;
|
mVertices->shaderFlags = mVertices->shaderFlags | Renderer::ShaderFlags::PREMULTIPLIED;
|
||||||
mRenderer->drawTriangleStrips(&mVertices[0], 4);
|
mRenderer->drawTriangleStrips(&mVertices[0], 4);
|
||||||
}
|
}
|
||||||
|
@ -535,6 +548,10 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (elem->has("cornerRadius"))
|
||||||
|
mCornerRadius =
|
||||||
|
glm::clamp(elem->get<float>("cornerRadius"), 0.0f, 0.5f) * mRenderer->getScreenWidth();
|
||||||
|
|
||||||
if (properties && elem->has("imageType")) {
|
if (properties && elem->has("imageType")) {
|
||||||
std::string imageTypes {elem->get<std::string>("imageType")};
|
std::string imageTypes {elem->get<std::string>("imageType")};
|
||||||
for (auto& character : imageTypes) {
|
for (auto& character : imageTypes) {
|
||||||
|
|
|
@ -89,6 +89,8 @@ public:
|
||||||
void setSaturation(float saturation) override;
|
void setSaturation(float saturation) override;
|
||||||
void setDimming(float dimming) override;
|
void setDimming(float dimming) override;
|
||||||
void setClipRegion(const glm::vec4& clipRegion);
|
void setClipRegion(const glm::vec4& clipRegion);
|
||||||
|
void setCornerRadius(float radius) { mCornerRadius = radius; }
|
||||||
|
void setCornerAntiAliasing(bool state) { mCornerAntiAliasing = state; }
|
||||||
|
|
||||||
void setReflectionsFalloff(float falloff) override { mReflectionsFalloff = falloff; }
|
void setReflectionsFalloff(float falloff) override { mReflectionsFalloff = falloff; }
|
||||||
void setFlipX(bool state) override; // Mirror on the X axis.
|
void setFlipX(bool state) override; // Mirror on the X axis.
|
||||||
|
@ -159,7 +161,9 @@ private:
|
||||||
|
|
||||||
std::shared_ptr<TextureResource> mTexture;
|
std::shared_ptr<TextureResource> mTexture;
|
||||||
float mFadeOpacity;
|
float mFadeOpacity;
|
||||||
|
float mCornerRadius;
|
||||||
float mReflectionsFalloff;
|
float mReflectionsFalloff;
|
||||||
|
bool mCornerAntiAliasing;
|
||||||
bool mFading;
|
bool mFading;
|
||||||
bool mForceLoad;
|
bool mForceLoad;
|
||||||
bool mDynamic;
|
bool mDynamic;
|
||||||
|
|
|
@ -40,6 +40,7 @@ LottieAnimComponent::LottieAnimComponent()
|
||||||
, mIterationCount {0}
|
, mIterationCount {0}
|
||||||
, mPlayCount {0}
|
, mPlayCount {0}
|
||||||
, mTargetIsMax {false}
|
, mTargetIsMax {false}
|
||||||
|
, mCornerRadius {0.0f}
|
||||||
, mColorShift {0xFFFFFFFF}
|
, mColorShift {0xFFFFFFFF}
|
||||||
, mColorShiftEnd {0xFFFFFFFF}
|
, mColorShiftEnd {0xFFFFFFFF}
|
||||||
, mColorGradientHorizontal {true}
|
, mColorGradientHorizontal {true}
|
||||||
|
@ -342,6 +343,10 @@ void LottieAnimComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
mIterationCount *= 2;
|
mIterationCount *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (elem->has("cornerRadius"))
|
||||||
|
mCornerRadius =
|
||||||
|
glm::clamp(elem->get<float>("cornerRadius"), 0.0f, 0.5f) * mRenderer->getScreenWidth();
|
||||||
|
|
||||||
if (properties & COLOR) {
|
if (properties & COLOR) {
|
||||||
if (elem->has("color")) {
|
if (elem->has("color")) {
|
||||||
mColorShift = elem->get<unsigned int>("color");
|
mColorShift = elem->get<unsigned int>("color");
|
||||||
|
@ -579,6 +584,11 @@ void LottieAnimComponent::render(const glm::mat4& parentTrans)
|
||||||
vertices->dimming = mDimming;
|
vertices->dimming = mDimming;
|
||||||
vertices->shaderFlags = Renderer::ShaderFlags::PREMULTIPLIED;
|
vertices->shaderFlags = Renderer::ShaderFlags::PREMULTIPLIED;
|
||||||
|
|
||||||
|
if (mCornerRadius > 0.0f) {
|
||||||
|
vertices->cornerRadius = mCornerRadius;
|
||||||
|
vertices->shaderFlags = vertices->shaderFlags | Renderer::ShaderFlags::ROUNDED_CORNERS;
|
||||||
|
}
|
||||||
|
|
||||||
// Render it.
|
// Render it.
|
||||||
mRenderer->drawTriangleStrips(&vertices[0], 4);
|
mRenderer->drawTriangleStrips(&vertices[0], 4);
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,6 +90,7 @@ private:
|
||||||
int mPlayCount;
|
int mPlayCount;
|
||||||
bool mTargetIsMax;
|
bool mTargetIsMax;
|
||||||
|
|
||||||
|
float mCornerRadius;
|
||||||
unsigned int mColorShift;
|
unsigned int mColorShift;
|
||||||
unsigned int mColorShiftEnd;
|
unsigned int mColorShiftEnd;
|
||||||
bool mColorGradientHorizontal;
|
bool mColorGradientHorizontal;
|
||||||
|
|
|
@ -16,14 +16,16 @@
|
||||||
|
|
||||||
#include <SDL2/SDL_timer.h>
|
#include <SDL2/SDL_timer.h>
|
||||||
|
|
||||||
#define SCREENSAVER_FADE_IN_TIME 1100
|
#define SCREENSAVER_FADE_IN_TIME 900
|
||||||
#define MEDIA_VIEWER_FADE_IN_TIME 600
|
#define MEDIA_VIEWER_FADE_IN_TIME 600
|
||||||
|
|
||||||
VideoComponent::VideoComponent()
|
VideoComponent::VideoComponent()
|
||||||
: mVideoWidth {0}
|
: mRenderer {Renderer::getInstance()}
|
||||||
|
, mVideoWidth {0}
|
||||||
, mVideoHeight {0}
|
, mVideoHeight {0}
|
||||||
, mColorShift {0xFFFFFFFF}
|
, mColorShift {0xFFFFFFFF}
|
||||||
, mColorShiftEnd {0xFFFFFFFF}
|
, mColorShiftEnd {0xFFFFFFFF}
|
||||||
|
, mVideoCornerRadius {0.0f}
|
||||||
, mColorGradientHorizontal {true}
|
, mColorGradientHorizontal {true}
|
||||||
, mTargetSize {0.0f, 0.0f}
|
, mTargetSize {0.0f, 0.0f}
|
||||||
, mVideoAreaPos {0.0f, 0.0f}
|
, mVideoAreaPos {0.0f, 0.0f}
|
||||||
|
@ -131,7 +133,7 @@ void VideoComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
|
|
||||||
glm::vec2 scale {getParent() ?
|
glm::vec2 scale {getParent() ?
|
||||||
getParent()->getSize() :
|
getParent()->getSize() :
|
||||||
glm::vec2 {Renderer::getScreenWidth(), Renderer::getScreenHeight()}};
|
glm::vec2 {mRenderer->getScreenWidth(), mRenderer->getScreenHeight()}};
|
||||||
|
|
||||||
if (properties & ThemeFlags::SIZE) {
|
if (properties & ThemeFlags::SIZE) {
|
||||||
if (elem->has("size")) {
|
if (elem->has("size")) {
|
||||||
|
@ -225,6 +227,14 @@ void VideoComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (elem->has("imageCornerRadius"))
|
||||||
|
mStaticImage.setCornerRadius(glm::clamp(elem->get<float>("imageCornerRadius"), 0.0f, 0.5f) *
|
||||||
|
mRenderer->getScreenWidth());
|
||||||
|
|
||||||
|
if (elem->has("videoCornerRadius"))
|
||||||
|
mVideoCornerRadius = glm::clamp(elem->get<float>("videoCornerRadius"), 0.0f, 0.5f) *
|
||||||
|
mRenderer->getScreenWidth();
|
||||||
|
|
||||||
if (elem->has("default")) {
|
if (elem->has("default")) {
|
||||||
const std::string defaultVideo {elem->get<std::string>("default")};
|
const std::string defaultVideo {elem->get<std::string>("default")};
|
||||||
if (ResourceManager::getInstance().fileExists(defaultVideo)) {
|
if (ResourceManager::getInstance().fileExists(defaultVideo)) {
|
||||||
|
@ -332,6 +342,14 @@ void VideoComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
if (elem->has("pillarboxes"))
|
if (elem->has("pillarboxes"))
|
||||||
mDrawPillarboxes = elem->get<bool>("pillarboxes");
|
mDrawPillarboxes = elem->get<bool>("pillarboxes");
|
||||||
|
|
||||||
|
// The black frame is rendered behind all videos and may be expanded to render pillarboxes
|
||||||
|
// or letterboxes.
|
||||||
|
mBlackFrame.setZIndex(mZIndex);
|
||||||
|
mBlackFrame.setCornerRadius(mVideoCornerRadius);
|
||||||
|
mBlackFrame.setCornerAntiAliasing(false);
|
||||||
|
mBlackFrame.setColorShift(0x000000FF);
|
||||||
|
mBlackFrame.setImage(":/graphics/white.png");
|
||||||
|
|
||||||
if (elem->has("pillarboxThreshold")) {
|
if (elem->has("pillarboxThreshold")) {
|
||||||
const glm::vec2 pillarboxThreshold {elem->get<glm::vec2>("pillarboxThreshold")};
|
const glm::vec2 pillarboxThreshold {elem->get<glm::vec2>("pillarboxThreshold")};
|
||||||
mPillarboxThreshold.x = glm::clamp(pillarboxThreshold.x, 0.2f, 1.0f);
|
mPillarboxThreshold.x = glm::clamp(pillarboxThreshold.x, 0.2f, 1.0f);
|
||||||
|
|
|
@ -99,12 +99,15 @@ protected:
|
||||||
IMAGE
|
IMAGE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Renderer* mRenderer;
|
||||||
ImageComponent mStaticImage;
|
ImageComponent mStaticImage;
|
||||||
|
ImageComponent mBlackFrame;
|
||||||
|
|
||||||
unsigned mVideoWidth;
|
unsigned mVideoWidth;
|
||||||
unsigned mVideoHeight;
|
unsigned mVideoHeight;
|
||||||
unsigned int mColorShift;
|
unsigned int mColorShift;
|
||||||
unsigned int mColorShiftEnd;
|
unsigned int mColorShiftEnd;
|
||||||
|
float mVideoCornerRadius;
|
||||||
bool mColorGradientHorizontal;
|
bool mColorGradientHorizontal;
|
||||||
glm::vec2 mTargetSize;
|
glm::vec2 mTargetSize;
|
||||||
glm::vec2 mVideoAreaPos;
|
glm::vec2 mVideoAreaPos;
|
||||||
|
|
|
@ -30,8 +30,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VideoFFmpegComponent::VideoFFmpegComponent()
|
VideoFFmpegComponent::VideoFFmpegComponent()
|
||||||
: mRenderer {Renderer::getInstance()}
|
: mBlackFrameOffset {0.0f, 0.0f}
|
||||||
, mRectangleOffset {0.0f, 0.0f}
|
|
||||||
, mFrameProcessingThread {nullptr}
|
, mFrameProcessingThread {nullptr}
|
||||||
, mFormatContext {nullptr}
|
, mFormatContext {nullptr}
|
||||||
, mVideoStream {nullptr}
|
, mVideoStream {nullptr}
|
||||||
|
@ -176,31 +175,23 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
|
||||||
|
|
||||||
if (mIsPlaying && mFormatContext) {
|
if (mIsPlaying && mFormatContext) {
|
||||||
Renderer::Vertex vertices[4];
|
Renderer::Vertex vertices[4];
|
||||||
mRenderer->setMatrix(trans);
|
|
||||||
|
|
||||||
unsigned int rectColor {0x000000FF};
|
if (!mScreensaverMode && !mMediaViewerMode) {
|
||||||
|
mBlackFrame.setOpacity(mOpacity * mThemeOpacity);
|
||||||
if (!mGeneralFade && mThemeOpacity != 1.0f)
|
mBlackFrame.render(trans);
|
||||||
rectColor = static_cast<int>(mThemeOpacity * 255.0f);
|
|
||||||
if (mGeneralFade && (mOpacity != 1.0f || mThemeOpacity != 1.0f))
|
|
||||||
rectColor = static_cast<int>(mFadeIn * mOpacity * mThemeOpacity * 255.0f);
|
|
||||||
|
|
||||||
// Render the black rectangle behind the video.
|
|
||||||
if (mVideoRectangleCoords.size() == 4) {
|
|
||||||
mRenderer->drawRect(mVideoRectangleCoords[0], mVideoRectangleCoords[1],
|
|
||||||
mVideoRectangleCoords[2], mVideoRectangleCoords[3], // Line break.
|
|
||||||
rectColor, rectColor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mRenderer->setMatrix(trans);
|
||||||
|
|
||||||
// This is needed to avoid a slight gap before the video starts playing.
|
// This is needed to avoid a slight gap before the video starts playing.
|
||||||
if (!mDecodedFrame)
|
if (!mDecodedFrame)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
vertices[0] = {{0.0f + mRectangleOffset.x, 0.0f + mRectangleOffset.y }, {mTopLeftCrop.x, 1.0f - mBottomRightCrop.y}, 0xFFFFFFFF};
|
vertices[0] = {{0.0f + mBlackFrameOffset.x, 0.0f + mBlackFrameOffset.y }, {mTopLeftCrop.x, 1.0f - mBottomRightCrop.y}, 0xFFFFFFFF};
|
||||||
vertices[1] = {{0.0f + mRectangleOffset.x, mSize.y + mRectangleOffset.y }, {mTopLeftCrop.x, 1.0f - mTopLeftCrop.y }, 0xFFFFFFFF};
|
vertices[1] = {{0.0f + mBlackFrameOffset.x, mSize.y + mBlackFrameOffset.y }, {mTopLeftCrop.x, 1.0f - mTopLeftCrop.y }, 0xFFFFFFFF};
|
||||||
vertices[2] = {{mSize.x + mRectangleOffset.x, 0.0f + + mRectangleOffset.y }, {mBottomRightCrop.x * 1.0f, 1.0f - mBottomRightCrop.y}, 0xFFFFFFFF};
|
vertices[2] = {{mSize.x + mBlackFrameOffset.x, 0.0f + + mBlackFrameOffset.y }, {mBottomRightCrop.x * 1.0f, 1.0f - mBottomRightCrop.y}, 0xFFFFFFFF};
|
||||||
vertices[3] = {{mSize.x + mRectangleOffset.x, mSize.y + + mRectangleOffset.y}, {mBottomRightCrop.x * 1.0f, 1.0f - mTopLeftCrop.y }, 0xFFFFFFFF};
|
vertices[3] = {{mSize.x + mBlackFrameOffset.x, mSize.y + + mBlackFrameOffset.y}, {mBottomRightCrop.x * 1.0f, 1.0f - mTopLeftCrop.y }, 0xFFFFFFFF};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
vertices[0].color = mColorShift;
|
vertices[0].color = mColorShift;
|
||||||
|
@ -213,12 +204,22 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
|
||||||
vertices[i].position = glm::round(vertices[i].position);
|
vertices[i].position = glm::round(vertices[i].position);
|
||||||
|
|
||||||
if (mFadeIn < 1.0f || mThemeOpacity < 1.0f)
|
if (mFadeIn < 1.0f || mThemeOpacity < 1.0f)
|
||||||
vertices->opacity = mFadeIn * mThemeOpacity;
|
vertices->opacity = mOpacity * mThemeOpacity;
|
||||||
|
|
||||||
vertices->brightness = mBrightness;
|
vertices->brightness = mBrightness;
|
||||||
vertices->saturation = mSaturation * mThemeSaturation;
|
vertices->saturation = mSaturation * mThemeSaturation;
|
||||||
|
vertices->saturation = 1.0f;
|
||||||
vertices->dimming = mDimming;
|
vertices->dimming = mDimming;
|
||||||
|
|
||||||
|
if (mVideoCornerRadius > 0.0f) {
|
||||||
|
// We don't want to apply anti-aliasing to rounded corners as the black frame is
|
||||||
|
// rendered behind the video and that would generate ugly edge artifacts for any
|
||||||
|
// videos with lighter content.
|
||||||
|
vertices->cornerRadius = mVideoCornerRadius;
|
||||||
|
vertices->shaderFlags =
|
||||||
|
vertices->shaderFlags | Renderer::ShaderFlags::ROUNDED_CORNERS_NO_AA;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_lock<std::mutex> pictureLock {mPictureMutex};
|
std::unique_lock<std::mutex> pictureLock {mPictureMutex};
|
||||||
|
|
||||||
if (!mOutputPicture.hasBeenRendered) {
|
if (!mOutputPicture.hasBeenRendered) {
|
||||||
|
@ -266,6 +267,9 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
|
||||||
if (mRenderScanlines)
|
if (mRenderScanlines)
|
||||||
vertices[0].shaders = Renderer::Shader::SCANLINES;
|
vertices[0].shaders = Renderer::Shader::SCANLINES;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
vertices[0].opacity = mFadeIn;
|
||||||
|
}
|
||||||
|
|
||||||
mRenderer->drawTriangleStrips(&vertices[0], 4, Renderer::BlendFactor::SRC_ALPHA,
|
mRenderer->drawTriangleStrips(&vertices[0], 4, Renderer::BlendFactor::SRC_ALPHA,
|
||||||
Renderer::BlendFactor::ONE_MINUS_SRC_ALPHA);
|
Renderer::BlendFactor::ONE_MINUS_SRC_ALPHA);
|
||||||
|
@ -985,22 +989,24 @@ void VideoFFmpegComponent::outputFrames()
|
||||||
mEndOfVideo = true;
|
mEndOfVideo = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoFFmpegComponent::calculateBlackRectangle()
|
void VideoFFmpegComponent::calculateBlackFrame()
|
||||||
{
|
{
|
||||||
// Calculate the position and size for the black rectangle that will be rendered behind
|
// Calculate the position and size for the black frame image that will be rendered behind
|
||||||
// videos. If the option to display pillarboxes (and letterboxes) is enabled, then this
|
// videos. If the option to display pillarboxes (and letterboxes) is enabled, then this
|
||||||
// would extend to the entire video area (if above the threshold as defined below) or
|
// would extend to the entire video area (if above the threshold as explained below) or
|
||||||
// otherwise it will exactly match the video size. The reason to add a black rectangle
|
// otherwise it will exactly match the video size. The reason to add a black frame behind
|
||||||
// behind videos in this second instance is that the scanline rendering will make the
|
// videos in this second instance is that the scanline rendering will make the video
|
||||||
// video partially transparent so this may avoid some unforseen issues with some themes.
|
// partially transparent so this may avoid some unforseen issues with some themes.
|
||||||
|
// Another reason is that it always take a short while to initiate the video player which
|
||||||
|
// means no video texture is rendered for that brief moment, and it looks better to draw
|
||||||
|
// the black frame during this time period as most game videos also fade in from black.
|
||||||
// In general, adding very narrow pillarboxes or letterboxes doesn't look good, so by
|
// In general, adding very narrow pillarboxes or letterboxes doesn't look good, so by
|
||||||
// default this is not done unless the size of the video vs the overall video area is
|
// default this is not done unless the size of the video vs the overall video area is
|
||||||
// above the threshold defined by mPillarboxThreshold. By default this is set to 0.85
|
// above the threshold defined by mPillarboxThreshold. By default this is set to 0.85
|
||||||
// for the X axis and 0.90 for the Y axis, but this is theme-controllable via the
|
// for the X axis and 0.90 for the Y axis, but this is theme-controllable via the
|
||||||
// pillarboxThreshold property.
|
// pillarboxThreshold property.
|
||||||
if (mVideoAreaPos != glm::vec2 {0.0f, 0.0f} && mVideoAreaSize != glm::vec2 {0.0f, 0.0f}) {
|
if (mVideoAreaPos != glm::vec2 {0.0f, 0.0f} && mVideoAreaSize != glm::vec2 {0.0f, 0.0f}) {
|
||||||
mVideoRectangleCoords.clear();
|
mBlackFrameOffset = {0.0f, 0.0f};
|
||||||
mRectangleOffset = {0.0f, 0.0f};
|
|
||||||
|
|
||||||
if (mDrawPillarboxes) {
|
if (mDrawPillarboxes) {
|
||||||
float rectHeight {0.0f};
|
float rectHeight {0.0f};
|
||||||
|
@ -1037,26 +1043,23 @@ void VideoFFmpegComponent::calculateBlackRectangle()
|
||||||
// the video correctly.
|
// the video correctly.
|
||||||
if (mOrigin != glm::vec2 {0.5f, 0.5f}) {
|
if (mOrigin != glm::vec2 {0.5f, 0.5f}) {
|
||||||
if (rectWidth > mSize.x)
|
if (rectWidth > mSize.x)
|
||||||
mRectangleOffset.x -= (rectWidth - mSize.x) * (mOrigin.x - 0.5f);
|
mBlackFrameOffset.x -= (rectWidth - mSize.x) * (mOrigin.x - 0.5f);
|
||||||
else if (rectHeight > mSize.y)
|
else if (rectHeight > mSize.y)
|
||||||
mRectangleOffset.y -= (rectHeight - mSize.y) * (mOrigin.y - 0.5f);
|
mBlackFrameOffset.y -= (rectHeight - mSize.y) * (mOrigin.y - 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate the rectangle coordinates to be used in render().
|
// Set the black frame position and size.
|
||||||
const float offsetX {rectWidth - mSize.x};
|
const float offsetX {rectWidth - mSize.x};
|
||||||
const float offsetY {rectHeight - mSize.y};
|
const float offsetY {rectHeight - mSize.y};
|
||||||
mVideoRectangleCoords.emplace_back(std::round((-offsetX / 2.0f) + mRectangleOffset.x));
|
mBlackFrame.setPosition((-offsetX / 2.0f) + mBlackFrameOffset.x,
|
||||||
mVideoRectangleCoords.emplace_back(std::round((-offsetY / 2.0f) + mRectangleOffset.y));
|
(-offsetY / 2.0f) + mBlackFrameOffset.y);
|
||||||
mVideoRectangleCoords.emplace_back(std::round(rectWidth));
|
mBlackFrame.setResize(rectWidth, rectHeight);
|
||||||
mVideoRectangleCoords.emplace_back(std::round(rectHeight));
|
|
||||||
}
|
}
|
||||||
// If the option to display pillarboxes is disabled, then make the rectangle equivalent
|
|
||||||
// to the size of the video.
|
|
||||||
else {
|
else {
|
||||||
mVideoRectangleCoords.emplace_back(0.0f);
|
// If the option to display pillarboxes is disabled, then set the black frame to the
|
||||||
mVideoRectangleCoords.emplace_back(0.0f);
|
// same position and size as the video.
|
||||||
mVideoRectangleCoords.emplace_back(std::round(mSize.x));
|
mBlackFrame.setPosition(0.0f, 0.0f);
|
||||||
mVideoRectangleCoords.emplace_back(std::round(mSize.y));
|
mBlackFrame.setResize(mSize.x, mSize.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1553,8 +1556,7 @@ void VideoFFmpegComponent::startVideoStream()
|
||||||
// the video screeensaver.
|
// the video screeensaver.
|
||||||
resize();
|
resize();
|
||||||
|
|
||||||
// Calculate pillarbox/letterbox sizes.
|
calculateBlackFrame();
|
||||||
calculateBlackRectangle();
|
|
||||||
|
|
||||||
mFadeIn = 0.0f;
|
mFadeIn = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,15 +82,14 @@ private:
|
||||||
// Output frames to AudioManager and to the video surface (via the main thread).
|
// Output frames to AudioManager and to the video surface (via the main thread).
|
||||||
void outputFrames();
|
void outputFrames();
|
||||||
|
|
||||||
// Calculate the black rectangle that is shown behind videos with non-standard aspect ratios.
|
// Calculate the black frame that is rendered behind all videos and which may also be
|
||||||
void calculateBlackRectangle();
|
// adding pillarboxes/letterboxes.
|
||||||
|
void calculateBlackFrame();
|
||||||
|
|
||||||
// Detect and initialize the hardware decoder.
|
// Detect and initialize the hardware decoder.
|
||||||
static void detectHWDecoder();
|
static void detectHWDecoder();
|
||||||
bool decoderInitHW();
|
bool decoderInitHW();
|
||||||
|
|
||||||
Renderer* mRenderer;
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static inline enum AVHWDeviceType sDeviceType {AV_HWDEVICE_TYPE_NONE};
|
static inline enum AVHWDeviceType sDeviceType {AV_HWDEVICE_TYPE_NONE};
|
||||||
static inline enum AVPixelFormat sPixelFormat {AV_PIX_FMT_NONE};
|
static inline enum AVPixelFormat sPixelFormat {AV_PIX_FMT_NONE};
|
||||||
|
@ -99,8 +98,7 @@ private:
|
||||||
static inline std::vector<std::string> sHWDecodedVideos;
|
static inline std::vector<std::string> sHWDecodedVideos;
|
||||||
|
|
||||||
std::shared_ptr<TextureResource> mTexture;
|
std::shared_ptr<TextureResource> mTexture;
|
||||||
std::vector<float> mVideoRectangleCoords;
|
glm::vec2 mBlackFrameOffset;
|
||||||
glm::vec2 mRectangleOffset;
|
|
||||||
|
|
||||||
std::unique_ptr<std::thread> mFrameProcessingThread;
|
std::unique_ptr<std::thread> mFrameProcessingThread;
|
||||||
std::mutex mPictureMutex;
|
std::mutex mPictureMutex;
|
||||||
|
|
|
@ -166,6 +166,7 @@ private:
|
||||||
bool mItemAxisHorizontal;
|
bool mItemAxisHorizontal;
|
||||||
float mItemAxisRotation;
|
float mItemAxisRotation;
|
||||||
bool mLinearInterpolation;
|
bool mLinearInterpolation;
|
||||||
|
float mImageCornerRadius;
|
||||||
unsigned int mImageColorShift;
|
unsigned int mImageColorShift;
|
||||||
unsigned int mImageColorShiftEnd;
|
unsigned int mImageColorShiftEnd;
|
||||||
bool mImageColorGradientHorizontal;
|
bool mImageColorGradientHorizontal;
|
||||||
|
@ -241,6 +242,7 @@ CarouselComponent<T>::CarouselComponent()
|
||||||
, mItemAxisHorizontal {false}
|
, mItemAxisHorizontal {false}
|
||||||
, mItemAxisRotation {0.0f}
|
, mItemAxisRotation {0.0f}
|
||||||
, mLinearInterpolation {false}
|
, mLinearInterpolation {false}
|
||||||
|
, mImageCornerRadius {0.0f}
|
||||||
, mImageColorShift {0xFFFFFFFF}
|
, mImageColorShift {0xFFFFFFFF}
|
||||||
, mImageColorShiftEnd {0xFFFFFFFF}
|
, mImageColorShiftEnd {0xFFFFFFFF}
|
||||||
, mImageColorGradientHorizontal {true}
|
, mImageColorGradientHorizontal {true}
|
||||||
|
@ -309,6 +311,7 @@ void CarouselComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeDat
|
||||||
item->setResize(glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
item->setResize(glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
||||||
else if (mImagefit == ImageFit::COVER)
|
else if (mImagefit == ImageFit::COVER)
|
||||||
item->setCroppedSize(glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
item->setCroppedSize(glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
||||||
|
item->setCornerRadius(mImageCornerRadius);
|
||||||
item->setImage(entry.data.imagePath);
|
item->setImage(entry.data.imagePath);
|
||||||
item->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
item->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
||||||
if (mImageBrightness != 0.0)
|
if (mImageBrightness != 0.0)
|
||||||
|
@ -339,6 +342,7 @@ void CarouselComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeDat
|
||||||
else if (mImagefit == ImageFit::COVER)
|
else if (mImagefit == ImageFit::COVER)
|
||||||
mDefaultImage->setCroppedSize(
|
mDefaultImage->setCroppedSize(
|
||||||
glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
||||||
|
mDefaultImage->setCornerRadius(mImageCornerRadius);
|
||||||
mDefaultImage->setImage(entry.data.defaultImagePath);
|
mDefaultImage->setImage(entry.data.defaultImagePath);
|
||||||
mDefaultImage->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
mDefaultImage->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
||||||
if (mImageBrightness != 0.0)
|
if (mImageBrightness != 0.0)
|
||||||
|
@ -413,6 +417,7 @@ void CarouselComponent<T>::updateEntry(Entry& entry, const std::shared_ptr<Theme
|
||||||
item->setResize(glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
item->setResize(glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
||||||
else if (mImagefit == ImageFit::COVER)
|
else if (mImagefit == ImageFit::COVER)
|
||||||
item->setCroppedSize(glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
item->setCroppedSize(glm::round(mItemSize * (mItemScale >= 1.0f ? mItemScale : 1.0f)));
|
||||||
|
item->setCornerRadius(mImageCornerRadius);
|
||||||
item->setImage(entry.data.imagePath);
|
item->setImage(entry.data.imagePath);
|
||||||
item->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
item->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
||||||
if (mImageBrightness != 0.0)
|
if (mImageBrightness != 0.0)
|
||||||
|
@ -1429,6 +1434,10 @@ void CarouselComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (elem->has("imageCornerRadius"))
|
||||||
|
mImageCornerRadius = glm::clamp(elem->get<float>("imageCornerRadius"), 0.0f, 0.5f) *
|
||||||
|
(mItemScale >= 1.0f ? mItemScale : 1.0f) * mRenderer->getScreenWidth();
|
||||||
|
|
||||||
mImageSelectedColor = mImageColorShift;
|
mImageSelectedColor = mImageColorShift;
|
||||||
mImageSelectedColorEnd = mImageColorShiftEnd;
|
mImageSelectedColorEnd = mImageColorShiftEnd;
|
||||||
|
|
||||||
|
|
|
@ -162,6 +162,7 @@ private:
|
||||||
float mUnfocusedItemDimming;
|
float mUnfocusedItemDimming;
|
||||||
ImageFit mImagefit;
|
ImageFit mImagefit;
|
||||||
float mImageRelativeScale;
|
float mImageRelativeScale;
|
||||||
|
float mImageCornerRadius;
|
||||||
unsigned int mImageColor;
|
unsigned int mImageColor;
|
||||||
unsigned int mImageColorEnd;
|
unsigned int mImageColorEnd;
|
||||||
bool mImageColorGradientHorizontal;
|
bool mImageColorGradientHorizontal;
|
||||||
|
@ -238,6 +239,7 @@ GridComponent<T>::GridComponent()
|
||||||
, mUnfocusedItemDimming {1.0f}
|
, mUnfocusedItemDimming {1.0f}
|
||||||
, mImagefit {ImageFit::CONTAIN}
|
, mImagefit {ImageFit::CONTAIN}
|
||||||
, mImageRelativeScale {1.0f}
|
, mImageRelativeScale {1.0f}
|
||||||
|
, mImageCornerRadius {0.0f}
|
||||||
, mImageColor {0xFFFFFFFF}
|
, mImageColor {0xFFFFFFFF}
|
||||||
, mImageColorEnd {0xFFFFFFFF}
|
, mImageColorEnd {0xFFFFFFFF}
|
||||||
, mImageColorGradientHorizontal {true}
|
, mImageColorGradientHorizontal {true}
|
||||||
|
@ -306,6 +308,7 @@ void GridComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeData>&
|
||||||
item->setResize(mItemSize * mImageRelativeScale);
|
item->setResize(mItemSize * mImageRelativeScale);
|
||||||
else if (mImagefit == ImageFit::COVER)
|
else if (mImagefit == ImageFit::COVER)
|
||||||
item->setCroppedSize(mItemSize * mImageRelativeScale);
|
item->setCroppedSize(mItemSize * mImageRelativeScale);
|
||||||
|
item->setCornerRadius(mImageCornerRadius);
|
||||||
item->setImage(entry.data.imagePath);
|
item->setImage(entry.data.imagePath);
|
||||||
item->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
item->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
||||||
if (mImageBrightness != 0.0)
|
if (mImageBrightness != 0.0)
|
||||||
|
@ -338,6 +341,7 @@ void GridComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeData>&
|
||||||
mDefaultImage->setResize(mItemSize * mImageRelativeScale);
|
mDefaultImage->setResize(mItemSize * mImageRelativeScale);
|
||||||
else if (mImagefit == ImageFit::COVER)
|
else if (mImagefit == ImageFit::COVER)
|
||||||
mDefaultImage->setCroppedSize(mItemSize * mImageRelativeScale);
|
mDefaultImage->setCroppedSize(mItemSize * mImageRelativeScale);
|
||||||
|
mDefaultImage->setCornerRadius(mImageCornerRadius);
|
||||||
mDefaultImage->setImage(entry.data.defaultImagePath);
|
mDefaultImage->setImage(entry.data.defaultImagePath);
|
||||||
mDefaultImage->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
mDefaultImage->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
||||||
if (mImageBrightness != 0.0)
|
if (mImageBrightness != 0.0)
|
||||||
|
@ -395,6 +399,7 @@ void GridComponent<T>::updateEntry(Entry& entry, const std::shared_ptr<ThemeData
|
||||||
item->setResize(mItemSize * mImageRelativeScale);
|
item->setResize(mItemSize * mImageRelativeScale);
|
||||||
else if (mImagefit == ImageFit::COVER)
|
else if (mImagefit == ImageFit::COVER)
|
||||||
item->setCroppedSize(mItemSize * mImageRelativeScale);
|
item->setCroppedSize(mItemSize * mImageRelativeScale);
|
||||||
|
item->setCornerRadius(mImageCornerRadius);
|
||||||
item->setImage(entry.data.imagePath);
|
item->setImage(entry.data.imagePath);
|
||||||
item->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
item->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
||||||
if (mImageBrightness != 0.0)
|
if (mImageBrightness != 0.0)
|
||||||
|
@ -1121,6 +1126,12 @@ void GridComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
mBackgroundImage->setColorGradientHorizontal(false);
|
mBackgroundImage->setColorGradientHorizontal(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
float backgroundCornerRadius {0.0f};
|
||||||
|
if (elem->has("backgroundCornerRadius"))
|
||||||
|
backgroundCornerRadius =
|
||||||
|
glm::clamp(elem->get<float>("backgroundCornerRadius"), 0.0f, 0.5f) *
|
||||||
|
(mItemScale >= 1.0f ? mItemScale : 1.0f) * mRenderer->getScreenWidth();
|
||||||
|
mBackgroundImage->setCornerRadius(backgroundCornerRadius);
|
||||||
mBackgroundImage->setImage(elem->get<std::string>("backgroundImage"));
|
mBackgroundImage->setImage(elem->get<std::string>("backgroundImage"));
|
||||||
mBackgroundImagePath = path;
|
mBackgroundImagePath = path;
|
||||||
}
|
}
|
||||||
|
@ -1146,6 +1157,12 @@ void GridComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
mSelectorImage->setColorGradientHorizontal(false);
|
mSelectorImage->setColorGradientHorizontal(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
float selectorCornerRadius {0.0f};
|
||||||
|
if (elem->has("selectorCornerRadius"))
|
||||||
|
selectorCornerRadius =
|
||||||
|
glm::clamp(elem->get<float>("selectorCornerRadius"), 0.0f, 0.5f) *
|
||||||
|
(mItemScale >= 1.0f ? mItemScale : 1.0f) * mRenderer->getScreenWidth();
|
||||||
|
mSelectorImage->setCornerRadius(selectorCornerRadius);
|
||||||
mSelectorImage->setImage(elem->get<std::string>("selectorImage"));
|
mSelectorImage->setImage(elem->get<std::string>("selectorImage"));
|
||||||
mSelectorImagePath = path;
|
mSelectorImagePath = path;
|
||||||
}
|
}
|
||||||
|
@ -1236,6 +1253,10 @@ void GridComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
mItemSpacing.y = ((mItemSize.y * mItemScale) - mItemSize.y) / 2.0f;
|
mItemSpacing.y = ((mItemSize.y * mItemScale) - mItemSize.y) / 2.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (elem->has("imageCornerRadius"))
|
||||||
|
mImageCornerRadius = glm::clamp(elem->get<float>("imageCornerRadius"), 0.0f, 0.5f) *
|
||||||
|
(mItemScale >= 1.0f ? mItemScale : 1.0f) * mRenderer->getScreenWidth();
|
||||||
|
|
||||||
if (elem->has("imageColor")) {
|
if (elem->has("imageColor")) {
|
||||||
mImageColor = elem->get<unsigned int>("imageColor");
|
mImageColor = elem->get<unsigned int>("imageColor");
|
||||||
mImageColorEnd = mImageColor;
|
mImageColorEnd = mImageColor;
|
||||||
|
|
|
@ -49,11 +49,13 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ShaderFlags {
|
enum ShaderFlags {
|
||||||
PREMULTIPLIED = 0x00000001,
|
PREMULTIPLIED = 0x00000001,
|
||||||
FONT_TEXTURE = 0x00000002,
|
FONT_TEXTURE = 0x00000002,
|
||||||
POST_PROCESSING = 0x00000004,
|
POST_PROCESSING = 0x00000004,
|
||||||
CLIPPING = 0x00000008,
|
CLIPPING = 0x00000008,
|
||||||
ROTATED = 0x00000010 // Screen rotated 90 or 270 degrees.
|
ROTATED = 0x00000010, // Screen rotated 90 or 270 degrees.
|
||||||
|
ROUNDED_CORNERS = 0x00000020,
|
||||||
|
ROUNDED_CORNERS_NO_AA = 0x00000040
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
@ -66,6 +68,7 @@ public:
|
||||||
float opacity;
|
float opacity;
|
||||||
float saturation;
|
float saturation;
|
||||||
float dimming;
|
float dimming;
|
||||||
|
float cornerRadius;
|
||||||
float reflectionsFalloff;
|
float reflectionsFalloff;
|
||||||
float blurStrength;
|
float blurStrength;
|
||||||
unsigned int shaders;
|
unsigned int shaders;
|
||||||
|
@ -76,6 +79,7 @@ public:
|
||||||
, opacity {1.0f}
|
, opacity {1.0f}
|
||||||
, saturation {1.0f}
|
, saturation {1.0f}
|
||||||
, dimming {1.0f}
|
, dimming {1.0f}
|
||||||
|
, cornerRadius {0.0f}
|
||||||
, reflectionsFalloff {0.0f}
|
, reflectionsFalloff {0.0f}
|
||||||
, blurStrength {0.0f}
|
, blurStrength {0.0f}
|
||||||
, shaders {0}
|
, shaders {0}
|
||||||
|
@ -95,6 +99,7 @@ public:
|
||||||
, opacity {1.0f}
|
, opacity {1.0f}
|
||||||
, saturation {1.0f}
|
, saturation {1.0f}
|
||||||
, dimming {1.0f}
|
, dimming {1.0f}
|
||||||
|
, cornerRadius {0.0f}
|
||||||
, reflectionsFalloff {0.0f}
|
, reflectionsFalloff {0.0f}
|
||||||
, blurStrength {0.0f}
|
, blurStrength {0.0f}
|
||||||
, shaders {0}
|
, shaders {0}
|
||||||
|
|
|
@ -505,6 +505,11 @@ void RendererOpenGL::drawTriangleStrips(const Vertex* vertices,
|
||||||
mCoreShader->setOpacity(vertices->opacity);
|
mCoreShader->setOpacity(vertices->opacity);
|
||||||
mCoreShader->setSaturation(vertices->saturation);
|
mCoreShader->setSaturation(vertices->saturation);
|
||||||
mCoreShader->setDimming(vertices->dimming);
|
mCoreShader->setDimming(vertices->dimming);
|
||||||
|
if (vertices->shaderFlags & ShaderFlags::ROUNDED_CORNERS ||
|
||||||
|
vertices->shaderFlags & ShaderFlags::ROUNDED_CORNERS_NO_AA) {
|
||||||
|
mCoreShader->setTextureSize({width, height});
|
||||||
|
mCoreShader->setCornerRadius(vertices->cornerRadius);
|
||||||
|
}
|
||||||
mCoreShader->setReflectionsFalloff(vertices->reflectionsFalloff);
|
mCoreShader->setReflectionsFalloff(vertices->reflectionsFalloff);
|
||||||
mCoreShader->setFlags(vertices->shaderFlags);
|
mCoreShader->setFlags(vertices->shaderFlags);
|
||||||
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
|
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
|
||||||
|
|
|
@ -23,6 +23,7 @@ ShaderOpenGL::ShaderOpenGL()
|
||||||
, mShaderOpacity {0}
|
, mShaderOpacity {0}
|
||||||
, mShaderSaturation {0}
|
, mShaderSaturation {0}
|
||||||
, mShaderDimming {0}
|
, mShaderDimming {0}
|
||||||
|
, mCornerRadius {0}
|
||||||
, mShaderReflectionsFalloff {0}
|
, mShaderReflectionsFalloff {0}
|
||||||
, mBlurStrength {0}
|
, mBlurStrength {0}
|
||||||
, mShaderFlags {0}
|
, mShaderFlags {0}
|
||||||
|
@ -128,6 +129,7 @@ void ShaderOpenGL::getVariableLocations(GLuint programID)
|
||||||
mShaderOpacity = glGetUniformLocation(mProgramID, "opacity");
|
mShaderOpacity = glGetUniformLocation(mProgramID, "opacity");
|
||||||
mShaderSaturation = glGetUniformLocation(mProgramID, "saturation");
|
mShaderSaturation = glGetUniformLocation(mProgramID, "saturation");
|
||||||
mShaderDimming = glGetUniformLocation(mProgramID, "dimming");
|
mShaderDimming = glGetUniformLocation(mProgramID, "dimming");
|
||||||
|
mCornerRadius = glGetUniformLocation(mProgramID, "cornerRadius");
|
||||||
mShaderReflectionsFalloff = glGetUniformLocation(mProgramID, "reflectionsFalloff");
|
mShaderReflectionsFalloff = glGetUniformLocation(mProgramID, "reflectionsFalloff");
|
||||||
mBlurStrength = glGetUniformLocation(mProgramID, "blurStrength");
|
mBlurStrength = glGetUniformLocation(mProgramID, "blurStrength");
|
||||||
mShaderFlags = glGetUniformLocation(mProgramID, "shaderFlags");
|
mShaderFlags = glGetUniformLocation(mProgramID, "shaderFlags");
|
||||||
|
@ -194,6 +196,12 @@ void ShaderOpenGL::setDimming(GLfloat dimming)
|
||||||
GL_CHECK_ERROR(glUniform1f(mShaderDimming, dimming));
|
GL_CHECK_ERROR(glUniform1f(mShaderDimming, dimming));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShaderOpenGL::setCornerRadius(GLfloat cornerRadius)
|
||||||
|
{
|
||||||
|
if (mCornerRadius != -1)
|
||||||
|
GL_CHECK_ERROR(glUniform1f(mCornerRadius, cornerRadius));
|
||||||
|
}
|
||||||
|
|
||||||
void ShaderOpenGL::setReflectionsFalloff(GLfloat falloff)
|
void ShaderOpenGL::setReflectionsFalloff(GLfloat falloff)
|
||||||
{
|
{
|
||||||
if (mShaderReflectionsFalloff != -1)
|
if (mShaderReflectionsFalloff != -1)
|
||||||
|
|
|
@ -73,6 +73,7 @@ public:
|
||||||
void setOpacity(GLfloat opacity);
|
void setOpacity(GLfloat opacity);
|
||||||
void setSaturation(GLfloat saturation);
|
void setSaturation(GLfloat saturation);
|
||||||
void setDimming(GLfloat dimming);
|
void setDimming(GLfloat dimming);
|
||||||
|
void setCornerRadius(GLfloat cornerRadius);
|
||||||
void setReflectionsFalloff(GLfloat falloff);
|
void setReflectionsFalloff(GLfloat falloff);
|
||||||
void setBlurStrength(GLfloat blurStrength);
|
void setBlurStrength(GLfloat blurStrength);
|
||||||
void setFlags(GLuint flags);
|
void setFlags(GLuint flags);
|
||||||
|
@ -101,6 +102,7 @@ private:
|
||||||
GLint mShaderOpacity;
|
GLint mShaderOpacity;
|
||||||
GLint mShaderSaturation;
|
GLint mShaderSaturation;
|
||||||
GLint mShaderDimming;
|
GLint mShaderDimming;
|
||||||
|
GLint mCornerRadius;
|
||||||
GLint mShaderReflectionsFalloff;
|
GLint mShaderReflectionsFalloff;
|
||||||
GLint mBlurStrength;
|
GLint mBlurStrength;
|
||||||
GLint mShaderFlags;
|
GLint mShaderFlags;
|
||||||
|
|
BIN
resources/graphics/white.png
Normal file
BIN
resources/graphics/white.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5 KiB |
|
@ -39,6 +39,8 @@ out vec4 FragColor;
|
||||||
// 0x00000004 - Post processing
|
// 0x00000004 - Post processing
|
||||||
// 0x00000008 - Clipping
|
// 0x00000008 - Clipping
|
||||||
// 0x00000010 - Screen rotated 90 or 270 degrees
|
// 0x00000010 - Screen rotated 90 or 270 degrees
|
||||||
|
// 0x00000020 - Rounded corners
|
||||||
|
// 0x00000040 - Rounded corners with no anti-aliasing
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,6 +39,8 @@ out vec4 FragColor;
|
||||||
// 0x00000004 - Post processing
|
// 0x00000004 - Post processing
|
||||||
// 0x00000008 - Clipping
|
// 0x00000008 - Clipping
|
||||||
// 0x00000010 - Screen rotated 90 or 270 degrees
|
// 0x00000010 - Screen rotated 90 or 270 degrees
|
||||||
|
// 0x00000020 - Rounded corners
|
||||||
|
// 0x00000040 - Rounded corners with no anti-aliasing
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
// EmulationStation Desktop Edition
|
// EmulationStation Desktop Edition
|
||||||
// core.glsl
|
// core.glsl
|
||||||
//
|
//
|
||||||
// Core shader functionality:
|
// Core shader functionality.
|
||||||
// Clipping, brightness, saturation, opacity, dimming and reflections falloff.
|
|
||||||
//
|
//
|
||||||
|
|
||||||
// Vertex section of code:
|
// Vertex section of code:
|
||||||
|
@ -38,11 +37,13 @@ in vec2 position;
|
||||||
in vec2 texCoord;
|
in vec2 texCoord;
|
||||||
in vec4 color;
|
in vec4 color;
|
||||||
|
|
||||||
|
uniform vec2 textureSize;
|
||||||
uniform vec4 clipRegion;
|
uniform vec4 clipRegion;
|
||||||
uniform float brightness;
|
uniform float brightness;
|
||||||
uniform float saturation;
|
uniform float saturation;
|
||||||
uniform float opacity;
|
uniform float opacity;
|
||||||
uniform float dimming;
|
uniform float dimming;
|
||||||
|
uniform float cornerRadius;
|
||||||
uniform float reflectionsFalloff;
|
uniform float reflectionsFalloff;
|
||||||
uniform uint shaderFlags;
|
uniform uint shaderFlags;
|
||||||
|
|
||||||
|
@ -55,6 +56,8 @@ out vec4 FragColor;
|
||||||
// 0x00000004 - Post processing
|
// 0x00000004 - Post processing
|
||||||
// 0x00000008 - Clipping
|
// 0x00000008 - Clipping
|
||||||
// 0x00000010 - Screen rotated 90 or 270 degrees
|
// 0x00000010 - Screen rotated 90 or 270 degrees
|
||||||
|
// 0x00000020 - Rounded corners
|
||||||
|
// 0x00000040 - Rounded corners with no anti-aliasing
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
@ -72,6 +75,34 @@ void main()
|
||||||
|
|
||||||
vec4 sampledColor = texture(textureSampler, texCoord);
|
vec4 sampledColor = texture(textureSampler, texCoord);
|
||||||
|
|
||||||
|
// Rounded corners.
|
||||||
|
if (0x0u != (shaderFlags & 0x20u) || 0x0u != (shaderFlags & 0x40u)) {
|
||||||
|
float radius = cornerRadius;
|
||||||
|
// Don't go beyond half the width and height.
|
||||||
|
if (radius > textureSize.x / 2.0)
|
||||||
|
radius = textureSize.x / 2.0;
|
||||||
|
if (radius > textureSize.y / 2.0)
|
||||||
|
radius = textureSize.y / 2.0;
|
||||||
|
|
||||||
|
vec2 q = abs(position - textureSize / 2.0) -
|
||||||
|
(vec2(textureSize.x / 2.0, textureSize.y / 2.0) - radius);
|
||||||
|
float pixelDistance = length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - radius;
|
||||||
|
|
||||||
|
if (pixelDistance > 0.0) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
float pixelValue;
|
||||||
|
if (0x0u != (shaderFlags & 0x20u))
|
||||||
|
pixelValue = 1.0 - smoothstep(-0.75, 0.5, pixelDistance);
|
||||||
|
else
|
||||||
|
pixelValue = 1.0;
|
||||||
|
|
||||||
|
sampledColor.a *= pixelValue;
|
||||||
|
sampledColor.rgb *= pixelValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Brightness.
|
// Brightness.
|
||||||
if (brightness != 0.0) {
|
if (brightness != 0.0) {
|
||||||
sampledColor.rgb /= sampledColor.a;
|
sampledColor.rgb /= sampledColor.a;
|
||||||
|
|
|
@ -100,6 +100,8 @@ uniform float OutputGamma;
|
||||||
// 0x00000004 - Post processing
|
// 0x00000004 - Post processing
|
||||||
// 0x00000008 - Clipping
|
// 0x00000008 - Clipping
|
||||||
// 0x00000010 - Screen rotated 90 or 270 degrees
|
// 0x00000010 - Screen rotated 90 or 270 degrees
|
||||||
|
// 0x00000020 - Rounded corners
|
||||||
|
// 0x00000040 - Rounded corners with no anti-aliasing
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue