Changed the renderer pixel format from RGBA to BGRA.

Also implemented premultiplied alpha for all images, animations and videos and improved the carousel reflection falloff logic.
This commit is contained in:
Leon Styhre 2022-10-28 00:08:41 +02:00
parent ab11f36ece
commit 3c82bb4dfb
16 changed files with 71 additions and 67 deletions

View file

@ -39,6 +39,8 @@ std::vector<unsigned char> ImageIO::loadFromMemoryRGBA32(const unsigned char* da
fiBitmap = fiConverted; fiBitmap = fiConverted;
} }
} }
FreeImage_PreMultiplyWithAlpha(fiBitmap);
if (fiBitmap != nullptr) { if (fiBitmap != nullptr) {
width = FreeImage_GetWidth(fiBitmap); width = FreeImage_GetWidth(fiBitmap);
height = FreeImage_GetHeight(fiBitmap); height = FreeImage_GetHeight(fiBitmap);
@ -49,16 +51,7 @@ std::vector<unsigned char> ImageIO::loadFromMemoryRGBA32(const unsigned char* da
const BYTE* scanLine {FreeImage_GetScanLine(fiBitmap, static_cast<int>(i))}; const BYTE* scanLine {FreeImage_GetScanLine(fiBitmap, static_cast<int>(i))};
memcpy(tempData + (i * width * 4), scanLine, width * 4); memcpy(tempData + (i * width * 4), scanLine, width * 4);
} }
// Convert from BGRA to RGBA.
for (size_t i = 0; i < width * height; ++i) {
RGBQUAD bgra {reinterpret_cast<RGBQUAD*>(tempData)[i]};
RGBQUAD rgba;
rgba.rgbBlue = bgra.rgbRed;
rgba.rgbGreen = bgra.rgbGreen;
rgba.rgbRed = bgra.rgbBlue;
rgba.rgbReserved = bgra.rgbReserved;
reinterpret_cast<RGBQUAD*>(tempData)[i] = rgba;
}
rawData = std::vector<unsigned char> {tempData, tempData + width * height * 4}; rawData = std::vector<unsigned char> {tempData, tempData + width * height * 4};
// Free bitmap data. // Free bitmap data.
FreeImage_Unload(fiBitmap); FreeImage_Unload(fiBitmap);

View file

@ -138,7 +138,7 @@ bool Window::init()
mBackgroundOverlay->setImage(":/graphics/frame.png"); mBackgroundOverlay->setImage(":/graphics/frame.png");
mBackgroundOverlay->setResize(mRenderer->getScreenWidth(), mRenderer->getScreenHeight()); mBackgroundOverlay->setResize(mRenderer->getScreenWidth(), mRenderer->getScreenHeight());
mPostprocessedBackground = TextureResource::get(""); mPostprocessedBackground = TextureResource::get("", false, false, false, false, false);
mListScrollFont = Font::get(FONT_SIZE_LARGE); mListScrollFont = Font::get(FONT_SIZE_LARGE);

View file

@ -136,7 +136,7 @@ public:
void setAllowTextScrolling(bool value) { mAllowTextScrolling = value; } void setAllowTextScrolling(bool value) { mAllowTextScrolling = value; }
bool getAllowTextScrolling() { return mAllowTextScrolling; } bool getAllowTextScrolling() { return mAllowTextScrolling; }
// For Lottie animations. // For GIF and Lottie animations.
void setAllowFileAnimation(bool value) { mAllowFileAnimation = value; } void setAllowFileAnimation(bool value) { mAllowFileAnimation = value; }
bool getAllowFileAnimation() { return mAllowFileAnimation; } bool getAllowFileAnimation() { return mAllowFileAnimation; }

View file

@ -190,10 +190,11 @@ void GIFAnimComponent::setAnimation(const std::string& path)
mSize.x = static_cast<float>(width); mSize.x = static_cast<float>(width);
mSize.y = static_cast<float>(height); mSize.y = static_cast<float>(height);
FreeImage_PreMultiplyWithAlpha(mFrame);
mPictureRGBA.resize(mFileWidth * mFileHeight * 4); mPictureRGBA.resize(mFileWidth * mFileHeight * 4);
FreeImage_ConvertToRawBits(reinterpret_cast<BYTE*>(&mPictureRGBA.at(0)), mFrame, filePitch, 32, FreeImage_ConvertToRawBits(reinterpret_cast<BYTE*>(&mPictureRGBA.at(0)), mFrame, filePitch, 32,
FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE, 1); FI_RGBA_BLUE, FI_RGBA_GREEN, FI_RGBA_RED, 1);
mTexture->initFromPixels(&mPictureRGBA.at(0), mFileWidth, mFileHeight); mTexture->initFromPixels(&mPictureRGBA.at(0), mFileWidth, mFileHeight);
@ -453,6 +454,7 @@ void GIFAnimComponent::render(const glm::mat4& parentTrans)
FIF_GIF, &mAnimIO, static_cast<fi_handle>(mAnimFile), GIF_PLAYBACK); FIF_GIF, &mAnimIO, static_cast<fi_handle>(mAnimFile), GIF_PLAYBACK);
mFrame = FreeImage_LockPage(mAnimation, mFrameNum); mFrame = FreeImage_LockPage(mAnimation, mFrameNum);
FreeImage_PreMultiplyWithAlpha(mFrame);
mPictureRGBA.clear(); mPictureRGBA.clear();
mPictureRGBA.resize(mFrameSize); mPictureRGBA.resize(mFrameSize);
@ -496,7 +498,7 @@ void GIFAnimComponent::render(const glm::mat4& parentTrans)
vertices->saturation = mSaturation * mThemeSaturation; vertices->saturation = mSaturation * mThemeSaturation;
vertices->opacity = mOpacity * mThemeOpacity; vertices->opacity = mOpacity * mThemeOpacity;
vertices->dimming = mDimming; vertices->dimming = mDimming;
vertices->shaderFlags = Renderer::ShaderFlags::BGRA_TO_RGBA; vertices->shaderFlags = Renderer::ShaderFlags::PREMULTIPLIED;
// Render it. // Render it.
mRenderer->drawTriangleStrips(&vertices[0], 4); mRenderer->drawTriangleStrips(&vertices[0], 4);

View file

@ -350,7 +350,7 @@ void ImageComponent::render(const glm::mat4& parentTrans)
mClipRegion.w - mClipRegion.y, 0xFF000033, 0xFF000033); mClipRegion.w - mClipRegion.y, 0xFF000033, 0xFF000033);
} }
// An image with zero size would normally indicate a corrupt image file. // An image with zero size would normally indicate a corrupt image file.
if (mTexture->getSize() != glm::ivec2 {}) { if (mTexture->getSize() != glm::ivec2 {0, 0}) {
// Actually draw the image. // Actually draw the image.
// The bind() function returns false if the texture is not currently loaded. A blank // The bind() function returns false if the texture is not currently loaded. A blank
// texture is bound in this case but we want to handle a fade so it doesn't just // texture is bound in this case but we want to handle a fade so it doesn't just
@ -367,6 +367,7 @@ void ImageComponent::render(const glm::mat4& parentTrans)
mVertices->dimming = mDimming; mVertices->dimming = mDimming;
mVertices->reflectionsFalloff = mReflectionsFalloff; mVertices->reflectionsFalloff = mReflectionsFalloff;
mVertices->shaderFlags = mVertices->shaderFlags | Renderer::ShaderFlags::PREMULTIPLIED;
mRenderer->drawTriangleStrips(&mVertices[0], 4); mRenderer->drawTriangleStrips(&mVertices[0], 4);
} }
else { else {

View file

@ -487,7 +487,7 @@ void LottieAnimComponent::render(const glm::mat4& parentTrans)
vertices->saturation = mSaturation * mThemeSaturation; vertices->saturation = mSaturation * mThemeSaturation;
vertices->opacity = mOpacity * mThemeOpacity; vertices->opacity = mOpacity * mThemeOpacity;
vertices->dimming = mDimming; vertices->dimming = mDimming;
vertices->shaderFlags = Renderer::ShaderFlags::BGRA_TO_RGBA; vertices->shaderFlags = Renderer::ShaderFlags::PREMULTIPLIED;
// Render it. // Render it.
mRenderer->drawTriangleStrips(&vertices[0], 4); mRenderer->drawTriangleStrips(&vertices[0], 4);

View file

@ -134,6 +134,7 @@ void NinePatchComponent::render(const glm::mat4& parentTrans)
if (mTexture && mVertices != nullptr) { if (mTexture && mVertices != nullptr) {
mRenderer->setMatrix(trans); mRenderer->setMatrix(trans);
mVertices->opacity = mOpacity; mVertices->opacity = mOpacity;
mVertices->shaderFlags = Renderer::ShaderFlags::PREMULTIPLIED;
mTexture->bind(); mTexture->bind();
mRenderer->drawTriangleStrips(&mVertices[0], 6 * 9); mRenderer->drawTriangleStrips(&mVertices[0], 6 * 9);
} }

View file

@ -224,7 +224,8 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans)
} }
} }
mRenderer->drawTriangleStrips(&vertices[0], 4); mRenderer->drawTriangleStrips(&vertices[0], 4, Renderer::BlendFactor::SRC_ALPHA,
Renderer::BlendFactor::ONE_MINUS_SRC_ALPHA);
} }
else { else {
if (mVisible) if (mVisible)
@ -435,7 +436,7 @@ bool VideoFFmpegComponent::setupVideoFilters()
} }
filterDescription.append("format=pix_fmts=") filterDescription.append("format=pix_fmts=")
.append(std::string(av_get_pix_fmt_name(AV_PIX_FMT_RGBA))); .append(std::string(av_get_pix_fmt_name(AV_PIX_FMT_BGRA)));
returnValue = avfilter_graph_parse_ptr(mVFilterGraph, filterDescription.c_str(), returnValue = avfilter_graph_parse_ptr(mVFilterGraph, filterDescription.c_str(),
&mVFilterInputs, &mVFilterOutputs, nullptr); &mVFilterInputs, &mVFilterOutputs, nullptr);

View file

@ -898,19 +898,14 @@ template <typename T> void CarouselComponent<T>::render(const glm::mat4& parentT
mEntries.at(renderItem.index).data.defaultItemPath != "")) { mEntries.at(renderItem.index).data.defaultItemPath != "")) {
glm::mat4 reflectionTrans {glm::translate( glm::mat4 reflectionTrans {glm::translate(
renderItem.trans, glm::vec3 {0.0f, comp->getSize().y * renderItem.scale, 0.0f})}; renderItem.trans, glm::vec3 {0.0f, comp->getSize().y * renderItem.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)}; float falloff {glm::clamp(mReflectionsFalloff, 0.0f, 1.0f)};
falloff = mReflectionsOpacity * (1.0f - falloff); falloff = mReflectionsOpacity * (1.0f - falloff);
comp->setColorShiftEnd(0xFFFFFF00 | static_cast<int>(falloff * 255.0f)); comp->setOpacity(comp->getOpacity() * mReflectionsOpacity);
// "Extra" falloff as a value of 1.0 already fades the image completely. if (mReflectionsFalloff > 0.0f)
if (mReflectionsFalloff > 1.0f) comp->setReflectionsFalloff(comp->getSize().y / mReflectionsFalloff);
comp->setReflectionsFalloff(mReflectionsFalloff - 1.0f);
comp->setFlipY(true); comp->setFlipY(true);
comp->render(reflectionTrans); comp->render(reflectionTrans);
comp->setFlipY(false); comp->setFlipY(false);
comp->setColorShift(colorShift);
comp->setReflectionsFalloff(0.0f); comp->setReflectionsFalloff(0.0f);
} }
@ -1146,7 +1141,7 @@ void CarouselComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
mReflectionsOpacity = glm::clamp(elem->get<float>("reflectionsOpacity"), 0.1f, 1.0f); mReflectionsOpacity = glm::clamp(elem->get<float>("reflectionsOpacity"), 0.1f, 1.0f);
if (elem->has("reflectionsFalloff")) if (elem->has("reflectionsFalloff"))
mReflectionsFalloff = glm::clamp(elem->get<float>("reflectionsFalloff"), 0.0f, 5.0f); mReflectionsFalloff = glm::clamp(elem->get<float>("reflectionsFalloff"), 0.0f, 10.0f);
if (elem->has("unfocusedItemOpacity")) if (elem->has("unfocusedItemOpacity"))
mUnfocusedItemOpacity = mUnfocusedItemOpacity =

View file

@ -37,22 +37,15 @@ void Renderer::setIcon()
if (!rawData.empty()) { if (!rawData.empty()) {
ImageIO::flipPixelsVert(rawData.data(), width, height); ImageIO::flipPixelsVert(rawData.data(), width, height);
#if SDL_BYTEORDER == SDL_BIG_ENDIAN constexpr unsigned int bmask {0x00FF0000};
unsigned int rmask {0xFF000000}; constexpr unsigned int gmask {0x0000FF00};
unsigned int gmask {0x00FF0000}; constexpr unsigned int rmask {0x000000FF};
unsigned int bmask {0x0000FF00}; constexpr unsigned int amask {0xFF000000};
unsigned int amask {0x000000FF};
#else
unsigned int rmask {0x000000FF};
unsigned int gmask {0x0000FF00};
unsigned int bmask {0x00FF0000};
unsigned int amask {0xFF000000};
#endif
// Try creating SDL surface from logo data. // Try creating SDL surface from logo data.
SDL_Surface* logoSurface {SDL_CreateRGBSurfaceFrom( SDL_Surface* logoSurface {SDL_CreateRGBSurfaceFrom(
static_cast<void*>(rawData.data()), static_cast<int>(width), static_cast<int>(height), static_cast<void*>(rawData.data()), static_cast<int>(width), static_cast<int>(height),
32, static_cast<int>(width * 4), rmask, gmask, bmask, amask)}; 32, static_cast<int>(width * 4), bmask, gmask, rmask, amask)};
if (logoSurface != nullptr) { if (logoSurface != nullptr) {
SDL_SetWindowIcon(mSDLWindow, logoSurface); SDL_SetWindowIcon(mSDLWindow, logoSurface);

View file

@ -49,7 +49,7 @@ public:
}; };
enum ShaderFlags { enum ShaderFlags {
BGRA_TO_RGBA = 0x00000001, PREMULTIPLIED = 0x00000001,
FONT_TEXTURE = 0x00000002, FONT_TEXTURE = 0x00000002,
POST_PROCESSING = 0x00000004, POST_PROCESSING = 0x00000004,
CLIPPING = 0x00000008 CLIPPING = 0x00000008
@ -201,7 +201,7 @@ public:
virtual void drawTriangleStrips( virtual void drawTriangleStrips(
const Vertex* vertices, const Vertex* vertices,
const unsigned int numVertices, const unsigned int numVertices,
const BlendFactor srcBlendFactor = BlendFactor::SRC_ALPHA, const BlendFactor srcBlendFactor = BlendFactor::ONE,
const BlendFactor dstBlendFactor = BlendFactor::ONE_MINUS_SRC_ALPHA) = 0; const BlendFactor dstBlendFactor = BlendFactor::ONE_MINUS_SRC_ALPHA) = 0;
virtual void setMatrix(const glm::mat4& matrix) = 0; virtual void setMatrix(const glm::mat4& matrix) = 0;
virtual void setScissor(const Rect& scissor) = 0; virtual void setScissor(const Rect& scissor) = 0;

View file

@ -248,13 +248,13 @@ bool RendererOpenGL::createContext()
GL_CHECK_ERROR(glBindVertexArray(mVertexBuffer2)); GL_CHECK_ERROR(glBindVertexArray(mVertexBuffer2));
uint8_t data[4] {255, 255, 255, 255}; uint8_t data[4] {255, 255, 255, 255};
mWhiteTexture = createTexture(TextureType::RGBA, false, false, false, true, 1, 1, data); mWhiteTexture = createTexture(TextureType::BGRA, false, false, false, true, 1, 1, data);
mPostProcTexture1 = createTexture(TextureType::RGBA, false, false, false, false, mPostProcTexture1 = createTexture(TextureType::BGRA, false, false, false, false,
static_cast<unsigned int>(getScreenWidth()), static_cast<unsigned int>(getScreenWidth()),
static_cast<unsigned int>(getScreenHeight()), nullptr); static_cast<unsigned int>(getScreenHeight()), nullptr);
mPostProcTexture2 = createTexture(TextureType::RGBA, false, false, false, false, mPostProcTexture2 = createTexture(TextureType::BGRA, false, false, false, false,
static_cast<unsigned int>(getScreenWidth()), static_cast<unsigned int>(getScreenWidth()),
static_cast<unsigned int>(getScreenHeight()), nullptr); static_cast<unsigned int>(getScreenHeight()), nullptr);
@ -376,8 +376,13 @@ unsigned int RendererOpenGL::createTexture(const TextureType type,
linearMagnify ? static_cast<GLfloat>(GL_LINEAR) : linearMagnify ? static_cast<GLfloat>(GL_LINEAR) :
static_cast<GLfloat>(GL_NEAREST))); static_cast<GLfloat>(GL_NEAREST)));
#if defined(USE_OPENGLES)
GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType, GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType,
GL_UNSIGNED_BYTE, data)); GL_UNSIGNED_BYTE, data));
#else
GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, textureType,
GL_UNSIGNED_BYTE, data));
#endif
if (mipmapping) if (mipmapping)
GL_CHECK_ERROR(glGenerateMipmap(GL_TEXTURE_2D)); GL_CHECK_ERROR(glGenerateMipmap(GL_TEXTURE_2D));
@ -626,7 +631,12 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
else else
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO2)); GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO2));
GL_CHECK_ERROR(glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, textureRGBA)); #if defined(USE_OPENGLES)
GL_CHECK_ERROR(
glReadPixels(0, 0, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, textureRGBA));
#else
GL_CHECK_ERROR(glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, textureRGBA));
#endif
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
} }

View file

@ -63,7 +63,7 @@ public:
void drawTriangleStrips( void drawTriangleStrips(
const Vertex* vertices, const Vertex* vertices,
const unsigned int numVertices, const unsigned int numVertices,
const BlendFactor srcBlendFactor = BlendFactor::SRC_ALPHA, const BlendFactor srcBlendFactor = BlendFactor::ONE,
const BlendFactor dstBlendFactor = BlendFactor::ONE_MINUS_SRC_ALPHA) override; const BlendFactor dstBlendFactor = BlendFactor::ONE_MINUS_SRC_ALPHA) override;
void shaderPostprocessing( void shaderPostprocessing(

View file

@ -248,8 +248,9 @@ void Font::renderTextCache(TextCache* cache)
it->verts[0].shaderFlags = Renderer::ShaderFlags::FONT_TEXTURE; it->verts[0].shaderFlags = Renderer::ShaderFlags::FONT_TEXTURE;
mRenderer->bindTexture(*it->textureIdPtr); mRenderer->bindTexture(*it->textureIdPtr);
mRenderer->drawTriangleStrips(&it->verts[0], mRenderer->drawTriangleStrips(
static_cast<const unsigned int>(it->verts.size())); &it->verts[0], static_cast<const unsigned int>(it->verts.size()),
Renderer::BlendFactor::SRC_ALPHA, Renderer::BlendFactor::ONE_MINUS_SRC_ALPHA);
} }
} }

View file

@ -61,7 +61,7 @@ bool TextureData::initSVGFromMemory(const std::string& fileData)
auto svgImage = lunasvg::Document::loadFromData(fileData); auto svgImage = lunasvg::Document::loadFromData(fileData);
if (svgImage == nullptr) { if (svgImage == nullptr) {
LOG(LogDebug) << "TextureData::initSVGFromMemory(): Couldn't parse SVG image \"" << mPath LOG(LogError) << "TextureData::initSVGFromMemory(): Couldn't parse SVG image \"" << mPath
<< "\""; << "\"";
mInvalidSVGFile = true; mInvalidSVGFile = true;
return false; return false;
@ -107,7 +107,6 @@ bool TextureData::initSVGFromMemory(const std::string& fileData)
if (rasterize) { if (rasterize) {
auto bitmap = svgImage->renderToBitmap(mWidth, mHeight); auto bitmap = svgImage->renderToBitmap(mWidth, mHeight);
bitmap.convertToRGBA();
mDataRGBA.insert(mDataRGBA.begin(), std::move(bitmap.data()), mDataRGBA.insert(mDataRGBA.begin(), std::move(bitmap.data()),
std::move(bitmap.data() + mWidth * mHeight * 4)); std::move(bitmap.data() + mWidth * mHeight * 4));
@ -221,7 +220,7 @@ bool TextureData::uploadAndBind()
// Upload texture. // Upload texture.
mTextureID = mTextureID =
mRenderer->createTexture(Renderer::TextureType::RGBA, true, mLinearMagnify, mMipmapping, mRenderer->createTexture(Renderer::TextureType::BGRA, true, mLinearMagnify, mMipmapping,
mTile, static_cast<const unsigned int>(mWidth), mTile, static_cast<const unsigned int>(mWidth),
static_cast<const unsigned int>(mHeight), mDataRGBA.data()); static_cast<const unsigned int>(mHeight), mDataRGBA.data());
} }

View file

@ -4,7 +4,7 @@
// core.glsl // core.glsl
// //
// Core shader functionality: // Core shader functionality:
// clipping, opacity, saturation, dimming and BGRA to RGBA conversion. // Clipping, opacity, saturation, dimming and reflections falloff.
// //
// Vertex section of code: // Vertex section of code:
@ -24,7 +24,7 @@ void main(void)
gl_Position = MVPMatrix * vec4(positionVertex.xy, 0.0, 1.0); gl_Position = MVPMatrix * vec4(positionVertex.xy, 0.0, 1.0);
position = positionVertex; position = positionVertex;
texCoord = texCoordVertex; texCoord = texCoordVertex;
color.rgba = colorVertex.abgr; color.abgr = colorVertex.rgba;
} }
// Fragment section of code: // Fragment section of code:
@ -49,7 +49,7 @@ uniform sampler2D textureSampler;
out vec4 FragColor; out vec4 FragColor;
// shaderFlags: // shaderFlags:
// 0x00000001 - BGRA to RGBA conversion // 0x00000001 - Premultiplied alpha (BGRA)
// 0x00000002 - Font texture // 0x00000002 - Font texture
// 0x00000004 - Post processing // 0x00000004 - Post processing
// 0x00000008 - Clipping // 0x00000008 - Clipping
@ -57,7 +57,7 @@ out vec4 FragColor;
void main() void main()
{ {
// Discard any pixels outside the clipping region. // Discard any pixels outside the clipping region.
if (0u != (shaderFlags & 8u)) { if (0x0u != (shaderFlags & 0x8u)) {
if (position.x < clipRegion.x) if (position.x < clipRegion.x)
discard; discard;
else if (position.y < clipRegion.y) else if (position.y < clipRegion.y)
@ -71,19 +71,31 @@ void main()
vec4 sampledColor = texture(textureSampler, texCoord); vec4 sampledColor = texture(textureSampler, texCoord);
// For fonts the alpha information is stored in the red channel. // For fonts the alpha information is stored in the red channel.
if (0u != (shaderFlags & 2u)) if (0x0u != (shaderFlags & 0x2u))
sampledColor = vec4(1.0, 1.0, 1.0, sampledColor.r); sampledColor = vec4(1.0, 1.0, 1.0, sampledColor.r);
sampledColor *= color; // Different color calculations depending on whether the texture contains premultiplied
// alpha or straight alpha values.
if (0x0u != (shaderFlags & 0x01u)) {
sampledColor.rgb *= color.rgb;
sampledColor *= color.a;
}
else {
sampledColor *= color;
}
// When post-processing we drop the alpha channel to avoid strange issues // When post-processing we drop the alpha channel to avoid strange issues with some
// with some graphics drivers. // graphics drivers.
if (0u != (shaderFlags & 4u)) if (0x0u != (shaderFlags & 0x4u))
sampledColor.a = 1.0; sampledColor.a = 1.0;
// Opacity. // Opacity.
if (opacity != 1.0) if (opacity != 1.0) {
sampledColor.a = sampledColor.a * opacity; if (0x0u == (shaderFlags & 0x01u))
sampledColor.a *= opacity;
else
sampledColor *= opacity;
}
// Saturation. // Saturation.
if (saturation != 1.0) { if (saturation != 1.0) {
@ -98,13 +110,9 @@ void main()
sampledColor *= dimColor; sampledColor *= dimColor;
} }
// BGRA to RGBA conversion.
if (0u != (shaderFlags & 1u))
sampledColor = sampledColor.bgra;
// Reflections falloff. // Reflections falloff.
if (reflectionsFalloff > 0.0) if (reflectionsFalloff > 0.0)
sampledColor.a = mix(sampledColor.a, sampledColor.a - reflectionsFalloff, texCoord.y); sampledColor.argb *= mix(0.0, 1.0, reflectionsFalloff - position.y) / reflectionsFalloff;
FragColor = sampledColor; FragColor = sampledColor;
} }