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;
mColorShiftEnd = color;
}
virtual void setColorShiftEnd(unsigned int color) { mColorShiftEnd = color; }
virtual void setOriginalColor(unsigned int color) { mColorOriginalValue = 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) {}

View file

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

View file

@ -40,6 +40,7 @@ ImageComponent::ImageComponent(bool forceLoad, bool dynamic)
, mColorShiftEnd {0xFFFFFFFF}
, mColorGradientHorizontal {true}
, mFadeOpacity {0.0f}
, mReflectionsFalloff {0.0f}
, mFading {false}
, mForceLoad {forceLoad}
, mDynamic {dynamic}
@ -248,7 +249,7 @@ void ImageComponent::cropTransparentPadding(const float maxSizeX, const float ma
glm::ivec2 imageSize {mTexture.get()->getSize()};
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
// the pixels (as in RGBARGBARGBA).
@ -377,7 +378,7 @@ void ImageComponent::updateVertices()
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) |
static_cast<unsigned char>((mColorShift & 0xFF) * opacity)};
const unsigned int colorEnd {(mColorShiftEnd & 0xFFFFFF00) |
@ -421,6 +422,7 @@ void ImageComponent::render(const glm::mat4& parentTrans)
mVertices->saturation = mSaturation * mThemeSaturation;
mVertices->opacity = mThemeOpacity;
mVertices->dimming = mDimming;
mVertices->reflectionsFalloff = mReflectionsFalloff;
mRenderer->drawTriangleStrips(&mVertices[0], 4);
}

View file

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

View file

@ -117,6 +117,7 @@ private:
CarouselType mType;
std::string mItemType;
std::string mDefaultItem;
bool mLegacyMode;
std::shared_ptr<Font> mFont;
unsigned int mTextColor;
unsigned int mTextBackgroundColor;
@ -133,6 +134,11 @@ private:
unsigned int mCarouselColor;
unsigned int mCarouselColorEnd;
bool mColorGradientHorizontal;
bool mReflections;
float mReflectionsOpacity;
float mReflectionsFalloff;
float mHorizontalOffset;
float mVerticalOffset;
};
template <typename T>
@ -146,6 +152,7 @@ CarouselComponent<T>::CarouselComponent()
, mPreviousScrollVelocity {0}
, mTriggerJump {false}
, mType {CarouselType::HORIZONTAL}
, mLegacyMode {false}
, mFont {Font::get(FONT_SIZE_LARGE)}
, mTextColor {0x000000FF}
, mTextBackgroundColor {0xFFFFFF00}
@ -161,6 +168,11 @@ CarouselComponent<T>::CarouselComponent()
, mCarouselColor {0}
, mCarouselColorEnd {0}
, 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))) {
auto item = std::make_shared<ImageComponent>(false, false);
item->setLinearInterpolation(true);
item->setMaxSize(glm::round(mItemSize * mItemScale));
item->setMaxSize(mItemSize * mItemScale);
item->applyTheme(theme, "system", "image_logo",
ThemeFlags::PATH | ThemeFlags::COLOR);
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);
item->setLinearInterpolation(true);
item->setImage(entry.data.itemPath);
item->setMaxSize(glm::round(mItemSize * mItemScale));
item->setMaxSize(mItemSize * mItemScale);
item->applyTheme(theme, "system", "", ThemeFlags::ALL);
item->setRotateByTargetSize(true);
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);
defaultItem->setLinearInterpolation(true);
defaultItem->setImage(entry.data.defaultItemPath);
defaultItem->setMaxSize(glm::round(mItemSize * mItemScale));
defaultItem->setMaxSize(mItemSize * mItemScale);
defaultItem->applyTheme(theme, "system", "", ThemeFlags::ALL);
defaultItem->setRotateByTargetSize(true);
entry.data.item = defaultItem;
@ -403,37 +415,60 @@ template <typename T> void CarouselComponent<T>::render(const glm::mat4& parentT
float xOff {0.0f};
float yOff {0.0f};
switch (mType) {
case CarouselType::HORIZONTAL_WHEEL:
case CarouselType::VERTICAL_WHEEL:
xOff = std::round((mSize.x - mItemSize.x) / 2.0f - (mEntryCamOffset * itemSpacing.y));
yOff = (mSize.y - mItemSize.y) / 2.0f;
break;
case CarouselType::VERTICAL:
itemSpacing.y =
((mSize.y - (mItemSize.y * mMaxItemCount)) / (mMaxItemCount)) + mItemSize.y;
yOff = (mSize.y - mItemSize.y) / 2.0f - (mEntryCamOffset * itemSpacing.y);
if (mItemHorizontalAlignment == ALIGN_LEFT)
if (mType == CarouselType::HORIZONTAL_WHEEL || mType == CarouselType::VERTICAL_WHEEL) {
xOff = (mSize.x - mItemSize.x) / 2.0f - (mEntryCamOffset * itemSpacing.y);
yOff = (mSize.y - mItemSize.y) / 2.0f;
}
else if (mType == CarouselType::VERTICAL) {
itemSpacing.y = ((mSize.y - (mItemSize.y * mMaxItemCount)) / (mMaxItemCount)) + mItemSize.y;
yOff = (mSize.y - mItemSize.y) / 2.0f - (mEntryCamOffset * itemSpacing.y);
if (mItemHorizontalAlignment == ALIGN_LEFT) {
if (mLegacyMode)
xOff = mItemSize.x / 10.0f;
else if (mItemHorizontalAlignment == ALIGN_RIGHT)
xOff = mSize.x - (mItemSize.x * 1.1f);
else
xOff = (mSize.x - mItemSize.x) / 2.0f;
break;
case CarouselType::HORIZONTAL:
default:
itemSpacing.x =
((mSize.x - (mItemSize.x * mMaxItemCount)) / (mMaxItemCount)) + mItemSize.x;
xOff = std::round((mSize.x - mItemSize.x) / 2.0f - (mEntryCamOffset * itemSpacing.x));
if (mItemVerticalAlignment == ALIGN_TOP)
xOff = 0.0f;
}
else if (mItemHorizontalAlignment == ALIGN_RIGHT) {
if (mLegacyMode)
xOff = mSize.x - mItemSize.x * 1.1f;
else
xOff = mSize.x - mItemSize.x;
}
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;
else if (mItemVerticalAlignment == ALIGN_BOTTOM)
else
yOff = 0.0f;
}
else if (mItemVerticalAlignment == ALIGN_BOTTOM) {
if (mLegacyMode)
yOff = mSize.y - (mItemSize.y * 1.1f);
else
yOff = mSize.y - mItemSize.y - (mReflections ? ((mItemSize.y * mItemScale)) : 0.0f);
}
else {
if (mLegacyMode)
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 itemInclusion {static_cast<int>(std::ceil(mMaxItemCount / 2.0f))};
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) {
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)
index += static_cast<int>(mEntries.size());
while (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};
if (singleEntry)
distance = 0.0f;
float scale {1.0f + ((mItemScale - 1.0f) * (1.0f - fabsf(distance)))};
scale = std::min(mItemScale, std::max(1.0f, scale));
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};
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);
}
// 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->setOpacity(opacity);
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();
}
@ -522,6 +572,8 @@ void CarouselComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
if (!elem)
return;
mLegacyMode = theme->isLegacyTheme();
if (elem->has("type")) {
const std::string type {elem->get<std::string>("type")};
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"))
mItemScale = glm::clamp(elem->get<float>("itemScale"), 0.5f, 3.0f);
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"))
mUnfocusedItemOpacity =
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"))
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);
if (elem->has("maxLogoCount")) {
if (theme->isLegacyTheme())
mMaxItemCount =
std::ceil(glm::clamp(elem->get<float>("maxLogoCount"), 0.5f, 30.0f));
else
mMaxItemCount = glm::clamp(elem->get<float>("maxLogoCount"), 0.5f, 30.0f);
}
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 (theme->isLegacyTheme())
mMaxItemCount = std::ceil(glm::clamp(elem->get<float>("maxLogoCount"), 0.5f, 30.0f));
else
mMaxItemCount = glm::clamp(elem->get<float>("maxLogoCount"), 0.5f, 30.0f);
}
if (elem->has("logoRotation"))
mItemRotation = elem->get<float>("logoRotation");
if (elem->has("logoRotationOrigin"))
mItemRotationOrigin = elem->get<glm::vec2>("logoRotationOrigin");
if (elem->has("logoRotation"))
mItemRotation = elem->get<float>("logoRotation");
if (elem->has("logoRotationOrigin"))
mItemRotationOrigin = elem->get<glm::vec2>("logoRotationOrigin");
if (elem->has("logoAlignment")) {
const std::string alignment {elem->get<std::string>("logoAlignment")};
if (alignment == "left" && mType != CarouselType::HORIZONTAL) {
mItemHorizontalAlignment = ALIGN_LEFT;
mItemVerticalAlignment = ALIGN_CENTER;
}
else if (alignment == "right" && mType != CarouselType::HORIZONTAL) {
mItemHorizontalAlignment = ALIGN_RIGHT;
mItemVerticalAlignment = ALIGN_CENTER;
}
else if (alignment == "top" && mType != CarouselType::VERTICAL) {
mItemVerticalAlignment = ALIGN_TOP;
mItemHorizontalAlignment = ALIGN_CENTER;
}
else if (alignment == "bottom" && mType != CarouselType::VERTICAL) {
mItemVerticalAlignment = ALIGN_BOTTOM;
mItemHorizontalAlignment = ALIGN_CENTER;
}
else if (alignment == "center") {
mItemHorizontalAlignment = ALIGN_CENTER;
mItemVerticalAlignment = ALIGN_CENTER;
}
else {
LOG(LogWarning) << "CarouselComponent: Invalid theme configuration, property "
"<logoAlignment> defined as \""
<< alignment << "\"";
mItemHorizontalAlignment = ALIGN_CENTER;
mItemVerticalAlignment = ALIGN_CENTER;
if (elem->has("logoAlignment")) {
const std::string alignment {elem->get<std::string>("logoAlignment")};
if (alignment == "left" && mType != CarouselType::HORIZONTAL) {
mItemHorizontalAlignment = ALIGN_LEFT;
mItemVerticalAlignment = ALIGN_CENTER;
}
else if (alignment == "right" && mType != CarouselType::HORIZONTAL) {
mItemHorizontalAlignment = ALIGN_RIGHT;
mItemVerticalAlignment = ALIGN_CENTER;
}
else if (alignment == "top" && mType != CarouselType::VERTICAL) {
mItemVerticalAlignment = ALIGN_TOP;
mItemHorizontalAlignment = ALIGN_CENTER;
}
else if (alignment == "bottom" && mType != CarouselType::VERTICAL) {
mItemVerticalAlignment = ALIGN_BOTTOM;
mItemHorizontalAlignment = ALIGN_CENTER;
}
else if (alignment == "center") {
mItemHorizontalAlignment = ALIGN_CENTER;
mItemVerticalAlignment = ALIGN_CENTER;
}
else {
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);
if (elem->has("textColor"))

View file

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

View file

@ -277,8 +277,8 @@ void RendererOpenGL::destroyContext()
void RendererOpenGL::setMatrix(const glm::mat4& matrix)
{
mTrans = matrix;
mTrans = getProjectionMatrix() * mTrans;
// Set matrix for use with shader.
mTrans = getProjectionMatrix() * matrix;
}
void RendererOpenGL::setScissor(const Rect& scissor)
@ -421,6 +421,7 @@ void RendererOpenGL::drawTriangleStrips(const Vertex* vertices,
mCoreShader->setOpacity(vertices->opacity);
mCoreShader->setSaturation(vertices->saturation);
mCoreShader->setDimming(vertices->dimming);
mCoreShader->setReflectionsFalloff(vertices->reflectionsFalloff);
mCoreShader->setFlags(vertices->shaderFlags);
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
mLastShader = mCoreShader;

View file

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

View file

@ -71,6 +71,7 @@ public:
void setOpacity(GLfloat opacity);
void setSaturation(GLfloat saturation);
void setDimming(GLfloat dimming);
void setReflectionsFalloff(GLfloat falloff);
void setFlags(GLuint flags);
// Sets the shader program to use the loaded shaders.
void activateShaders();
@ -95,6 +96,7 @@ private:
GLint mShaderOpacity;
GLint mShaderSaturation;
GLint mShaderDimming;
GLint mShaderReflectionsFalloff;
GLint mShaderFlags;
};

View file

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