Added sf::VertexBuffer class.

This commit is contained in:
binary1248 2017-10-24 18:57:26 +02:00 committed by Lukas Dürrenberger
parent fe39af4ec8
commit 61cdcd47ca
10 changed files with 1165 additions and 47 deletions

View File

@ -54,6 +54,7 @@
#include <SFML/Graphics/Transformable.hpp>
#include <SFML/Graphics/Vertex.hpp>
#include <SFML/Graphics/VertexArray.hpp>
#include <SFML/Graphics/VertexBuffer.hpp>
#include <SFML/Graphics/View.hpp>

View File

@ -43,6 +43,7 @@
namespace sf
{
class Drawable;
class VertexBuffer;
////////////////////////////////////////////////////////////
/// \brief Base class for all render targets (window, texture, ...)
@ -247,6 +248,26 @@ public:
void draw(const Vertex* vertices, std::size_t vertexCount,
PrimitiveType type, const RenderStates& states = RenderStates::Default);
////////////////////////////////////////////////////////////
/// \brief Draw primitives defined by a vertex buffer
///
/// \param vertexBuffer Vertex buffer
/// \param states Render states to use for drawing
///
////////////////////////////////////////////////////////////
void draw(const VertexBuffer& vertexBuffer, const RenderStates& states = RenderStates::Default);
////////////////////////////////////////////////////////////
/// \brief Draw primitives defined by a vertex buffer
///
/// \param vertexBuffer Vertex buffer
/// \param firstVertex Index of the first vertex to render
/// \param vertexCount Number of vertices to render
/// \param states Render states to use for drawing
///
////////////////////////////////////////////////////////////
void draw(const VertexBuffer& vertexBuffer, std::size_t firstVertex, std::size_t vertexCount, const RenderStates& states = RenderStates::Default);
////////////////////////////////////////////////////////////
/// \brief Return the size of the rendering region of the target
///
@ -402,6 +423,33 @@ private:
////////////////////////////////////////////////////////////
void applyShader(const Shader* shader);
////////////////////////////////////////////////////////////
/// \brief Setup environment for drawing
///
/// \param useVertexCache Are we going to use the vertex cache?
/// \param states Render states to use for drawing
///
////////////////////////////////////////////////////////////
void setupDraw(bool useVertexCache, const RenderStates& states);
////////////////////////////////////////////////////////////
/// \brief Draw the primitives
///
/// \param type Type of primitives to draw
/// \param firstVertex Index of the first vertex to use when drawing
/// \param vertexCount Number of vertices to use when drawing
///
////////////////////////////////////////////////////////////
void drawPrimitives(PrimitiveType type, std::size_t firstVertex, std::size_t vertexCount);
////////////////////////////////////////////////////////////
/// \brief Clean up environment after drawing
///
/// \param states Render states used for drawing
///
////////////////////////////////////////////////////////////
void cleanupDraw(const RenderStates& states);
////////////////////////////////////////////////////////////
/// \brief Render states cache
///

View File

@ -0,0 +1,408 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2017 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.
//
////////////////////////////////////////////////////////////
#ifndef SFML_VERTEXBUFFER_HPP
#define SFML_VERTEXBUFFER_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/Export.hpp>
#include <SFML/Graphics/PrimitiveType.hpp>
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Window/GlResource.hpp>
namespace sf
{
class RenderTarget;
class 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 Usage
{
Stream, ///< Constantly changing data
Dynamic, ///< Occasionally changing data
Static ///< Rarely changing data
};
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
/// Creates an empty vertex buffer.
///
////////////////////////////////////////////////////////////
VertexBuffer();
////////////////////////////////////////////////////////////
/// \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();
////////////////////////////////////////////////////////////
/// \brief Create the vertex buffer
///
/// Creates the vertex buffer and allocates enough graphics
/// memory to hold \p vertexCount vertices. Any previously
/// allocated memory is freed in the process.
///
/// In order to deallocate previously allocated memory pass 0
/// as \p 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
///
////////////////////////////////////////////////////////////
bool create(std::size_t vertexCount);
////////////////////////////////////////////////////////////
/// \brief Return the vertex count
///
/// \return Number of vertices in the vertex buffer
///
////////////////////////////////////////////////////////////
std::size_t getVertexCount() const;
////////////////////////////////////////////////////////////
/// \brief Update the whole buffer from an array of vertices
///
/// The \a vertex array is assumed to have the same size as
/// the \a 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 \a 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
///
////////////////////////////////////////////////////////////
bool update(const Vertex* vertices);
////////////////////////////////////////////////////////////
/// \brief Update a part of the buffer from an array of vertices
///
/// \p offset is specified as the number of vertices to skip
/// from the beginning of the buffer.
///
/// If \p offset is 0 and \p vertexCount is equal to the size of
/// the currently created buffer, its whole contents are replaced.
///
/// If \p offset is 0 and \p vertexCount is greater than the
/// size of the currently created buffer, a new buffer is created
/// containing the vertex data.
///
/// If \p offset is 0 and \p vertexCount is less than the size of
/// the currently created buffer, only the corresponding region
/// is updated.
///
/// If \p offset is not 0 and \p offset + \p 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
///
////////////////////////////////////////////////////////////
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
///
////////////////////////////////////////////////////////////
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);
////////////////////////////////////////////////////////////
/// \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
///
////////////////////////////////////////////////////////////
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::Points.
///
/// \param type Type of primitive
///
////////////////////////////////////////////////////////////
void setPrimitiveType(PrimitiveType type);
////////////////////////////////////////////////////////////
/// \brief Get the type of primitives drawn by the vertex buffer
///
/// \return Primitive type
///
////////////////////////////////////////////////////////////
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 primitive type is sf::VertexBuffer::Stream.
///
/// \param usage Usage specifier
///
////////////////////////////////////////////////////////////
void setUsage(Usage usage);
////////////////////////////////////////////////////////////
/// \brief Get the usage specifier of this vertex buffer
///
/// \return Usage specifier
///
////////////////////////////////////////////////////////////
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(NULL);
/// // 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
///
////////////////////////////////////////////////////////////
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
///
////////////////////////////////////////////////////////////
virtual void draw(RenderTarget& target, RenderStates states) const;
private:
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
unsigned int m_buffer; ///< Internal buffer identifier
std::size_t m_size; ///< Size in Vertexes of the currently allocated buffer
PrimitiveType m_primitiveType; ///< Type of primitives to draw
Usage m_usage; ///< How this vertex buffer is to be used
};
} // namespace sf
#endif // SFML_VERTEXBUFFER_HPP
////////////////////////////////////////////////////////////
/// \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
/// behaviour, 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
/// sf::Vertex vertices[15];
/// ...
/// sf::VertexBuffer triangles(sf::Triangles);
/// triangles.create(15);
/// triangles.update(vertices);
/// ...
/// window.draw(triangles);
/// \endcode
///
/// \see sf::Vertex, sf::VertexArray
///
////////////////////////////////////////////////////////////

View File

@ -72,6 +72,8 @@ set(DRAWABLES_SRC
${INCROOT}/Text.hpp
${SRCROOT}/VertexArray.cpp
${INCROOT}/VertexArray.hpp
${SRCROOT}/VertexBuffer.cpp
${INCROOT}/VertexBuffer.hpp
)
source_group("drawables" FILES ${DRAWABLES_SRC})

View File

@ -53,6 +53,19 @@
#define GLEXT_GL_CLAMP GL_CLAMP_TO_EDGE
#define GLEXT_GL_CLAMP_TO_EDGE GL_CLAMP_TO_EDGE
// Core since 1.1
// 1.1 does not support GL_STREAM_DRAW so we just define it to GL_DYNAMIC_DRAW
#define GLEXT_vertex_buffer_object true
#define GLEXT_GL_ARRAY_BUFFER GL_ARRAY_BUFFER
#define GLEXT_GL_DYNAMIC_DRAW GL_DYNAMIC_DRAW
#define GLEXT_GL_STATIC_DRAW GL_STATIC_DRAW
#define GLEXT_GL_STREAM_DRAW GL_DYNAMIC_DRAW
#define GLEXT_glBindBuffer glBindBuffer
#define GLEXT_glBufferData glBufferData
#define GLEXT_glBufferSubData glBufferSubData
#define GLEXT_glDeleteBuffers glDeleteBuffers
#define GLEXT_glGenBuffers glGenBuffers
// The following extensions are listed chronologically
// Extension macro first, followed by tokens then
// functions according to the corresponding specification
@ -114,6 +127,9 @@
// Core since 3.0
#define GLEXT_framebuffer_blit false
// Core since 3.0 - NV_copy_buffer
#define GLEXT_copy_buffer false
// Core since 3.0 - EXT_sRGB
#ifdef GL_EXT_sRGB
#define GLEXT_texture_sRGB GL_EXT_sRGB
@ -168,6 +184,22 @@
#define GLEXT_blend_func_separate sfogl_ext_EXT_blend_func_separate
#define GLEXT_glBlendFuncSeparate glBlendFuncSeparateEXT
// Core since 1.5 - ARB_vertex_buffer_object
#define GLEXT_vertex_buffer_object sfogl_ext_ARB_vertex_buffer_object
#define GLEXT_GL_ARRAY_BUFFER GL_ARRAY_BUFFER_ARB
#define GLEXT_GL_DYNAMIC_DRAW GL_DYNAMIC_DRAW_ARB
#define GLEXT_GL_READ_ONLY GL_READ_ONLY_ARB
#define GLEXT_GL_STATIC_DRAW GL_STATIC_DRAW_ARB
#define GLEXT_GL_STREAM_DRAW GL_STREAM_DRAW_ARB
#define GLEXT_GL_WRITE_ONLY GL_WRITE_ONLY_ARB
#define GLEXT_glBindBuffer glBindBufferARB
#define GLEXT_glBufferData glBufferDataARB
#define GLEXT_glBufferSubData glBufferSubDataARB
#define GLEXT_glDeleteBuffers glDeleteBuffersARB
#define GLEXT_glGenBuffers glGenBuffersARB
#define GLEXT_glMapBuffer glMapBufferARB
#define GLEXT_glUnmapBuffer glUnmapBufferARB
// Core since 2.0 - ARB_shading_language_100
#define GLEXT_shading_language_100 sfogl_ext_ARB_shading_language_100
@ -254,6 +286,12 @@
#define GLEXT_GL_DRAW_FRAMEBUFFER_BINDING GL_DRAW_FRAMEBUFFER_BINDING_EXT
#define GLEXT_GL_READ_FRAMEBUFFER_BINDING GL_READ_FRAMEBUFFER_BINDING_EXT
// Core since 3.1 - ARB_copy_buffer
#define GLEXT_copy_buffer sfogl_ext_ARB_copy_buffer
#define GLEXT_GL_COPY_READ_BUFFER GL_COPY_READ_BUFFER
#define GLEXT_GL_COPY_WRITE_BUFFER GL_COPY_WRITE_BUFFER
#define GLEXT_glCopyBufferSubData glCopyBufferSubData
// Core since 3.2 - ARB_geometry_shader4
#define GLEXT_geometry_shader4 sfogl_ext_ARB_geometry_shader4
#define GLEXT_GL_GEOMETRY_SHADER GL_GEOMETRY_SHADER_ARB

View File

@ -7,6 +7,7 @@ EXT_blend_minmax
EXT_blend_subtract
ARB_multitexture
EXT_blend_func_separate
ARB_vertex_buffer_object
ARB_shading_language_100
ARB_shader_objects
ARB_vertex_shader
@ -16,4 +17,5 @@ EXT_blend_equation_separate
EXT_texture_sRGB
EXT_framebuffer_object
EXT_framebuffer_blit
ARB_copy_buffer
ARB_geometry_shader4

View File

@ -39,6 +39,7 @@ int sfogl_ext_EXT_blend_minmax = sfogl_LOAD_FAILED;
int sfogl_ext_EXT_blend_subtract = sfogl_LOAD_FAILED;
int sfogl_ext_ARB_multitexture = sfogl_LOAD_FAILED;
int sfogl_ext_EXT_blend_func_separate = sfogl_LOAD_FAILED;
int sfogl_ext_ARB_vertex_buffer_object = sfogl_LOAD_FAILED;
int sfogl_ext_ARB_shading_language_100 = sfogl_LOAD_FAILED;
int sfogl_ext_ARB_shader_objects = sfogl_LOAD_FAILED;
int sfogl_ext_ARB_vertex_shader = sfogl_LOAD_FAILED;
@ -48,6 +49,7 @@ int sfogl_ext_EXT_blend_equation_separate = sfogl_LOAD_FAILED;
int sfogl_ext_EXT_texture_sRGB = sfogl_LOAD_FAILED;
int sfogl_ext_EXT_framebuffer_object = sfogl_LOAD_FAILED;
int sfogl_ext_EXT_framebuffer_blit = sfogl_LOAD_FAILED;
int sfogl_ext_ARB_copy_buffer = sfogl_LOAD_FAILED;
int sfogl_ext_ARB_geometry_shader4 = sfogl_LOAD_FAILED;
void (GL_FUNCPTR *sf_ptrc_glBlendEquationEXT)(GLenum) = NULL;
@ -254,6 +256,69 @@ static int Load_EXT_blend_func_separate()
return numFailed;
}
void (GL_FUNCPTR *sf_ptrc_glBindBufferARB)(GLenum, GLuint) = NULL;
void (GL_FUNCPTR *sf_ptrc_glBufferDataARB)(GLenum, GLsizeiptrARB, const void*, GLenum) = NULL;
void (GL_FUNCPTR *sf_ptrc_glBufferSubDataARB)(GLenum, GLintptrARB, GLsizeiptrARB, const void*) = NULL;
void (GL_FUNCPTR *sf_ptrc_glDeleteBuffersARB)(GLsizei, const GLuint*) = NULL;
void (GL_FUNCPTR *sf_ptrc_glGenBuffersARB)(GLsizei, GLuint*) = NULL;
void (GL_FUNCPTR *sf_ptrc_glGetBufferParameterivARB)(GLenum, GLenum, GLint*) = NULL;
void (GL_FUNCPTR *sf_ptrc_glGetBufferPointervARB)(GLenum, GLenum, void**) = NULL;
void (GL_FUNCPTR *sf_ptrc_glGetBufferSubDataARB)(GLenum, GLintptrARB, GLsizeiptrARB, void*) = NULL;
GLboolean (GL_FUNCPTR *sf_ptrc_glIsBufferARB)(GLuint) = NULL;
void* (GL_FUNCPTR *sf_ptrc_glMapBufferARB)(GLenum, GLenum) = NULL;
GLboolean (GL_FUNCPTR *sf_ptrc_glUnmapBufferARB)(GLenum) = NULL;
static int Load_ARB_vertex_buffer_object()
{
int numFailed = 0;
sf_ptrc_glBindBufferARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLuint)>(glLoaderGetProcAddress("glBindBufferARB"));
if (!sf_ptrc_glBindBufferARB)
numFailed++;
sf_ptrc_glBufferDataARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLsizeiptrARB, const void*, GLenum)>(glLoaderGetProcAddress("glBufferDataARB"));
if (!sf_ptrc_glBufferDataARB)
numFailed++;
sf_ptrc_glBufferSubDataARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLintptrARB, GLsizeiptrARB, const void*)>(glLoaderGetProcAddress("glBufferSubDataARB"));
if (!sf_ptrc_glBufferSubDataARB)
numFailed++;
sf_ptrc_glDeleteBuffersARB = reinterpret_cast<void (GL_FUNCPTR *)(GLsizei, const GLuint*)>(glLoaderGetProcAddress("glDeleteBuffersARB"));
if (!sf_ptrc_glDeleteBuffersARB)
numFailed++;
sf_ptrc_glGenBuffersARB = reinterpret_cast<void (GL_FUNCPTR *)(GLsizei, GLuint*)>(glLoaderGetProcAddress("glGenBuffersARB"));
if (!sf_ptrc_glGenBuffersARB)
numFailed++;
sf_ptrc_glGetBufferParameterivARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLint*)>(glLoaderGetProcAddress("glGetBufferParameterivARB"));
if (!sf_ptrc_glGetBufferParameterivARB)
numFailed++;
sf_ptrc_glGetBufferPointervARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, void**)>(glLoaderGetProcAddress("glGetBufferPointervARB"));
if (!sf_ptrc_glGetBufferPointervARB)
numFailed++;
sf_ptrc_glGetBufferSubDataARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLintptrARB, GLsizeiptrARB, void*)>(glLoaderGetProcAddress("glGetBufferSubDataARB"));
if (!sf_ptrc_glGetBufferSubDataARB)
numFailed++;
sf_ptrc_glIsBufferARB = reinterpret_cast<GLboolean (GL_FUNCPTR *)(GLuint)>(glLoaderGetProcAddress("glIsBufferARB"));
if (!sf_ptrc_glIsBufferARB)
numFailed++;
sf_ptrc_glMapBufferARB = reinterpret_cast<void* (GL_FUNCPTR *)(GLenum, GLenum)>(glLoaderGetProcAddress("glMapBufferARB"));
if (!sf_ptrc_glMapBufferARB)
numFailed++;
sf_ptrc_glUnmapBufferARB = reinterpret_cast<GLboolean (GL_FUNCPTR *)(GLenum)>(glLoaderGetProcAddress("glUnmapBufferARB"));
if (!sf_ptrc_glUnmapBufferARB)
numFailed++;
return numFailed;
}
void (GL_FUNCPTR *sf_ptrc_glAttachObjectARB)(GLhandleARB, GLhandleARB) = NULL;
void (GL_FUNCPTR *sf_ptrc_glCompileShaderARB)(GLhandleARB) = NULL;
GLhandleARB (GL_FUNCPTR *sf_ptrc_glCreateProgramObjectARB)() = NULL;
@ -814,6 +879,19 @@ static int Load_EXT_framebuffer_blit()
return numFailed;
}
void (GL_FUNCPTR *sf_ptrc_glCopyBufferSubData)(GLenum, GLenum, GLintptr, GLintptr, GLsizeiptr) = NULL;
static int Load_ARB_copy_buffer()
{
int numFailed = 0;
sf_ptrc_glCopyBufferSubData = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLintptr, GLintptr, GLsizeiptr)>(glLoaderGetProcAddress("glCopyBufferSubData"));
if (!sf_ptrc_glCopyBufferSubData)
numFailed++;
return numFailed;
}
void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureARB)(GLenum, GLenum, GLuint, GLint) = NULL;
void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureFaceARB)(GLenum, GLenum, GLuint, GLint, GLenum) = NULL;
void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureLayerARB)(GLenum, GLenum, GLuint, GLint, GLint) = NULL;
@ -850,13 +928,14 @@ typedef struct sfogl_StrToExtMap_s
PFN_LOADFUNCPOINTERS LoadExtension;
} sfogl_StrToExtMap;
static sfogl_StrToExtMap ExtensionMap[16] = {
static sfogl_StrToExtMap ExtensionMap[18] = {
{"GL_SGIS_texture_edge_clamp", &sfogl_ext_SGIS_texture_edge_clamp, NULL},
{"GL_EXT_texture_edge_clamp", &sfogl_ext_EXT_texture_edge_clamp, NULL},
{"GL_EXT_blend_minmax", &sfogl_ext_EXT_blend_minmax, Load_EXT_blend_minmax},
{"GL_EXT_blend_subtract", &sfogl_ext_EXT_blend_subtract, NULL},
{"GL_ARB_multitexture", &sfogl_ext_ARB_multitexture, Load_ARB_multitexture},
{"GL_EXT_blend_func_separate", &sfogl_ext_EXT_blend_func_separate, Load_EXT_blend_func_separate},
{"GL_ARB_vertex_buffer_object", &sfogl_ext_ARB_vertex_buffer_object, Load_ARB_vertex_buffer_object},
{"GL_ARB_shading_language_100", &sfogl_ext_ARB_shading_language_100, NULL},
{"GL_ARB_shader_objects", &sfogl_ext_ARB_shader_objects, Load_ARB_shader_objects},
{"GL_ARB_vertex_shader", &sfogl_ext_ARB_vertex_shader, Load_ARB_vertex_shader},
@ -866,10 +945,11 @@ static sfogl_StrToExtMap ExtensionMap[16] = {
{"GL_EXT_texture_sRGB", &sfogl_ext_EXT_texture_sRGB, NULL},
{"GL_EXT_framebuffer_object", &sfogl_ext_EXT_framebuffer_object, Load_EXT_framebuffer_object},
{"GL_EXT_framebuffer_blit", &sfogl_ext_EXT_framebuffer_blit, Load_EXT_framebuffer_blit},
{"GL_ARB_copy_buffer", &sfogl_ext_ARB_copy_buffer, Load_ARB_copy_buffer},
{"GL_ARB_geometry_shader4", &sfogl_ext_ARB_geometry_shader4, Load_ARB_geometry_shader4}
};
static int g_extensionMapSize = 16;
static int g_extensionMapSize = 18;
static void ClearExtensionVars()
@ -880,6 +960,7 @@ static void ClearExtensionVars()
sfogl_ext_EXT_blend_subtract = sfogl_LOAD_FAILED;
sfogl_ext_ARB_multitexture = sfogl_LOAD_FAILED;
sfogl_ext_EXT_blend_func_separate = sfogl_LOAD_FAILED;
sfogl_ext_ARB_vertex_buffer_object = sfogl_LOAD_FAILED;
sfogl_ext_ARB_shading_language_100 = sfogl_LOAD_FAILED;
sfogl_ext_ARB_shader_objects = sfogl_LOAD_FAILED;
sfogl_ext_ARB_vertex_shader = sfogl_LOAD_FAILED;
@ -889,6 +970,7 @@ static void ClearExtensionVars()
sfogl_ext_EXT_texture_sRGB = sfogl_LOAD_FAILED;
sfogl_ext_EXT_framebuffer_object = sfogl_LOAD_FAILED;
sfogl_ext_EXT_framebuffer_blit = sfogl_LOAD_FAILED;
sfogl_ext_ARB_copy_buffer = sfogl_LOAD_FAILED;
sfogl_ext_ARB_geometry_shader4 = sfogl_LOAD_FAILED;
}

View File

@ -176,6 +176,7 @@ extern int sfogl_ext_EXT_blend_minmax;
extern int sfogl_ext_EXT_blend_subtract;
extern int sfogl_ext_ARB_multitexture;
extern int sfogl_ext_EXT_blend_func_separate;
extern int sfogl_ext_ARB_vertex_buffer_object;
extern int sfogl_ext_ARB_shading_language_100;
extern int sfogl_ext_ARB_shader_objects;
extern int sfogl_ext_ARB_vertex_shader;
@ -185,6 +186,7 @@ extern int sfogl_ext_EXT_blend_equation_separate;
extern int sfogl_ext_EXT_texture_sRGB;
extern int sfogl_ext_EXT_framebuffer_object;
extern int sfogl_ext_EXT_framebuffer_blit;
extern int sfogl_ext_ARB_copy_buffer;
extern int sfogl_ext_ARB_geometry_shader4;
#define GL_CLAMP_TO_EDGE_SGIS 0x812F
@ -240,6 +242,38 @@ extern int sfogl_ext_ARB_geometry_shader4;
#define GL_BLEND_SRC_ALPHA_EXT 0x80CB
#define GL_BLEND_SRC_RGB_EXT 0x80C9
#define GL_ARRAY_BUFFER_ARB 0x8892
#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894
#define GL_BUFFER_ACCESS_ARB 0x88BB
#define GL_BUFFER_MAPPED_ARB 0x88BC
#define GL_BUFFER_MAP_POINTER_ARB 0x88BD
#define GL_BUFFER_SIZE_ARB 0x8764
#define GL_BUFFER_USAGE_ARB 0x8765
#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
#define GL_DYNAMIC_COPY_ARB 0x88EA
#define GL_DYNAMIC_DRAW_ARB 0x88E8
#define GL_DYNAMIC_READ_ARB 0x88E9
#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893
#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
#define GL_READ_ONLY_ARB 0x88B8
#define GL_READ_WRITE_ARB 0x88BA
#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
#define GL_STATIC_COPY_ARB 0x88E6
#define GL_STATIC_DRAW_ARB 0x88E4
#define GL_STATIC_READ_ARB 0x88E5
#define GL_STREAM_COPY_ARB 0x88E2
#define GL_STREAM_DRAW_ARB 0x88E0
#define GL_STREAM_READ_ARB 0x88E1
#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
#define GL_WRITE_ONLY_ARB 0x88B9
#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C
#define GL_BOOL_ARB 0x8B56
@ -385,6 +419,9 @@ extern int sfogl_ext_ARB_geometry_shader4;
#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA
#define GL_READ_FRAMEBUFFER_EXT 0x8CA8
#define GL_COPY_READ_BUFFER 0x8F36
#define GL_COPY_WRITE_BUFFER 0x8F37
#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9
@ -1022,6 +1059,32 @@ extern void (GL_FUNCPTR *sf_ptrc_glBlendFuncSeparateEXT)(GLenum, GLenum, GLenum,
#define glBlendFuncSeparateEXT sf_ptrc_glBlendFuncSeparateEXT
#endif // GL_EXT_blend_func_separate
#ifndef GL_ARB_vertex_buffer_object
#define GL_ARB_vertex_buffer_object 1
extern void (GL_FUNCPTR *sf_ptrc_glBindBufferARB)(GLenum, GLuint);
#define glBindBufferARB sf_ptrc_glBindBufferARB
extern void (GL_FUNCPTR *sf_ptrc_glBufferDataARB)(GLenum, GLsizeiptrARB, const void*, GLenum);
#define glBufferDataARB sf_ptrc_glBufferDataARB
extern void (GL_FUNCPTR *sf_ptrc_glBufferSubDataARB)(GLenum, GLintptrARB, GLsizeiptrARB, const void*);
#define glBufferSubDataARB sf_ptrc_glBufferSubDataARB
extern void (GL_FUNCPTR *sf_ptrc_glDeleteBuffersARB)(GLsizei, const GLuint*);
#define glDeleteBuffersARB sf_ptrc_glDeleteBuffersARB
extern void (GL_FUNCPTR *sf_ptrc_glGenBuffersARB)(GLsizei, GLuint*);
#define glGenBuffersARB sf_ptrc_glGenBuffersARB
extern void (GL_FUNCPTR *sf_ptrc_glGetBufferParameterivARB)(GLenum, GLenum, GLint*);
#define glGetBufferParameterivARB sf_ptrc_glGetBufferParameterivARB
extern void (GL_FUNCPTR *sf_ptrc_glGetBufferPointervARB)(GLenum, GLenum, void**);
#define glGetBufferPointervARB sf_ptrc_glGetBufferPointervARB
extern void (GL_FUNCPTR *sf_ptrc_glGetBufferSubDataARB)(GLenum, GLintptrARB, GLsizeiptrARB, void*);
#define glGetBufferSubDataARB sf_ptrc_glGetBufferSubDataARB
extern GLboolean (GL_FUNCPTR *sf_ptrc_glIsBufferARB)(GLuint);
#define glIsBufferARB sf_ptrc_glIsBufferARB
extern void* (GL_FUNCPTR *sf_ptrc_glMapBufferARB)(GLenum, GLenum);
#define glMapBufferARB sf_ptrc_glMapBufferARB
extern GLboolean (GL_FUNCPTR *sf_ptrc_glUnmapBufferARB)(GLenum);
#define glUnmapBufferARB sf_ptrc_glUnmapBufferARB
#endif // GL_ARB_vertex_buffer_object
#ifndef GL_ARB_shader_objects
#define GL_ARB_shader_objects 1
@ -1254,6 +1317,12 @@ extern void (GL_FUNCPTR *sf_ptrc_glBlitFramebufferEXT)(GLint, GLint, GLint, GLin
#define glBlitFramebufferEXT sf_ptrc_glBlitFramebufferEXT
#endif // GL_EXT_framebuffer_blit
#ifndef GL_ARB_copy_buffer
#define GL_ARB_copy_buffer 1
extern void (GL_FUNCPTR *sf_ptrc_glCopyBufferSubData)(GLenum, GLenum, GLintptr, GLintptr, GLsizeiptr);
#define glCopyBufferSubData sf_ptrc_glCopyBufferSubData
#endif // GL_ARB_copy_buffer
#ifndef GL_ARB_geometry_shader4
#define GL_ARB_geometry_shader4 1
extern void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureARB)(GLenum, GLenum, GLuint, GLint);

View File

@ -30,10 +30,21 @@
#include <SFML/Graphics/Shader.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/Graphics/VertexArray.hpp>
#include <SFML/Graphics/VertexBuffer.hpp>
#include <SFML/Graphics/GLCheck.hpp>
#include <SFML/System/Err.hpp>
#include <cassert>
#include <iostream>
#include <algorithm>
// GL_QUADS is unavailable on OpenGL ES, thus we need to define GL_QUADS ourselves
#ifdef SFML_OPENGL_ES
#define GL_QUADS 0
#endif // SFML_OPENGL_ES
namespace
{
@ -211,17 +222,13 @@ void RenderTarget::draw(const Vertex* vertices, std::size_t vertexCount,
err() << "sf::Quads primitive type is not supported on OpenGL ES platforms, drawing skipped" << std::endl;
return;
}
#define GL_QUADS 0
#endif
if (setActive(true))
{
// First set the persistent OpenGL states if it's the very first call
if (!m_cache.glStatesSet)
resetGLStates();
// Check if the vertex count is low enough so that we can pre-transform them
bool useVertexCache = (vertexCount <= StatesCache::VertexCacheSize);
if (useVertexCache)
{
// Pre-transform the vertices and store them into the vertex cache
@ -232,32 +239,9 @@ void RenderTarget::draw(const Vertex* vertices, std::size_t vertexCount,
vertex.color = vertices[i].color;
vertex.texCoords = vertices[i].texCoords;
}
// Since vertices are transformed, we must use an identity transform to render them
if (!m_cache.useVertexCache)
glCheck(glLoadIdentity());
}
else
{
applyTransform(states.transform);
}
// Apply the view
if (m_cache.viewChanged)
applyCurrentView();
// Apply the blend mode
if (states.blendMode != m_cache.lastBlendMode)
applyBlendMode(states.blendMode);
// Apply the texture
Uint64 textureId = states.texture ? states.texture->m_cacheId : 0;
if (textureId != m_cache.lastTextureId)
applyTexture(states.texture);
// Apply the shader
if (states.shader)
applyShader(states.shader);
setupDraw(useVertexCache, states);
// Check if texture coordinates array is needed, and update client state accordingly
bool enableTexCoordsArray = (states.texture || states.shader);
@ -292,22 +276,8 @@ void RenderTarget::draw(const Vertex* vertices, std::size_t vertexCount,
glCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), data + 12));
}
// Find the OpenGL primitive type
static const GLenum modes[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES,
GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS};
GLenum mode = modes[type];
// Draw the primitives
glCheck(glDrawArrays(mode, 0, static_cast<GLsizei>(vertexCount)));
// Unbind the shader, if any
if (states.shader)
applyShader(NULL);
// If the texture we used to draw belonged to a RenderTexture, then forcibly unbind that texture.
// This prevents a bug where some drivers do not clear RenderTextures properly.
if (states.texture && states.texture->m_fboAttachment)
applyTexture(NULL);
drawPrimitives(type, 0, vertexCount);
cleanupDraw(states);
// Update the cache
m_cache.useVertexCache = useVertexCache;
@ -316,6 +286,73 @@ void RenderTarget::draw(const Vertex* vertices, std::size_t vertexCount,
}
////////////////////////////////////////////////////////////
void RenderTarget::draw(const VertexBuffer& vertexBuffer, const RenderStates& states)
{
draw(vertexBuffer, 0, vertexBuffer.getVertexCount(), states);
}
////////////////////////////////////////////////////////////
void RenderTarget::draw(const VertexBuffer& vertexBuffer, std::size_t firstVertex,
std::size_t vertexCount, const RenderStates& states)
{
// VertexBuffer not supported?
if (!VertexBuffer::isAvailable())
{
err() << "sf::VertexBuffer is not available, drawing skipped" << std::endl;
return;
}
// Sanity check
if (firstVertex > vertexBuffer.getVertexCount())
return;
// Clamp vertexCount to something that makes sense
vertexCount = std::min(vertexCount, vertexBuffer.getVertexCount() - firstVertex);
// Nothing to draw?
if (!vertexCount || !vertexBuffer.getNativeHandle())
return;
// GL_QUADS is unavailable on OpenGL ES
#ifdef SFML_OPENGL_ES
if (vertexBuffer.getPrimitiveType() == Quads)
{
err() << "sf::Quads primitive type is not supported on OpenGL ES platforms, drawing skipped" << std::endl;
return;
}
#endif
if (setActive(true))
{
setupDraw(false, states);
// Bind vertex buffer
VertexBuffer::bind(&vertexBuffer);
// Always enable texture coordinates
if (!m_cache.texCoordsArrayEnabled)
glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
glCheck(glVertexPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast<const void*>(0)));
glCheck(glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), reinterpret_cast<const void*>(8)));
glCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast<const void*>(12)));
drawPrimitives(vertexBuffer.getPrimitiveType(), firstVertex, vertexCount);
// Unbind vertex buffer
VertexBuffer::bind(NULL);
cleanupDraw(states);
// Update the cache
m_cache.useVertexCache = false;
m_cache.texCoordsArrayEnabled = true;
}
}
////////////////////////////////////////////////////////////
void RenderTarget::pushGLStates()
{
@ -372,6 +409,7 @@ void RenderTarget::resetGLStates()
{
// Check here to make sure a context change does not happen after activate(true)
bool shaderAvailable = Shader::isAvailable();
bool vertexBufferAvailable = VertexBuffer::isAvailable();
// Workaround for states not being properly reset on
// macOS unless a context switch really takes place
@ -411,6 +449,9 @@ void RenderTarget::resetGLStates()
if (shaderAvailable)
applyShader(NULL);
if (vertexBufferAvailable)
glCheck(VertexBuffer::bind(NULL));
m_cache.texCoordsArrayEnabled = true;
m_cache.useVertexCache = false;
@ -527,6 +568,70 @@ void RenderTarget::applyShader(const Shader* shader)
Shader::bind(shader);
}
////////////////////////////////////////////////////////////
void RenderTarget::setupDraw(bool useVertexCache, const RenderStates& states)
{
// First set the persistent OpenGL states if it's the very first call
if (!m_cache.glStatesSet)
resetGLStates();
if (useVertexCache)
{
// Since vertices are transformed, we must use an identity transform to render them
if (!m_cache.useVertexCache)
glCheck(glLoadIdentity());
}
else
{
applyTransform(states.transform);
}
// Apply the view
if (m_cache.viewChanged)
applyCurrentView();
// Apply the blend mode
if (states.blendMode != m_cache.lastBlendMode)
applyBlendMode(states.blendMode);
// Apply the texture
Uint64 textureId = states.texture ? states.texture->m_cacheId : 0;
if (textureId != m_cache.lastTextureId)
applyTexture(states.texture);
// Apply the shader
if (states.shader)
applyShader(states.shader);
}
////////////////////////////////////////////////////////////
void RenderTarget::drawPrimitives(PrimitiveType type, std::size_t firstVertex, std::size_t vertexCount)
{
// Find the OpenGL primitive type
static const GLenum modes[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES,
GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS};
GLenum mode = modes[type];
// Draw the primitives
glCheck(glDrawArrays(mode, firstVertex, static_cast<GLsizei>(vertexCount)));
}
////////////////////////////////////////////////////////////
void RenderTarget::cleanupDraw(const RenderStates& states)
{
// Unbind the shader, if any
if (states.shader)
applyShader(NULL);
// If the texture we used to draw belonged to a RenderTexture, then forcibly unbind that texture.
// This prevents a bug where some drivers do not clear RenderTextures properly.
if (states.texture && states.texture->m_fboAttachment)
applyTexture(NULL);
}
} // namespace sf

View File

@ -0,0 +1,363 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2017 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.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/VertexBuffer.hpp>
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/Vertex.hpp>
#include <SFML/Graphics/GLCheck.hpp>
#include <SFML/System/Mutex.hpp>
#include <SFML/System/Lock.hpp>
#include <SFML/System/Err.hpp>
#include <cstring>
namespace
{
sf::Mutex isAvailableMutex;
GLenum usageToGlEnum(sf::VertexBuffer::Usage usage)
{
switch (usage)
{
case sf::VertexBuffer::Static: return GLEXT_GL_STATIC_DRAW;
case sf::VertexBuffer::Dynamic: return GLEXT_GL_DYNAMIC_DRAW;
default: return GLEXT_GL_STREAM_DRAW;
}
}
}
namespace sf
{
////////////////////////////////////////////////////////////
VertexBuffer::VertexBuffer() :
m_buffer (0),
m_size (0),
m_primitiveType(Points),
m_usage (Stream)
{
}
////////////////////////////////////////////////////////////
VertexBuffer::VertexBuffer(PrimitiveType type) :
m_buffer (0),
m_size (0),
m_primitiveType(type),
m_usage (Stream)
{
}
////////////////////////////////////////////////////////////
VertexBuffer::VertexBuffer(VertexBuffer::Usage usage) :
m_buffer (0),
m_size (0),
m_primitiveType(Points),
m_usage (usage)
{
}
////////////////////////////////////////////////////////////
VertexBuffer::VertexBuffer(PrimitiveType type, VertexBuffer::Usage usage) :
m_buffer (0),
m_size (0),
m_primitiveType(type),
m_usage (usage)
{
}
////////////////////////////////////////////////////////////
VertexBuffer::VertexBuffer(const VertexBuffer& copy) :
m_buffer (0),
m_size (0),
m_primitiveType(copy.m_primitiveType),
m_usage (copy.m_usage)
{
if (copy.m_buffer && copy.m_size)
{
if (!create(copy.m_size))
{
err() << "Could not create vertex buffer for copying" << std::endl;
return;
}
if (!update(copy))
err() << "Could not copy vertex buffer" << std::endl;
}
}
////////////////////////////////////////////////////////////
VertexBuffer::~VertexBuffer()
{
if (m_buffer)
{
TransientContextLock contextLock;
glCheck(GLEXT_glDeleteBuffers(1, &m_buffer));
}
}
////////////////////////////////////////////////////////////
bool VertexBuffer::create(std::size_t vertexCount)
{
if (!isAvailable())
return false;
TransientContextLock contextLock;
if (!m_buffer)
glCheck(GLEXT_glGenBuffers(1, &m_buffer));
if (!m_buffer)
{
err() << "Could not create vertex buffer, generation failed" << std::endl;
return false;
}
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
glCheck(GLEXT_glBufferData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * vertexCount, 0, usageToGlEnum(m_usage)));
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, 0));
m_size = vertexCount;
return true;
}
////////////////////////////////////////////////////////////
std::size_t VertexBuffer::getVertexCount() const
{
return m_size;
}
////////////////////////////////////////////////////////////
bool VertexBuffer::update(const Vertex* vertices)
{
return update(vertices, m_size, 0);
}
////////////////////////////////////////////////////////////
bool VertexBuffer::update(const Vertex* vertices, std::size_t vertexCount, unsigned int offset)
{
// Sanity checks
if (!m_buffer)
return false;
if (!vertices)
return false;
if (offset && (offset + vertexCount > m_size))
return false;
TransientContextLock contextLock;
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
// Check if we need to resize or orphan the buffer
if (vertexCount >= m_size)
{
glCheck(GLEXT_glBufferData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * vertexCount, 0, usageToGlEnum(m_usage)));
m_size = vertexCount;
}
glCheck(GLEXT_glBufferSubData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * offset, sizeof(Vertex) * vertexCount, vertices));
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, 0));
return true;
}
////////////////////////////////////////////////////////////
bool VertexBuffer::update(const VertexBuffer& vertexBuffer)
{
#ifdef SFML_OPENGL_ES
return false;
#else
if (!m_buffer || !vertexBuffer.m_buffer)
return false;
TransientContextLock contextLock;
// Make sure that extensions are initialized
sf::priv::ensureExtensionsInit();
if (GLEXT_copy_buffer)
{
glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_READ_BUFFER, vertexBuffer.m_buffer));
glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_WRITE_BUFFER, m_buffer));
glCheck(GLEXT_glCopyBufferSubData(GLEXT_GL_COPY_READ_BUFFER, GLEXT_GL_COPY_WRITE_BUFFER, 0, 0, sizeof(Vertex) * vertexBuffer.m_size));
glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_WRITE_BUFFER, 0));
glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_READ_BUFFER, 0));
return true;
}
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
glCheck(GLEXT_glBufferData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * vertexBuffer.m_size, 0, usageToGlEnum(m_usage)));
void* destination = 0;
glCheck(destination = GLEXT_glMapBuffer(GLEXT_GL_ARRAY_BUFFER, GLEXT_GL_WRITE_ONLY));
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, vertexBuffer.m_buffer));
void* source = 0;
glCheck(source = GLEXT_glMapBuffer(GLEXT_GL_ARRAY_BUFFER, GLEXT_GL_READ_ONLY));
std::memcpy(destination, source, sizeof(Vertex) * vertexBuffer.m_size);
GLboolean sourceResult = GL_FALSE;
glCheck(sourceResult = GLEXT_glUnmapBuffer(GLEXT_GL_ARRAY_BUFFER));
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
GLboolean destinationResult = GL_FALSE;
glCheck(destinationResult = GLEXT_glUnmapBuffer(GLEXT_GL_ARRAY_BUFFER));
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, 0));
if ((sourceResult == GL_FALSE) || (destinationResult == GL_FALSE))
return false;
return true;
#endif // SFML_OPENGL_ES
}
////////////////////////////////////////////////////////////
VertexBuffer& VertexBuffer::operator =(const VertexBuffer& right)
{
VertexBuffer temp(right);
swap(temp);
return *this;
}
////////////////////////////////////////////////////////////
void VertexBuffer::swap(VertexBuffer& right)
{
std::swap(m_size, right.m_size);
std::swap(m_buffer, right.m_buffer);
std::swap(m_primitiveType, right.m_primitiveType);
std::swap(m_usage, right.m_usage);
}
////////////////////////////////////////////////////////////
unsigned int VertexBuffer::getNativeHandle() const
{
return m_buffer;
}
////////////////////////////////////////////////////////////
void VertexBuffer::bind(const VertexBuffer* vertexBuffer)
{
if (!isAvailable())
return;
TransientContextLock lock;
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, vertexBuffer ? vertexBuffer->m_buffer : 0));
}
////////////////////////////////////////////////////////////
void VertexBuffer::setPrimitiveType(PrimitiveType type)
{
m_primitiveType = type;
}
////////////////////////////////////////////////////////////
PrimitiveType VertexBuffer::getPrimitiveType() const
{
return m_primitiveType;
}
////////////////////////////////////////////////////////////
void VertexBuffer::setUsage(VertexBuffer::Usage usage)
{
m_usage = usage;
}
////////////////////////////////////////////////////////////
VertexBuffer::Usage VertexBuffer::getUsage() const
{
return m_usage;
}
////////////////////////////////////////////////////////////
bool VertexBuffer::isAvailable()
{
Lock lock(isAvailableMutex);
static bool checked = false;
static bool available = false;
if (!checked)
{
checked = true;
TransientContextLock contextLock;
// Make sure that extensions are initialized
sf::priv::ensureExtensionsInit();
available = GLEXT_vertex_buffer_object;
}
return available;
}
////////////////////////////////////////////////////////////
void VertexBuffer::draw(RenderTarget& target, RenderStates states) const
{
if (m_buffer && m_size)
target.draw(*this, 0, m_size, states);
}
} // namespace sf