Added reflections support to CarouselComponent.

This commit is contained in:
Leon Styhre 2022-04-18 21:37:58 +02:00
parent 79c61b2d8a
commit 1798b96cf8
10 changed files with 220 additions and 112 deletions

View file

@ -207,8 +207,13 @@ public:
mColorShift = color; mColorShift = color;
mColorShiftEnd = color; mColorShiftEnd = color;
} }
virtual void setColorShiftEnd(unsigned int color) { mColorShiftEnd = color; }
virtual void setOriginalColor(unsigned int color) { mColorOriginalValue = color; } virtual void setOriginalColor(unsigned int color) { mColorOriginalValue = color; }
virtual void setChangedColor(unsigned int color) { mColorChangedValue = color; } virtual void setChangedColor(unsigned int color) { mColorChangedValue = color; }
virtual void setColorGradientHorizontal(bool horizontal) {}
virtual void setReflectionsFalloff(float falloff) {}
virtual void setFlipX(bool flip) {}
virtual void setFlipY(bool flip) {}
virtual void setImage(const std::string& path, bool tile = false) {} virtual void setImage(const std::string& path, bool tile = false) {}

View file

@ -262,6 +262,11 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"itemRotationOrigin", NORMALIZED_PAIR}, {"itemRotationOrigin", NORMALIZED_PAIR},
{"itemHorizontalAlignment", STRING}, {"itemHorizontalAlignment", STRING},
{"itemVerticalAlignment", STRING}, {"itemVerticalAlignment", STRING},
{"horizontalOffset", FLOAT},
{"verticalOffset", FLOAT},
{"reflections", BOOLEAN},
{"reflectionsOpacity", FLOAT},
{"reflectionsFalloff", FLOAT},
{"unfocusedItemOpacity", FLOAT}, {"unfocusedItemOpacity", FLOAT},
{"maxItemCount", FLOAT}, {"maxItemCount", FLOAT},
{"defaultLogo", PATH}, // For backward compatibility with legacy themes. {"defaultLogo", PATH}, // For backward compatibility with legacy themes.

View file

@ -40,6 +40,7 @@ ImageComponent::ImageComponent(bool forceLoad, bool dynamic)
, mColorShiftEnd {0xFFFFFFFF} , mColorShiftEnd {0xFFFFFFFF}
, mColorGradientHorizontal {true} , mColorGradientHorizontal {true}
, mFadeOpacity {0.0f} , mFadeOpacity {0.0f}
, mReflectionsFalloff {0.0f}
, mFading {false} , mFading {false}
, mForceLoad {forceLoad} , mForceLoad {forceLoad}
, mDynamic {dynamic} , mDynamic {dynamic}
@ -248,7 +249,7 @@ void ImageComponent::cropTransparentPadding(const float maxSizeX, const float ma
glm::ivec2 imageSize {mTexture.get()->getSize()}; glm::ivec2 imageSize {mTexture.get()->getSize()};
cimg_library::CImg<unsigned char> imageCImg(imageSize.x, imageSize.y, 1, 4, 0); cimg_library::CImg<unsigned char> imageCImg(imageSize.x, imageSize.y, 1, 4, 0);
int paddingCoords[4] {}; int paddingCoords[4] {0, 0, 0, 0};
// We need to convert our RGBA data to the CImg internal format as CImg does not interleave // We need to convert our RGBA data to the CImg internal format as CImg does not interleave
// the pixels (as in RGBARGBARGBA). // the pixels (as in RGBARGBARGBA).
@ -377,7 +378,7 @@ void ImageComponent::updateVertices()
void ImageComponent::updateColors() void ImageComponent::updateColors()
{ {
const float opacity = (mOpacity * (mFading ? mFadeOpacity : 1.0f)); const float opacity {mOpacity * (mFading ? mFadeOpacity : 1.0f)};
const unsigned int color {(mColorShift & 0xFFFFFF00) | const unsigned int color {(mColorShift & 0xFFFFFF00) |
static_cast<unsigned char>((mColorShift & 0xFF) * opacity)}; static_cast<unsigned char>((mColorShift & 0xFF) * opacity)};
const unsigned int colorEnd {(mColorShiftEnd & 0xFFFFFF00) | const unsigned int colorEnd {(mColorShiftEnd & 0xFFFFFF00) |
@ -421,6 +422,7 @@ void ImageComponent::render(const glm::mat4& parentTrans)
mVertices->saturation = mSaturation * mThemeSaturation; mVertices->saturation = mSaturation * mThemeSaturation;
mVertices->opacity = mThemeOpacity; mVertices->opacity = mThemeOpacity;
mVertices->dimming = mDimming; mVertices->dimming = mDimming;
mVertices->reflectionsFalloff = mReflectionsFalloff;
mRenderer->drawTriangleStrips(&mVertices[0], 4); mRenderer->drawTriangleStrips(&mVertices[0], 4);
} }

View file

@ -66,8 +66,8 @@ public:
// Multiply all pixels in the image by this color when rendering. // Multiply all pixels in the image by this color when rendering.
void setColorShift(unsigned int color) override; void setColorShift(unsigned int color) override;
void setColorShiftEnd(unsigned int color); void setColorShiftEnd(unsigned int color) override;
void setColorGradientHorizontal(bool horizontal); void setColorGradientHorizontal(bool horizontal) override;
unsigned int getColorShift() const override { return mColorShift; } unsigned int getColorShift() const override { return mColorShift; }
@ -75,8 +75,9 @@ public:
void setSaturation(float saturation) override; void setSaturation(float saturation) override;
void setDimming(float dimming) override; void setDimming(float dimming) override;
void setFlipX(bool flip); // Mirror on the X axis. void setReflectionsFalloff(float falloff) override { mReflectionsFalloff = falloff; }
void setFlipY(bool flip); // Mirror on the Y axis. void setFlipX(bool flip) override; // Mirror on the X axis.
void setFlipY(bool flip) override; // Mirror on the Y axis.
// Flag indicating if rotation should be based on target size vs. actual size. // Flag indicating if rotation should be based on target size vs. actual size.
void setRotateByTargetSize(bool rotate) { mRotateByTargetSize = rotate; } void setRotateByTargetSize(bool rotate) { mRotateByTargetSize = rotate; }
@ -129,6 +130,7 @@ private:
std::shared_ptr<TextureResource> mTexture; std::shared_ptr<TextureResource> mTexture;
float mFadeOpacity; float mFadeOpacity;
float mReflectionsFalloff;
bool mFading; bool mFading;
bool mForceLoad; bool mForceLoad;
bool mDynamic; bool mDynamic;

View file

@ -117,6 +117,7 @@ private:
CarouselType mType; CarouselType mType;
std::string mItemType; std::string mItemType;
std::string mDefaultItem; std::string mDefaultItem;
bool mLegacyMode;
std::shared_ptr<Font> mFont; std::shared_ptr<Font> mFont;
unsigned int mTextColor; unsigned int mTextColor;
unsigned int mTextBackgroundColor; unsigned int mTextBackgroundColor;
@ -133,6 +134,11 @@ private:
unsigned int mCarouselColor; unsigned int mCarouselColor;
unsigned int mCarouselColorEnd; unsigned int mCarouselColorEnd;
bool mColorGradientHorizontal; bool mColorGradientHorizontal;
bool mReflections;
float mReflectionsOpacity;
float mReflectionsFalloff;
float mHorizontalOffset;
float mVerticalOffset;
}; };
template <typename T> template <typename T>
@ -146,6 +152,7 @@ CarouselComponent<T>::CarouselComponent()
, mPreviousScrollVelocity {0} , mPreviousScrollVelocity {0}
, mTriggerJump {false} , mTriggerJump {false}
, mType {CarouselType::HORIZONTAL} , mType {CarouselType::HORIZONTAL}
, mLegacyMode {false}
, mFont {Font::get(FONT_SIZE_LARGE)} , mFont {Font::get(FONT_SIZE_LARGE)}
, mTextColor {0x000000FF} , mTextColor {0x000000FF}
, mTextBackgroundColor {0xFFFFFF00} , mTextBackgroundColor {0xFFFFFF00}
@ -161,6 +168,11 @@ CarouselComponent<T>::CarouselComponent()
, mCarouselColor {0} , mCarouselColor {0}
, mCarouselColorEnd {0} , mCarouselColorEnd {0}
, mColorGradientHorizontal {true} , mColorGradientHorizontal {true}
, mReflections {false}
, mReflectionsOpacity {0.5f}
, mReflectionsFalloff {1.0f}
, mHorizontalOffset {0.0f}
, mVerticalOffset {0.0f}
{ {
} }
@ -183,7 +195,7 @@ void CarouselComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeDat
(!defaultPath.empty() && ResourceManager::getInstance().fileExists(defaultPath))) { (!defaultPath.empty() && ResourceManager::getInstance().fileExists(defaultPath))) {
auto item = std::make_shared<ImageComponent>(false, false); auto item = std::make_shared<ImageComponent>(false, false);
item->setLinearInterpolation(true); item->setLinearInterpolation(true);
item->setMaxSize(glm::round(mItemSize * mItemScale)); item->setMaxSize(mItemSize * mItemScale);
item->applyTheme(theme, "system", "image_logo", item->applyTheme(theme, "system", "image_logo",
ThemeFlags::PATH | ThemeFlags::COLOR); ThemeFlags::PATH | ThemeFlags::COLOR);
item->setRotateByTargetSize(true); item->setRotateByTargetSize(true);
@ -197,7 +209,7 @@ void CarouselComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeDat
auto item = std::make_shared<ImageComponent>(false, false); auto item = std::make_shared<ImageComponent>(false, false);
item->setLinearInterpolation(true); item->setLinearInterpolation(true);
item->setImage(entry.data.itemPath); item->setImage(entry.data.itemPath);
item->setMaxSize(glm::round(mItemSize * mItemScale)); item->setMaxSize(mItemSize * mItemScale);
item->applyTheme(theme, "system", "", ThemeFlags::ALL); item->applyTheme(theme, "system", "", ThemeFlags::ALL);
item->setRotateByTargetSize(true); item->setRotateByTargetSize(true);
entry.data.item = item; entry.data.item = item;
@ -207,7 +219,7 @@ void CarouselComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeDat
auto defaultItem = std::make_shared<ImageComponent>(false, false); auto defaultItem = std::make_shared<ImageComponent>(false, false);
defaultItem->setLinearInterpolation(true); defaultItem->setLinearInterpolation(true);
defaultItem->setImage(entry.data.defaultItemPath); defaultItem->setImage(entry.data.defaultItemPath);
defaultItem->setMaxSize(glm::round(mItemSize * mItemScale)); defaultItem->setMaxSize(mItemSize * mItemScale);
defaultItem->applyTheme(theme, "system", "", ThemeFlags::ALL); defaultItem->applyTheme(theme, "system", "", ThemeFlags::ALL);
defaultItem->setRotateByTargetSize(true); defaultItem->setRotateByTargetSize(true);
entry.data.item = defaultItem; entry.data.item = defaultItem;
@ -403,37 +415,60 @@ template <typename T> void CarouselComponent<T>::render(const glm::mat4& parentT
float xOff {0.0f}; float xOff {0.0f};
float yOff {0.0f}; float yOff {0.0f};
switch (mType) { if (mType == CarouselType::HORIZONTAL_WHEEL || mType == CarouselType::VERTICAL_WHEEL) {
case CarouselType::HORIZONTAL_WHEEL: xOff = (mSize.x - mItemSize.x) / 2.0f - (mEntryCamOffset * itemSpacing.y);
case CarouselType::VERTICAL_WHEEL: yOff = (mSize.y - mItemSize.y) / 2.0f;
xOff = std::round((mSize.x - mItemSize.x) / 2.0f - (mEntryCamOffset * itemSpacing.y)); }
yOff = (mSize.y - mItemSize.y) / 2.0f; else if (mType == CarouselType::VERTICAL) {
break; itemSpacing.y = ((mSize.y - (mItemSize.y * mMaxItemCount)) / (mMaxItemCount)) + mItemSize.y;
case CarouselType::VERTICAL: yOff = (mSize.y - mItemSize.y) / 2.0f - (mEntryCamOffset * itemSpacing.y);
itemSpacing.y = if (mItemHorizontalAlignment == ALIGN_LEFT) {
((mSize.y - (mItemSize.y * mMaxItemCount)) / (mMaxItemCount)) + mItemSize.y; if (mLegacyMode)
yOff = (mSize.y - mItemSize.y) / 2.0f - (mEntryCamOffset * itemSpacing.y);
if (mItemHorizontalAlignment == ALIGN_LEFT)
xOff = mItemSize.x / 10.0f; xOff = mItemSize.x / 10.0f;
else if (mItemHorizontalAlignment == ALIGN_RIGHT)
xOff = mSize.x - (mItemSize.x * 1.1f);
else else
xOff = (mSize.x - mItemSize.x) / 2.0f; xOff = 0.0f;
break; }
case CarouselType::HORIZONTAL: else if (mItemHorizontalAlignment == ALIGN_RIGHT) {
default: if (mLegacyMode)
itemSpacing.x = xOff = mSize.x - mItemSize.x * 1.1f;
((mSize.x - (mItemSize.x * mMaxItemCount)) / (mMaxItemCount)) + mItemSize.x; else
xOff = std::round((mSize.x - mItemSize.x) / 2.0f - (mEntryCamOffset * itemSpacing.x)); xOff = mSize.x - mItemSize.x;
if (mItemVerticalAlignment == ALIGN_TOP) }
else {
xOff = (mSize.x - mItemSize.x) / 2.0f;
}
}
else { // HORIZONTAL.
itemSpacing.x = ((mSize.x - (mItemSize.x * mMaxItemCount)) / (mMaxItemCount)) + mItemSize.x;
xOff = (mSize.x - mItemSize.x) / 2.0f - (mEntryCamOffset * itemSpacing.x);
if (mItemVerticalAlignment == ALIGN_TOP) {
if (mLegacyMode)
yOff = mItemSize.y / 10.0f; yOff = mItemSize.y / 10.0f;
else if (mItemVerticalAlignment == ALIGN_BOTTOM) else
yOff = 0.0f;
}
else if (mItemVerticalAlignment == ALIGN_BOTTOM) {
if (mLegacyMode)
yOff = mSize.y - (mItemSize.y * 1.1f); yOff = mSize.y - (mItemSize.y * 1.1f);
else else
yOff = mSize.y - mItemSize.y - (mReflections ? ((mItemSize.y * mItemScale)) : 0.0f);
}
else {
if (mLegacyMode)
yOff = (mSize.y - mItemSize.y) / 2.0f; yOff = (mSize.y - mItemSize.y) / 2.0f;
break; else
yOff = (mSize.y - (mItemSize.y * (mReflections ? 2.0f : 1.0f))) / 2.0f;
}
} }
if (!mLegacyMode) {
xOff += mSize.x * mHorizontalOffset;
yOff += mSize.y * mVerticalOffset;
}
xOff = std::round(xOff);
yOff = std::round(yOff);
int center {static_cast<int>(mEntryCamOffset)}; int center {static_cast<int>(mEntryCamOffset)};
int itemInclusion {static_cast<int>(std::ceil(mMaxItemCount / 2.0f))}; int itemInclusion {static_cast<int>(std::ceil(mMaxItemCount / 2.0f))};
bool singleEntry {mEntries.size() == 1}; bool singleEntry {mEntries.size() == 1};
@ -441,28 +476,27 @@ template <typename T> void CarouselComponent<T>::render(const glm::mat4& parentT
for (int i = center - itemInclusion; i < center + itemInclusion + 2; ++i) { for (int i = center - itemInclusion; i < center + itemInclusion + 2; ++i) {
int index {i}; int index {i};
// If there is only a single entry, then only render the item once (in the center).
if (singleEntry) {
mEntries.at(0).data.item->render(
glm::translate(carouselTrans, glm::vec3 {0 + xOff, 0 + yOff, 0.0f}));
break;
}
while (index < 0) while (index < 0)
index += static_cast<int>(mEntries.size()); index += static_cast<int>(mEntries.size());
while (index >= static_cast<int>(mEntries.size())) while (index >= static_cast<int>(mEntries.size()))
index -= static_cast<int>(mEntries.size()); index -= static_cast<int>(mEntries.size());
glm::mat4 itemTrans {carouselTrans};
itemTrans = glm::translate(
itemTrans, glm::vec3 {i * itemSpacing.x + xOff, i * itemSpacing.y + yOff, 0.0f});
float distance {i - mEntryCamOffset}; float distance {i - mEntryCamOffset};
if (singleEntry)
distance = 0.0f;
float scale {1.0f + ((mItemScale - 1.0f) * (1.0f - fabsf(distance)))}; float scale {1.0f + ((mItemScale - 1.0f) * (1.0f - fabsf(distance)))};
scale = std::min(mItemScale, std::max(1.0f, scale)); scale = std::min(mItemScale, std::max(1.0f, scale));
scale /= mItemScale; scale /= mItemScale;
glm::mat4 itemTrans {carouselTrans};
if (singleEntry)
itemTrans = glm::translate(carouselTrans, glm::vec3 {xOff, yOff, 0.0f});
else
itemTrans = glm::translate(
itemTrans, glm::vec3 {i * itemSpacing.x + xOff, i * itemSpacing.y + yOff, 0.0f});
float opacity {0.0f}; float opacity {0.0f};
if (distance == 0.0f || mUnfocusedItemOpacity == 1.0f) { if (distance == 0.0f || mUnfocusedItemOpacity == 1.0f) {
@ -486,17 +520,33 @@ template <typename T> void CarouselComponent<T>::render(const glm::mat4& parentT
comp->setRotationOrigin(mItemRotationOrigin); comp->setRotationOrigin(mItemRotationOrigin);
} }
// When running at lower resolutions, prevent the scale-down to go all the way to
// the minimum value. This avoids potential single-pixel alignment issues when the
// item can't be vertically placed exactly in the middle of the carousel. Although
// the problem theoretically exists at all resolutions, it's not visble at around
// 1080p and above.
if (std::min(Renderer::getScreenWidth(), Renderer::getScreenHeight()) < 1080.0f)
scale = glm::clamp(scale, 1.0f / mItemScale + 0.01f, 1.0f);
comp->setScale(scale); comp->setScale(scale);
comp->setOpacity(opacity); comp->setOpacity(opacity);
comp->render(itemTrans); comp->render(itemTrans);
// Don't attempt to add reflections for text entries.
if (mReflections && (mEntries.at(index).data.itemPath != "" ||
mEntries.at(index).data.defaultItemPath != "")) {
itemTrans =
glm::translate(itemTrans, glm::vec3 {0.0f, comp->getSize().y * scale, 0.0f});
const unsigned int colorShift {comp->getColorShift()};
comp->setColorGradientHorizontal(false);
comp->setColorShift(0xFFFFFF00 | static_cast<int>(mReflectionsOpacity * 255.0f));
float falloff {glm::clamp(mReflectionsFalloff, 0.0f, 1.0f)};
falloff = mReflectionsOpacity * (1.0f - falloff);
comp->setColorShiftEnd(0xFFFFFF00 | static_cast<int>(falloff * 255.0f));
// "Extra" falloff as a value of 1.0 already fades the image completely.
if (mReflectionsFalloff > 1.0f)
comp->setReflectionsFalloff(mReflectionsFalloff - 1.0f);
comp->setFlipY(true);
comp->render(itemTrans);
comp->setFlipY(false);
comp->setColorShift(colorShift);
comp->setReflectionsFalloff(0.0f);
}
if (singleEntry)
break;
} }
mRenderer->popClipRect(); mRenderer->popClipRect();
} }
@ -522,6 +572,8 @@ void CarouselComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
if (!elem) if (!elem)
return; return;
mLegacyMode = theme->isLegacyTheme();
if (elem->has("type")) { if (elem->has("type")) {
const std::string type {elem->get<std::string>("type")}; const std::string type {elem->get<std::string>("type")};
if (type == "horizontal") { if (type == "horizontal") {
@ -567,7 +619,7 @@ void CarouselComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
} }
} }
if (!theme->isLegacyTheme()) { if (!mLegacyMode) {
if (elem->has("itemScale")) if (elem->has("itemScale"))
mItemScale = glm::clamp(elem->get<float>("itemScale"), 0.5f, 3.0f); mItemScale = glm::clamp(elem->get<float>("itemScale"), 0.5f, 3.0f);
if (elem->has("itemSize")) { if (elem->has("itemSize")) {
@ -633,76 +685,99 @@ void CarouselComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
} }
} }
if (elem->has("horizontalOffset"))
mHorizontalOffset = glm::clamp(elem->get<float>("horizontalOffset"), -1.0f, 1.0f);
if (elem->has("verticalOffset"))
mVerticalOffset = glm::clamp(elem->get<float>("verticalOffset"), -1.0f, 1.0f);
if (elem->has("reflections") && elem->get<bool>("reflections")) {
if (mType == CarouselType::HORIZONTAL) {
mReflections = elem->get<bool>("reflections");
}
else {
LOG(LogWarning) << "CarouselComponent: Invalid theme configuration, property "
"<reflections> only supported for horizontal carousel type";
}
}
if (elem->has("reflectionsOpacity"))
mReflectionsOpacity = glm::clamp(elem->get<float>("reflectionsOpacity"), 0.1f, 1.0f);
if (elem->has("reflectionsFalloff"))
mReflectionsFalloff = glm::clamp(elem->get<float>("reflectionsFalloff"), 0.0f, 5.0f);
if (elem->has("unfocusedItemOpacity")) if (elem->has("unfocusedItemOpacity"))
mUnfocusedItemOpacity = mUnfocusedItemOpacity =
glm::clamp(elem->get<float>("unfocusedItemOpacity"), 0.1f, 1.0f); glm::clamp(elem->get<float>("unfocusedItemOpacity"), 0.1f, 1.0f);
} }
// Start of legacy themes only section. // Legacy themes.
if (mLegacyMode) {
if (elem->has("logoScale"))
mItemScale = glm::clamp(elem->get<float>("logoScale"), 0.5f, 3.0f);
if (elem->has("logoSize")) {
// Keep size within a 0.05 and 1.0 multiple of the screen size.
glm::vec2 itemSize {elem->get<glm::vec2>("logoSize")};
if (std::max(itemSize.x, itemSize.y) > 1.0f) {
itemSize /= std::max(itemSize.x, itemSize.y);
}
else if (std::min(itemSize.x, itemSize.y) < 0.005f) {
float ratio {std::min(itemSize.x, itemSize.y) / 0.005f};
itemSize /= ratio;
// Just an extra precaution if a crazy ratio was used.
itemSize.x = glm::clamp(itemSize.x, 0.005f, 1.0f);
itemSize.y = glm::clamp(itemSize.y, 0.005f, 1.0f);
}
mItemSize =
itemSize * glm::vec2(Renderer::getScreenWidth(), Renderer::getScreenHeight());
}
if (elem->has("logoScale")) if (elem->has("maxLogoCount")) {
mItemScale = glm::clamp(elem->get<float>("logoScale"), 0.5f, 3.0f); if (theme->isLegacyTheme())
if (elem->has("logoSize")) { mMaxItemCount =
// Keep size within a 0.05 and 1.0 multiple of the screen size. std::ceil(glm::clamp(elem->get<float>("maxLogoCount"), 0.5f, 30.0f));
glm::vec2 itemSize {elem->get<glm::vec2>("logoSize")}; else
if (std::max(itemSize.x, itemSize.y) > 1.0f) { mMaxItemCount = glm::clamp(elem->get<float>("maxLogoCount"), 0.5f, 30.0f);
itemSize /= std::max(itemSize.x, itemSize.y);
} }
else if (std::min(itemSize.x, itemSize.y) < 0.005f) {
float ratio {std::min(itemSize.x, itemSize.y) / 0.005f};
itemSize /= ratio;
// Just an extra precaution if a crazy ratio was used.
itemSize.x = glm::clamp(itemSize.x, 0.005f, 1.0f);
itemSize.y = glm::clamp(itemSize.y, 0.005f, 1.0f);
}
mItemSize = itemSize * glm::vec2(Renderer::getScreenWidth(), Renderer::getScreenHeight());
}
if (elem->has("maxLogoCount")) { if (elem->has("logoRotation"))
if (theme->isLegacyTheme()) mItemRotation = elem->get<float>("logoRotation");
mMaxItemCount = std::ceil(glm::clamp(elem->get<float>("maxLogoCount"), 0.5f, 30.0f)); if (elem->has("logoRotationOrigin"))
else mItemRotationOrigin = elem->get<glm::vec2>("logoRotationOrigin");
mMaxItemCount = glm::clamp(elem->get<float>("maxLogoCount"), 0.5f, 30.0f);
}
if (elem->has("logoRotation")) if (elem->has("logoAlignment")) {
mItemRotation = elem->get<float>("logoRotation"); const std::string alignment {elem->get<std::string>("logoAlignment")};
if (elem->has("logoRotationOrigin")) if (alignment == "left" && mType != CarouselType::HORIZONTAL) {
mItemRotationOrigin = elem->get<glm::vec2>("logoRotationOrigin"); mItemHorizontalAlignment = ALIGN_LEFT;
mItemVerticalAlignment = ALIGN_CENTER;
if (elem->has("logoAlignment")) { }
const std::string alignment {elem->get<std::string>("logoAlignment")}; else if (alignment == "right" && mType != CarouselType::HORIZONTAL) {
if (alignment == "left" && mType != CarouselType::HORIZONTAL) { mItemHorizontalAlignment = ALIGN_RIGHT;
mItemHorizontalAlignment = ALIGN_LEFT; mItemVerticalAlignment = ALIGN_CENTER;
mItemVerticalAlignment = ALIGN_CENTER; }
} else if (alignment == "top" && mType != CarouselType::VERTICAL) {
else if (alignment == "right" && mType != CarouselType::HORIZONTAL) { mItemVerticalAlignment = ALIGN_TOP;
mItemHorizontalAlignment = ALIGN_RIGHT; mItemHorizontalAlignment = ALIGN_CENTER;
mItemVerticalAlignment = ALIGN_CENTER; }
} else if (alignment == "bottom" && mType != CarouselType::VERTICAL) {
else if (alignment == "top" && mType != CarouselType::VERTICAL) { mItemVerticalAlignment = ALIGN_BOTTOM;
mItemVerticalAlignment = ALIGN_TOP; mItemHorizontalAlignment = ALIGN_CENTER;
mItemHorizontalAlignment = ALIGN_CENTER; }
} else if (alignment == "center") {
else if (alignment == "bottom" && mType != CarouselType::VERTICAL) { mItemHorizontalAlignment = ALIGN_CENTER;
mItemVerticalAlignment = ALIGN_BOTTOM; mItemVerticalAlignment = ALIGN_CENTER;
mItemHorizontalAlignment = ALIGN_CENTER; }
} else {
else if (alignment == "center") { LOG(LogWarning) << "CarouselComponent: Invalid theme configuration, property "
mItemHorizontalAlignment = ALIGN_CENTER; "<logoAlignment> defined as \""
mItemVerticalAlignment = ALIGN_CENTER; << alignment << "\"";
} mItemHorizontalAlignment = ALIGN_CENTER;
else { mItemVerticalAlignment = ALIGN_CENTER;
LOG(LogWarning) << "CarouselComponent: Invalid theme configuration, property " }
"<logoAlignment> defined as \""
<< alignment << "\"";
mItemHorizontalAlignment = ALIGN_CENTER;
mItemVerticalAlignment = ALIGN_CENTER;
} }
} }
// End of legacy theme section.
mFont = Font::getFromTheme(elem, properties, mFont); mFont = Font::getFromTheme(elem, properties, mFont);
if (elem->has("textColor")) if (elem->has("textColor"))

View file

@ -62,6 +62,7 @@ public:
float opacity; float opacity;
float saturation; float saturation;
float dimming; float dimming;
float reflectionsFalloff;
unsigned int shaders; unsigned int shaders;
unsigned int shaderFlags; unsigned int shaderFlags;
@ -69,6 +70,7 @@ public:
: opacity {1.0f} : opacity {1.0f}
, saturation {1.0f} , saturation {1.0f}
, dimming {1.0f} , dimming {1.0f}
, reflectionsFalloff {0.0f}
, shaders {0} , shaders {0}
, shaderFlags {0} , shaderFlags {0}
{ {
@ -81,6 +83,7 @@ public:
, opacity {1.0f} , opacity {1.0f}
, saturation {1.0f} , saturation {1.0f}
, dimming {1.0f} , dimming {1.0f}
, reflectionsFalloff {0.0f}
, shaders {0} , shaders {0}
, shaderFlags {0} , shaderFlags {0}
{ {

View file

@ -277,8 +277,8 @@ void RendererOpenGL::destroyContext()
void RendererOpenGL::setMatrix(const glm::mat4& matrix) void RendererOpenGL::setMatrix(const glm::mat4& matrix)
{ {
mTrans = matrix; // Set matrix for use with shader.
mTrans = getProjectionMatrix() * mTrans; mTrans = getProjectionMatrix() * matrix;
} }
void RendererOpenGL::setScissor(const Rect& scissor) void RendererOpenGL::setScissor(const Rect& scissor)
@ -421,6 +421,7 @@ 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);
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));
mLastShader = mCoreShader; mLastShader = mCoreShader;

View file

@ -22,6 +22,7 @@ ShaderOpenGL::ShaderOpenGL()
, mShaderOpacity {0} , mShaderOpacity {0}
, mShaderSaturation {0} , mShaderSaturation {0}
, mShaderDimming {0} , mShaderDimming {0}
, mShaderReflectionsFalloff {0}
, mShaderFlags {0} , mShaderFlags {0}
{ {
} }
@ -123,6 +124,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");
mShaderReflectionsFalloff = glGetUniformLocation(mProgramID, "reflectionsFalloff");
mShaderFlags = glGetUniformLocation(mProgramID, "shaderFlags"); mShaderFlags = glGetUniformLocation(mProgramID, "shaderFlags");
} }
@ -174,6 +176,12 @@ void ShaderOpenGL::setDimming(GLfloat dimming)
GL_CHECK_ERROR(glUniform1f(mShaderDimming, dimming)); GL_CHECK_ERROR(glUniform1f(mShaderDimming, dimming));
} }
void ShaderOpenGL::setReflectionsFalloff(GLfloat falloff)
{
if (mShaderReflectionsFalloff != -1)
GL_CHECK_ERROR(glUniform1f(mShaderReflectionsFalloff, falloff));
}
void ShaderOpenGL::setFlags(GLuint flags) void ShaderOpenGL::setFlags(GLuint flags)
{ {
if (mShaderFlags != -1) if (mShaderFlags != -1)

View file

@ -71,6 +71,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 setReflectionsFalloff(GLfloat falloff);
void setFlags(GLuint flags); void setFlags(GLuint flags);
// Sets the shader program to use the loaded shaders. // Sets the shader program to use the loaded shaders.
void activateShaders(); void activateShaders();
@ -95,6 +96,7 @@ private:
GLint mShaderOpacity; GLint mShaderOpacity;
GLint mShaderSaturation; GLint mShaderSaturation;
GLint mShaderDimming; GLint mShaderDimming;
GLint mShaderReflectionsFalloff;
GLint mShaderFlags; GLint mShaderFlags;
}; };

View file

@ -37,6 +37,7 @@ in vec2 texCoord;
uniform float opacity; uniform float opacity;
uniform float saturation; uniform float saturation;
uniform float dimming; uniform float dimming;
uniform float reflectionsFalloff;
uniform uint shaderFlags; uniform uint shaderFlags;
uniform sampler2D textureSampler; uniform sampler2D textureSampler;
@ -83,6 +84,10 @@ void main()
if (0u != (shaderFlags & 1u)) if (0u != (shaderFlags & 1u))
sampledColor = sampledColor.bgra; sampledColor = sampledColor.bgra;
// Reflections falloff.
if (reflectionsFalloff > 0.0)
sampledColor.a = mix(sampledColor.a, sampledColor.a - reflectionsFalloff, texCoord.y);
FragColor = sampledColor; FragColor = sampledColor;
} }
#endif #endif