//////////////////////////////////////////////////////////// // // 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. // //////////////////////////////////////////////////////////// #ifndef SFML_TRANSFORMABLE_HPP #define SFML_TRANSFORMABLE_HPP //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// #include #include namespace sf { //////////////////////////////////////////////////////////// /// \brief Decomposed transform defined by a position, a rotation and a scale /// //////////////////////////////////////////////////////////// class SFML_GRAPHICS_API Transformable { public : //////////////////////////////////////////////////////////// /// \brief Default constructor /// //////////////////////////////////////////////////////////// Transformable(); //////////////////////////////////////////////////////////// /// \brief Virtual destructor /// //////////////////////////////////////////////////////////// virtual ~Transformable(); //////////////////////////////////////////////////////////// /// \brief set the position of the object /// /// This function completely overwrites the previous position. /// See the move function to apply an offset based on the previous position instead. /// The default position of a transformable object is (0, 0). /// /// \param x X coordinate of the new position /// \param y Y coordinate of the new position /// /// \see move, getPosition /// //////////////////////////////////////////////////////////// void setPosition(float x, float y); //////////////////////////////////////////////////////////// /// \brief set the position of the object /// /// This function completely overwrites the previous position. /// See the move function to apply an offset based on the previous position instead. /// The default position of a transformable object is (0, 0). /// /// \param position New position /// /// \see move, getPosition /// //////////////////////////////////////////////////////////// void setPosition(const Vector2f& position); //////////////////////////////////////////////////////////// /// \brief set the orientation of the object /// /// This function completely overwrites the previous rotation. /// See the rotate function to add an angle based on the previous rotation instead. /// The default rotation of a transformable object is 0. /// /// \param angle New rotation, in degrees /// /// \see rotate, getRotation /// //////////////////////////////////////////////////////////// void setRotation(float angle); //////////////////////////////////////////////////////////// /// \brief set the scale factors of the object /// /// This function completely overwrites the previous scale. /// See the scale function to add a factor based on the previous scale instead. /// The default scale of a transformable object is (1, 1). /// /// \param factorX New horizontal scale factor /// \param factorY New vertical scale factor /// /// \see scale, getScale /// //////////////////////////////////////////////////////////// void setScale(float factorX, float factorY); //////////////////////////////////////////////////////////// /// \brief set the scale factors of the object /// /// This function completely overwrites the previous scale. /// See the scale function to add a factor based on the previous scale instead. /// The default scale of a transformable object is (1, 1). /// /// \param factors New scale factors /// /// \see scale, getScale /// //////////////////////////////////////////////////////////// void setScale(const Vector2f& factors); //////////////////////////////////////////////////////////// /// \brief set the local origin of the object /// /// The origin of an object defines the center point for /// all transformations (position, scale, rotation). /// The coordinates of this point must be relative to the /// top-left corner of the object, and ignore all /// transformations (position, scale, rotation). /// The default origin of a transformable object is (0, 0). /// /// \param x X coordinate of the new origin /// \param y Y coordinate of the new origin /// /// \see getOrigin /// //////////////////////////////////////////////////////////// void setOrigin(float x, float y); //////////////////////////////////////////////////////////// /// \brief set the local origin of the object /// /// The origin of an object defines the center point for /// all transformations (position, scale, rotation). /// The coordinates of this point must be relative to the /// top-left corner of the object, and ignore all /// transformations (position, scale, rotation). /// The default origin of a transformable object is (0, 0). /// /// \param origin New origin /// /// \see getOrigin /// //////////////////////////////////////////////////////////// void setOrigin(const Vector2f& origin); //////////////////////////////////////////////////////////// /// \brief get the position of the object /// /// \return Current position /// /// \see setPosition /// //////////////////////////////////////////////////////////// const Vector2f& getPosition() const; //////////////////////////////////////////////////////////// /// \brief get the orientation of the object /// /// The rotation is always in the range [0, 360]. /// /// \return Current rotation, in degrees /// /// \see setRotation /// //////////////////////////////////////////////////////////// float getRotation() const; //////////////////////////////////////////////////////////// /// \brief get the current scale of the object /// /// \return Current scale factors /// /// \see setScale /// //////////////////////////////////////////////////////////// const Vector2f& getScale() const; //////////////////////////////////////////////////////////// /// \brief get the local origin of the object /// /// \return Current origin /// /// \see setOrigin /// //////////////////////////////////////////////////////////// const Vector2f& getOrigin() const; //////////////////////////////////////////////////////////// /// \brief Move the object by a given offset /// /// This function adds to the current position of the object, /// unlike setPosition which overwrites it. /// Thus, it is equivalent to the following code: /// \code /// sf::Vector2f pos = object.getPosition(); /// object.setPosition(pos.x + offsetX, pos.y + offsetY); /// \endcode /// /// \param offsetX X offset /// \param offsetY Y offset /// /// \see setPosition /// //////////////////////////////////////////////////////////// void move(float offsetX, float offsetY); //////////////////////////////////////////////////////////// /// \brief Move the object by a given offset /// /// This function adds to the current position of the object, /// unlike setPosition which overwrites it. /// Thus, it is equivalent to the following code: /// \code /// object.setPosition(object.getPosition() + offset); /// \endcode /// /// \param offset Offset /// /// \see setPosition /// //////////////////////////////////////////////////////////// void move(const Vector2f& offset); //////////////////////////////////////////////////////////// /// \brief Rotate the object /// /// This function adds to the current rotation of the object, /// unlike setRotation which overwrites it. /// Thus, it is equivalent to the following code: /// \code /// object.setRotation(object.getRotation() + angle); /// \endcode /// /// \param angle Angle of rotation, in degrees /// //////////////////////////////////////////////////////////// void rotate(float angle); //////////////////////////////////////////////////////////// /// \brief Scale the object /// /// This function multiplies the current scale of the object, /// unlike setScale which overwrites it. /// Thus, it is equivalent to the following code: /// \code /// sf::Vector2f scale = object.getScale(); /// object.setScale(scale.x * factorX, scale.y * factorY); /// \endcode /// /// \param factorX Horizontal scale factor /// \param factorY Vertical scale factor /// /// \see setScale /// //////////////////////////////////////////////////////////// void scale(float factorX, float factorY); //////////////////////////////////////////////////////////// /// \brief Scale the object /// /// This function multiplies the current scale of the object, /// unlike setScale which overwrites it. /// Thus, it is equivalent to the following code: /// \code /// sf::Vector2f scale = object.getScale(); /// object.setScale(scale.x * factor.x, scale.y * factor.y); /// \endcode /// /// \param factor Scale factors /// /// \see setScale /// //////////////////////////////////////////////////////////// void scale(const Vector2f& factor); //////////////////////////////////////////////////////////// /// \brief get the combined transform of the object /// /// \return Transform combining the position/rotation/scale/origin of the object /// /// \see getInverseTransform /// //////////////////////////////////////////////////////////// const Transform& getTransform() const; //////////////////////////////////////////////////////////// /// \brief get the inverse of the combined transform of the object /// /// \return Inverse of the combined transformations applied to the object /// /// \see getTransform /// //////////////////////////////////////////////////////////// const Transform& getInverseTransform() const; private : //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// Vector2f m_origin; ///< Origin of translation/rotation/scaling of the object Vector2f m_position; ///< Position of the object in the 2D world float m_rotation; ///< Orientation of the object, in degrees Vector2f m_scale; ///< Scale of the object mutable Transform m_transform; ///< Combined transformation of the object mutable bool m_transformNeedUpdate; ///< Does the transform need to be recomputed? mutable Transform m_inverseTransform; ///< Combined transformation of the object mutable bool m_inverseTransformNeedUpdate; ///< Does the transform need to be recomputed? }; } // namespace sf #endif // SFML_TRANSFORMABLE_HPP //////////////////////////////////////////////////////////// /// \class sf::Transformable /// \ingroup graphics /// /// This class is provided for convenience, on top of sf::Transform. /// /// sf::Transform, as a low-level class, offers a great level of /// flexibility but it is not always convenient to manage. Indeed, /// one can easily combine any kind of operation, such as a translation /// followed by a rotation followed by a scaling, but once the result /// transform is built, there's no way to go backward and, let's say, /// change only the rotation without modifying the translation and scaling. /// The entire transform must be recomputed, which means that you /// need to retrieve the initial translation and scale factors as /// well, and combine them the same way you did before updating the /// rotation. This is a tedious operation, and it requires to store /// all the individual components of the final transform. /// /// That's exactly what sf::Transformable was written for: it hides /// these variables and the composed transform behind an easy to use /// interface. You can set or get any of the individual components /// without worrying about the others. It also provides the composed /// transform (as a sf::Transform), and keeps it up-to-date. /// /// In addition to the position, rotation and scale, sf::Transformable /// provides an "origin" component, which represents the local origin /// of the three other components. Let's take an example with a 10x10 /// pixels sprite. By default, the sprite is positioned/rotated/scaled /// relatively to its top-left corner, because it is the local point /// (0, 0). But if we change the origin to be (5, 5), the sprite will /// be positioned/rotated/scaled around its center instead. And if /// we set the origin to (10, 10), it will be transformed around its /// bottom-right corner. /// /// To keep the sf::Transformable class simple, there's only one /// origin for all the components. You cannot position the sprite /// relatively to its top-left corner while rotating it around its /// center, for example. To do such things, use sf::Transform directly. /// /// sf::Transformable can be used as a base class. It is often /// combined with sf::Drawable -- that's what SFML's sprites, /// texts and shapes do. /// \code /// class MyEntity : public sf::Transformable, public sf::Drawable /// { /// virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const /// { /// states.transform *= getTransform(); /// target.draw(..., states); /// } /// }; /// /// MyEntity entity; /// entity.setPosition(10, 20); /// entity.setRotation(45); /// window.draw(entity); /// \endcode /// /// It can also be used as a member, if you don't want to use /// its API directly (because you don't need all its functions, /// or you have different naming conventions for example). /// \code /// class MyEntity /// { /// public : /// void SetPosition(const MyVector& v) /// { /// myTransform.setPosition(v.x(), v.y()); /// } /// /// void Draw(sf::RenderTarget& target) const /// { /// target.draw(..., myTransform.getTransform()); /// } /// /// private : /// sf::Transformable myTransform; /// }; /// \endcode /// /// \see sf::Transform /// ////////////////////////////////////////////////////////////