Browse Source

Mesh rework, part 2: reworked internals.

* VAOs are used only if the extension is supported.
 * Removed finalize() and other already useless stuff.
 * Preparation for DSA and state tracking.
pull/7/head
Vladimír Vondruš 14 years ago
parent
commit
10e64d2d27
  1. 4
      src/Context.cpp
  2. 65
      src/IndexedMesh.cpp
  3. 80
      src/IndexedMesh.h
  4. 157
      src/Mesh.cpp
  5. 132
      src/Mesh.h

4
src/Context.cpp

@ -23,6 +23,8 @@
#include "AbstractTexture.h" #include "AbstractTexture.h"
#include "Buffer.h" #include "Buffer.h"
#include "Extensions.h" #include "Extensions.h"
#include "IndexedMesh.h"
#include "Mesh.h"
#include "Implementation/State.h" #include "Implementation/State.h"
#include "BufferedTexture.h" #include "BufferedTexture.h"
@ -205,6 +207,8 @@ Context::Context() {
AbstractTexture::initializeContextBasedFunctionality(this); AbstractTexture::initializeContextBasedFunctionality(this);
Buffer::initializeContextBasedFunctionality(this); Buffer::initializeContextBasedFunctionality(this);
BufferedTexture::initializeContextBasedFunctionality(this); BufferedTexture::initializeContextBasedFunctionality(this);
IndexedMesh::initializeContextBasedFunctionality(this);
Mesh::initializeContextBasedFunctionality(this);
} }
Context::~Context() { Context::~Context() {

65
src/IndexedMesh.cpp

@ -17,21 +17,28 @@
#include <Utility/Debug.h> #include <Utility/Debug.h>
#include "Context.h"
#include "Extensions.h"
namespace Magnum { namespace Magnum {
void IndexedMesh::draw() { IndexedMesh::CreateIndexedImplementation IndexedMesh::createIndexedImplementation = &IndexedMesh::createIndexedImplementationDefault;
/* Vertex array must be bound before finalization */ IndexedMesh::BindIndexedImplementation IndexedMesh::bindIndexedImplementation = &IndexedMesh::bindIndexedImplementationDefault;
#ifndef MAGNUM_TARGET_GLES
bind(); IndexedMesh::IndexedMesh(Mesh::Primitive primitive): Mesh(primitive), _indexCount(0), _indexType(Type::UnsignedShort) {
#endif _indexBuffer.setTargetHint(Buffer::Target::ElementArray);
(this->*createIndexedImplementation)();
}
finalize(); IndexedMesh::IndexedMesh(Mesh::Primitive primitive, GLsizei vertexCount, GLsizei indexCount, Type indexType): Mesh(primitive, vertexCount), _indexCount(indexCount), _indexType(indexType) {
_indexBuffer.setTargetHint(Buffer::Target::ElementArray);
/* Buffers must be bound after initialization */ (this->*createIndexedImplementation)();
#ifdef MAGNUM_TARGET_GLES }
void IndexedMesh::draw() {
bind(); bind();
_indexBuffer.bind(Buffer::Target::ElementArray);
#endif
/** @todo Start at given index */ /** @todo Start at given index */
glDrawElements(static_cast<GLenum>(primitive()), _indexCount, static_cast<GLenum>(_indexType), nullptr); glDrawElements(static_cast<GLenum>(primitive()), _indexCount, static_cast<GLenum>(_indexType), nullptr);
@ -39,20 +46,40 @@ void IndexedMesh::draw() {
unbind(); unbind();
} }
#ifndef DOXYGEN_GENERATING_OUTPUT void IndexedMesh::bind() {
void IndexedMesh::finalize() {
if(isFinalized()) return;
CORRADE_ASSERT(_indexCount, "IndexedMesh: the mesh has zero index count!", ); CORRADE_ASSERT(_indexCount, "IndexedMesh: the mesh has zero index count!", );
/* Finalize attribute positions */ Mesh::bind();
Mesh::finalize(); (this->*bindIndexedImplementation)();
}
void IndexedMesh::initializeContextBasedFunctionality(Context* context) {
if(context->isExtensionSupported<Extensions::GL::APPLE::vertex_array_object>()) {
#ifndef MAGNUM_TARGET_GLES
Debug() << "IndexedMesh: using" << Extensions::GL::APPLE::vertex_array_object::string() << "features";
createIndexedImplementation = &IndexedMesh::createIndexedImplementationVAO;
bindIndexedImplementation = &IndexedMesh::bindIndexedImplementationVAO;
#endif
}
}
void IndexedMesh::createIndexedImplementationDefault() {}
#ifndef MAGNUM_TARGET_GLES
void IndexedMesh::createIndexedImplementationVAO() {
glBindVertexArray(vao);
/* Bind index buffer to VAO too */
#ifndef MAGNUM_TARGET_GLES
_indexBuffer.bind(Buffer::Target::ElementArray); _indexBuffer.bind(Buffer::Target::ElementArray);
#endif
} }
#endif #endif
void IndexedMesh::bindIndexedImplementationDefault() {
_indexBuffer.bind(Buffer::Target::ElementArray);
}
#ifndef MAGNUM_TARGET_GLES
void IndexedMesh::bindIndexedImplementationVAO() {}
#endif
} }

80
src/IndexedMesh.h

@ -25,21 +25,39 @@
namespace Magnum { namespace Magnum {
/** /**
* @brief Indexed mesh @brief Indexed mesh
*/
@section IndexedMesh-configuration Indexed mesh configuration
Next to @ref Mesh-configuration "everything needed for non-indexed mesh" you
have to specify also index count and type (either in constructor or using
setIndexCount() and setIndexType()). Then fill index buffer or use
MeshTools::compressIndices() to conveniently fill the index buffer and set
index count and type.
@section IndexedMesh-drawing Rendering meshes
From user point-of-view the operation is the same as for
@ref Mesh-drawing "non-indexed meshes".
@section IndexedMesh-performance-optimization Performance optimizations
If @extension{APPLE,vertex_array_object} is supported, next to
@ref Mesh-performance-optimization "optimizations in Mesh itself" the index
buffer is bound on object construction instead of in every draw() call.
*/
class MAGNUM_EXPORT IndexedMesh: public Mesh { class MAGNUM_EXPORT IndexedMesh: public Mesh {
friend class Context;
public: public:
/** /**
* @brief Implicit constructor * @brief Implicit constructor
* @param primitive Primitive type * @param primitive Primitive type
* *
* Allows creating the object without knowing anything about mesh data. * @see @fn_gl{BindVertexArray} (if @extension{APPLE,vertex_array_object}
* Note that you have to call setVertexCount(), setIndexCount() and * is available)
* setIndexType() manually for mesh to draw properly.
*/ */
inline IndexedMesh(Primitive primitive = Primitive::Triangles): Mesh(primitive), _indexCount(0), _indexType(Type::UnsignedShort) { IndexedMesh(Primitive primitive = Primitive::Triangles);
_indexBuffer.setTargetHint(Buffer::Target::ElementArray);
}
/** /**
* @brief Constructor * @brief Constructor
@ -47,10 +65,12 @@ class MAGNUM_EXPORT IndexedMesh: public Mesh {
* @param vertexCount Count of unique vertices * @param vertexCount Count of unique vertices
* @param indexCount Count of indices * @param indexCount Count of indices
* @param indexType Type of indices (indexable, see TypeTraits) * @param indexType Type of indices (indexable, see TypeTraits)
*
* @see setPrimitive(), setVertexCount(), setIndexCount(),
* setIndexType(), @fn_gl{BindVertexArray} (if
* @extension{APPLE,vertex_array_object} is available)
*/ */
inline IndexedMesh(Primitive primitive, GLsizei vertexCount, GLsizei indexCount, Type indexType = Type::UnsignedShort): Mesh(primitive, vertexCount), _indexCount(indexCount), _indexType(indexType) { IndexedMesh(Primitive primitive, GLsizei vertexCount, GLsizei indexCount, Type indexType = Type::UnsignedShort);
_indexBuffer.setTargetHint(Buffer::Target::ElementArray);
}
/** @brief Index count */ /** @brief Index count */
inline GLsizei indexCount() const { return _indexCount; } inline GLsizei indexCount() const { return _indexCount; }
@ -60,7 +80,6 @@ class MAGNUM_EXPORT IndexedMesh: public Mesh {
* @return Pointer to self (for method chaining) * @return Pointer to self (for method chaining)
* *
* @see MeshTools::compressIndices() * @see MeshTools::compressIndices()
* @todo definalize after that?
*/ */
inline IndexedMesh* setIndexCount(GLsizei count) { inline IndexedMesh* setIndexCount(GLsizei count) {
_indexCount = count; _indexCount = count;
@ -73,6 +92,8 @@ class MAGNUM_EXPORT IndexedMesh: public Mesh {
/** /**
* @brief Set index type * @brief Set index type
* @return Pointer to self (for method chaining) * @return Pointer to self (for method chaining)
*
* @see MeshTools::compressIndices()
*/ */
inline IndexedMesh* setIndexType(Type type) { inline IndexedMesh* setIndexType(Type type) {
_indexType = type; _indexType = type;
@ -90,20 +111,35 @@ class MAGNUM_EXPORT IndexedMesh: public Mesh {
/** /**
* @brief Draw the mesh * @brief Draw the mesh
* *
* Expects an active shader with all uniforms set. * Expects an active shader with all uniforms set. See
* @see Buffer::bind(), bind(), unbind(), finalize(), @fn_gl{DrawElements} * @ref AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation"
* for more information.
* @see @fn_gl{EnableVertexAttribArray}, @fn_gl{BindBuffer},
* @fn_gl{VertexAttribPointer}, @fn_gl{DisableVertexAttribArray}
* or @fn_gl{BindVertexArray} (if @extension{APPLE,vertex_array_object}
* is available), @fn_gl{DrawElements}
*/ */
void draw(); void draw();
protected:
/**
* @brief Finalize the mesh
*
* @see Mesh::finalize(), Buffer::bind()
*/
MAGNUM_LOCAL void finalize();
private: private:
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
void MAGNUM_LOCAL bind();
typedef void(IndexedMesh::*CreateIndexedImplementation)();
void MAGNUM_LOCAL createIndexedImplementationDefault();
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL createIndexedImplementationVAO();
#endif
static MAGNUM_LOCAL CreateIndexedImplementation createIndexedImplementation;
typedef void(IndexedMesh::*BindIndexedImplementation)();
void MAGNUM_LOCAL bindIndexedImplementationDefault();
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL bindIndexedImplementationVAO();
#endif
static MAGNUM_LOCAL BindIndexedImplementation bindIndexedImplementation;
Buffer _indexBuffer; Buffer _indexBuffer;
GLsizei _indexCount; GLsizei _indexCount;
Type _indexType; Type _indexType;

157
src/Mesh.cpp

@ -18,59 +18,38 @@
#include <Utility/Debug.h> #include <Utility/Debug.h>
#include "Buffer.h" #include "Buffer.h"
#include "Context.h"
#include "Extensions.h"
using namespace std; using namespace std;
namespace Magnum { namespace Magnum {
Mesh::Mesh(Mesh&& other): Mesh::CreateImplementation Mesh::createImplementation = &Mesh::createImplementationDefault;
#ifndef MAGNUM_TARGET_GLES Mesh::DestroyImplementation Mesh::destroyImplementation = &Mesh::destroyImplementationDefault;
vao(other.vao), Mesh::BindAttributeImplementation Mesh::bindAttributeImplementation = &Mesh::bindAttributeImplementationDefault;
#endif Mesh::BindImplementation Mesh::bindImplementation = &Mesh::bindImplementationDefault;
_primitive(other._primitive), _vertexCount(other._vertexCount), finalized(other.finalized), attributes(other.attributes) Mesh::UnbindImplementation Mesh::unbindImplementation = &Mesh::unbindImplementationDefault;
{
#ifndef MAGNUM_TARGET_GLES
other.vao = 0;
#endif
}
void Mesh::destroy() { Mesh::Mesh(Mesh&& other): vao(other.vao), _primitive(other._primitive), _vertexCount(other._vertexCount), attributes(other.attributes) {
#ifndef MAGNUM_TARGET_GLES other.vao = 0;
glDeleteVertexArrays(1, &vao);
#endif
} }
Mesh& Mesh::operator=(Mesh&& other) { Mesh& Mesh::operator=(Mesh&& other) {
destroy(); (this->*destroyImplementation)();
#ifndef MAGNUM_TARGET_GLES
vao = other.vao; vao = other.vao;
#endif
_primitive = other._primitive; _primitive = other._primitive;
_vertexCount = other._vertexCount; _vertexCount = other._vertexCount;
finalized = other.finalized;
attributes = other.attributes; attributes = other.attributes;
#ifndef MAGNUM_TARGET_GLES
other.vao = 0; other.vao = 0;
#endif
return *this; return *this;
} }
void Mesh::draw() { void Mesh::draw() {
/* Vertex array must be bound before finalization */
#ifndef MAGNUM_TARGET_GLES
bind();
#endif
/* Finalize, if not already */
finalize();
/* Buffers must be bound after initialization */
#ifdef MAGNUM_TARGET_GLES
bind(); bind();
#endif
/** @todo Start at given index */ /** @todo Start at given index */
glDrawArrays(static_cast<GLenum>(_primitive), 0, _vertexCount); glDrawArrays(static_cast<GLenum>(_primitive), 0, _vertexCount);
@ -78,65 +57,99 @@ void Mesh::draw() {
unbind(); unbind();
} }
#ifndef DOXYGEN_GENERATING_OUTPUT
void Mesh::bind() { void Mesh::bind() {
#ifndef MAGNUM_TARGET_GLES CORRADE_ASSERT((_vertexCount == 0) == attributes.empty(), "Mesh: vertex count is non-zero, but no attributes are bound", );
glBindVertexArray(vao);
#else
bindBuffers();
#endif
}
void Mesh::unbind() { (this->*bindImplementation)();
#ifndef MAGNUM_TARGET_GLES
glBindVertexArray(0);
#else
for(const Attribute& attribute: attributes)
glDisableVertexAttribArray(attribute.location);
#endif
} }
void Mesh::finalize() { void Mesh::addVertexAttribute(Buffer* buffer, GLuint location, GLint count, Type type, GLintptr offset, GLsizei stride) {
/* Already finalized */ CORRADE_ASSERT(_vertexCount != 0, "Mesh: vertex count must be set before binding attributes", );
if(finalized) return;
CORRADE_ASSERT((_vertexCount == 0) == attributes.empty(), "Mesh: vertex count is non-zero, but no attributes are bound", ); attributes.push_back({
buffer,
location,
count,
type,
offset,
stride
});
finalized = true; (this->*bindAttributeImplementation)(attributes.back());
}
void Mesh::vertexAttribPointer(const Mesh::Attribute& attribute) {
glEnableVertexAttribArray(attribute.location);
attribute.buffer->bind(Buffer::Target::Array);
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
bindBuffers(); if(TypeInfo::isIntegral(attribute.type))
glVertexAttribIPointer(attribute.location, attribute.count, static_cast<GLenum>(attribute.type), attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
else
#endif #endif
glVertexAttribPointer(attribute.location, attribute.count, static_cast<GLenum>(attribute.type), GL_FALSE, attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
} }
void Mesh::bindBuffers() { void Mesh::initializeContextBasedFunctionality(Context* context) {
/* Bind all attributes to this buffer */ if(context->isExtensionSupported<Extensions::GL::APPLE::vertex_array_object>()) {
for(const Attribute& attribute: attributes) {
glEnableVertexAttribArray(attribute.location);
attribute.buffer->bind(Buffer::Target::Array);
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
if(TypeInfo::isIntegral(attribute.type)) Debug() << "Mesh: using" << Extensions::GL::APPLE::vertex_array_object::string() << "features";
glVertexAttribIPointer(attribute.location, attribute.count, static_cast<GLenum>(attribute.type), attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
else createImplementation = &Mesh::createImplementationVAO;
destroyImplementation = &Mesh::destroyImplementationVAO;
bindAttributeImplementation = &Mesh::bindAttributeImplementationVAO;
bindImplementation = &Mesh::bindImplementationVAO;
unbindImplementation = &Mesh::unbindImplementationVAO;
#endif #endif
glVertexAttribPointer(attribute.location, attribute.count, static_cast<GLenum>(attribute.type), GL_FALSE, attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
} }
} }
void Mesh::createImplementationDefault() {}
#ifndef MAGNUM_TARGET_GLES
void Mesh::createImplementationVAO() {
glGenVertexArrays(1, &vao);
}
#endif #endif
void Mesh::addVertexAttribute(Buffer* buffer, GLuint location, GLint count, Type type, GLintptr offset, GLsizei stride) { void Mesh::destroyImplementationDefault() {}
CORRADE_ASSERT(_vertexCount != 0, "Mesh: vertex count must be set before binding attributes", );
attributes.push_back({ #ifndef MAGNUM_TARGET_GLES
buffer, void Mesh::destroyImplementationVAO() {
location, glDeleteVertexArrays(1, &vao);
count,
type,
offset,
stride
});
} }
#endif
void Mesh::bindAttributeImplementationDefault(const Attribute&) {}
#ifndef MAGNUM_TARGET_GLES
void Mesh::bindAttributeImplementationVAO(const Attribute& attribute) {
glBindVertexArray(vao);
vertexAttribPointer(attribute);
}
#endif
void Mesh::bindImplementationDefault() {
for(const Attribute& attribute: attributes)
vertexAttribPointer(attribute);
}
#ifndef MAGNUM_TARGET_GLES
void Mesh::bindImplementationVAO() {
glBindVertexArray(vao);
}
#endif
void Mesh::unbindImplementationDefault() {
for(const Attribute& attribute: attributes)
glDisableVertexAttribArray(attribute.location);
}
#ifndef MAGNUM_TARGET_GLES
void Mesh::unbindImplementationVAO() {
glBindVertexArray(0);
}
#endif
} }

132
src/Mesh.h

@ -27,6 +27,7 @@
namespace Magnum { namespace Magnum {
class Buffer; class Buffer;
class Context;
/** /**
@brief Base class for managing non-indexed meshes @brief Base class for managing non-indexed meshes
@ -77,8 +78,12 @@ mesh->setPrimitive(plane.primitive())
Basic workflow is to set up respective shader (see @ref AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation" for more infromation) and call Mesh::draw(). Basic workflow is to set up respective shader (see @ref AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation" for more infromation) and call Mesh::draw().
VAOs are used for desktop OpenGL (not in OpenGL ES). @section Mesh-performance-optimization Performance optimizations
@requires_gl30 Extension @extension{APPLE,vertex_array_object}
If @extension{APPLE,vertex_array_object} is supported, VAOs are used instead
of binding the buffers and specifying vertex attribute pointers in each
draw() call.
@requires_gl30 Extension @extension{EXT,gpu_shader4} (for unsigned integer attributes) @requires_gl30 Extension @extension{EXT,gpu_shader4} (for unsigned integer attributes)
@todo Support for normalized values (e.g. for color as char[4] passed to @todo Support for normalized values (e.g. for color as char[4] passed to
@ -90,6 +95,9 @@ VAOs are used for desktop OpenGL (not in OpenGL ES).
@todo Redo in a way that allows glMultiDrawArrays, glDrawArraysInstanced etc. @todo Redo in a way that allows glMultiDrawArrays, glDrawArraysInstanced etc.
*/ */
class MAGNUM_EXPORT Mesh { class MAGNUM_EXPORT Mesh {
friend class IndexedMesh;
friend class Context;
Mesh(const Mesh& other) = delete; Mesh(const Mesh& other) = delete;
Mesh& operator=(const Mesh& other) = delete; Mesh& operator=(const Mesh& other) = delete;
@ -331,12 +339,11 @@ class MAGNUM_EXPORT Mesh {
* @param primitive Primitive type * @param primitive Primitive type
* @param vertexCount Vertex count * @param vertexCount Vertex count
* *
* @see @fn_gl{GenVertexArrays}, setPrimitive(), setVertexCount() * @see setPrimitive(), setVertexCount(), @fn_gl{GenVertexArrays} (if
* @extension{APPLE,vertex_array_object} is available)
*/ */
inline Mesh(Primitive primitive = Primitive::Triangles, GLsizei vertexCount = 0): _primitive(primitive), _vertexCount(vertexCount), finalized(false) { inline Mesh(Primitive primitive = Primitive::Triangles, GLsizei vertexCount = 0): _primitive(primitive), _vertexCount(vertexCount) {
#ifndef MAGNUM_TARGET_GLES (this->*createImplementation)();
glGenVertexArrays(1, &vao);
#endif
} }
/** @brief Move constructor */ /** @brief Move constructor */
@ -345,20 +352,16 @@ class MAGNUM_EXPORT Mesh {
/** /**
* @brief Destructor * @brief Destructor
* *
* @see @fn_gl{DeleteVertexArrays} * @see @fn_gl{DeleteVertexArrays} (if
* @extension{APPLE,vertex_array_object} is available)
*/ */
inline virtual ~Mesh() { destroy(); } inline virtual ~Mesh() {
(this->*destroyImplementation)();
}
/** @brief Move assignment */ /** @brief Move assignment */
Mesh& operator=(Mesh&& other); Mesh& operator=(Mesh&& other);
/**
* @brief Whether the mesh is finalized
*
* When the mesh is finalized, no new attributes can be bound.
*/
inline bool isFinalized() const { return finalized; }
/** @brief Primitive type */ /** @brief Primitive type */
inline Primitive primitive() const { return _primitive; } inline Primitive primitive() const { return _primitive; }
@ -385,7 +388,6 @@ class MAGNUM_EXPORT Mesh {
*/ */
inline Mesh* setVertexCount(GLsizei vertexCount) { inline Mesh* setVertexCount(GLsizei vertexCount) {
_vertexCount = vertexCount; _vertexCount = vertexCount;
finalized = false;
attributes.clear(); attributes.clear();
return this; return this;
} }
@ -428,7 +430,10 @@ class MAGNUM_EXPORT Mesh {
* mesh, you must ensure it will exist for whole lifetime of the * mesh, you must ensure it will exist for whole lifetime of the
* mesh and delete it afterwards. * mesh and delete it afterwards.
* *
* @see addInterleavedVertexBuffer() * @see addInterleavedVertexBuffer(), @fn_gl{BindVertexArray},
* @fn_gl{EnableVertexAttribArray}, @fn_gl{BindBuffer},
* @fn_gl{VertexAttribPointer} (if
* @extension{APPLE,vertex_array_object} is available)
*/ */
template<class ...T> inline Mesh* addVertexBuffer(Buffer* buffer, const T&... attributes) { template<class ...T> inline Mesh* addVertexBuffer(Buffer* buffer, const T&... attributes) {
addVertexBufferInternal(buffer, 0, attributes...); addVertexBufferInternal(buffer, 0, attributes...);
@ -485,7 +490,10 @@ class MAGNUM_EXPORT Mesh {
* mesh, you must ensure it will exist for whole lifetime of the * mesh, you must ensure it will exist for whole lifetime of the
* mesh and delete it afterwards. * mesh and delete it afterwards.
* *
* @see addVertexBufferStride(), addVertexBuffer() * @see addVertexBufferStride(), addVertexBuffer(),
* @fn_gl{BindVertexArray}, @fn_gl{EnableVertexAttribArray},
* @fn_gl{BindBuffer}, @fn_gl{VertexAttribPointer} (if
* @extension{APPLE,vertex_array_object} is available)
*/ */
template<class ...T> inline Mesh* addInterleavedVertexBuffer(Buffer* buffer, GLintptr offset, const T&... attributes) { template<class ...T> inline Mesh* addInterleavedVertexBuffer(Buffer* buffer, GLintptr offset, const T&... attributes) {
addInterleavedVertexBufferInternal(buffer, offset, strideOfInterleaved(attributes...), attributes...); addInterleavedVertexBufferInternal(buffer, offset, strideOfInterleaved(attributes...), attributes...);
@ -505,42 +513,16 @@ class MAGNUM_EXPORT Mesh {
/** /**
* @brief Draw the mesh * @brief Draw the mesh
* *
* Expects an active shader with all uniforms set. * Expects an active shader with all uniforms set. See
* @see bind(), unbind(), finalize(), @fn_gl{DrawArrays} * @ref AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation"
* for more information.
* @see @fn_gl{EnableVertexAttribArray}, @fn_gl{BindBuffer},
* @fn_gl{VertexAttribPointer}, @fn_gl{DisableVertexAttribArray}
* or @fn_gl{BindVertexArray} (if @extension{APPLE,vertex_array_object}
* is available), @fn_gl{DrawArrays}
*/ */
virtual void draw(); virtual void draw();
protected:
/**
* @brief Bind all buffers
*
* @see @fn_gl{EnableVertexAttribArray}, @fn_gl{VertexAttribPointer}
*/
void bindBuffers();
/**
* @brief Bind vertex array or all buffers
*
* @see @fn_gl{BindVertexArray} or bindBuffers()
*/
void bind();
/**
* @brief Unbind vertex array or all buffers
*
* @see @fn_gl{BindVertexArray} or @fn_gl{DisableVertexAttribArray}
*/
void unbind();
/**
* @brief Finalize the mesh
*
* Computes location and stride of each attribute in its buffer. After
* this function is called, no new attribute can be bound.
* @see bindBuffers()
*/
MAGNUM_LOCAL void finalize();
private: private:
struct MAGNUM_LOCAL Attribute { struct MAGNUM_LOCAL Attribute {
Buffer* buffer; Buffer* buffer;
@ -551,6 +533,8 @@ class MAGNUM_EXPORT Mesh {
GLsizei stride; GLsizei stride;
}; };
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
/* Adding non-interleaved vertex attributes */ /* Adding non-interleaved vertex attributes */
template<GLuint location, class T, class ...U> inline void addVertexBufferInternal(Buffer* buffer, GLintptr offset, const AbstractShaderProgram::Attribute<location, T>&, const U&... attributes) { template<GLuint location, class T, class ...U> inline void addVertexBufferInternal(Buffer* buffer, GLintptr offset, const AbstractShaderProgram::Attribute<location, T>&, const U&... attributes) {
addVertexAttribute(buffer, location, TypeTraits<T>::count(), TypeTraits<T>::type(), offset, 0); addVertexAttribute(buffer, location, TypeTraits<T>::count(), TypeTraits<T>::type(), offset, 0);
@ -588,14 +572,52 @@ class MAGNUM_EXPORT Mesh {
void MAGNUM_EXPORT addVertexAttribute(Buffer* buffer, GLuint location, GLint count, Type type, GLintptr offset, GLsizei stride); void MAGNUM_EXPORT addVertexAttribute(Buffer* buffer, GLuint location, GLint count, Type type, GLintptr offset, GLsizei stride);
void destroy(); void MAGNUM_LOCAL bind();
inline void unbind() {
(this->*unbindImplementation)();
}
void MAGNUM_LOCAL vertexAttribPointer(const Attribute& attribute);
typedef void(Mesh::*CreateImplementation)();
void MAGNUM_LOCAL createImplementationDefault();
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
GLuint vao; void MAGNUM_LOCAL createImplementationVAO();
#endif
static CreateImplementation createImplementation;
typedef void(Mesh::*DestroyImplementation)();
void MAGNUM_LOCAL destroyImplementationDefault();
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL destroyImplementationVAO();
#endif #endif
static DestroyImplementation destroyImplementation;
typedef void(Mesh::*BindAttributeImplementation)(const Attribute&);
void MAGNUM_LOCAL bindAttributeImplementationDefault(const Attribute& attribute);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL bindAttributeImplementationVAO(const Attribute& attribute);
#endif
static MAGNUM_LOCAL BindAttributeImplementation bindAttributeImplementation;
typedef void(Mesh::*BindImplementation)();
void MAGNUM_LOCAL bindImplementationDefault();
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL bindImplementationVAO();
#endif
static MAGNUM_LOCAL BindImplementation bindImplementation;
typedef void(Mesh::*UnbindImplementation)();
void MAGNUM_LOCAL unbindImplementationDefault();
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL unbindImplementationVAO();
#endif
static MAGNUM_LOCAL UnbindImplementation unbindImplementation;
GLuint vao;
Primitive _primitive; Primitive _primitive;
GLsizei _vertexCount; GLsizei _vertexCount;
bool finalized;
std::vector<Attribute> attributes; std::vector<Attribute> attributes;
}; };

Loading…
Cancel
Save