diff --git a/src/AbstractShaderProgram.h b/src/AbstractShaderProgram.h
index 5c2306051..bd0cdfaf9 100644
--- a/src/AbstractShaderProgram.h
+++ b/src/AbstractShaderProgram.h
@@ -44,12 +44,12 @@ class Shader;
This class is designed to be used via subclassing. Subclasses define these
functions and properties:
- - %Attribute location typedefs defining locations and types
- for attribute binding with Mesh::bindAttribute(), for example:
+ - %Attribute definitions with location and type for
+ configuring meshes, for example:
@code
-typedef Attribute<0, Point3D> Position;
-typedef Attribute<1, Vector3> Normal;
-typedef Attribute<2, Vector2> TextureCoords;
+static const Attribute<0, Point3D> Position;
+static const Attribute<1, Vector3> Normal;
+static const Attribute<2, Vector2> TextureCoordinates;
@endcode
@todoc Output attribute location (for bindFragmentDataLocationIndexed(),
referenced also from Framebuffer::mapDefaultForDraw() / Framebuffer::mapForDraw())
@@ -103,7 +103,7 @@ shader code, e.g.:
// or #extension GL_ARB_explicit_attrib_location: enable
layout(location = 0) in vec4 position;
layout(location = 1) in vec3 normal;
-layout(location = 2) in vec2 textureCoords;
+layout(location = 2) in vec2 textureCoordinates;
@endcode
Similarly for ouput attributes, you can also specify blend equation color
index for them (see Framebuffer::BlendFunction for more information about
@@ -131,9 +131,9 @@ attaching the shaders and linking the program:
@code
// Shaders attached...
-bindAttributeLocation(Position::Location, "position");
-bindAttributeLocation(Normal::Location, "normal");
-bindAttributeLocation(TextureCoords::Location, "textureCoords");
+bindAttributeLocation(Position.Location, "position");
+bindAttributeLocation(Normal.Location, "normal");
+bindAttributeLocation(TextureCoords.Location, "textureCoordinates");
bindFragmentDataLocationIndexed(0, 0, "color");
bindFragmentDataLocationIndexed(1, 1, "ambient");
@@ -185,10 +185,11 @@ setUniform(SpecularTextureUniform, SpecularTextureLayer);
@section AbstractShaderProgram-rendering-workflow Rendering workflow
-Basic workflow with %AbstractShaderProgram subclasses is: instancing the class
-(once at the beginning), then in draw event setting uniforms and marking the
-shader for use, binding required textures to their respective layers using
-AbstractTexture::bind(GLint) and calling Mesh::draw(). For example:
+Basic workflow with %AbstractShaderProgram subclasses is to instance the class
+and configuring attribute binding in meshes (see @ref Mesh-configuration "Mesh documentation"
+for more information) at the beginning, then in draw event setting uniforms
+and marking the shader for use, binding required textures to their respective
+layers using AbstractTexture::bind(GLint) and calling Mesh::draw(). Example:
@code
shader->setTransformation(transformation)
->setProjection(projection)
@@ -205,9 +206,9 @@ The engine tracks currently used shader program to avoid unnecessary calls to
@fn_gl{UseProgram}.
If extension @extension{ARB,separate_shader_objects} or
-@extension{EXT,direct_state_access} is available, uniform setting
-functions use DSA functions to avoid unnecessary calls to @fn_gl{UseProgram}.
-See setUniform(GLint, GLfloat) documentation for more information.
+@extension{EXT,direct_state_access} is available, uniform setting functions
+use DSA functions to avoid unnecessary calls to @fn_gl{UseProgram}. See
+setUniform(GLint, GLfloat) documentation for more information.
To achieve least state changes, set all uniforms in one run -- method chaining
comes in handy.
diff --git a/src/Mesh.cpp b/src/Mesh.cpp
index bd763af43..9c91ff31b 100644
--- a/src/Mesh.cpp
+++ b/src/Mesh.cpp
@@ -27,7 +27,7 @@ Mesh::Mesh(Mesh&& other):
#ifndef MAGNUM_TARGET_GLES
vao(other.vao),
#endif
- _primitive(other._primitive), _vertexCount(other._vertexCount), finalized(other.finalized), _buffers(other._buffers), _attributes(other._attributes)
+ _primitive(other._primitive), _vertexCount(other._vertexCount), finalized(other.finalized), attributes(other.attributes)
{
#ifndef MAGNUM_TARGET_GLES
other.vao = 0;
@@ -35,9 +35,6 @@ Mesh::Mesh(Mesh&& other):
}
void Mesh::destroy() {
- for(auto& it: _buffers)
- delete it.first;
-
#ifndef MAGNUM_TARGET_GLES
glDeleteVertexArrays(1, &vao);
#endif
@@ -52,8 +49,7 @@ Mesh& Mesh::operator=(Mesh&& other) {
_primitive = other._primitive;
_vertexCount = other._vertexCount;
finalized = other.finalized;
- _buffers = other._buffers;
- _attributes = other._attributes;
+ attributes = other.attributes;
#ifndef MAGNUM_TARGET_GLES
other.vao = 0;
@@ -62,13 +58,6 @@ Mesh& Mesh::operator=(Mesh&& other) {
return *this;
}
-Buffer* Mesh::addBuffer(BufferType interleaved) {
- Buffer* buffer = new Buffer(Buffer::Target::Array);
- _buffers.insert(make_pair(buffer, make_pair(interleaved, vector())));
-
- return buffer;
-}
-
void Mesh::draw() {
/* Vertex array must be bound before finalization */
#ifndef MAGNUM_TARGET_GLES
@@ -102,8 +91,8 @@ void Mesh::unbind() {
#ifndef MAGNUM_TARGET_GLES
glBindVertexArray(0);
#else
- for(set::const_iterator it = _attributes.begin(); it != _attributes.end(); ++it)
- glDisableVertexAttribArray(*it);
+ for(const Attribute& attribute: attributes)
+ glDisableVertexAttribArray(attribute.location);
#endif
}
@@ -111,45 +100,8 @@ void Mesh::finalize() {
/* Already finalized */
if(finalized) return;
- CORRADE_ASSERT(_vertexCount, "Mesh: the mesh has zero vertex count!", );
-
- /* Finalize attribute positions for every buffer */
- for(auto& it: _buffers) {
- /* Avoid confustion */
- bool interleaved = it.second.first == BufferType::Interleaved;
- vector& attributes = it.second.second;
-
- /* Interleaved buffer, set stride and position of first attribute */
- if(interleaved) {
- /* Set attribute position and compute stride */
- GLsizei stride = 0;
- for(vector::iterator ait = attributes.begin(); ait != attributes.end(); ++ait) {
- /* The attribute is positioned at the end of previous */
- ait->pointer = reinterpret_cast(stride);
-
- /* Add attribute size (per vertex) to stride */
- stride += ait->size*TypeInfo::sizeOf(ait->type);
- }
-
- /* Set computed stride for all attributes */
- for(vector::iterator ait = attributes.begin(); ait != attributes.end(); ++ait)
- ait->stride = stride;
-
- /* Non-interleaved buffer, set position of every attribute */
- } else {
- /* Set attribute position */
- GLsizei position = 0;
- for(vector::iterator ait = attributes.begin(); ait != attributes.end(); ++ait) {
- /* The attribute is positioned at the end of previous attribute array */
- ait->pointer = reinterpret_cast(position);
-
- /* Add attribute size (for all vertices) to position */
- position += ait->size*TypeInfo::sizeOf(ait->type)*_vertexCount;
- }
- }
- }
+ CORRADE_ASSERT((_vertexCount == 0) == attributes.empty(), "Mesh: vertex count is non-zero, but no attributes are bound", );
- /* Mesh is now finalized, attribute binding is not allowed */
finalized = true;
#ifndef MAGNUM_TARGET_GLES
@@ -158,46 +110,33 @@ void Mesh::finalize() {
}
void Mesh::bindBuffers() {
- /* Enable vertex arrays for all attributes */
- for(set::const_iterator it = _attributes.begin(); it != _attributes.end(); ++it)
- glEnableVertexAttribArray(*it);
-
- for(auto& it: _buffers) {
- /* Avoid confusion */
- vector& attributes = it.second.second;
-
- /* Bind buffer */
- it.first->bind();
-
- /* Bind all attributes to this buffer */
- for(vector::const_iterator ait = attributes.begin(); ait != attributes.end(); ++ait)
- #ifndef MAGNUM_TARGET_GLES
- if(TypeInfo::isIntegral(ait->type))
- glVertexAttribIPointer(ait->attribute, ait->size, static_cast(ait->type), ait->stride, ait->pointer);
- else
- #endif
- glVertexAttribPointer(ait->attribute, ait->size, static_cast(ait->type), GL_FALSE, ait->stride, ait->pointer);
+ /* Bind all attributes to this buffer */
+ for(const Attribute& attribute: attributes) {
+ glEnableVertexAttribArray(attribute.location);
+
+ attribute.buffer->bind(Buffer::Target::Array);
+
+ #ifndef MAGNUM_TARGET_GLES
+ if(TypeInfo::isIntegral(attribute.type))
+ glVertexAttribIPointer(attribute.location, attribute.count, static_cast(attribute.type), attribute.stride, reinterpret_cast(attribute.offset));
+ else
+ #endif
+ glVertexAttribPointer(attribute.location, attribute.count, static_cast(attribute.type), GL_FALSE, attribute.stride, reinterpret_cast(attribute.offset));
}
}
#endif
-void Mesh::bindAttribute(Buffer* buffer, GLuint attribute, GLint size, Type type) {
- /* The mesh is finalized or attribute is already bound, nothing to do */
- if(finalized || _attributes.find(attribute) != _attributes.end()) return;
-
- /* If buffer is not managed by this mesh, nothing to do */
- auto found = _buffers.find(buffer);
- if(found == _buffers.end()) return;
-
- Attribute a;
- a.attribute = attribute;
- a.size = size;
- a.type = type;
- a.stride = 0;
- a.pointer = nullptr;
-
- found->second.second.push_back(a);
- _attributes.insert(attribute);
+void Mesh::addVertexAttribute(Buffer* buffer, GLuint location, GLint count, Type type, GLintptr offset, GLsizei stride) {
+ CORRADE_ASSERT(_vertexCount != 0, "Mesh: vertex count must be set before binding attributes", );
+
+ attributes.push_back({
+ buffer,
+ location,
+ count,
+ type,
+ offset,
+ stride
+ });
}
}
diff --git a/src/Mesh.h b/src/Mesh.h
index 284346110..2e8aee8d0 100644
--- a/src/Mesh.h
+++ b/src/Mesh.h
@@ -19,11 +19,9 @@
* @brief Class Magnum::Mesh
*/
-#include