From 951b774c704d2c9d51c0a1e2caa41423d35e6e21 Mon Sep 17 00:00:00 2001 From: Thomas Galvin Date: Mon, 20 Jan 2014 20:52:45 -0500 Subject: [PATCH] Implemented a more flexible blending system (fixes #298) --- include/SFML/Graphics/BlendMode.hpp | 151 ++++++++++++++++++++++++++-- src/SFML/Graphics/BlendMode.cpp | 93 +++++++++++++++++ src/SFML/Graphics/CMakeLists.txt | 7 +- src/SFML/Graphics/RenderTarget.cpp | 84 ++++++++++------ 4 files changed, 293 insertions(+), 42 deletions(-) create mode 100644 src/SFML/Graphics/BlendMode.cpp diff --git a/include/SFML/Graphics/BlendMode.hpp b/include/SFML/Graphics/BlendMode.hpp index 4b12e117..1a93a711 100644 --- a/include/SFML/Graphics/BlendMode.hpp +++ b/include/SFML/Graphics/BlendMode.hpp @@ -25,22 +25,161 @@ #ifndef SFML_BLENDMODE_HPP #define SFML_BLENDMODE_HPP +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + namespace sf { + //////////////////////////////////////////////////////////// /// \ingroup graphics -/// \brief Available blending modes for drawing +/// \brief Blending modes for drawing /// //////////////////////////////////////////////////////////// -enum BlendMode +struct SFML_GRAPHICS_API BlendMode { - BlendAlpha, ///< Pixel = Source * Source.a + Dest * (1 - Source.a) - BlendAdd, ///< Pixel = Source + Dest - BlendMultiply, ///< Pixel = Source * Dest - BlendNone ///< Pixel = Source + //////////////////////////////////////////////////////// + /// \ingroup graphics + /// \brief Enumeration of the blending factors + /// + //////////////////////////////////////////////////////// + enum BlendFactor + { + Zero, ///< (0,0,0,0) + One, ///< (1,1,1,1) + SrcColor, ///< (src.r,src.g,src.b,src.a) + OneMinusSrcColor, ///< (1,1,1,1) - (src.r,src.g,src.b,src.a) + DstColor, ///< (dst.r,dst.g,dst.b,dst.a) + OneMinusDstColor, ///< (1,1,1,1) - (dst.r,dst.g,dst.b,dst.a) + SrcAlpha, ///< (src.a,src.a,src.a,src.a) + OneMinusSrcAlpha, ///< (1,1,1,1) - (src.a,src.a,src.a,src.a) + DstAlpha, ///< (dst.a,dst.a,dst.a,dst.a) + OneMinusDstAlpha, ///< (1,1,1,1) - (dst.a,dst.a,dst.a,dst.a) + }; + + //////////////////////////////////////////////////////// + /// \ingroup graphics + /// \brief Enumeration of the blending equations + /// + //////////////////////////////////////////////////////// + enum BlendEquation + { + Add, ///< Pixel = Source * SourceFactor + Dst * DstFactor + Subtract, ///< Pixel = Source * SourceFactor - Dst * DstFactor + }; + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Constructs a blending mode that does alpha blending. + /// + //////////////////////////////////////////////////////////// + BlendMode(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the blend mode given the factors and equation. + /// + /// \param colorSourceFactor Specifies how to compute the source factor for the color channels. + /// \param colorDstFactor Specifies how to compute the destination factor for the color channels. + /// \param colorBlendEquation Specifies how to combine the source and destination colors. + /// \param alphaSourceFactor Specifies how to compute the source factor. + /// \param alphaDstFactor Specifies how to compute the destination factor. + /// \param alphaBlendEquation Specifies how to combine the source and destination alphas. + /// + /// + //////////////////////////////////////////////////////////// + BlendMode(BlendFactor colorSourceFactor, BlendFactor colorDstFactor, + BlendEquation colorBlendEquation, BlendFactor alphaSourceFactor, + BlendFactor alphaDstFactor, BlendEquation alphaBlendEquation); + + //////////////////////////////////////////////////////////// + // Member Data + //////////////////////////////////////////////////////////// + BlendFactor colorSrcFactor; ///< Source blending factor for the color channels + BlendFactor colorDstFactor; ///< Destination blending factor for the color channels + BlendEquation colorEquation; ///< Blending equation for the color channels + BlendFactor alphaSrcFactor; ///< Source blending factor for the alpha channel + BlendFactor alphaDstFactor; ///< Destination blending factor for the alpha channel + BlendEquation alphaEquation; ///< Blending equation for the alpha channel }; +//////////////////////////////////////////////////////////// +/// \relates BlendMode +/// \brief Overload of the == operator +/// +/// This operator compares two blending modes and checks if they are equal. +/// +/// \param left Left operand +/// \param right Right operand +/// +/// \return True if blending modes are equal, false if they are different +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API bool operator ==(const BlendMode& left, const BlendMode& right); + +//////////////////////////////////////////////////////////// +/// \relates BlendMode +/// \brief Overload of the != operator +/// +/// This operator compares two blending modes and checks if they are different. +/// +/// \param left Left operand +/// \param right Right operand +/// +/// \return True if blending modes are different, false if they are equal +/// +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API bool operator !=(const BlendMode& left, const BlendMode& right); + + +//////////////////////////////////////////////////////////// +// Commonly used blending modes +//////////////////////////////////////////////////////////// +SFML_GRAPHICS_API extern const BlendMode BlendAlpha; +SFML_GRAPHICS_API extern const BlendMode BlendAdd; +SFML_GRAPHICS_API extern const BlendMode BlendMultiply; +SFML_GRAPHICS_API extern const BlendMode BlendNone; + } // namespace sf #endif // SFML_BLENDMODE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::BlendMode +/// \ingroup graphics +/// +/// sf::BlendMode is a class that represents a blend mode. A +/// blend mode is composed of 6 components: +/// \li %Color Source Factor (colorSrcFactor) +/// \li %Color Destination Factor (colorDstFactor) +/// \li %Color Blend Equation (colorEquation) +/// \li Alpha Source Factor (alphaSrcFactor) +/// \li Alpha Destination Factor (alphaDstFactor) +/// \li Alpha Blend Equation (alphaEquation) +/// +/// Each component has its own setter function. These make +/// modifying a blending mode rather easy: +/// +/// \code +/// sf::BlendMode blendMode; // Standard alpha blending +/// blendMode.colorSrcFactor = sf::BlendMode::One; // Pre-multiplied alpha blending +/// blendMode.colorEquation = sf::BlendMode::Subtract; // An exotic subtraction blending mode +/// \endcode +/// +/// The most common blending modes are defined as const +/// variables for convenience and compatibility with older +/// code: +/// +/// \code +/// sf::BlendMode alphaBlending = sf::BlendAlpha; +/// sf::BlendMode additiveBlending = sf::BlendAdd; +/// sf::BlendMode multiplicativeBlending = sf::BlendMultipy; +/// sf::BlendMode noBlending = sf::BlendNone; +/// \endcode +/// +//////////////////////////////////////////////////////////// diff --git a/src/SFML/Graphics/BlendMode.cpp b/src/SFML/Graphics/BlendMode.cpp new file mode 100644 index 00000000..4145a228 --- /dev/null +++ b/src/SFML/Graphics/BlendMode.cpp @@ -0,0 +1,93 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2013 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +// Commonly used blending modes +//////////////////////////////////////////////////////////// +const BlendMode BlendAlpha(BlendMode::SrcAlpha, BlendMode::OneMinusSrcAlpha, BlendMode::Add, + BlendMode::One, BlendMode::OneMinusSrcAlpha, BlendMode::Add); +const BlendMode BlendAdd(BlendMode::SrcAlpha, BlendMode::One, BlendMode::Add, + BlendMode::One, BlendMode::One, BlendMode::Add); +const BlendMode BlendMultiply(BlendMode::DstColor, BlendMode::Zero, BlendMode::Add, + BlendMode::DstColor, BlendMode::Zero, BlendMode::Add); +const BlendMode BlendNone(BlendMode::One, BlendMode::Zero, BlendMode::Add, + BlendMode::One, BlendMode::Zero, BlendMode::Add); + + +//////////////////////////////////////////////////////////// +BlendMode::BlendMode() : +colorSrcFactor(BlendMode::SrcAlpha), +colorDstFactor(BlendMode::OneMinusSrcAlpha), +colorEquation (BlendMode::Add), +alphaSrcFactor(BlendMode::One), +alphaDstFactor(BlendMode::OneMinusSrcAlpha), +alphaEquation (BlendMode::Add) +{ + +} + + +//////////////////////////////////////////////////////////// +BlendMode::BlendMode(BlendFactor colorSourceFactor, BlendFactor colorDstFactor, + BlendEquation colorBlendEquation, BlendFactor alphaSourceFactor, + BlendFactor alphaDstFactor, BlendEquation alphaBlendEquation) : +colorSrcFactor(colorSourceFactor), +colorDstFactor(colorDstFactor), +colorEquation (colorBlendEquation), +alphaSrcFactor(alphaSourceFactor), +alphaDstFactor(alphaDstFactor), +alphaEquation (alphaBlendEquation) +{ + +} + + +//////////////////////////////////////////////////////////// +bool operator ==(const BlendMode& left, const BlendMode& right) +{ + return (left.colorSrcFactor == right.colorSrcFactor) && + (left.colorDstFactor == right.colorDstFactor) && + (left.colorEquation == right.colorEquation) && + (left.alphaSrcFactor == right.alphaSrcFactor) && + (left.alphaDstFactor == right.alphaDstFactor) && + (left.alphaEquation == right.alphaEquation); +} + + +//////////////////////////////////////////////////////////// +bool operator !=(const BlendMode& left, const BlendMode& right) +{ + return !(left == right); +} + +} // namespace sf diff --git a/src/SFML/Graphics/CMakeLists.txt b/src/SFML/Graphics/CMakeLists.txt index ca11e1b0..999483af 100644 --- a/src/SFML/Graphics/CMakeLists.txt +++ b/src/SFML/Graphics/CMakeLists.txt @@ -4,6 +4,7 @@ set(SRCROOT ${PROJECT_SOURCE_DIR}/src/SFML/Graphics) # all source files set(SRC + ${SRCROOT}/BlendMode.cpp ${INCROOT}/BlendMode.hpp ${SRCROOT}/Color.cpp ${INCROOT}/Color.hpp @@ -86,15 +87,15 @@ source_group("stb_image" FILES ${STB_SRC}) # let CMake know about our additional graphics libraries paths (on Windows and OSX) if(SFML_OS_WINDOWS OR SFML_OS_MACOSX) set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/jpeg") -endif() - +endif() + if(SFML_OS_WINDOWS) set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/libfreetype/windows") set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/libfreetype/windows/freetype") elseif(SFML_OS_MACOSX) set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/libfreetype/osx") set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${PROJECT_SOURCE_DIR}/extlibs/headers/libfreetype/osx/freetype2") - set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-osx/Frameworks") + set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${PROJECT_SOURCE_DIR}/extlibs/libs-osx/Frameworks") endif() # find external libraries diff --git a/src/SFML/Graphics/RenderTarget.cpp b/src/SFML/Graphics/RenderTarget.cpp index 9c94bebb..e5a62ec5 100644 --- a/src/SFML/Graphics/RenderTarget.cpp +++ b/src/SFML/Graphics/RenderTarget.cpp @@ -35,6 +35,41 @@ #include +namespace +{ + // Convert an sf::BlendMode::BlendFactor constant to the corresponding OpenGL constant. + sf::Uint32 factorToGlConstant(sf::BlendMode::BlendFactor blendFactor) + { + switch (blendFactor) + { + default: + case sf::BlendMode::Zero: return GL_ZERO; + case sf::BlendMode::One: return GL_ONE; + case sf::BlendMode::SrcColor: return GL_SRC_COLOR; + case sf::BlendMode::OneMinusSrcColor: return GL_ONE_MINUS_SRC_COLOR; + case sf::BlendMode::DstColor: return GL_DST_COLOR; + case sf::BlendMode::OneMinusDstColor: return GL_ONE_MINUS_DST_COLOR; + case sf::BlendMode::SrcAlpha: return GL_SRC_ALPHA; + case sf::BlendMode::OneMinusSrcAlpha: return GL_ONE_MINUS_SRC_ALPHA; + case sf::BlendMode::DstAlpha: return GL_DST_ALPHA; + case sf::BlendMode::OneMinusDstAlpha: return GL_ONE_MINUS_DST_ALPHA; + } + } + + + // Convert an sf::BlendMode::BlendEquation constant to the corresponding OpenGL constant. + sf::Uint32 equationToGlConstant(sf::BlendMode::BlendEquation blendEquation) + { + switch (blendEquation) + { + default: + case sf::BlendMode::Add: return GL_FUNC_ADD; + case sf::BlendMode::Subtract: return GL_FUNC_SUBTRACT; + } + } +} + + namespace sf { //////////////////////////////////////////////////////////// @@ -355,38 +390,20 @@ void RenderTarget::applyCurrentView() //////////////////////////////////////////////////////////// void RenderTarget::applyBlendMode(BlendMode mode) { - switch (mode) - { - // glBlendFuncSeparateEXT is used when available to avoid an incorrect alpha value when the target - // is a RenderTexture -- in this case the alpha value must be written directly to the target buffer + // Apply the blend mode, falling back to the non-separate versions if necessary + if (GLEW_EXT_blend_func_separate) + glCheck(glBlendFuncSeparateEXT(factorToGlConstant(mode.colorSrcFactor), + factorToGlConstant(mode.colorDstFactor), factorToGlConstant(mode.alphaSrcFactor), + factorToGlConstant(mode.alphaDstFactor))); + else + glCheck(glBlendFunc(factorToGlConstant(mode.colorSrcFactor), + factorToGlConstant(mode.colorDstFactor))); - // Alpha blending - default : - case BlendAlpha : - if (GLEW_EXT_blend_func_separate) - glCheck(glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); - else - glCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - break; - - // Additive blending - case BlendAdd : - if (GLEW_EXT_blend_func_separate) - glCheck(glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE)); - else - glCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE)); - break; - - // Multiplicative blending - case BlendMultiply : - glCheck(glBlendFunc(GL_DST_COLOR, GL_ZERO)); - break; - - // No blending - case BlendNone : - glCheck(glBlendFunc(GL_ONE, GL_ZERO)); - break; - } + if (GLEW_EXT_blend_equation_separate) + glCheck(glBlendEquationSeparateEXT(equationToGlConstant(mode.colorEquation), + equationToGlConstant(mode.alphaEquation))); + else + glCheck(glBlendEquation(equationToGlConstant(mode.colorEquation))); m_cache.lastBlendMode = mode; } @@ -436,8 +453,9 @@ void RenderTarget::applyShader(const Shader* shader) // to render them. // // * Blending mode -// It's a simple integral value, so we can easily check -// whether the value to apply is the same as before or not. +// Since it overloads the == operator, we can easily check +// whether any of the 6 blending components changed and, +// thus, whether we need to update the blend mode. // // * Texture // Storing the pointer or OpenGL ID of the last used texture