//////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library // Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) // // 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. // //////////////////////////////////////////////////////////// #pragma once //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// #include #include #include #include #include #include namespace sf { class RenderTarget; struct Vertex; //////////////////////////////////////////////////////////// /// \brief Vertex buffer storage for one or more 2D primitives /// //////////////////////////////////////////////////////////// class SFML_GRAPHICS_API VertexBuffer : public Drawable, private GlResource { public: //////////////////////////////////////////////////////////// /// \brief Usage specifiers /// /// If data is going to be updated once or more every frame, /// set the usage to Stream. If data is going to be set once /// and used for a long time without being modified, set the /// usage to Static. For everything else Dynamic should be a /// good compromise. /// //////////////////////////////////////////////////////////// enum class Usage { Stream, //!< Constantly changing data Dynamic, //!< Occasionally changing data Static //!< Rarely changing data }; //////////////////////////////////////////////////////////// /// \brief Default constructor /// /// Creates an empty vertex buffer. /// //////////////////////////////////////////////////////////// VertexBuffer() = default; //////////////////////////////////////////////////////////// /// \brief Construct a `VertexBuffer` with a specific `PrimitiveType` /// /// Creates an empty vertex buffer and sets its primitive type to \p type. /// /// \param type Type of primitive /// //////////////////////////////////////////////////////////// explicit VertexBuffer(PrimitiveType type); //////////////////////////////////////////////////////////// /// \brief Construct a `VertexBuffer` with a specific usage specifier /// /// Creates an empty vertex buffer and sets its usage to \p usage. /// /// \param usage Usage specifier /// //////////////////////////////////////////////////////////// explicit VertexBuffer(Usage usage); //////////////////////////////////////////////////////////// /// \brief Construct a `VertexBuffer` with a specific `PrimitiveType` and usage specifier /// /// Creates an empty vertex buffer and sets its primitive type /// to \p type and usage to \p usage. /// /// \param type Type of primitive /// \param usage Usage specifier /// //////////////////////////////////////////////////////////// VertexBuffer(PrimitiveType type, Usage usage); //////////////////////////////////////////////////////////// /// \brief Copy constructor /// /// \param copy instance to copy /// //////////////////////////////////////////////////////////// VertexBuffer(const VertexBuffer& copy); //////////////////////////////////////////////////////////// /// \brief Destructor /// //////////////////////////////////////////////////////////// ~VertexBuffer() override; //////////////////////////////////////////////////////////// /// \brief Create the vertex buffer /// /// Creates the vertex buffer and allocates enough graphics /// memory to hold `vertexCount` vertices. Any previously /// allocated memory is freed in the process. /// /// In order to deallocate previously allocated memory pass 0 /// as `vertexCount`. Don't forget to recreate with a non-zero /// value when graphics memory should be allocated again. /// /// \param vertexCount Number of vertices worth of memory to allocate /// /// \return `true` if creation was successful /// //////////////////////////////////////////////////////////// [[nodiscard]] bool create(std::size_t vertexCount); //////////////////////////////////////////////////////////// /// \brief Return the vertex count /// /// \return Number of vertices in the vertex buffer /// //////////////////////////////////////////////////////////// [[nodiscard]] std::size_t getVertexCount() const; //////////////////////////////////////////////////////////// /// \brief Update the whole buffer from an array of vertices /// /// The vertex array is assumed to have the same size as /// the created buffer. /// /// No additional check is performed on the size of the vertex /// array. Passing invalid arguments will lead to undefined /// behavior. /// /// This function does nothing if `vertices` is null or if the /// buffer was not previously created. /// /// \param vertices Array of vertices to copy to the buffer /// /// \return `true` if the update was successful /// //////////////////////////////////////////////////////////// [[nodiscard]] bool update(const Vertex* vertices); //////////////////////////////////////////////////////////// /// \brief Update a part of the buffer from an array of vertices /// /// `offset` is specified as the number of vertices to skip /// from the beginning of the buffer. /// /// If `offset` is 0 and `vertexCount` is equal to the size of /// the currently created buffer, its whole contents are replaced. /// /// If `offset` is 0 and `vertexCount` is greater than the /// size of the currently created buffer, a new buffer is created /// containing the vertex data. /// /// If `offset` is 0 and `vertexCount` is less than the size of /// the currently created buffer, only the corresponding region /// is updated. /// /// If `offset` is not 0 and `offset` + `vertexCount` is greater /// than the size of the currently created buffer, the update fails. /// /// No additional check is performed on the size of the vertex /// array. Passing invalid arguments will lead to undefined /// behavior. /// /// \param vertices Array of vertices to copy to the buffer /// \param vertexCount Number of vertices to copy /// \param offset Offset in the buffer to copy to /// /// \return `true` if the update was successful /// //////////////////////////////////////////////////////////// [[nodiscard]] bool update(const Vertex* vertices, std::size_t vertexCount, unsigned int offset); //////////////////////////////////////////////////////////// /// \brief Copy the contents of another buffer into this buffer /// /// \param vertexBuffer Vertex buffer whose contents to copy into this vertex buffer /// /// \return `true` if the copy was successful /// //////////////////////////////////////////////////////////// [[nodiscard]] bool update(const VertexBuffer& vertexBuffer); //////////////////////////////////////////////////////////// /// \brief Overload of assignment operator /// /// \param right Instance to assign /// /// \return Reference to self /// //////////////////////////////////////////////////////////// VertexBuffer& operator=(const VertexBuffer& right); //////////////////////////////////////////////////////////// /// \brief Swap the contents of this vertex buffer with those of another /// /// \param right Instance to swap with /// //////////////////////////////////////////////////////////// void swap(VertexBuffer& right) noexcept; //////////////////////////////////////////////////////////// /// \brief Get the underlying OpenGL handle of the vertex buffer. /// /// You shouldn't need to use this function, unless you have /// very specific stuff to implement that SFML doesn't support, /// or implement a temporary workaround until a bug is fixed. /// /// \return OpenGL handle of the vertex buffer or 0 if not yet created /// //////////////////////////////////////////////////////////// [[nodiscard]] unsigned int getNativeHandle() const; //////////////////////////////////////////////////////////// /// \brief Set the type of primitives to draw /// /// This function defines how the vertices must be interpreted /// when it's time to draw them. /// /// The default primitive type is `sf::PrimitiveType::Points`. /// /// \param type Type of primitive /// //////////////////////////////////////////////////////////// void setPrimitiveType(PrimitiveType type); //////////////////////////////////////////////////////////// /// \brief Get the type of primitives drawn by the vertex buffer /// /// \return Primitive type /// //////////////////////////////////////////////////////////// [[nodiscard]] PrimitiveType getPrimitiveType() const; //////////////////////////////////////////////////////////// /// \brief Set the usage specifier of this vertex buffer /// /// This function provides a hint about how this vertex buffer is /// going to be used in terms of data update frequency. /// /// After changing the usage specifier, the vertex buffer has /// to be updated with new data for the usage specifier to /// take effect. /// /// The default usage type is `sf::VertexBuffer::Usage::Stream`. /// /// \param usage Usage specifier /// //////////////////////////////////////////////////////////// void setUsage(Usage usage); //////////////////////////////////////////////////////////// /// \brief Get the usage specifier of this vertex buffer /// /// \return Usage specifier /// //////////////////////////////////////////////////////////// [[nodiscard]] Usage getUsage() const; //////////////////////////////////////////////////////////// /// \brief Bind a vertex buffer for rendering /// /// This function is not part of the graphics API, it mustn't be /// used when drawing SFML entities. It must be used only if you /// mix `sf::VertexBuffer` with OpenGL code. /// /// \code /// sf::VertexBuffer vb1, vb2; /// ... /// sf::VertexBuffer::bind(&vb1); /// // draw OpenGL stuff that use vb1... /// sf::VertexBuffer::bind(&vb2); /// // draw OpenGL stuff that use vb2... /// sf::VertexBuffer::bind(nullptr); /// // draw OpenGL stuff that use no vertex buffer... /// \endcode /// /// \param vertexBuffer Pointer to the vertex buffer to bind, can be null to use no vertex buffer /// //////////////////////////////////////////////////////////// static void bind(const VertexBuffer* vertexBuffer); //////////////////////////////////////////////////////////// /// \brief Tell whether or not the system supports vertex buffers /// /// This function should always be called before using /// the vertex buffer features. If it returns `false`, then /// any attempt to use `sf::VertexBuffer` will fail. /// /// \return `true` if vertex buffers are supported, `false` otherwise /// //////////////////////////////////////////////////////////// [[nodiscard]] static bool isAvailable(); private: //////////////////////////////////////////////////////////// /// \brief Draw the vertex buffer to a render target /// /// \param target Render target to draw to /// \param states Current render states /// //////////////////////////////////////////////////////////// void draw(RenderTarget& target, RenderStates states) const override; //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// unsigned int m_buffer{}; //!< Internal buffer identifier std::size_t m_size{}; //!< Size in Vertices of the currently allocated buffer PrimitiveType m_primitiveType{PrimitiveType::Points}; //!< Type of primitives to draw Usage m_usage{Usage::Stream}; //!< How this vertex buffer is to be used }; //////////////////////////////////////////////////////////// /// \brief Swap the contents of one vertex buffer with those of another /// /// \param left First instance to swap /// \param right Second instance to swap /// //////////////////////////////////////////////////////////// SFML_GRAPHICS_API void swap(VertexBuffer& left, VertexBuffer& right) noexcept; } // namespace sf //////////////////////////////////////////////////////////// /// \class sf::VertexBuffer /// \ingroup graphics /// /// `sf::VertexBuffer` is a simple wrapper around a dynamic /// buffer of vertices and a primitives type. /// /// Unlike `sf::VertexArray`, the vertex data is stored in /// graphics memory. /// /// In situations where a large amount of vertex data would /// have to be transferred from system memory to graphics memory /// every frame, using `sf::VertexBuffer` can help. By using a /// `sf::VertexBuffer`, data that has not been changed between frames /// does not have to be re-transferred from system to graphics /// memory as would be the case with `sf::VertexArray`. If data transfer /// is a bottleneck, this can lead to performance gains. /// /// Using `sf::VertexBuffer`, the user also has the ability to only modify /// a portion of the buffer in graphics memory. This way, a large buffer /// can be allocated at the start of the application and only the /// applicable portions of it need to be updated during the course of /// the application. This allows the user to take full control of data /// transfers between system and graphics memory if they need to. /// /// In special cases, the user can make use of multiple threads to update /// vertex data in multiple distinct regions of the buffer simultaneously. /// This might make sense when e.g. the position of multiple objects has to /// be recalculated very frequently. The computation load can be spread /// across multiple threads as long as there are no other data dependencies. /// /// Simultaneous updates to the vertex buffer are not guaranteed to be /// carried out by the driver in any specific order. Updating the same /// region of the buffer from multiple threads will not cause undefined /// behavior, however the final state of the buffer will be unpredictable. /// /// Simultaneous updates of distinct non-overlapping regions of the buffer /// are also not guaranteed to complete in a specific order. However, in /// this case the user can make sure to synchronize the writer threads at /// well-defined points in their code. The driver will make sure that all /// pending data transfers complete before the vertex buffer is sourced /// by the rendering pipeline. /// /// It inherits `sf::Drawable`, but unlike other drawables it /// is not transformable. /// /// Example: /// \code /// std::array vertices; /// ... /// sf::VertexBuffer triangles(sf::PrimitiveType::Triangles); /// triangles.create(vertices.size()); /// triangles.update(vertices.data()); /// ... /// window.draw(triangles); /// \endcode /// /// \see `sf::Vertex`, `sf::VertexArray` /// ////////////////////////////////////////////////////////////