Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: sf::Quad  (Read 9675 times)

0 Members and 1 Guest are viewing this topic.

Kalith

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
sf::Quad
« on: June 17, 2010, 11:45:13 pm »
Hi!

I've been using SFML recently and found it to be really great :)
The only concern I have right now, is that it lacks the ability to render a simple arbitrary quad on the screen.
I mean, for each of the 4 vertices : arbitrary position, arbitrary uv coordinates and arbitrary color.

So I wrote a sf::Quad class that does just that.

Usage :
Code: [Select]
sf::Quad quad;
quad.SetImage(...);

// Set on screen coordinates (absolute)
quad.SetVertexPosition(0, sf::Vector2f(0, 0));
quad.SetVertexPosition(1, sf::Vector2f(64,0));
quad.SetVertexPosition(2, sf::Vector2f(0, 64));
quad.SetVertexPosition(3, sf::Vector2f(64,64));

// Set uv coordinates (normalized)
quad.SetVertexUVs(0, sf::Vector2f(0,0));
quad.SetVertexUVs(1, sf::Vector2f(1,0));
quad.SetVertexUVs(2, sf::Vector2f(0,1));
quad.SetVertexUVs(3, sf::Vector2f(1,1));

// Set color
quad.SetVertexColor(0, sf::Color::Red);
quad.SetVertexColor(1, sf::Color::Green);
quad.SetVertexColor(2, sf::Color::Blue);
quad.SetVertexColor(3, sf::Color::Magenta);


I'm not familiar with SFML's coding conventions, but I tried to mimic what I saw in sf::Sprite. Hope it fits well.

Anyway, here you are (based on SFML-2.0 15/06/2010 snapshot) :

Quad.hpp
Code: [Select]
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2009 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_QUAD_HPP
#define SFML_QUAD_HPP

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/Resource.hpp>
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Rect.hpp>


namespace sf
{
class Image;

////////////////////////////////////////////////////////////
/// \brief Like Sprite, but allows control of the four
///        vertices that composes the Quad (position, color,
///        texture coordinates).
///
////////////////////////////////////////////////////////////
class SFML_API Quad : public Drawable
{
public :

    ////////////////////////////////////////////////////////////
    /// \brief Default constructor
    ///
    /// Creates an empty quad with no source image.
    ///
    ////////////////////////////////////////////////////////////
    Quad();

    ////////////////////////////////////////////////////////////
    /// \brief Construct the quad from a source image
    ///
    /// \param image    Source image, that the sprite will display
    /// \param color    Global color of the sprite
    ///
    /// \see SetImage
    ///
    ////////////////////////////////////////////////////////////
    explicit Quad(const Image& image, const Color& color = Color(255, 255, 255, 255));

    ////////////////////////////////////////////////////////////
    /// \brief Change the source image of the quad
    ///
    /// The \a image argument refers to an image that must
    /// exist as long as the quad uses it. Indeed, the quad
    /// doesn't store its own copy of the image, but rather keeps
    /// a pointer to the one that you passed to this function.
    /// If the source image is destroyed and the quad tries to
    /// use it, it may appear as a white rectangle.
    ///
    /// \param image New image
    ///
    /// \see GetImage
    ///
    ////////////////////////////////////////////////////////////
    void SetImage(const Image& image);

    ////////////////////////////////////////////////////////////
    /// \brief Set the global color of the object
    ///
    /// This global color affects the entire object, and modulates
    /// (multiplies) its original pixels.
    /// The default color is white.
    ///
    /// \param color New color
    ///
    /// \see GetColor
    ///
    ////////////////////////////////////////////////////////////
    void SetColor(const Color& color);

    ////////////////////////////////////////////////////////////
    /// \brief Change the position of a vertex
    ///
    /// The vertex position is relative to the sprite's position.
    ///
    /// \param index Index of the vertex
    /// \param color New color of the vertex
    ///
    ////////////////////////////////////////////////////////////
    void SetVertexPosition(unsigned int index, const Vector2f& pos);

    ////////////////////////////////////////////////////////////
    /// \brief Change the color of a vertex
    ///
    /// \param index Index of the vertex
    /// \param color New color of the vertex
    ///
    ////////////////////////////////////////////////////////////
    void SetVertexColor(unsigned int index, const Color& color);

    ////////////////////////////////////////////////////////////
    /// \brief Change the uv coordinates of a vertex
    ///
    /// \param index Index of the vertex
    /// \param uv    The UV coordinates of the vertex
    ///
    ////////////////////////////////////////////////////////////
    void SetVertexUVs(unsigned int index, const Vector2f& uv);

    ////////////////////////////////////////////////////////////
    /// \brief Get the source image of the sprite
    ///
    /// If the sprite has no source image, or if the image
    /// doesn't exist anymore, a NULL pointer is returned.
    /// The returned pointer is const, which means that you can't
    /// modify the image when you retrieve it with this function.
    ///
    /// \return Pointer to the sprite's image
    ///
    /// \see SetImage
    ///
    ////////////////////////////////////////////////////////////
    const Image* GetImage() const;

    ////////////////////////////////////////////////////////////
    /// \brief Get the position of a vertex
    ///
    /// The vertex position on the screen is absolute and
    /// doesn't depend on the actual quad's position.
    ///
    /// \param index Index of the vertex
    ///
    /// \return Position of the vertex
    ///
    ////////////////////////////////////////////////////////////
    const Vector2f& GetVertexPosition(unsigned int index) const;

    ////////////////////////////////////////////////////////////
    /// \brief Get the color of a vertex
    ///
    /// \param index Index of the vertex
    ///
    /// \return Color of the vertex
    ///
    ////////////////////////////////////////////////////////////
    const Color& GetVertexColor(unsigned int index) const;

    ////////////////////////////////////////////////////////////
    /// \brief Get the uv coordinates of a vertex
    ///
    /// \param index Index of the vertex
    ///
    /// \return UV coordiantes of the vertex
    ///
    ////////////////////////////////////////////////////////////
    const Vector2f& GetVertexUVs(unsigned int index) const;

protected :

    ////////////////////////////////////////////////////////////
    /// \brief Draw the object to a render target
    ///
    /// \param target   Render target
    /// \param renderer Renderer providing low-level rendering commands
    ///
    ////////////////////////////////////////////////////////////
    virtual void Render(RenderTarget& target, Renderer& renderer) const;

private :

    ////////////////////////////////////////////////////////////
    // Member data
    ////////////////////////////////////////////////////////////
    struct Vertex
    {
        Vertex(const Vector2f& pos = Vector2f(0, 0), const Vector2f& uv = Vector2f(0, 0), const Color& color = Color(255, 255, 255));

        Vector2f Position;
        Color    Col;
        Vector2f UV;
    };

    ResourcePtr<Image> myImage; ///< Image used to draw the quad
    Vertex             myV[4];  ///< Array of vertices
};

} // namespace sf


#endif // SFML_QUAD_HPP


////////////////////////////////////////////////////////////
/// \class sf::Quad
///
/// sf::Quad is a drawable class that allows to display an
/// image (or a part of it) on a render target just like
/// sf::Sprite, but with increased flexibility, at the cost
/// of ease of use.
///
/// Most functions from sf::Drawable are hidden: position,
/// rotation, scale and origin. Color and blend mode are
/// still available.
///
/// It is important to note that, like sf::Sprite, the
/// sf::Quad instance doesn't copy the image that it uses,
/// it only keeps a reference to it.
/// Thus, a sf::Image must not be destructed while it is
/// used by a sf::Quad (i.e. never write a function that
/// uses a local sf::Image instance for creating a quad).
///
/// Usage example:
/// \code
/// // Declare and load an image
/// sf::Image image;
/// image.LoadFromFile("image.png");
///
/// // Create a sprite
/// sf::Quad quad;
/// quad.SetImage(image);
/// quad.SetVertexPosition(0, sf::Vector2f(0, 0));
/// quad.SetVertexPosition(1, sf::Vector2f(16,0));
/// quad.SetVertexPosition(2, sf::Vector2f(0, 16));
/// quad.SetVertexPosition(3, sf::Vector2f(16,16));
///
/// // Display it
/// window.Draw(quad); // window is a sf::RenderWindow
/// \endcode
///
/// \see sf::Image
///
////////////////////////////////////////////////////////////


Quad.cpp :
Code: [Select]
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2009 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 <SFML/Graphics/Quad.hpp>
#include <SFML/Graphics/Image.hpp>
#include <SFML/Graphics/Renderer.hpp>
#include <utility>

namespace sf
{
////////////////////////////////////////////////////////////
Quad::Quad()
{

}


////////////////////////////////////////////////////////////
Quad::Quad(const Image& image, const Color& color) :
Drawable (Vector2f(0,0), Vector2f(1,1), 0, color)
{
    SetImage(image);
}


////////////////////////////////////////////////////////////
void Quad::SetImage(const Image& image)
{
    // If there was no valid image before, force adjusting to the new image size
    bool adjustToNewSize = false;
    if (!myImage)
        adjustToNewSize = true;

    // Assign the new image
    myImage = &image;

    // If we want to adjust the size and the new image is valid, we adjust the source rectangle
    if (adjustToNewSize && (image.GetWidth() > 0) && (image.GetHeight() > 0))
    {
        FloatRect coords = myImage->GetTexCoords(IntRect(0, 0, image.GetWidth(), image.GetHeight()));

        float left   = coords.Left;
        float top    = coords.Top;
        float right  = coords.Left + coords.Width;
        float bottom = coords.Top + coords.Height;

        myV[0].UV = Vector2f(left,  top);
        myV[1].UV = Vector2f(right, top);
        myV[2].UV = Vector2f(left,  bottom);
        myV[3].UV = Vector2f(right, bottom);
    }
}


////////////////////////////////////////////////////////////
void Quad::SetColor(const Color& color)
{
    Drawable::SetColor(color);
}


////////////////////////////////////////////////////////////
void Quad::SetVertexPosition(unsigned int index, const Vector2f& pos)
{
    myV[index].Position = pos;
}


////////////////////////////////////////////////////////////
void Quad::SetVertexColor(unsigned int index, const Color& color)
{
    myV[index].Col = color;
}


////////////////////////////////////////////////////////////
void Quad::SetVertexUVs(unsigned int index, const Vector2f& uv)
{
    myV[index].UV = uv;
}


////////////////////////////////////////////////////////////
const Image* Quad::GetImage() const
{
    return myImage;
}


////////////////////////////////////////////////////////////
const Vector2f& Quad::GetVertexPosition(unsigned int index) const
{
    return myV[index].Position;
}

////////////////////////////////////////////////////////////
const Color& Quad::GetVertexColor(unsigned int index) const
{
    return myV[index].Col;
}

////////////////////////////////////////////////////////////
const Vector2f& Quad::GetVertexUVs(unsigned int index) const
{
    return myV[index].UV;
}


////////////////////////////////////////////////////////////
void Quad::Render(RenderTarget&, Renderer& renderer) const
{
    // Bind the texture
    renderer.SetTexture(myImage);

    renderer.Begin(Renderer::TriangleStrip);
    for (unsigned int i = 0; i < 4; ++i)
        renderer.AddVertex(myV[i].Position.x, myV[i].Position.y, myV[i].UV.x, myV[i].UV.y, myV[i].Col);
    renderer.End();
}


////////////////////////////////////////////////////////////
Quad::Vertex::Vertex(const Vector2f& pos, const Vector2f& uv, const Color& color) : Position(pos), Col(color), UV(uv)
{
}

} // namespace sf
Kal.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
sf::Quad
« Reply #1 on: June 18, 2010, 12:00:59 am »
Hi

This is something that I've already been thinking about for SFML 2. I have the idea to provide more generic and low-level mechanisms for rendering 2D geometry, that would be similar to your sf::Quad but even more generic. It would basically be able to replace both sf::Sprite and sf::Shape. It would also be able to hold and optimize custom static geometry, such as a map composed of hundreds of tiles.

Why did you disable the functions inherited from sf::Drawable? All of them should work just fine with your code.
Laurent Gomila - SFML developer

Kalith

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
sf::Quad
« Reply #2 on: June 18, 2010, 06:34:03 pm »
Quote from: "Laurent"
Hi

This is something that I've already been thinking about for SFML 2. I have the idea to provide more generic and low-level mechanisms for rendering 2D geometry, that would be similar to your sf::Quad but even more generic. It would basically be able to replace both sf::Sprite and sf::Shape. It would also be able to hold and optimize custom static geometry, such as a map composed of hundreds of tiles.

Sounds great ! At first I thought sf::Shape would fit my needs, but I realized it couldn't use images so I dropped the idea.
I needed a mix between sf::Sprite and sf::Shape... and that's exactly what you're describing :)

Quote from: "Laurent"
Why did you disable the functions inherited from sf::Drawable? All of them should work just fine with your code.

... actually you're right. I thought calling them would transform the vertices in an awkward way, but if you set the offset properly there is no problem at all. Else, all transformation will be done with the top-left corner of the screen as reference point, right?
Anyway, thanks for pointing that out. I'll edit my first message.
Kal.