From 63af8596182c3d8f731614237d4e0ff24364a591 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Fri, 11 Mar 2022 23:17:04 +0100 Subject: [PATCH] Modernized the OpenGL renderer and replaced most fixed function pipeline code with shaders. Also greatly improved the shader post processing performance and added component dimming support. --- es-app/src/MediaViewer.cpp | 2 +- es-app/src/Screensaver.cpp | 36 +- es-core/src/GuiComponent.cpp | 13 +- es-core/src/GuiComponent.h | 9 +- es-core/src/Window.cpp | 24 +- es-core/src/animations/LambdaAnimation.h | 4 +- es-core/src/components/ComponentList.cpp | 8 +- es-core/src/components/GIFAnimComponent.cpp | 11 +- es-core/src/components/ImageComponent.cpp | 29 +- es-core/src/components/ImageComponent.h | 1 + .../src/components/LottieAnimComponent.cpp | 11 +- es-core/src/components/NinePatchComponent.cpp | 20 +- es-core/src/components/RatingComponent.cpp | 25 +- es-core/src/components/TextComponent.cpp | 29 +- es-core/src/components/TextComponent.h | 1 + es-core/src/components/VideoComponent.cpp | 1 + .../src/components/VideoFFmpegComponent.cpp | 42 +- es-core/src/renderers/Renderer.cpp | 164 +++---- es-core/src/renderers/Renderer.h | 94 +++-- es-core/src/renderers/Renderer_GL21.cpp | 399 +++++++++--------- es-core/src/renderers/Shader_GL21.cpp | 32 +- es-core/src/renderers/Shader_GL21.h | 12 +- es-core/src/resources/Font.cpp | 32 +- es-core/src/resources/Font.h | 2 + resources/shaders/glsl/core.glsl | 74 ++++ 25 files changed, 553 insertions(+), 522 deletions(-) create mode 100644 resources/shaders/glsl/core.glsl diff --git a/es-app/src/MediaViewer.cpp b/es-app/src/MediaViewer.cpp index 08592341d..f04fc7284 100644 --- a/es-app/src/MediaViewer.cpp +++ b/es-app/src/MediaViewer.cpp @@ -87,7 +87,7 @@ void MediaViewer::render(const glm::mat4& /*parentTrans*/) mVideo->render(trans); #if defined(USE_OPENGL_21) - Renderer::shaderParameters videoParameters; + Renderer::postProcessingParams videoParameters; unsigned int shaders {0}; if (Settings::getInstance()->getBool("MediaViewerVideoScanlines")) shaders = Renderer::SHADER_SCANLINES; diff --git a/es-app/src/Screensaver.cpp b/es-app/src/Screensaver.cpp index 439f89fae..92018cc83 100644 --- a/es-app/src/Screensaver.cpp +++ b/es-app/src/Screensaver.cpp @@ -237,22 +237,20 @@ void Screensaver::goToGame() void Screensaver::renderScreensaver() { std::string screensaverType = Settings::getInstance()->getString("ScreensaverType"); + glm::mat4 trans {Renderer::getIdentity()}; + Renderer::setMatrix(trans); if (mVideoScreensaver && screensaverType == "video") { // Render a black background below the video. - Renderer::setMatrix(Renderer::getIdentity()); Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0x000000FF, 0x000000FF); // Only render the video if the state requires it. - if (static_cast(mState) >= STATE_FADE_IN_VIDEO) { - glm::mat4 trans {Renderer::getIdentity()}; + if (static_cast(mState) >= STATE_FADE_IN_VIDEO) mVideoScreensaver->render(trans); - } } else if (mImageScreensaver && screensaverType == "slideshow") { // Render a black background below the image. - Renderer::setMatrix(Renderer::getIdentity()); Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0x000000FF, 0x000000FF); @@ -267,7 +265,6 @@ void Screensaver::renderScreensaver() } if (isScreensaverActive()) { - Renderer::setMatrix(Renderer::getIdentity()); if (Settings::getInstance()->getString("ScreensaverType") == "slideshow") { if (mHasMediaFiles) { #if defined(USE_OPENGL_21) @@ -299,8 +296,8 @@ void Screensaver::renderScreensaver() else if (Settings::getInstance()->getString("ScreensaverType") == "video") { if (mHasMediaFiles) { #if defined(USE_OPENGL_21) - Renderer::shaderParameters videoParameters; - unsigned int shaders = 0; + Renderer::postProcessingParams videoParameters; + unsigned int shaders {0}; if (Settings::getInstance()->getBool("ScreensaverVideoScanlines")) shaders = Renderer::SHADER_SCANLINES; if (Settings::getInstance()->getBool("ScreensaverVideoBlur")) { @@ -327,9 +324,6 @@ void Screensaver::renderScreensaver() #endif if (Settings::getInstance()->getBool("ScreensaverVideoGameInfo") && mGameOverlay) { if (mGameOverlayRectangleCoords.size() == 4) { -#if defined(USE_OPENGL_21) - Renderer::shaderPostprocessing(Renderer::SHADER_OPACITY); -#endif Renderer::drawRect( mGameOverlayRectangleCoords[0], mGameOverlayRectangleCoords[1], mGameOverlayRectangleCoords[2], mGameOverlayRectangleCoords[3], @@ -352,13 +346,13 @@ void Screensaver::renderScreensaver() if (mFallbackScreensaver || Settings::getInstance()->getString("ScreensaverType") == "dim") { #if defined(USE_OPENGL_21) - Renderer::shaderParameters dimParameters; - dimParameters.fragmentDimValue = mDimValue; - Renderer::shaderPostprocessing(Renderer::SHADER_DIM, dimParameters); - if (mDimValue > 0.4) - mDimValue = glm::clamp(mDimValue - 0.021f, 0.4f, 1.0f); - dimParameters.fragmentSaturation = mSaturationAmount; - Renderer::shaderPostprocessing(Renderer::SHADER_DESATURATE, dimParameters); + Renderer::postProcessingParams dimParameters; + dimParameters.dim = mDimValue; + Renderer::shaderPostprocessing(Renderer::SHADER_CORE, dimParameters); + if (mDimValue > 0.63) + mDimValue = glm::clamp(mDimValue - 0.015f, 0.68f, 1.0f); + dimParameters.saturation = mSaturationAmount; + Renderer::shaderPostprocessing(Renderer::SHADER_CORE, dimParameters); if (mSaturationAmount > 0.0) mSaturationAmount = glm::clamp(mSaturationAmount - 0.035f, 0.0f, 1.0f); #else @@ -368,9 +362,9 @@ void Screensaver::renderScreensaver() } else if (Settings::getInstance()->getString("ScreensaverType") == "black") { #if defined(USE_OPENGL_21) - Renderer::shaderParameters blackParameters; - blackParameters.fragmentDimValue = mDimValue; - Renderer::shaderPostprocessing(Renderer::SHADER_DIM, blackParameters); + Renderer::postProcessingParams blackParameters; + blackParameters.dim = mDimValue; + Renderer::shaderPostprocessing(Renderer::SHADER_CORE, blackParameters); if (mDimValue > 0.0) mDimValue = glm::clamp(mDimValue - 0.045f, 0.0f, 1.0f); #else diff --git a/es-core/src/GuiComponent.cpp b/es-core/src/GuiComponent.cpp index 42b24a565..1435644d7 100644 --- a/es-core/src/GuiComponent.cpp +++ b/es-core/src/GuiComponent.cpp @@ -20,7 +20,6 @@ GuiComponent::GuiComponent() : mWindow {Window::getInstance()} , mParent {nullptr} , mColor {0} - , mSaturation {1.0f} , mColorShift {0} , mColorShiftEnd {0} , mColorOriginalValue {0} @@ -31,6 +30,8 @@ GuiComponent::GuiComponent() , mRotationOrigin {0.5f, 0.5f} , mSize {0.0f, 0.0f} , mOpacity {1.0f} + , mSaturation {1.0f} + , mDim {1.0f} , mThemeOpacity {1.0f} , mRotation {0.0f} , mScale {1.0f} @@ -191,6 +192,16 @@ void GuiComponent::setOpacity(float opacity) (*it)->setOpacity(opacity); } +void GuiComponent::setDim(float dim) +{ + if (mDim == dim) + return; + + mDim = dim; + for (auto it = mChildren.cbegin(); it != mChildren.cend(); ++it) + (*it)->setDim(dim); +} + const glm::mat4& GuiComponent::getTransform() { mTransform = Renderer::getIdentity(); diff --git a/es-core/src/GuiComponent.h b/es-core/src/GuiComponent.h index 4af2ae4be..c935339b9 100644 --- a/es-core/src/GuiComponent.h +++ b/es-core/src/GuiComponent.h @@ -194,12 +194,14 @@ public: virtual void stopListScrolling() {} virtual const float getOpacity() const { return mOpacity; } virtual void setOpacity(float opacity); + virtual float getSaturation() const { return static_cast(mColor); } + virtual void setSaturation(float saturation) { mSaturation = saturation; } + virtual const float getDim() const { return mDim; } + virtual void setDim(float dim); virtual unsigned int getColor() const { return mColor; } virtual unsigned int getColorShift() const { return mColorShift; } virtual float getLineSpacing() { return 0.0f; } virtual void setColor(unsigned int color) { mColor = color; } - virtual float getSaturation() const { return static_cast(mColor); } - virtual void setSaturation(float saturation) { mSaturation = saturation; } virtual void setColorShift(unsigned int color) { mColorShift = color; @@ -286,7 +288,6 @@ protected: std::string mThemeGameSelector; unsigned int mColor; - float mSaturation; unsigned int mColorShift; unsigned int mColorShiftEnd; unsigned int mColorOriginalValue; @@ -299,6 +300,8 @@ protected: glm::vec2 mSize; float mOpacity; + float mSaturation; + float mDim; float mThemeOpacity; float mRotation; float mScale; diff --git a/es-core/src/Window.cpp b/es-core/src/Window.cpp index 2bf71f6df..127686f8a 100644 --- a/es-core/src/Window.cpp +++ b/es-core/src/Window.cpp @@ -453,13 +453,13 @@ void Window::render() #if (CLOCK_BACKGROUND_CREATION) const auto backgroundStartTime = std::chrono::system_clock::now(); #endif - unsigned char* processedTexture { - new unsigned char[static_cast(Renderer::getScreenWidth()) * - static_cast(Renderer::getScreenHeight()) * 4]}; + std::vector processedTexture( + static_cast(Renderer::getScreenWidth()) * + static_cast(Renderer::getScreenHeight()) * 4); // De-focus the background using multiple passes of gaussian blur, with the number // of iterations relative to the screen resolution. - Renderer::shaderParameters backgroundParameters; + Renderer::postProcessingParams backgroundParameters; if (Settings::getInstance()->getBool("MenuBlurBackground")) { float heightModifier = Renderer::getScreenHeightModifier(); @@ -481,22 +481,21 @@ void Window::render() // clang-format on // Also dim the background slightly. - backgroundParameters.fragmentDimValue = 0.60f; + backgroundParameters.dim = 0.60f; Renderer::shaderPostprocessing(Renderer::SHADER_BLUR_HORIZONTAL | - Renderer::SHADER_BLUR_VERTICAL | - Renderer::SHADER_DIM, - backgroundParameters, processedTexture); + Renderer::SHADER_BLUR_VERTICAL, + backgroundParameters, &processedTexture[0]); } else { // Dim the background slightly. - backgroundParameters.fragmentDimValue = 0.60f; - Renderer::shaderPostprocessing(Renderer::SHADER_DIM, backgroundParameters, - processedTexture); + backgroundParameters.dim = 0.60f; + Renderer::shaderPostprocessing(Renderer::SHADER_CORE, backgroundParameters, + &processedTexture[0]); } mPostprocessedBackground->initFromPixels( - processedTexture, static_cast(Renderer::getScreenWidth()), + &processedTexture[0], static_cast(Renderer::getScreenWidth()), static_cast(Renderer::getScreenHeight())); mBackgroundOverlay->setImage(mPostprocessedBackground); @@ -511,7 +510,6 @@ void Window::render() mBackgroundOverlayOpacity = 0.1f; } - delete[] processedTexture; mCachedBackground = true; #if (CLOCK_BACKGROUND_CREATION) diff --git a/es-core/src/animations/LambdaAnimation.h b/es-core/src/animations/LambdaAnimation.h index 79bbb3acc..a6dea3ec1 100644 --- a/es-core/src/animations/LambdaAnimation.h +++ b/es-core/src/animations/LambdaAnimation.h @@ -3,7 +3,7 @@ // EmulationStation Desktop Edition // LambdaAnimation.h // -// Basic animation controls, to be used in lambda expressions. +// Custom animations, expressed as lambdas. // #ifndef ES_CORE_ANIMATIONS_LAMBDA_ANIMATION_H @@ -13,8 +13,6 @@ #include -// Useful for simple one-off animations, you can supply the animation's apply(t) -// function directly in the constructor as a lambda. class LambdaAnimation : public Animation { public: diff --git a/es-core/src/components/ComponentList.cpp b/es-core/src/components/ComponentList.cpp index 56dee14b0..020657b85 100644 --- a/es-core/src/components/ComponentList.cpp +++ b/es-core/src/components/ComponentList.cpp @@ -382,11 +382,11 @@ void ComponentList::render(const glm::mat4& parentTrans) if (mOpacity == 1.0f) { Renderer::drawRect(0.0f, mSelectorBarOffset, std::ceil(mSize.x), selectedRowHeight, - 0xFFFFFFFF, 0xFFFFFFFF, false, mOpacity, trans, + 0xFFFFFFFF, 0xFFFFFFFF, false, mOpacity, mDim, Renderer::Blend::ONE_MINUS_DST_COLOR, Renderer::Blend::ZERO); Renderer::drawRect(0.0f, mSelectorBarOffset, std::ceil(mSize.x), selectedRowHeight, - 0x777777FF, 0x777777FF, false, mOpacity, trans, Renderer::Blend::ONE, + 0x777777FF, 0x777777FF, false, mOpacity, mDim, Renderer::Blend::ONE, Renderer::Blend::ONE); } @@ -402,12 +402,12 @@ void ComponentList::render(const glm::mat4& parentTrans) float y = 0; for (unsigned int i = 0; i < mEntries.size(); ++i) { Renderer::drawRect(0.0f, y, std::ceil(mSize.x), 1.0f * Renderer::getScreenHeightModifier(), - 0xC6C7C6FF, 0xC6C7C6FF, false, mOpacity, trans); + 0xC6C7C6FF, 0xC6C7C6FF, false, mOpacity, mDim); y += getRowHeight(mEntries.at(i).data); } Renderer::drawRect(0.0f, y, std::ceil(mSize.x), 1.0f * Renderer::getScreenHeightModifier(), - 0xC6C7C6FF, 0xC6C7C6FF, false, mOpacity, trans); + 0xC6C7C6FF, 0xC6C7C6FF, false, mOpacity, mDim); Renderer::popClipRect(); } diff --git a/es-core/src/components/GIFAnimComponent.cpp b/es-core/src/components/GIFAnimComponent.cpp index 6e242d186..642a57951 100644 --- a/es-core/src/components/GIFAnimComponent.cpp +++ b/es-core/src/components/GIFAnimComponent.cpp @@ -487,14 +487,13 @@ void GIFAnimComponent::render(const glm::mat4& parentTrans) for (int i = 0; i < 4; ++i) vertices[i].pos = glm::round(vertices[i].pos); -#if defined(USE_OPENGL_21) - // Perform color space conversion from BGRA to RGBA. - vertices[0].opacity = mThemeOpacity; - vertices[0].shaders = Renderer::SHADER_BGRA_TO_RGBA; -#endif + vertices->saturation = mSaturation; + vertices->opacity = mOpacity * mThemeOpacity; + vertices->dim = mDim; + vertices->convertBGRAToRGBA = true; // Render it. Renderer::setMatrix(trans); - Renderer::drawTriangleStrips(&vertices[0], 4, trans); + Renderer::drawTriangleStrips(&vertices[0], 4); } } diff --git a/es-core/src/components/ImageComponent.cpp b/es-core/src/components/ImageComponent.cpp index 155408cc3..ca66f1a55 100644 --- a/es-core/src/components/ImageComponent.cpp +++ b/es-core/src/components/ImageComponent.cpp @@ -333,6 +333,12 @@ void ImageComponent::setSaturation(float saturation) updateColors(); } +void ImageComponent::setDim(float dim) +{ + // Set dim value. + mDim = dim; +} + void ImageComponent::updateVertices() { if (!mTexture) @@ -371,12 +377,11 @@ void ImageComponent::updateVertices() void ImageComponent::updateColors() { - const float opacity = (mOpacity * mThemeOpacity * (mFading ? mFadeOpacity : 1.0f)); - const unsigned int color = Renderer::convertRGBAToABGR( - (mColorShift & 0xFFFFFF00) | static_cast((mColorShift & 0xFF) * opacity)); - const unsigned int colorEnd = - Renderer::convertRGBAToABGR((mColorShiftEnd & 0xFFFFFF00) | - static_cast((mColorShiftEnd & 0xFF) * opacity)); + const float opacity = (mOpacity * (mFading ? mFadeOpacity : 1.0f)); + const unsigned int color {(mColorShift & 0xFFFFFF00) | + static_cast((mColorShift & 0xFF) * opacity)}; + const unsigned int colorEnd {(mColorShiftEnd & 0xFFFFFF00) | + static_cast((mColorShiftEnd & 0xFF) * opacity)}; mVertices[0].col = color; mVertices[1].col = mColorGradientHorizontal ? color : colorEnd; @@ -413,13 +418,11 @@ void ImageComponent::render(const glm::mat4& parentTrans) else fadeIn(mTexture->bind()); -#if defined(USE_OPENGL_21) - if (mSaturation < 1.0) { - mVertices[0].shaders = Renderer::SHADER_DESATURATE; - mVertices[0].saturation = mSaturation; - } -#endif - Renderer::drawTriangleStrips(&mVertices[0], 4, trans); + mVertices->saturation = mSaturation; + mVertices->opacity = mThemeOpacity; + mVertices->dim = mDim; + + Renderer::drawTriangleStrips(&mVertices[0], 4); } else { if (!mTexture) { diff --git a/es-core/src/components/ImageComponent.h b/es-core/src/components/ImageComponent.h index e06d41924..97afc4067 100644 --- a/es-core/src/components/ImageComponent.h +++ b/es-core/src/components/ImageComponent.h @@ -73,6 +73,7 @@ public: void setOpacity(float opacity) override; void setSaturation(float saturation) override; + void setDim(float dim) override; void setFlipX(bool flip); // Mirror on the X axis. void setFlipY(bool flip); // Mirror on the Y axis. diff --git a/es-core/src/components/LottieAnimComponent.cpp b/es-core/src/components/LottieAnimComponent.cpp index 3c25a0b87..6b1bb4b87 100644 --- a/es-core/src/components/LottieAnimComponent.cpp +++ b/es-core/src/components/LottieAnimComponent.cpp @@ -472,13 +472,12 @@ void LottieAnimComponent::render(const glm::mat4& parentTrans) for (int i = 0; i < 4; ++i) vertices[i].pos = glm::round(vertices[i].pos); -#if defined(USE_OPENGL_21) - // Perform color space conversion from BGRA to RGBA. - vertices[0].opacity = mThemeOpacity; - vertices[0].shaders = Renderer::SHADER_BGRA_TO_RGBA; -#endif + vertices->saturation = mSaturation; + vertices->opacity = mOpacity * mThemeOpacity; + vertices->dim = mDim; + vertices->convertBGRAToRGBA = true; // Render it. - Renderer::drawTriangleStrips(&vertices[0], 4, trans); + Renderer::drawTriangleStrips(&vertices[0], 4); } } diff --git a/es-core/src/components/NinePatchComponent.cpp b/es-core/src/components/NinePatchComponent.cpp index e74a7ed2f..d34c3f175 100644 --- a/es-core/src/components/NinePatchComponent.cpp +++ b/es-core/src/components/NinePatchComponent.cpp @@ -35,14 +35,11 @@ NinePatchComponent::~NinePatchComponent() void NinePatchComponent::updateColors() { - const unsigned int edgeColor {Renderer::convertRGBAToABGR(mEdgeColor)}; - const unsigned int centerColor {Renderer::convertRGBAToABGR(mCenterColor)}; - for (int i = 0; i < 6 * 9; ++i) - mVertices[i].col = edgeColor; + mVertices[i].col = mEdgeColor; for (int i = 6 * 4; i < 6; ++i) - mVertices[(6 * 4) + i].col = centerColor; + mVertices[(6 * 4) + i].col = mCenterColor; } void NinePatchComponent::buildVertices() @@ -135,18 +132,9 @@ void NinePatchComponent::render(const glm::mat4& parentTrans) if (mTexture && mVertices != nullptr) { Renderer::setMatrix(trans); - if (mOpacity < 1.0f) { - mVertices[0].shaders = Renderer::SHADER_OPACITY; - mVertices[0].opacity = mOpacity; - } - else if (mVertices[0].shaders & Renderer::SHADER_OPACITY) { - // We have reached full opacity, so disable the opacity shader and set - // the vertex opacity to 1.0. - mVertices[0].shaders ^= Renderer::SHADER_OPACITY; - mVertices[0].opacity = 1.0f; - } + mVertices->opacity = mOpacity; mTexture->bind(); - Renderer::drawTriangleStrips(&mVertices[0], 6 * 9, trans); + Renderer::drawTriangleStrips(&mVertices[0], 6 * 9); } renderChildren(trans); diff --git a/es-core/src/components/RatingComponent.cpp b/es-core/src/components/RatingComponent.cpp index af178780c..81793d3ce 100644 --- a/es-core/src/components/RatingComponent.cpp +++ b/es-core/src/components/RatingComponent.cpp @@ -124,27 +124,24 @@ void RatingComponent::updateVertices() const float h {getSize().y}; // Ss the same as a single star's width. const float w {getSize().y * mValue * numStars}; const float fw {getSize().y * numStars}; - const unsigned int color {Renderer::convertRGBAToABGR(mColorShift)}; // clang-format off - mVertices[0] = {{0.0f, 0.0f}, {0.0f, 1.0f}, color}; - mVertices[1] = {{0.0f, h }, {0.0f, 0.0f}, color}; - mVertices[2] = {{w, 0.0f}, {mValue * numStars, 1.0f}, color}; - mVertices[3] = {{w, h }, {mValue * numStars, 0.0f}, color}; + mVertices[0] = {{0.0f, 0.0f}, {0.0f, 1.0f}, mColorShift}; + mVertices[1] = {{0.0f, h }, {0.0f, 0.0f}, mColorShift}; + mVertices[2] = {{w, 0.0f}, {mValue * numStars, 1.0f}, mColorShift}; + mVertices[3] = {{w, h }, {mValue * numStars, 0.0f}, mColorShift}; - mVertices[4] = {{0.0f, 0.0f}, {0.0f, 1.0f}, color}; - mVertices[5] = {{0.0f, h }, {0.0f, 0.0f}, color}; - mVertices[6] = {{fw, 0.0f}, {numStars, 1.0f}, color}; - mVertices[7] = {{fw, h }, {numStars, 0.0f}, color}; + mVertices[4] = {{0.0f, 0.0f}, {0.0f, 1.0f}, mColorShift}; + mVertices[5] = {{0.0f, h }, {0.0f, 0.0f}, mColorShift}; + mVertices[6] = {{fw, 0.0f}, {numStars, 1.0f}, mColorShift}; + mVertices[7] = {{fw, h }, {numStars, 0.0f}, mColorShift}; // clang-format on } void RatingComponent::updateColors() { - const unsigned int color {Renderer::convertRGBAToABGR(mColorShift)}; - for (int i = 0; i < 8; ++i) - mVertices[i].col = color; + mVertices[i].col = mColorShift; } void RatingComponent::render(const glm::mat4& parentTrans) @@ -165,9 +162,9 @@ void RatingComponent::render(const glm::mat4& parentTrans) if (mUnfilledTexture->bind()) { if (mUnfilledColor != mColorShift) { - const unsigned int color = Renderer::convertRGBAToABGR(mUnfilledColor); for (int i = 0; i < 8; ++i) - mVertices[i].col = (color & 0x00FFFFFF) + (mVertices[i].col & 0xFF000000); + mVertices[i].col = + (mUnfilledColor & 0xFFFFFF00) + (mVertices[i].col & 0x000000FF); } Renderer::drawTriangleStrips(&mVertices[4], 4); diff --git a/es-core/src/components/TextComponent.cpp b/es-core/src/components/TextComponent.cpp index eb2578172..84cca138b 100644 --- a/es-core/src/components/TextComponent.cpp +++ b/es-core/src/components/TextComponent.cpp @@ -92,17 +92,26 @@ void TextComponent::setBackgroundColor(unsigned int color) mBgColorOpacity = static_cast(mBgColor & 0x000000FF) / 255.0f; } -// Scale the opacity. void TextComponent::setOpacity(float opacity) { - float textOpacity {opacity * mColorOpacity * mThemeOpacity}; + float textOpacity {opacity * mColorOpacity}; mColor = (mColor & 0xFFFFFF00) | static_cast(textOpacity * 255.0f); - float textBackgroundOpacity {opacity * mBgColorOpacity * mThemeOpacity}; + float textBackgroundOpacity {opacity * mBgColorOpacity}; mBgColor = (mBgColor & 0xFFFFFF00) | static_cast(textBackgroundOpacity * 255.0f); onColorChanged(); GuiComponent::setOpacity(opacity); + + if (mTextCache) + mTextCache->setOpacity(mThemeOpacity); +} + +void TextComponent::setDim(float dim) +{ + mDim = dim; + if (mTextCache) + mTextCache->setDim(dim); } void TextComponent::setText(const std::string& text, bool update) @@ -152,11 +161,11 @@ void TextComponent::render(const glm::mat4& parentTrans) return; glm::mat4 trans {parentTrans * getTransform()}; + Renderer::setMatrix(trans); - if (mRenderBackground) { - Renderer::setMatrix(trans); - Renderer::drawRect(0.0f, 0.0f, mSize.x, mSize.y, mBgColor, mBgColor); - } + if (mRenderBackground) + Renderer::drawRect(0.0f, 0.0f, mSize.x, mSize.y, mBgColor, mBgColor, false, + mOpacity * mThemeOpacity, mDim); if (mTextCache) { const glm::vec2& textSize {mTextCache->metrics.size}; @@ -180,11 +189,9 @@ void TextComponent::render(const glm::mat4& parentTrans) } glm::vec3 off {0.0f, yOff, 0.0f}; - if (Settings::getInstance()->getBool("DebugText")) { - // Draw the "textbox" area, what we are aligned within. - Renderer::setMatrix(trans); + // Draw the "textbox" area, what we are aligned within. + if (Settings::getInstance()->getBool("DebugText")) Renderer::drawRect(0.0f, 0.0f, mSize.x, mSize.y, 0x0000FF33, 0x0000FF33); - } trans = glm::translate(trans, off); Renderer::setMatrix(trans); diff --git a/es-core/src/components/TextComponent.h b/es-core/src/components/TextComponent.h index ea6b2a2a0..239c5b54d 100644 --- a/es-core/src/components/TextComponent.h +++ b/es-core/src/components/TextComponent.h @@ -62,6 +62,7 @@ public: return static_cast((mColor & 0x000000FF) / 255.0f); } void setOpacity(float opacity) override; + void setDim(float dim) override; void setSelectable(bool status) { mSelectable = status; } diff --git a/es-core/src/components/VideoComponent.cpp b/es-core/src/components/VideoComponent.cpp index 29ba4a38b..5e964ae90 100644 --- a/es-core/src/components/VideoComponent.cpp +++ b/es-core/src/components/VideoComponent.cpp @@ -277,6 +277,7 @@ void VideoComponent::renderSnapshot(const glm::mat4& parentTrans) if (mStaticImagePath != "") { mStaticImage.setOpacity(mOpacity * mThemeOpacity); + mStaticImage.setDim(mDim); mStaticImage.render(parentTrans); } } diff --git a/es-core/src/components/VideoFFmpegComponent.cpp b/es-core/src/components/VideoFFmpegComponent.cpp index ec019f6ca..9bcb0e107 100644 --- a/es-core/src/components/VideoFFmpegComponent.cpp +++ b/es-core/src/components/VideoFFmpegComponent.cpp @@ -132,25 +132,13 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans) GuiComponent::renderChildren(trans); if (mIsPlaying && mFormatContext) { - unsigned int color; - - if (mDecodedFrame && mFadeIn < 1) { - const unsigned int fadeIn = static_cast(mFadeIn * 255.0f); - color = - Renderer::convertRGBAToABGR((fadeIn << 24) | (fadeIn << 16) | (fadeIn << 8) | 255); - } - else { - color = 0xFFFFFFFF; - } Renderer::Vertex vertices[4]; Renderer::setMatrix(parentTrans); unsigned int rectColor {0x000000FF}; - if (mThemeOpacity != 1.0f) { - color = (static_cast(mThemeOpacity * mFadeIn * 255.0f) << 24) + 0x00FFFFFF; + if (mThemeOpacity != 1.0f) rectColor = static_cast(mThemeOpacity * mFadeIn * 255.0f); - } // Render the black rectangle behind the video. if (mVideoRectangleCoords.size() == 4) { @@ -159,20 +147,26 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans) rectColor, rectColor); } + // This is needed to avoid a slight gap before the video starts playing. + if (!mDecodedFrame) + return; + // clang-format off - vertices[0] = {{0.0f + mRectangleOffset.x, 0.0f + mRectangleOffset.y }, {0.0f, 0.0f}, color}; - vertices[1] = {{0.0f + mRectangleOffset.x, mSize.y + mRectangleOffset.y }, {0.0f, 1.0f}, color}; - vertices[2] = {{mSize.x + mRectangleOffset.x, 0.0f + + mRectangleOffset.y }, {1.0f, 0.0f}, color}; - vertices[3] = {{mSize.x + mRectangleOffset.x, mSize.y + + mRectangleOffset.y}, {1.0f, 1.0f}, color}; + vertices[0] = {{0.0f + mRectangleOffset.x, 0.0f + mRectangleOffset.y }, {0.0f, 0.0f}, 0xFFFFFFFF}; + vertices[1] = {{0.0f + mRectangleOffset.x, mSize.y + mRectangleOffset.y }, {0.0f, 1.0f}, 0xFFFFFFFF}; + vertices[2] = {{mSize.x + mRectangleOffset.x, 0.0f + + mRectangleOffset.y }, {1.0f, 0.0f}, 0xFFFFFFFF}; + vertices[3] = {{mSize.x + mRectangleOffset.x, mSize.y + + mRectangleOffset.y}, {1.0f, 1.0f}, 0xFFFFFFFF}; // clang-format on // Round vertices. for (int i = 0; i < 4; ++i) vertices[i].pos = glm::round(vertices[i].pos); - // This is needed to avoid a slight gap before the video starts playing. - if (!mDecodedFrame) - return; + if (mDecodedFrame && (mFadeIn < 1.0f || mThemeOpacity < 1.0f)) + vertices->opacity = mFadeIn * mThemeOpacity; + + vertices->saturation = mSaturation; + vertices->dim = mDim; std::unique_lock pictureLock(mPictureMutex); @@ -213,25 +207,21 @@ void VideoFFmpegComponent::render(const glm::mat4& parentTrans) if (mTexture != nullptr) mTexture->bind(); -#if defined(USE_OPENGL_21) // Render scanlines if this option is enabled. However, if this is the media viewer // or the video screensaver, then skip this as the scanline rendering is then handled // in those modules as a postprocessing step. + if (!mScreensaverMode && !mMediaViewerMode) { vertices[0].opacity = mFadeIn * mThemeOpacity; if ((mLegacyTheme && Settings::getInstance()->getBool("GamelistVideoScanlines")) || (!mLegacyTheme && mRenderScanlines)) { vertices[0].shaders = Renderer::SHADER_SCANLINES; } - else { - vertices[0].shaders = Renderer::SHADER_OPACITY; - } } -#endif // Render it. Renderer::setMatrix(trans); - Renderer::drawTriangleStrips(&vertices[0], 4, trans); + Renderer::drawTriangleStrips(&vertices[0], 4); } else { if (mVisible) diff --git a/es-core/src/renderers/Renderer.cpp b/es-core/src/renderers/Renderer.cpp index 52de45e0b..d31767e4b 100644 --- a/es-core/src/renderers/Renderer.cpp +++ b/es-core/src/renderers/Renderer.cpp @@ -26,13 +26,14 @@ namespace Renderer static std::stack clipStack; static SDL_Window* sdlWindow {nullptr}; static glm::mat4 mProjectionMatrix {}; + static glm::mat4 mProjectionMatrixRotated {}; static int windowWidth {0}; static int windowHeight {0}; static int screenWidth {0}; static int screenHeight {0}; static int screenOffsetX {0}; static int screenOffsetY {0}; - static int screenRotate {0}; + static bool screenRotated {0}; static bool initialCursorState {1}; // Screen resolution modifiers relative to the 1920x1080 reference. static float screenHeightModifier {0.0f}; @@ -141,9 +142,7 @@ namespace Renderer screenOffsetY = Settings::getInstance()->getInt("ScreenOffsetY") ? Settings::getInstance()->getInt("ScreenOffsetY") : 0; - screenRotate = Settings::getInstance()->getInt("ScreenRotate") ? - Settings::getInstance()->getInt("ScreenRotate") : - 0; + screenRotated = Settings::getInstance()->getInt("ScreenRotate") == 2; // Prevent the application window from minimizing when switching windows (when launching // games or when manually switching windows using the task switcher). @@ -265,17 +264,13 @@ namespace Renderer swapBuffers(); #endif -#if defined(USE_OPENGL_21) LOG(LogInfo) << "Loading shaders..."; std::vector shaderFiles; - shaderFiles.push_back(":/shaders/glsl/desaturate.glsl"); - shaderFiles.push_back(":/shaders/glsl/opacity.glsl"); - shaderFiles.push_back(":/shaders/glsl/dim.glsl"); + shaderFiles.push_back(":/shaders/glsl/core.glsl"); shaderFiles.push_back(":/shaders/glsl/blur_horizontal.glsl"); shaderFiles.push_back(":/shaders/glsl/blur_vertical.glsl"); shaderFiles.push_back(":/shaders/glsl/scanlines.glsl"); - shaderFiles.push_back(":/shaders/glsl/bgra_to_rgba.glsl"); for (auto it = shaderFiles.cbegin(); it != shaderFiles.cend(); ++it) { Shader* loadShader = new Shader(); @@ -290,17 +285,14 @@ namespace Renderer sShaderProgramVector.push_back(loadShader); } -#endif return true; } static void destroyWindow() { -#if defined(USE_OPENGL_21) for (auto it = sShaderProgramVector.cbegin(); it != sShaderProgramVector.cend(); ++it) delete *it; -#endif destroyContext(); SDL_DestroyWindow(sdlWindow); @@ -319,56 +311,22 @@ namespace Renderer glm::mat4 projection {getIdentity()}; Rect viewport {0, 0, 0, 0}; - switch (screenRotate) { - case 1: { - viewport.x = windowWidth - screenOffsetY - screenHeight; - viewport.y = screenOffsetX; - viewport.w = screenHeight; - viewport.h = screenWidth; - projection = glm::ortho(0.0f, static_cast(screenHeight), - static_cast(screenWidth), 0.0f, -1.0f, 1.0f); - projection = glm::rotate(projection, glm::radians(90.0f), {0.0f, 0.0f, 1.0f}); - projection = glm::translate(projection, {0.0f, screenHeight * -1.0f, 0.0f}); - break; - } - case 2: { - viewport.x = windowWidth - screenOffsetX - screenWidth; - viewport.y = windowHeight - screenOffsetY - screenHeight; - viewport.w = screenWidth; - viewport.h = screenHeight; - projection = glm::ortho(0.0f, static_cast(screenWidth), - static_cast(screenHeight), 0.0f, -1.0f, 1.0f); - projection = glm::rotate(projection, glm::radians(180.0f), {0.0f, 0.0f, 1.0f}); - projection = - glm::translate(projection, {screenWidth * -1.0f, screenHeight * -1.0f, 0.0f}); - break; - } - case 3: { - viewport.x = screenOffsetY; - viewport.y = windowHeight - screenOffsetX - screenWidth; - viewport.w = screenHeight; - viewport.h = screenWidth; - projection = glm::ortho(0.0f, static_cast(screenHeight), - static_cast(screenWidth), 0.0f, -1.0f, 1.0f); - projection = glm::rotate(projection, glm::radians(270.0f), {0.0f, 0.0f, 1.0f}); - projection = glm::translate(projection, {screenWidth * -1.0f, 0.0f, 0.0f}); - break; - } - default: { - viewport.x = screenOffsetX; - viewport.y = screenOffsetY; - viewport.w = screenWidth; - viewport.h = screenHeight; - projection = glm::ortho(0.0f, static_cast(screenWidth), - static_cast(screenHeight), 0.0f, -1.0f, 1.0f); - break; - } - } + viewport.x = windowWidth - screenOffsetX - screenWidth; + viewport.y = windowHeight - screenOffsetY - screenHeight; + viewport.w = screenWidth; + viewport.h = screenHeight; + projection = glm::ortho(0.0f, static_cast(screenWidth), + static_cast(screenHeight), 0.0f, -1.0f, 1.0f); + projection = glm::rotate(projection, glm::radians(180.0f), {0.0f, 0.0f, 1.0f}); + mProjectionMatrixRotated = + glm::translate(projection, {screenWidth * -1.0f, screenHeight * -1.0f, 0.0f}); - mProjectionMatrix = projection; - - setViewport(viewport); - setProjection(projection); + viewport.x = screenOffsetX; + viewport.y = screenOffsetY; + viewport.w = screenWidth; + viewport.h = screenHeight; + mProjectionMatrix = glm::ortho(0.0f, static_cast(screenWidth), + static_cast(screenHeight), 0.0f, -1.0f, 1.0f); // This is required to avoid a brief white screen flash during startup on some systems. Renderer::drawRect(0.0f, 0.0f, static_cast(Renderer::getScreenWidth()), @@ -393,22 +351,12 @@ namespace Renderer if (box.h == 0) box.h = screenHeight - box.y; - switch (screenRotate) { - case 0: - box = Rect(screenOffsetX + box.x, screenOffsetY + box.y, box.w, box.h); - break; - case 1: - box = Rect(windowWidth - screenOffsetY - box.y - box.h, screenOffsetX + box.x, - box.h, box.w); - break; - case 2: - box = Rect(windowWidth - screenOffsetX - box.x - box.w, - windowHeight - screenOffsetY - box.y - box.h, box.w, box.h); - break; - case 3: - box = Rect(screenOffsetY + box.y, windowHeight - screenOffsetX - box.x - box.w, - box.h, box.w); - break; + if (screenRotated) { + box = Rect(windowWidth - screenOffsetX - box.x - box.w, + windowHeight - screenOffsetY - box.y - box.h, box.w, box.h); + } + else { + box = Rect(screenOffsetX + box.x, screenOffsetY + box.y, box.w, box.h); } // Make sure the box fits within clipStack.top(), and clip further accordingly. @@ -453,20 +401,18 @@ namespace Renderer const float y, const float w, const float h, - const unsigned int _color, - const unsigned int _colorEnd, + const unsigned int color, + const unsigned int colorEnd, bool horizontalGradient, const float opacity, - const glm::mat4& trans, + const float dim, const Blend::Factor srcBlendFactor, const Blend::Factor dstBlendFactor) { - const unsigned int rColor = convertRGBAToABGR(_color); - const unsigned int rColorEnd = convertRGBAToABGR(_colorEnd); Vertex vertices[4]; - float wL = w; - float hL = h; + float wL {w}; + float hL {h}; // If the width or height was scaled down to less than 1 pixel, then set it to // 1 pixel so that it will still render on lower resolutions. @@ -476,44 +422,21 @@ namespace Renderer hL = 1.0f; // clang-format off - vertices[0] = {{x, y }, {0.0f, 0.0f}, rColor}; - vertices[1] = {{x, y + hL}, {0.0f, 0.0f}, horizontalGradient ? rColor : rColorEnd}; - vertices[2] = {{x + wL, y }, {0.0f, 0.0f}, horizontalGradient ? rColorEnd : rColor}; - vertices[3] = {{x + wL, y + hL}, {0.0f, 0.0f}, rColorEnd}; + vertices[0] = {{x, y }, {0.0f, 0.0f}, color}; + vertices[1] = {{x, y + hL}, {0.0f, 0.0f}, horizontalGradient ? color : colorEnd}; + vertices[2] = {{x + wL, y }, {0.0f, 0.0f}, horizontalGradient ? colorEnd : color}; + vertices[3] = {{x + wL, y + hL}, {0.0f, 0.0f}, colorEnd}; // clang-format on // Round vertices. for (int i = 0; i < 4; ++i) vertices[i].pos = glm::round(vertices[i].pos); - if (opacity < 1.0) { - vertices[0].shaders = SHADER_OPACITY; - vertices[0].opacity = opacity; - } - else { - bindTexture(0); - } - drawTriangleStrips(vertices, 4, trans, srcBlendFactor, dstBlendFactor); - } + vertices->opacity = opacity; + vertices->dim = dim; - const unsigned int convertRGBAToABGR(const unsigned int _color) - { - unsigned char red = ((_color & 0xff000000) >> 24) & 255; - unsigned char green = ((_color & 0x00ff0000) >> 16) & 255; - unsigned char blue = ((_color & 0x0000ff00) >> 8) & 255; - unsigned char alpha = ((_color & 0x000000ff)) & 255; - - return alpha << 24 | blue << 16 | green << 8 | red; - } - - const unsigned int convertABGRToRGBA(const unsigned int _color) - { - unsigned char alpha = ((_color & 0xff000000) >> 24) & 255; - unsigned char blue = ((_color & 0x00ff0000) >> 16) & 255; - unsigned char green = ((_color & 0x0000ff00) >> 8) & 255; - unsigned char red = ((_color & 0x000000ff)) & 255; - - return red << 24 | green << 16 | blue << 8 | alpha; + bindTexture(0); + drawTriangleStrips(vertices, 4, srcBlendFactor, dstBlendFactor); } Shader* getShaderProgram(unsigned int shaderID) @@ -533,7 +456,14 @@ namespace Renderer return nullptr; } - const glm::mat4& getProjectionMatrix() { return mProjectionMatrix; } + const glm::mat4& getProjectionMatrix() + { + if (screenRotated) + return mProjectionMatrixRotated; + else + return mProjectionMatrix; + } + const glm::mat4& getProjectionMatrixNormal() { return mProjectionMatrix; } SDL_Window* getSDLWindow() { return sdlWindow; } const float getWindowWidth() { return static_cast(windowWidth); } const float getWindowHeight() { return static_cast(windowHeight); } @@ -541,7 +471,7 @@ namespace Renderer const float getScreenHeight() { return static_cast(screenHeight); } const float getScreenOffsetX() { return static_cast(screenOffsetX); } const float getScreenOffsetY() { return static_cast(screenOffsetY); } - const int getScreenRotate() { return screenRotate; } + const bool getScreenRotated() { return screenRotated; } const float getScreenWidthModifier() { return screenWidthModifier; } const float getScreenHeightModifier() { return screenHeightModifier; } const float getScreenAspectRatio() { return screenAspectRatio; } diff --git a/es-core/src/renderers/Renderer.h b/es-core/src/renderers/Renderer.h index 83dfe75db..95f72df36 100644 --- a/es-core/src/renderers/Renderer.h +++ b/es-core/src/renderers/Renderer.h @@ -20,39 +20,41 @@ struct SDL_Window; namespace Renderer { - const unsigned int SHADER_DESATURATE {1}; - const unsigned int SHADER_OPACITY {2}; - const unsigned int SHADER_DIM {4}; - const unsigned int SHADER_BLUR_HORIZONTAL {8}; - const unsigned int SHADER_BLUR_VERTICAL {16}; - const unsigned int SHADER_SCANLINES {32}; - const unsigned int SHADER_BGRA_TO_RGBA {64}; + // clang-format off + const unsigned int SHADER_CORE {0x00000001}; + const unsigned int SHADER_BLUR_HORIZONTAL {0x00000002}; + const unsigned int SHADER_BLUR_VERTICAL {0x00000004}; + const unsigned int SHADER_SCANLINES {0x00000008}; + // clang-format on - struct shaderParameters { - std::array textureSize; - std::array textureCoordinates; - float fragmentSaturation; - float fragmentDimValue; - float fragmentOpacity; + struct postProcessingParams { + float opacity; + float saturation; + float dim; + bool convertBGRAToRGBA; unsigned int blurPasses; + unsigned int shaders; - shaderParameters() - : textureSize {0.0f, 0.0f} - , textureCoordinates {0.0f, 0.0f, 0.0f, 0.0f} - , fragmentSaturation {1.0f} - , fragmentDimValue {0.4f} - , fragmentOpacity {1.0f} + postProcessingParams() + : opacity {1.0f} + , saturation {1.0f} + , dim {1.0f} + , convertBGRAToRGBA {false} , blurPasses {1} + , shaders {0} { } }; static std::vector sShaderProgramVector; - static GLuint shaderFBO; + static GLuint shaderFBO1; + static GLuint shaderFBO2; // This is simply to get rid of a GCC false positive -Wunused-variable compiler warning. - static GLuint shaderFBODummy = shaderFBO; + static GLuint shaderFBODummy1 {shaderFBO1}; + static GLuint shaderFBODummy2 {shaderFBO2}; static constexpr glm::mat4 getIdentity() { return glm::mat4 {1.0f}; } + static inline glm::mat4 mTrans {getIdentity()}; #if !defined(NDEBUG) #define GL_CHECK_ERROR(Function) (Function, _GLCheckError(#Function)) @@ -115,19 +117,34 @@ namespace Renderer }; struct Vertex { - Vertex() {} + glm::vec2 pos; + glm::vec2 tex; + unsigned int col; + float opacity; + float saturation; + float dim; + bool convertBGRAToRGBA; + unsigned int shaders; + + Vertex() + : opacity {1.0f} + , saturation {1.0f} + , dim {1.0f} + , convertBGRAToRGBA {false} + , shaders {0} + { + } Vertex(const glm::vec2& position, const glm::vec2& textureCoord, const unsigned int color) : pos(position) , tex(textureCoord) , col(color) + , opacity {1.0f} + , saturation {1.0f} + , dim {1.0f} + , convertBGRAToRGBA {false} + , shaders {0} { } - glm::vec2 pos; - glm::vec2 tex; - unsigned int col; - float saturation {1.0}; - float opacity {1.0}; - unsigned int shaders {0}; }; bool init(); @@ -142,7 +159,7 @@ namespace Renderer const unsigned int colorEnd, bool horizontalGradient = false, const float opacity = 1.0, - const glm::mat4& trans = getIdentity(), + const float dim = 1.0, const Blend::Factor srcBlendFactor = Blend::SRC_ALPHA, const Blend::Factor dstBlendFactor = Blend::ONE_MINUS_SRC_ALPHA); SDL_Window* getSDLWindow(); @@ -152,19 +169,18 @@ namespace Renderer const float getScreenHeight(); const float getScreenOffsetX(); const float getScreenOffsetY(); - const int getScreenRotate(); + const bool getScreenRotated(); const float getScreenWidthModifier(); const float getScreenHeightModifier(); const float getScreenAspectRatio(); - const unsigned int convertRGBAToABGR(const unsigned int color); - const unsigned int convertABGRToRGBA(const unsigned int color); - Shader* getShaderProgram(unsigned int shaderID); const glm::mat4& getProjectionMatrix(); - void shaderPostprocessing(const unsigned int shaders, - const Renderer::shaderParameters& parameters = shaderParameters(), - unsigned char* textureRGBA = nullptr); + const glm::mat4& getProjectionMatrixNormal(); + void shaderPostprocessing( + const unsigned int shaders, + const Renderer::postProcessingParams& parameters = postProcessingParams(), + unsigned char* textureRGBA = nullptr); void setupWindow(); bool createContext(); @@ -192,13 +208,9 @@ namespace Renderer const Blend::Factor dstBlendFactor = Blend::ONE_MINUS_SRC_ALPHA); void drawTriangleStrips(const Vertex* vertices, const unsigned int numVertices, - const glm::mat4& trans = getIdentity(), const Blend::Factor srcBlendFactor = Blend::SRC_ALPHA, - const Blend::Factor dstBlendFactor = Blend::ONE_MINUS_SRC_ALPHA, - const shaderParameters& parameters = shaderParameters()); - void setProjection(const glm::mat4& projection); + const Blend::Factor dstBlendFactor = Blend::ONE_MINUS_SRC_ALPHA); void setMatrix(const glm::mat4& matrix); - void setViewport(const Rect& viewport); void setScissor(const Rect& scissor); void setSwapInterval(); void swapBuffers(); diff --git a/es-core/src/renderers/Renderer_GL21.cpp b/es-core/src/renderers/Renderer_GL21.cpp index baced99e9..6a219356d 100644 --- a/es-core/src/renderers/Renderer_GL21.cpp +++ b/es-core/src/renderers/Renderer_GL21.cpp @@ -19,7 +19,9 @@ namespace Renderer { static SDL_GLContext sdlContext = nullptr; - static GLuint whiteTexture = 0; + static GLuint whiteTexture {0}; + static GLuint postProcTexture1 {0}; + static GLuint postProcTexture2 {0}; inline GLenum convertBlendFactor(const Blend::Factor _blendFactor) { @@ -44,10 +46,10 @@ namespace Renderer { // clang-format off switch (_type) { - case Texture::RGBA: { return GL_RGBA; } break; - case Texture::BGRA: { return GL_BGRA; } break; - case Texture::ALPHA: { return GL_ALPHA; } break; - default: { return GL_ZERO; } + case Texture::RGBA: { return GL_RGBA; } break; + case Texture::BGRA: { return GL_BGRA; } break; + case Texture::ALPHA: { return GL_LUMINANCE_ALPHA; } break; + default: { return GL_ZERO; } } // clang-format on } @@ -142,6 +144,14 @@ namespace Renderer return false; } + postProcTexture1 = createTexture(Texture::RGBA, Texture::RGBA, false, false, false, + static_cast(getScreenWidth()), + static_cast(getScreenHeight()), nullptr); + + postProcTexture2 = createTexture(Texture::RGBA, Texture::RGBA, false, false, false, + static_cast(getScreenWidth()), + static_cast(getScreenHeight()), nullptr); + uint8_t data[4] = {255, 255, 255, 255}; whiteTexture = createTexture(Texture::RGBA, Texture::RGBA, false, false, true, 1, 1, data); @@ -154,15 +164,20 @@ namespace Renderer GL_CHECK_ERROR(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); GL_CHECK_ERROR(glEnableClientState(GL_COLOR_ARRAY)); - // This is the framebuffer that will be used for shader rendering. - GL_CHECK_ERROR(glGenFramebuffers(1, &shaderFBO)); + // These framebuffers are used for the shader post processing. + GL_CHECK_ERROR(glGenFramebuffers(1, &shaderFBO1)); + GL_CHECK_ERROR(glGenFramebuffers(1, &shaderFBO2)); return true; } void destroyContext() { - GL_CHECK_ERROR(glDeleteFramebuffers(1, &shaderFBO)); + GL_CHECK_ERROR(glDeleteFramebuffers(1, &shaderFBO1)); + GL_CHECK_ERROR(glDeleteFramebuffers(1, &shaderFBO2)); + destroyTexture(postProcTexture1); + destroyTexture(postProcTexture2); + destroyTexture(whiteTexture); SDL_GL_DeleteContext(sdlContext); sdlContext = nullptr; } @@ -195,8 +210,23 @@ namespace Renderer linearMagnify ? static_cast(GL_LINEAR) : static_cast(GL_NEAREST))); - GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType, - GL_UNSIGNED_BYTE, data)); + if (textureType == GL_LUMINANCE_ALPHA) { + uint8_t* a_data {reinterpret_cast(data)}; + uint8_t* la_data {new uint8_t[width * height * 2]}; + for (uint32_t i = 0; i < (width * height); ++i) { + la_data[(i * 2) + 0] = 255; + la_data[(i * 2) + 1] = a_data ? a_data[i] : 255; + } + + GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, + textureType, GL_UNSIGNED_BYTE, la_data)); + + delete[] la_data; + } + else { + GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, + textureType, GL_UNSIGNED_BYTE, data)); + } return texture; } @@ -217,8 +247,27 @@ namespace Renderer const GLenum textureType = convertTextureType(type); GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); - GL_CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, textureType, - GL_UNSIGNED_BYTE, data)); + + // Regular GL_ALPHA textures are black + alpha when used in shaders, so create a + // GL_LUMINANCE_ALPHA texture instead so it's white + alpha. + if (textureType == GL_LUMINANCE_ALPHA) { + uint8_t* a_data {reinterpret_cast(data)}; + uint8_t* la_data {new uint8_t[width * height * 2]}; + for (uint32_t i = 0; i < (width * height); ++i) { + la_data[(i * 2) + 0] = 255; + la_data[(i * 2) + 1] = a_data ? a_data[i] : 255; + } + + GL_CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, textureType, + GL_UNSIGNED_BYTE, la_data)); + + delete[] la_data; + } + else { + GL_CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, textureType, + GL_UNSIGNED_BYTE, data)); + } + GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, whiteTexture)); } @@ -247,13 +296,11 @@ namespace Renderer void drawTriangleStrips(const Vertex* vertices, const unsigned int numVertices, - const glm::mat4& trans, const Blend::Factor srcBlendFactor, - const Blend::Factor dstBlendFactor, - const shaderParameters& parameters) + const Blend::Factor dstBlendFactor) { - const float width = vertices[3].pos[0]; - const float height = vertices[3].pos[1]; + const float width {vertices[3].pos[0]}; + const float height {vertices[3].pos[1]}; GL_CHECK_ERROR(glVertexPointer(2, GL_FLOAT, sizeof(Vertex), &vertices[0].pos)); GL_CHECK_ERROR(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &vertices[0].tex)); @@ -262,138 +309,78 @@ namespace Renderer GL_CHECK_ERROR( glBlendFunc(convertBlendFactor(srcBlendFactor), convertBlendFactor(dstBlendFactor))); -#if defined(USE_OPENGL_21) - if (vertices[0].shaders == 0) { - GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); - } - else { - // If saturation is set below the maximum (default) value, run the - // desaturation shader. - if (vertices->saturation < 1.0f || parameters.fragmentSaturation < 1.0f) { - Shader* runShader = getShaderProgram(SHADER_DESATURATE); - // Only try to use the shader if it has been loaded properly. - if (runShader) { - runShader->activateShaders(); - runShader->setModelViewProjectionMatrix(getProjectionMatrix() * trans); - runShader->setSaturation(vertices->saturation); - GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); - runShader->deactivateShaders(); - } - } - - if (vertices->shaders & SHADER_OPACITY) { - Shader* runShader = getShaderProgram(SHADER_OPACITY); - if (runShader) { - runShader->activateShaders(); - runShader->setModelViewProjectionMatrix(getProjectionMatrix() * trans); - vertices->opacity < 1.0f ? runShader->setOpacity(vertices->opacity) : - runShader->setOpacity(parameters.fragmentOpacity); - GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); - runShader->deactivateShaders(); - } - } - - // Check if any other shaders are set to be used and if so, run them. - if (vertices->shaders & SHADER_DIM) { - Shader* runShader = getShaderProgram(SHADER_DIM); - if (runShader) { - runShader->activateShaders(); - runShader->setModelViewProjectionMatrix(getProjectionMatrix() * trans); - runShader->setDimValue(parameters.fragmentDimValue); - GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); - runShader->deactivateShaders(); - } - } - - if (vertices->shaders & SHADER_BLUR_HORIZONTAL) { - Shader* runShader = getShaderProgram(SHADER_BLUR_HORIZONTAL); - if (runShader) { - runShader->activateShaders(); - runShader->setModelViewProjectionMatrix(getProjectionMatrix() * trans); - runShader->setTextureSize({width, height}); - GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); - runShader->deactivateShaders(); - } - } - - if (vertices->shaders & SHADER_BLUR_VERTICAL) { - Shader* runShader = getShaderProgram(SHADER_BLUR_VERTICAL); - if (runShader) { - runShader->activateShaders(); - runShader->setModelViewProjectionMatrix(getProjectionMatrix() * trans); - runShader->setTextureSize({width, height}); - GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); - runShader->deactivateShaders(); - } - } - - if (vertices->shaders & SHADER_SCANLINES) { - Shader* runShader = getShaderProgram(SHADER_SCANLINES); - float shaderWidth = width * 1.2f; - // Scale the scanlines relative to screen resolution. - float screenHeightModifier = getScreenHeightModifier(); - float relativeHeight = height / getScreenHeight(); - float shaderHeight = 0.0f; - if (relativeHeight == 1.0f) { - // Full screen. - float modifier = 1.30f - (0.1f * screenHeightModifier); - shaderHeight = height * modifier; - } - else { - // Portion of screen, e.g. gamelist view. - // Average the relative width and height to avoid applying exaggerated - // scanlines to videos with non-standard aspect ratios. - float relativeWidth = width / getScreenWidth(); - float relativeAdjustment = (relativeWidth + relativeHeight) / 2.0f; - float modifier = - 1.41f + relativeAdjustment / 7.0f - (0.14f * screenHeightModifier); - shaderHeight = height * modifier; - } - if (runShader) { - runShader->activateShaders(); - runShader->setModelViewProjectionMatrix(getProjectionMatrix() * trans); - runShader->setOpacity(vertices->opacity); - runShader->setTextureSize({shaderWidth, shaderHeight}); - GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); - runShader->deactivateShaders(); - } - } - - if (vertices->shaders & SHADER_BGRA_TO_RGBA) { - Shader* runShader = getShaderProgram(SHADER_BGRA_TO_RGBA); - if (runShader) { - runShader->activateShaders(); - runShader->setModelViewProjectionMatrix(getProjectionMatrix() * trans); - runShader->setOpacity(vertices->opacity); - GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); - runShader->deactivateShaders(); - } + if (vertices->shaders == 0 || vertices->shaders & SHADER_CORE) { + Shader* runShader = getShaderProgram(SHADER_CORE); + if (runShader) { + runShader->activateShaders(); + runShader->setModelViewProjectionMatrix(mTrans); + runShader->setOpacity(vertices->opacity); + runShader->setSaturation(vertices->saturation); + runShader->setDim(vertices->dim); + runShader->setBGRAToRGBA(vertices->convertBGRAToRGBA); + GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); + runShader->deactivateShaders(); + } + } + else if (vertices->shaders & SHADER_BLUR_HORIZONTAL) { + Shader* runShader = getShaderProgram(SHADER_BLUR_HORIZONTAL); + if (runShader) { + runShader->activateShaders(); + runShader->setModelViewProjectionMatrix(mTrans); + runShader->setTextureSize({width, height}); + GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); + runShader->deactivateShaders(); + } + return; + } + else if (vertices->shaders & SHADER_BLUR_VERTICAL) { + Shader* runShader = getShaderProgram(SHADER_BLUR_VERTICAL); + if (runShader) { + runShader->activateShaders(); + runShader->setModelViewProjectionMatrix(mTrans); + runShader->setTextureSize({width, height}); + GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); + runShader->deactivateShaders(); + } + return; + } + else if (vertices->shaders & SHADER_SCANLINES) { + Shader* runShader {getShaderProgram(SHADER_SCANLINES)}; + float shaderWidth {width * 1.2f}; + // Scale the scanlines relative to screen resolution. + float screenHeightModifier {getScreenHeightModifier()}; + float relativeHeight {height / getScreenHeight()}; + float shaderHeight {0.0f}; + if (relativeHeight == 1.0f) { + // Full screen. + float modifier {1.30f - (0.1f * screenHeightModifier)}; + shaderHeight = height * modifier; + } + else { + // Portion of screen, e.g. gamelist view. + // Average the relative width and height to avoid applying exaggerated + // scanlines to videos with non-standard aspect ratios. + float relativeWidth {width / getScreenWidth()}; + float relativeAdjustment {(relativeWidth + relativeHeight) / 2.0f}; + float modifier {1.41f + relativeAdjustment / 7.0f - (0.14f * screenHeightModifier)}; + shaderHeight = height * modifier; + } + if (runShader) { + runShader->activateShaders(); + runShader->setModelViewProjectionMatrix(mTrans); + runShader->setOpacity(vertices->opacity); + runShader->setTextureSize({shaderWidth, shaderHeight}); + GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices)); + runShader->deactivateShaders(); } } -#endif - } - - void setProjection(const glm::mat4& projection) - { - GL_CHECK_ERROR(glMatrixMode(GL_PROJECTION)); - GL_CHECK_ERROR(glLoadMatrixf(reinterpret_cast(&projection))); } void setMatrix(const glm::mat4& matrix) { - glm::mat4 newMatrix {matrix}; - newMatrix[3] = glm::round(newMatrix[3]); - - GL_CHECK_ERROR(glMatrixMode(GL_MODELVIEW)); - GL_CHECK_ERROR(glLoadMatrixf(reinterpret_cast(&newMatrix))); - } - - void setViewport(const Rect& viewport) - { - // glViewport starts at the bottom left of the window. - GL_CHECK_ERROR(glViewport(viewport.x, - static_cast(getWindowHeight()) - viewport.y - viewport.h, - viewport.w, viewport.h)); + mTrans = matrix; + mTrans[3] = glm::round(mTrans[3]); + mTrans = getProjectionMatrix() * mTrans; } void setScissor(const Rect& scissor) @@ -450,31 +437,31 @@ namespace Renderer } void shaderPostprocessing(unsigned int shaders, - const Renderer::shaderParameters& parameters, + const Renderer::postProcessingParams& parameters, unsigned char* textureRGBA) { Vertex vertices[4]; std::vector shaderList; - GLuint width {static_cast(getScreenWidth())}; - GLuint height {static_cast(getScreenHeight())}; - float widthf {static_cast(width)}; - float heightf {static_cast(height)}; + float widthf {getScreenWidth()}; + float heightf {getScreenHeight()}; + GLuint width {static_cast(widthf)}; + GLuint height {static_cast(heightf)}; // Set vertex positions and texture coordinates to full screen as all // postprocessing is applied to the complete screen area. // clang-format off - vertices[0] = { { 0.0f , 0.0f }, { 0.0f, 1.0f }, 0 }; - vertices[1] = { { 0.0f , heightf }, { 0.0f, 0.0f }, 0 }; - vertices[2] = { { widthf, 0.0f }, { 1.0f, 1.0f }, 0 }; - vertices[3] = { { widthf, heightf }, { 1.0f, 0.0f }, 0 }; + vertices[0] = {{0.0f, 0.0f }, {0.0f, 1.0f}, 0xFFFFFFFF}; + vertices[1] = {{0.0f, heightf}, {0.0f, 0.0f}, 0xFFFFFFFF}; + vertices[2] = {{widthf, 0.0f }, {1.0f, 1.0f}, 0xFFFFFFFF}; + vertices[3] = {{widthf, heightf}, {1.0f, 0.0f}, 0xFFFFFFFF}; // clang-format on - if (shaders & Renderer::SHADER_DESATURATE) - shaderList.push_back(Renderer::SHADER_DESATURATE); - if (shaders & Renderer::SHADER_OPACITY) - shaderList.push_back(Renderer::SHADER_OPACITY); - if (shaders & Renderer::SHADER_DIM) - shaderList.push_back(Renderer::SHADER_DIM); + vertices->opacity = parameters.opacity; + vertices->saturation = parameters.saturation; + vertices->dim = parameters.dim; + + shaderList.emplace_back(Renderer::SHADER_CORE); + if (shaders & Renderer::SHADER_BLUR_HORIZONTAL) shaderList.push_back(Renderer::SHADER_BLUR_HORIZONTAL); if (shaders & Renderer::SHADER_BLUR_VERTICAL) @@ -482,17 +469,30 @@ namespace Renderer if (shaders & Renderer::SHADER_SCANLINES) shaderList.push_back(Renderer::SHADER_SCANLINES); - if (parameters.fragmentSaturation < 1.0) - vertices[0].saturation = parameters.fragmentSaturation; - setMatrix(getIdentity()); - GLuint screenTexture = createTexture(Texture::RGBA, Texture::RGBA, false, false, false, - width, height, nullptr); + bindTexture(postProcTexture1); - GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); + GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO2)); + GL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + postProcTexture2, 0)); + + GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO1)); + + // Attach texture to the shader framebuffer. + GL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + postProcTexture1, 0)); + + // Blit the screen contents to postProcTexture. + GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, + GL_COLOR_BUFFER_BIT, GL_NEAREST)); + + GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO2)); + + bool firstFBO {true}; + int drawCalls {0}; for (size_t i = 0; i < shaderList.size(); ++i) { - vertices[0].shaders = shaderList[i]; + vertices->shaders = shaderList[i]; int shaderPasses = 1; // For the blur shaders there is an optional variable to set the number of passes // to execute, which proportionally affects the blur amount. @@ -502,42 +502,55 @@ namespace Renderer } for (int p = 0; p < shaderPasses; ++p) { - GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO)); - - // Attach the texture to the shader framebuffer. - GL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, screenTexture, 0)); - - // Blit the screen contents to screenTexture. - GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, - GL_COLOR_BUFFER_BIT, GL_NEAREST)); - - // Apply/render the shaders. - drawTriangleStrips(vertices, 4, getIdentity(), Blend::SRC_ALPHA, - Blend::ONE_MINUS_SRC_ALPHA, parameters); - - // If textureRGBA has an address, it means that the output should go to this - // texture rather than to the screen. The glReadPixels() function is slow, but - // since this will typically only run every now and then to create a cached - // screen texture, it doesn't really matter. - if (textureRGBA) { - GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO)); - GL_CHECK_ERROR( - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, textureRGBA)); + if (textureRGBA == nullptr && i == shaderList.size() - 1 && p == shaderPasses - 1) { + // If the screen is rotated and we're at an even number of drawcalls, then + // set the projection to a non-rotated state before making the last drawcall + // as the image would otherwise get rendered upside down. + if (getScreenRotated() && drawCalls % 2 == 0) { + mTrans = getIdentity(); + mTrans[3] = glm::round(mTrans[3]); + mTrans = getProjectionMatrixNormal() * mTrans; + } + // If it's the last shader pass, then render directly to the default framebuffer + // to avoid having to make an expensive glBlitFramebuffer() call. GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); + drawTriangleStrips(vertices, 4, Blend::SRC_ALPHA, Blend::ONE_MINUS_SRC_ALPHA); + break; + } + // Apply/render the shaders. + drawTriangleStrips(vertices, 4, Blend::SRC_ALPHA, Blend::ONE_MINUS_SRC_ALPHA); + ++drawCalls; + if (firstFBO) { + bindTexture(postProcTexture2); + GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO2)); + GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO1)); + firstFBO = false; } else { - // Blit the resulting postprocessed texture back to the primary framebuffer. - GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO)); - GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); - GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, - GL_COLOR_BUFFER_BIT, GL_NEAREST)); + bindTexture(postProcTexture1); + GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO1)); + GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO2)); + firstFBO = true; } } } + // If textureRGBA has an address, it means that the output should go to this + // texture rather than to the screen. The glReadPixels() function is slow, but + // since this will typically only run every now and then to create a cached + // screen texture, it doesn't really matter. + if (textureRGBA) { + if (firstFBO) + GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO1)); + else + GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO2)); + + GL_CHECK_ERROR( + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, textureRGBA)); + GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); + } + GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); - destroyTexture(screenTexture); } } // namespace Renderer diff --git a/es-core/src/renderers/Shader_GL21.cpp b/es-core/src/renderers/Shader_GL21.cpp index 51818b7e2..8725dafe1 100644 --- a/es-core/src/renderers/Shader_GL21.cpp +++ b/es-core/src/renderers/Shader_GL21.cpp @@ -21,10 +21,9 @@ namespace Renderer , shaderMVPMatrix {0} , shaderTextureSize {0} , shaderTextureCoord {0} - , shaderColor {0} - , shaderSaturation {0} , shaderOpacity {0} - , shaderDimValue {0} + , shaderSaturation {0} + , shaderDim {0} { } @@ -108,10 +107,10 @@ namespace Renderer shaderMVPMatrix = glGetUniformLocation(mProgramID, "MVPMatrix"); shaderTextureSize = glGetUniformLocation(mProgramID, "TextureSize"); shaderTextureCoord = glGetAttribLocation(mProgramID, "TexCoord"); - shaderColor = glGetAttribLocation(mProgramID, "COLOR"); - shaderSaturation = glGetUniformLocation(mProgramID, "saturation"); shaderOpacity = glGetUniformLocation(mProgramID, "opacity"); - shaderDimValue = glGetUniformLocation(mProgramID, "dimValue"); + shaderSaturation = glGetUniformLocation(mProgramID, "saturation"); + shaderDim = glGetUniformLocation(mProgramID, "dim"); + shaderBGRAToRGBA = glGetUniformLocation(mProgramID, "BGRAToRGBA"); } void Renderer::Shader::setModelViewProjectionMatrix(glm::mat4 mvpMatrix) @@ -135,11 +134,10 @@ namespace Renderer } } - void Renderer::Shader::setColor(std::array shaderVec4) + void Renderer::Shader::setOpacity(GLfloat opacity) { - if (shaderColor != GL_INVALID_OPERATION) - GL_CHECK_ERROR(glUniform4f(shaderColor, shaderVec4[0], shaderVec4[1], shaderVec4[2], - shaderVec4[3])); + if (shaderOpacity != GL_INVALID_VALUE && shaderOpacity != GL_INVALID_OPERATION) + GL_CHECK_ERROR(glUniform1f(shaderOpacity, opacity)); } void Renderer::Shader::setSaturation(GLfloat saturation) @@ -148,16 +146,16 @@ namespace Renderer GL_CHECK_ERROR(glUniform1f(shaderSaturation, saturation)); } - void Renderer::Shader::setOpacity(GLfloat opacity) + void Renderer::Shader::setDim(GLfloat dim) { - if (shaderOpacity != GL_INVALID_VALUE && shaderOpacity != GL_INVALID_OPERATION) - GL_CHECK_ERROR(glUniform1f(shaderOpacity, opacity)); + if (shaderDim != GL_INVALID_VALUE && shaderDim != GL_INVALID_OPERATION) + GL_CHECK_ERROR(glUniform1f(shaderDim, dim)); } - void Renderer::Shader::setDimValue(GLfloat dimValue) + void Renderer::Shader::setBGRAToRGBA(GLboolean BGRAToRGBA) { - if (shaderDimValue != GL_INVALID_VALUE && shaderDimValue != GL_INVALID_OPERATION) - GL_CHECK_ERROR(glUniform1f(shaderDimValue, dimValue)); + if (shaderBGRAToRGBA != GL_INVALID_VALUE && shaderBGRAToRGBA != GL_INVALID_OPERATION) + GL_CHECK_ERROR(glUniform1i(shaderBGRAToRGBA, BGRAToRGBA ? 1 : 0)); } void Renderer::Shader::activateShaders() @@ -205,7 +203,7 @@ namespace Renderer glGetShaderInfoLog(shaderID, maxLength, &logLength, &infoLog.front()); if (logLength > 0) { - LOG(LogDebug) << "Renderer_GL21::printShaderInfoLog(): Error in " + LOG(LogDebug) << "Shader_GL21::printShaderInfoLog(): Error in " << (shaderType == GL_VERTEX_SHADER ? "VERTEX section:\n" : "FRAGMENT section:\n") << std::string(infoLog.begin(), infoLog.end()); diff --git a/es-core/src/renderers/Shader_GL21.h b/es-core/src/renderers/Shader_GL21.h index 764a28af6..eca5f1bd4 100644 --- a/es-core/src/renderers/Shader_GL21.h +++ b/es-core/src/renderers/Shader_GL21.h @@ -49,10 +49,10 @@ namespace Renderer void setTextureSize(std::array shaderVec2); void setTextureCoordinates(std::array shaderVec4); - void setColor(std::array shaderVec4); - void setSaturation(GLfloat saturation); void setOpacity(GLfloat opacity); - void setDimValue(GLfloat dimValue); + void setSaturation(GLfloat saturation); + void setDim(GLfloat dim); + void setBGRAToRGBA(GLboolean BGRAToRGBA); // Sets the shader program to use the loaded shaders. void activateShaders(); // Sets the shader program to 0 which reverts to the fixed function pipeline. @@ -71,10 +71,10 @@ namespace Renderer GLint shaderMVPMatrix; GLint shaderTextureSize; GLint shaderTextureCoord; - GLint shaderColor; - GLint shaderSaturation; GLint shaderOpacity; - GLint shaderDimValue; + GLint shaderSaturation; + GLint shaderDim; + GLint shaderBGRAToRGBA; }; } // namespace Renderer diff --git a/es-core/src/resources/Font.cpp b/es-core/src/resources/Font.cpp index e76259281..0e82f7579 100644 --- a/es-core/src/resources/Font.cpp +++ b/es-core/src/resources/Font.cpp @@ -654,21 +654,19 @@ TextCache* Font::buildTextCache(const std::string& text, const float glyphStartX {x + glyph->bearing.x}; const glm::ivec2& textureSize {glyph->texture->textureSize}; - const unsigned int convertedColor = Renderer::convertRGBAToABGR(color); - vertices[1] = {{glyphStartX, y - glyph->bearing.y}, - {glyph->texPos.x, glyph->texPos.y}, - convertedColor}; + vertices[1] = { + {glyphStartX, y - glyph->bearing.y}, {glyph->texPos.x, glyph->texPos.y}, color}; vertices[2] = {{glyphStartX, y - glyph->bearing.y + (glyph->texSize.y * textureSize.y)}, {glyph->texPos.x, glyph->texPos.y + glyph->texSize.y}, - convertedColor}; + color}; vertices[3] = {{glyphStartX + glyph->texSize.x * textureSize.x, y - glyph->bearing.y}, {glyph->texPos.x + glyph->texSize.x, glyph->texPos.y}, - convertedColor}; + color}; vertices[4] = {{glyphStartX + glyph->texSize.x * textureSize.x, y - glyph->bearing.y + (glyph->texSize.y * textureSize.y)}, {glyph->texPos.x + glyph->texSize.x, glyph->texPos.y + glyph->texSize.y}, - convertedColor}; + color}; // Round vertices. for (int i = 1; i < 5; ++i) @@ -711,11 +709,25 @@ TextCache* Font::buildTextCache(const std::string& text, void TextCache::setColor(unsigned int color) { - const unsigned int convertedColor = Renderer::convertRGBAToABGR(color); - for (auto it = vertexLists.begin(); it != vertexLists.end(); ++it) for (auto it2 = it->verts.begin(); it2 != it->verts.end(); ++it2) - it2->col = convertedColor; + it2->col = color; +} + +void TextCache::setOpacity(float opacity) +{ + for (auto it = vertexLists.begin(); it != vertexLists.end(); ++it) { + for (auto it2 = it->verts.begin(); it2 != it->verts.end(); ++it2) + it2->opacity = opacity; + } +} + +void TextCache::setDim(float dim) +{ + for (auto it = vertexLists.begin(); it != vertexLists.end(); ++it) { + for (auto it2 = it->verts.begin(); it2 != it->verts.end(); ++it2) + it2->dim = dim; + } } std::shared_ptr Font::getFromTheme(const ThemeData::ThemeElement* elem, diff --git a/es-core/src/resources/Font.h b/es-core/src/resources/Font.h index 61ad7fbfa..d4c786477 100644 --- a/es-core/src/resources/Font.h +++ b/es-core/src/resources/Font.h @@ -206,6 +206,8 @@ public: } metrics; void setColor(unsigned int color); + void setOpacity(float opacity); + void setDim(float dim); friend Font; }; diff --git a/resources/shaders/glsl/core.glsl b/resources/shaders/glsl/core.glsl new file mode 100644 index 000000000..5bf72fe14 --- /dev/null +++ b/resources/shaders/glsl/core.glsl @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +// +// EmulationStation Desktop Edition +// core.glsl +// +// Core shader functionality: +// opacity, saturation, dimming and BGRA to RGBA conversion. +// + +#if defined(VERTEX) +// Vertex section of code: + +#if __VERSION__ >= 130 +#define COMPAT_VARYING out +#else +#define COMPAT_VARYING varying +#endif + +uniform mat4 MVPMatrix; +COMPAT_VARYING vec4 color; +COMPAT_VARYING vec2 texCoord; + +void main(void) +{ + texCoord = gl_MultiTexCoord0.xy; + color.rgba = gl_Color.abgr; + gl_Position = MVPMatrix * gl_Vertex; +} + +#elif defined(FRAGMENT) +// Fragment section of code: + +#if __VERSION__ >= 130 +#define COMPAT_VARYING out +#define COMPAT_TEXTURE texture +#else +#define COMPAT_VARYING varying +#define COMPAT_TEXTURE texture2D +#endif + +COMPAT_VARYING vec4 color; +COMPAT_VARYING vec2 texCoord; +uniform float opacity = 1.0f; +uniform float saturation = 1.0f; +uniform float dim = 1.0f; +uniform int BGRAToRGBA = 0; +uniform sampler2D myTexture; + +void main() +{ + vec4 color = COMPAT_TEXTURE(myTexture, texCoord) * color; + + // Opacity. + if (opacity != 1.0f) + color.a = color.a * opacity; + + // Saturation. + if (saturation != 1.0f) { + vec3 grayscale = vec3(dot(color.rgb, vec3(0.3f, 0.59f, 0.11f))); + vec3 blendedColor = mix(grayscale, color.rgb, saturation); + color = vec4(blendedColor, color.a); + } + + // Dimming + vec4 dimColor = vec4(dim, dim, dim, 1.0f); + color = vec4(color.rgba) * dimColor; + + // BGRA to RGBA conversion. + if (BGRAToRGBA == 1) + color = vec4(color.bgr, color.a); + + gl_FragColor = color; +} +#endif