diff --git a/include/SFML/Graphics/BlendMode.hpp b/include/SFML/Graphics/BlendMode.hpp index d1132464b..412286d06 100644 --- a/include/SFML/Graphics/BlendMode.hpp +++ b/include/SFML/Graphics/BlendMode.hpp @@ -25,22 +25,190 @@ #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 + //////////////////////////////////////////////////////// + /// \brief Enumeration of the blending factors + /// + /// The factors are mapped directly to their OpenGL equivalents, + /// specified by glBlendFunc() or glBlendFuncSeparate(). + //////////////////////////////////////////////////////// + enum Factor + { + 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) + }; + + //////////////////////////////////////////////////////// + /// \brief Enumeration of the blending equations + /// + /// The equations are mapped directly to their OpenGL equivalents, + /// specified by glBlendEquation() or glBlendEquationSeparate(). + //////////////////////////////////////////////////////// + enum Equation + { + Add, ///< Pixel = Src * SrcFactor + Dst * DstFactor + Subtract ///< Pixel = Src * SrcFactor - Dst * DstFactor + }; + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Constructs a blending mode that does alpha blending. + /// + //////////////////////////////////////////////////////////// + BlendMode(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the blend mode given the factors and equation. + /// + /// This constructor uses the same factors and equation for both + /// color and alpha components. It also defaults to the Add equation. + /// + /// \param sourceFactor Specifies how to compute the source factor for the color and alpha channels. + /// \param destinationFactor Specifies how to compute the destination factor for the color and alpha channels. + /// \param blendEquation Specifies how to combine the source and destination colors and alpha. + /// + //////////////////////////////////////////////////////////// + BlendMode(Factor sourceFactor, Factor destinationFactor, Equation blendEquation = Add); + + //////////////////////////////////////////////////////////// + /// \brief Construct the blend mode given the factors and equation. + /// + /// \param colorSourceFactor Specifies how to compute the source factor for the color channels. + /// \param colorDestinationFactor 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 alphaDestinationFactor Specifies how to compute the destination factor. + /// \param alphaBlendEquation Specifies how to combine the source and destination alphas. + /// + //////////////////////////////////////////////////////////// + BlendMode(Factor colorSourceFactor, Factor colorDestinationFactor, + Equation colorBlendEquation, Factor alphaSourceFactor, + Factor alphaDestinationFactor, Equation alphaBlendEquation); + + //////////////////////////////////////////////////////////// + // Member Data + //////////////////////////////////////////////////////////// + Factor colorSrcFactor; ///< Source blending factor for the color channels + Factor colorDstFactor; ///< Destination blending factor for the color channels + Equation colorEquation; ///< Blending equation for the color channels + Factor alphaSrcFactor; ///< Source blending factor for the alpha channel + Factor alphaDstFactor; ///< Destination blending factor for the alpha channel + Equation alphaEquation; ///< Blending equation for the alpha channel }; +//////////////////////////////////////////////////////////// +/// \relates BlendMode +/// \brief Overload of the == operator +/// +/// \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 +/// +/// \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; ///< Blend source and dest according to dest alpha +SFML_GRAPHICS_API extern const BlendMode BlendAdd; ///< Add source to dest +SFML_GRAPHICS_API extern const BlendMode BlendMultiply; ///< Multiply source and dest +SFML_GRAPHICS_API extern const BlendMode BlendNone; ///< Overwrite dest with source + } // namespace sf #endif // SFML_BLENDMODE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::BlendMode +/// \ingroup graphics +/// +/// sf::BlendMode is a class that represents a blend mode. A blend +/// mode determines how the colors of an object you draw are +/// mixed with the colors that are already in the buffer. +/// +/// The class is composed of 6 components, each of which has its +/// own public member variable: +/// \li %Color Source Factor (@ref colorSrcFactor) +/// \li %Color Destination Factor (@ref colorDstFactor) +/// \li %Color Blend Equation (@ref colorEquation) +/// \li Alpha Source Factor (@ref alphaSrcFactor) +/// \li Alpha Destination Factor (@ref alphaDstFactor) +/// \li Alpha Blend Equation (@ref alphaEquation) +/// +/// The source factor specifies how the pixel you are drawing contributes +/// to the final color. The destination factor specifies how the pixel +/// already drawn in the buffer contributes to the final color. +/// +/// The color channels RGB (red, green, blue; simply referred to as +/// color) and A (alpha; the transparency) can be treated separately. This +/// separation can be useful for specific blend modes, but most often you +/// won't need it and will simply treat the color as a single unit. +/// +/// The blend factors and equations correspond to their OpenGL equivalents. +/// In general, the color of the resulting pixel is calculated according +/// to the following formula (\a src is the color of the source pixel, \a dst +/// the color of the destination pixel, the other variables correspond to the +/// public members, with the equations being + or - operators): +/// \code +/// dst.rgb = colorSrcFactor * src.rgb (colorEquation) colorDstFactor * dst.rgb +/// dst.a = alphaSrcFactor * src.a (alphaEquation) alphaDstFactor * dst.a +/// \endcode +/// All factors and colors are represented as floating point numbers between +/// 0 and 1. Where necessary, the result is clamped to fit in that range. +/// +/// The most common blending modes are defined as constants +/// in the sf namespace: +/// +/// \code +/// sf::BlendMode alphaBlending = sf::BlendAlpha; +/// sf::BlendMode additiveBlending = sf::BlendAdd; +/// sf::BlendMode multiplicativeBlending = sf::BlendMultipy; +/// sf::BlendMode noBlending = sf::BlendNone; +/// \endcode +/// +/// In SFML, a blend mode can be specified every time you draw a sf::Drawable +/// object to a render target. It is part of the sf::RenderStates compound +/// that is passed to the member function sf::RenderTarget::draw(). +/// +/// \see sf::RenderStates, sf::RenderTarget +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/RenderStates.hpp b/include/SFML/Graphics/RenderStates.hpp index bae862978..986554b8e 100644 --- a/include/SFML/Graphics/RenderStates.hpp +++ b/include/SFML/Graphics/RenderStates.hpp @@ -66,7 +66,7 @@ public : /// \param theBlendMode Blend mode to use /// //////////////////////////////////////////////////////////// - RenderStates(BlendMode theBlendMode); + RenderStates(const BlendMode& theBlendMode); //////////////////////////////////////////////////////////// /// \brief Construct a default set of render states with a custom transform @@ -101,7 +101,7 @@ public : /// \param theShader Shader to use /// //////////////////////////////////////////////////////////// - RenderStates(BlendMode theBlendMode, const Transform& theTransform, + RenderStates(const BlendMode& theBlendMode, const Transform& theTransform, const Texture* theTexture, const Shader* theShader); //////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/RenderTarget.hpp b/include/SFML/Graphics/RenderTarget.hpp index 8995d12c5..033e2c78c 100644 --- a/include/SFML/Graphics/RenderTarget.hpp +++ b/include/SFML/Graphics/RenderTarget.hpp @@ -354,7 +354,7 @@ private: /// \param mode Blending mode to apply /// //////////////////////////////////////////////////////////// - void applyBlendMode(BlendMode mode); + void applyBlendMode(const BlendMode& mode); //////////////////////////////////////////////////////////// /// \brief Apply a new transform diff --git a/src/SFML/Graphics/BlendMode.cpp b/src/SFML/Graphics/BlendMode.cpp new file mode 100644 index 000000000..3d392f441 --- /dev/null +++ b/src/SFML/Graphics/BlendMode.cpp @@ -0,0 +1,103 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2014 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 + + +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); +const BlendMode BlendNone(BlendMode::One, BlendMode::Zero); + + +//////////////////////////////////////////////////////////// +BlendMode::BlendMode() : +colorSrcFactor(BlendMode::SrcAlpha), +colorDstFactor(BlendMode::OneMinusSrcAlpha), +colorEquation (BlendMode::Add), +alphaSrcFactor(BlendMode::One), +alphaDstFactor(BlendMode::OneMinusSrcAlpha), +alphaEquation (BlendMode::Add) +{ + +} + + +//////////////////////////////////////////////////////////// +BlendMode::BlendMode(Factor sourceFactor, Factor destinationFactor, Equation blendEquation) : +colorSrcFactor(sourceFactor), +colorDstFactor(destinationFactor), +colorEquation (blendEquation), +alphaSrcFactor(sourceFactor), +alphaDstFactor(destinationFactor), +alphaEquation (blendEquation) +{ + +} + + +//////////////////////////////////////////////////////////// +BlendMode::BlendMode(Factor colorSourceFactor, Factor colorDestinationFactor, + Equation colorBlendEquation, Factor alphaSourceFactor, + Factor alphaDestinationFactor, Equation alphaBlendEquation) : +colorSrcFactor(colorSourceFactor), +colorDstFactor(colorDestinationFactor), +colorEquation (colorBlendEquation), +alphaSrcFactor(alphaSourceFactor), +alphaDstFactor(alphaDestinationFactor), +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 713773bd2..f66fd416c 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 diff --git a/src/SFML/Graphics/GLExtensions.hpp b/src/SFML/Graphics/GLExtensions.hpp index 4161a6696..033dd8399 100644 --- a/src/SFML/Graphics/GLExtensions.hpp +++ b/src/SFML/Graphics/GLExtensions.hpp @@ -35,7 +35,9 @@ #include #define GLEXT_blend_func_separate GL_OES_blend_func_separate + #define GLEXT_blend_equation_separate GL_OES_blend_equation_separate #define GLEXT_glBlendFuncSeparate glBlendFuncSeparateOES + #define GLEXT_glBlendEquationSeparate glBlendEquationSeparateOES #define GLEXT_framebuffer_object GL_OES_framebuffer_object #define GLEXT_glGenFramebuffers glGenFramebuffersOES #define GLEXT_glGenRenderbuffers glGenRenderbuffersOES @@ -63,7 +65,9 @@ #include #define GLEXT_blend_func_separate GLEW_EXT_blend_func_separate + #define GLEXT_blend_equation_separate GLEW_EXT_blend_equation_separate #define GLEXT_glBlendFuncSeparate glBlendFuncSeparateEXT + #define GLEXT_glBlendEquationSeparate glBlendEquationSeparateEXT #define GLEXT_framebuffer_object GLEW_EXT_framebuffer_object #define GLEXT_glGenFramebuffers glGenFramebuffersEXT #define GLEXT_glGenRenderbuffers glGenRenderbuffersEXT diff --git a/src/SFML/Graphics/RenderStates.cpp b/src/SFML/Graphics/RenderStates.cpp index d66ec42a1..2ec3fb895 100644 --- a/src/SFML/Graphics/RenderStates.cpp +++ b/src/SFML/Graphics/RenderStates.cpp @@ -56,7 +56,7 @@ shader (NULL) //////////////////////////////////////////////////////////// -RenderStates::RenderStates(BlendMode theBlendMode) : +RenderStates::RenderStates(const BlendMode& theBlendMode) : blendMode(theBlendMode), transform(), texture (NULL), @@ -86,7 +86,7 @@ shader (theShader) //////////////////////////////////////////////////////////// -RenderStates::RenderStates(BlendMode theBlendMode, const Transform& theTransform, +RenderStates::RenderStates(const BlendMode& theBlendMode, const Transform& theTransform, const Texture* theTexture, const Shader* theShader) : blendMode(theBlendMode), transform(theTransform), diff --git a/src/SFML/Graphics/RenderTarget.cpp b/src/SFML/Graphics/RenderTarget.cpp index 430a46a82..e7ee14716 100644 --- a/src/SFML/Graphics/RenderTarget.cpp +++ b/src/SFML/Graphics/RenderTarget.cpp @@ -35,6 +35,41 @@ #include +namespace +{ + // Convert an sf::BlendMode::Factor constant to the corresponding OpenGL constant. + sf::Uint32 factorToGlConstant(sf::BlendMode::Factor 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::Equation blendEquation) + { + switch (blendEquation) + { + default: + case sf::BlendMode::Add: return GL_FUNC_ADD; + case sf::BlendMode::Subtract: return GL_FUNC_SUBTRACT; + } + } +} + + namespace sf { //////////////////////////////////////////////////////////// @@ -369,49 +404,31 @@ void RenderTarget::applyCurrentView() //////////////////////////////////////////////////////////// -void RenderTarget::applyBlendMode(BlendMode mode) +void RenderTarget::applyBlendMode(const BlendMode& mode) { - switch (mode) + // Apply the blend mode, falling back to the non-separate versions if necessary + if (GLEXT_blend_func_separate) { - // glBlendFuncSeparate 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 + glCheck(GLEXT_glBlendFuncSeparate( + 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 (GLEXT_blend_func_separate) - { - glCheck(GLEXT_glBlendFuncSeparate(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 (GLEXT_blend_func_separate) - { - glCheck(GLEXT_glBlendFuncSeparate(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 (GLEXT_blend_equation_separate) + { + glCheck(GLEXT_glBlendEquationSeparate( + equationToGlConstant(mode.colorEquation), + equationToGlConstant(mode.alphaEquation))); + } + else + { + glCheck(glBlendEquation(equationToGlConstant(mode.colorEquation))); } m_cache.lastBlendMode = mode; @@ -462,8 +479,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