Browse Source

Type-checked vertex attributes with type conversion possibility.

* Normalization of e.g. color components passed as unsigned byte to
   float values is possible.
 * BGRA vector component ordering is possible.
 * Proper type checking, allowing only GLSL-equivalent types to be used
   as attributes.
 * Reverted back to typedef'ing shader attributes, as type conversion
   can now be specified in constructor.
pull/7/head
Vladimír Vondruš 14 years ago
parent
commit
259a9f6666
  1. 322
      src/AbstractShaderProgram.h
  2. 114
      src/Mesh.cpp
  3. 197
      src/Mesh.h
  4. 7
      src/Shaders/PhongShader.cpp
  5. 4
      src/Shaders/PhongShader.h

322
src/AbstractShaderProgram.h

@ -21,8 +21,10 @@
#include <cstdint>
#include <string>
#include <Containers/EnumSet.h>
#include "Magnum.h"
#include "TypeTraits.h"
#include "magnumVisibility.h"
@ -37,8 +39,14 @@ namespace Math {
class Context;
class Shader;
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<class> struct Attribute;
}
#endif
/**
@brief Base class for shaders
@brief Base class for shader program implementations
@section AbstractShaderProgram-subclassing Subclassing workflow
@ -277,16 +285,146 @@ class MAGNUM_EXPORT AbstractShaderProgram {
/**
* @brief Base struct for attribute location and type
*
* See @ref AbstractShaderProgram-subclassing or Mesh::bindAttribute()
* for an example.
* Template parameter @p T is the type which is used for shader
* attribute, e.g. @ref Math::Vector4 "Vector4<GLint>" for `ivec4`.
* DataType is type of passed data when adding vertex buffers to mesh.
* By default it is the same as type used in shader (e.g.
* @ref DataType "DataType::Int" for @ref Math::Vector4 "Vector4<GLint>").
* It's also possible to pass integer data to floating-point shader
* inputs. In this case you may want to normalize the values (e.g.
* color components from 0-255 to 0.0f-1.0f) - see
* @ref DataOption "DataOption::Normalize".
*
* Only some types are allowed as attribute types, see
* @ref AbstractShaderProgram-types or TypeTraits::AttributeType for
* more information.
*
* @todo Support for BGRA attribute type (OpenGL 3.2, @extension{ARB,vertex_array_bgra})
* See @ref AbstractShaderProgram-subclassing for example usage in
* shaders and @ref Mesh-configuration for example usage when adding
* vertex buffers to mesh.
*/
template<GLuint i, class T> struct Attribute {
inline constexpr Attribute() = default;
static const GLuint Location = i; /**< Location to which the attribute is bound */
typedef T Type; /**< %Attribute type */
template<GLuint i, class T> class Attribute {
public:
/** @brief Location to which the attribute is bound */
static const GLuint Location = i;
/**
* @brief Type
*
* Type used in shader code.
* @see DataType
*/
typedef typename TypeTraits<T>::AttributeType Type;
/**
* @brief Data type
*
* Type of data passed to shader.
* @see Type, DataOptions, Attribute()
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
enum class DataType: GLenum {
UnsignedByte = GL_UNSIGNED_BYTE, /**< Unsigned byte */
Byte = GL_BYTE, /**< Byte */
UnsignedShort = GL_UNSIGNED_SHORT, /**< Unsigned short */
Short = GL_SHORT, /**< Short */
UnsignedInt = GL_UNSIGNED_INT, /**< Unsigned int */
Int = GL_INT, /**< Int */
/**
* Half float. Only for float attribute types.
* @requires_gl30 %Extension @extension{NV,half_float}
* @requires_gles30 %Extension @es_extension{OES,vertex_half_float}
*/
Half = GL_HALF_FLOAT,
/** Float. Only for float attribute types. */
Float = GL_FLOAT,
#ifndef MAGNUM_TARGET_GLES
/**
* Double. Only for float and double attribute types.
* @requires_gl Only floats are available in OpenGL ES.
*/
Double = GL_DOUBLE,
#endif
/* GL_FIXED not supported */
/**
* Unsigned 2.10.10.10 packed integer. Only for
* four-component float vector attribute type.
* @todo How about (incompatible) @es_extension{OES,vertex_type_10_10_10_2}?
* @requires_gl33 %Extension @extension{ARB,vertex_type_2_10_10_10_rev}
* @requires_gles30 (no extension providing this functionality)
*/
UnsignedInt2101010REV = GL_UNSIGNED_INT_2_10_10_10_REV,
/**
* Signed 2.10.10.10 packed integer. Only for
* four-component float vector attribute type.
* @requires_gl33 %Extension @extension{ARB,vertex_type_2_10_10_10_rev}
* @requires_gles30 (no extension providing this functionality)
*/
Int2101010REV = GL_INT_2_10_10_10_REV
};
#else
typedef typename Implementation::Attribute<T>::DataType DataType;
#endif
/**
* @brief Data option
* @see DataOptions, Attribute()
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
enum class DataOption: std::uint8_t {
/**
* Normalize integer components. Only for float attribute
* types. Default is to not normalize.
*/
Normalize = 1 << 0,
/**
* BGRA component ordering. Default is RGBA. Only for
* four-component float vector attribute type.
* @requires_gl32 %Extension @extension{ARB,vertex_array_bgra}
* @requires_gl Only RGBA component ordering is available
* on OpenGL ES.
*/
BGRA = 1 << 1
};
#else
typedef typename Implementation::Attribute<T>::DataOption DataOption;
#endif
/**
* @brief Data options
* @see Attribute()
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
typedef typename Corrade::Containers::EnumSet<DataOption, std::uint8_t> DataOptions;
#else
typedef typename Implementation::Attribute<T>::DataOptions DataOptions;
#endif
/**
* @brief Constructor
* @param dataType Type of passed data. Default is the
* same as type used in shader (e.g. DataType::Integer
* for Vector4<GLint>).
* @param dataOptions Data options. Default is no options.
*/
inline constexpr Attribute(DataType dataType = Implementation::Attribute<T>::DefaultDataType, DataOptions dataOptions = DataOptions()): _dataType(dataType), _dataOptions(dataOptions) {}
/** @brief Type of passed data */
inline constexpr DataType dataType() const { return _dataType; }
/** @brief Data options */
inline constexpr DataOptions dataOptions() const { return _dataOptions; }
private:
const DataType _dataType;
const DataOptions _dataOptions;
};
/**
@ -877,6 +1015,172 @@ class MAGNUM_EXPORT AbstractShaderProgram {
State state;
};
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<class> struct Attribute {};
template<> struct Attribute<GLfloat> {
enum class DataType: GLenum {
UnsignedByte = GL_UNSIGNED_BYTE,
Byte = GL_BYTE,
UnsignedShort = GL_UNSIGNED_SHORT,
Short = GL_SHORT,
UnsignedInt = GL_UNSIGNED_INT,
Int = GL_INT,
HalfFloat = GL_HALF_FLOAT,
Float = GL_FLOAT,
Double = GL_DOUBLE
};
enum class DataOption: std::uint8_t {
Normalized = 1 << 0
};
typedef Corrade::Containers::EnumSet<DataOption, std::uint8_t> DataOptions;
static const DataType DefaultDataType = DataType::Float;
inline constexpr static GLint size(DataOptions) { return 1; }
inline constexpr static std::size_t vectorCount() { return 1; }
};
CORRADE_ENUMSET_OPERATORS(Attribute<GLfloat>::DataOptions)
template<size_t vectorSize> struct Attribute<Math::Vector<vectorSize, GLfloat>>: public Attribute<GLfloat> {
inline constexpr static GLint size(DataOptions) { return vectorSize; }
inline constexpr static std::size_t vectorCount() { return 1; }
};
template<size_t cols, size_t rows> struct Attribute<Math::RectangularMatrix<cols, rows, GLfloat>>: public Attribute<GLfloat> {
inline constexpr static GLint size(DataOptions) { return rows; }
inline constexpr static std::size_t vectorCount() { return cols; }
};
template<size_t matrixSize> struct Attribute<Math::Matrix<matrixSize, GLfloat>>: public Attribute<GLfloat> {
inline constexpr static GLint size(DataOptions) { return matrixSize; }
inline constexpr static std::size_t vectorCount() { return matrixSize; }
};
template<> struct Attribute<Math::Vector<4, GLfloat>> {
enum class DataType: GLenum {
UnsignedByte = GL_UNSIGNED_BYTE,
Byte = GL_BYTE,
UnsignedShort = GL_UNSIGNED_SHORT,
Short = GL_SHORT,
UnsignedInt = GL_UNSIGNED_INT,
Int = GL_INT,
Half = GL_HALF_FLOAT,
Float = GL_FLOAT,
Double = GL_DOUBLE,
UnsignedAlpha2RGB10 = GL_UNSIGNED_INT_2_10_10_10_REV,
Alpha2RGB10 = GL_INT_2_10_10_10_REV
};
enum class DataOption: std::uint8_t {
Normalized = 1 << 0,
BGRA = 2 << 0
};
typedef Corrade::Containers::EnumSet<DataOption, std::uint8_t> DataOptions;
static const DataType DefaultDataType = DataType::Float;
inline constexpr static GLint size(DataOptions options) {
return options & DataOption::BGRA ? GL_BGRA : 4;
}
inline constexpr static std::size_t vectorCount() { return 1; }
};
typedef Math::Vector<4, GLfloat> _Vector4;
CORRADE_ENUMSET_OPERATORS(Attribute<_Vector4>::DataOptions)
template<> struct Attribute<GLint> {
enum class DataType: GLenum {
UnsignedByte = GL_UNSIGNED_BYTE,
Byte = GL_BYTE,
UnsignedShort = GL_UNSIGNED_SHORT,
Short = GL_SHORT,
UnsignedInt = GL_UNSIGNED_INT,
Int = GL_INT
};
enum class DataOption: std::uint8_t {};
typedef Corrade::Containers::EnumSet<DataOption, std::uint8_t> DataOptions;
static const DataType DefaultDataType = DataType::Int;
inline constexpr static GLint size() { return 1; }
};
template<> struct Attribute<GLuint> {
typedef Attribute<GLint>::DataType DataType;
typedef Attribute<GLint>::DataOption DataOption;
typedef Corrade::Containers::EnumSet<DataOption, std::uint8_t> DataOptions;
static const DataType DefaultDataType = DataType::UnsignedInt;
inline constexpr static GLint size() { return 1; }
};
template<size_t size> struct Attribute<Math::Vector<size, GLint>>: public Attribute<GLint> {
inline constexpr static GLint size() { return size; }
};
template<size_t size> struct Attribute<Math::Vector<size, GLuint>>: public Attribute<GLuint> {
inline constexpr static GLint size() { return size; }
};
template<> struct Attribute<GLdouble> {
enum class DataType: GLenum {
Double = GL_DOUBLE
};
enum class DataOption: std::uint8_t {};
typedef Corrade::Containers::EnumSet<DataOption, std::uint8_t> DataOptions;
static const DataType DefaultDataType = DataType::Double;
inline constexpr static GLint size() { return 1; }
inline constexpr static std::size_t vectorCount() { return 1; }
};
template<size_t cols, size_t rows> struct Attribute<Math::RectangularMatrix<cols, rows, GLdouble>>: public Attribute<GLdouble> {
inline constexpr static GLint size() { return rows; }
inline constexpr static std::size_t vectorCount() { return cols; }
};
template<size_t size> struct Attribute<Math::Matrix<size, GLdouble>>: public Attribute<GLdouble> {
inline constexpr static GLint size() { return size; }
inline constexpr static std::size_t vectorCount() { return size; }
};
template<size_t size> struct Attribute<Math::Vector<size, GLdouble>>: public Attribute<GLdouble> {
inline constexpr static GLint size() { return size; }
inline constexpr static std::size_t vectorCount() { return size; }
};
template<class T> struct Attribute<Math::Vector2<T>>: public Attribute<Math::Vector<2, T>> {};
template<class T> struct Attribute<Math::Vector3<T>>: public Attribute<Math::Vector<3, T>> {};
template<class T> struct Attribute<Math::Vector4<T>>: public Attribute<Math::Vector<4, T>> {};
template<class T> struct Attribute<Math::Point2D<T>>: public Attribute<Math::Vector3<T>> {};
template<class T> struct Attribute<Math::Point3D<T>>: public Attribute<Math::Vector4<T>> {};
template<class> class Color3;
template<class> class Color4;
template<class T> struct Attribute<Color3<T>>: public Attribute<Math::Vector3<T>> {};
template<class T> struct Attribute<Color4<T>>: public Attribute<Math::Vector4<T>> {};
template<class T> struct Attribute<Math::Matrix3<T>>: public Attribute<Math::Matrix<3, T>> {};
template<class T> struct Attribute<Math::Matrix4<T>>: public Attribute<Math::Matrix<4, T>> {};
}
#endif
}
#endif

114
src/Mesh.cpp

@ -29,7 +29,9 @@ namespace Magnum {
Mesh::CreateImplementation Mesh::createImplementation = &Mesh::createImplementationDefault;
Mesh::DestroyImplementation Mesh::destroyImplementation = &Mesh::destroyImplementationDefault;
Mesh::BindAttributeImplementation Mesh::bindAttributeImplementation = &Mesh::bindAttributeImplementationDefault;
Mesh::AttributePointerImplementation Mesh::attributePointerImplementation = &Mesh::attributePointerImplementationDefault;
Mesh::AttributeIPointerImplementation Mesh::attributeIPointerImplementation = &Mesh::attributePointerImplementationDefault;
Mesh::AttributeLPointerImplementation Mesh::attributeLPointerImplementation = &Mesh::attributePointerImplementationDefault;
Mesh::BindImplementation Mesh::bindImplementation = &Mesh::bindImplementationDefault;
Mesh::UnbindImplementation Mesh::unbindImplementation = &Mesh::unbindImplementationDefault;
@ -58,6 +60,16 @@ Mesh& Mesh::operator=(Mesh&& other) {
return *this;
}
Mesh* Mesh::setVertexCount(GLsizei vertexCount) {
_vertexCount = vertexCount;
attributes.clear();
#ifndef MAGNUM_TARGET_GLES
integerAttributes.clear();
longAttributes.clear();
#endif
return this;
}
void Mesh::draw() {
bind();
@ -78,34 +90,25 @@ void Mesh::bind() {
(this->*bindImplementation)();
}
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
});
(this->*bindAttributeImplementation)(attributes.back());
void Mesh::vertexAttribPointer(const Attribute& attribute) {
glEnableVertexAttribArray(attribute.location);
attribute.buffer->bind(Buffer::Target::Array);
glVertexAttribPointer(attribute.location, attribute.size, attribute.type, attribute.normalized, attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
}
void Mesh::vertexAttribPointer(const Mesh::Attribute& attribute) {
#ifndef MAGNUM_TARGET_GLES
void Mesh::vertexAttribPointer(const IntegerAttribute& attribute) {
glEnableVertexAttribArray(attribute.location);
attribute.buffer->bind(Buffer::Target::Array);
glVertexAttribIPointer(attribute.location, attribute.size, attribute.type, attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
}
#ifndef MAGNUM_TARGET_GLES
if(TypeInfo::isIntegral(attribute.type))
glVertexAttribIPointer(attribute.location, attribute.count, static_cast<GLenum>(attribute.type), attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
else if(attribute.type == Type::Double)
glVertexAttribLPointer(attribute.location, attribute.count, static_cast<GLenum>(attribute.type), attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
#endif
glVertexAttribPointer(attribute.location, attribute.count, static_cast<GLenum>(attribute.type), GL_FALSE, attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
void Mesh::vertexAttribPointer(const LongAttribute& attribute) {
glEnableVertexAttribArray(attribute.location);
attribute.buffer->bind(Buffer::Target::Array);
glVertexAttribLPointer(attribute.location, attribute.size, attribute.type, attribute.stride, reinterpret_cast<const GLvoid*>(attribute.offset));
}
#endif
void Mesh::initializeContextBasedFunctionality(Context* context) {
if(context->isExtensionSupported<Extensions::GL::APPLE::vertex_array_object>()) {
@ -117,8 +120,15 @@ void Mesh::initializeContextBasedFunctionality(Context* context) {
if(context->isExtensionSupported<Extensions::GL::EXT::direct_state_access>()) {
Debug() << "Mesg: using" << Extensions::GL::EXT::direct_state_access::string() << "features";
bindAttributeImplementation = &Mesh::bindAttributeImplementationDSA;
} else bindAttributeImplementation = &Mesh::bindAttributeImplementationVAO;
attributePointerImplementation = &Mesh::attributePointerImplementationDSA;
attributeIPointerImplementation = &Mesh::attributePointerImplementationDSA;
attributeLPointerImplementation = &Mesh::attributePointerImplementationDSA;
} else {
attributePointerImplementation = &Mesh::attributePointerImplementationVAO;
attributeIPointerImplementation = &Mesh::attributePointerImplementationVAO;
attributeLPointerImplementation = &Mesh::attributePointerImplementationVAO;
}
bindImplementation = &Mesh::bindImplementationVAO;
unbindImplementation = &Mesh::unbindImplementationVAO;
@ -142,29 +152,55 @@ void Mesh::destroyImplementationVAO() {
}
#endif
void Mesh::bindAttributeImplementationDefault(const Attribute&) {}
void Mesh::attributePointerImplementationDefault(const Attribute&) {}
#ifndef MAGNUM_TARGET_GLES
void Mesh::bindAttributeImplementationVAO(const Attribute& attribute) {
void Mesh::attributePointerImplementationVAO(const Attribute& attribute) {
bindVAO(vao);
vertexAttribPointer(attribute);
}
void Mesh::bindAttributeImplementationDSA(const Attribute& attribute) {
void Mesh::attributePointerImplementationDSA(const Attribute& attribute) {
glEnableVertexArrayAttribEXT(vao, attribute.location);
glVertexArrayVertexAttribOffsetEXT(vao, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.normalized, attribute.stride, attribute.offset);
}
#ifndef MAGNUM_TARGET_GLES
if(TypeInfo::isIntegral(attribute.type))
glVertexArrayVertexAttribIOffsetEXT(vao, attribute.buffer->id(), attribute.location, attribute.count, static_cast<GLenum>(attribute.type), attribute.stride, attribute.offset);
else if(attribute.type == Type::Double)
glVertexArrayVertexAttribLOffsetEXT(vao, attribute.buffer->id(), attribute.location, attribute.count, static_cast<GLenum>(attribute.type), attribute.stride, attribute.offset);
#endif
glVertexArrayVertexAttribOffsetEXT(vao, attribute.buffer->id(), attribute.location, attribute.count, static_cast<GLenum>(attribute.type), GL_FALSE, attribute.stride, attribute.offset);
void Mesh::attributePointerImplementationDefault(const IntegerAttribute&) {}
void Mesh::attributePointerImplementationVAO(const IntegerAttribute& attribute) {
bindVAO(vao);
vertexAttribPointer(attribute);
}
void Mesh::attributePointerImplementationDSA(const IntegerAttribute& attribute) {
glEnableVertexArrayAttribEXT(vao, attribute.location);
glVertexArrayVertexAttribIOffsetEXT(vao, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.stride, attribute.offset);
}
void Mesh::attributePointerImplementationDefault(const LongAttribute&) {}
void Mesh::attributePointerImplementationVAO(const LongAttribute& attribute) {
bindVAO(vao);
vertexAttribPointer(attribute);
}
void Mesh::attributePointerImplementationDSA(const LongAttribute& attribute) {
glEnableVertexArrayAttribEXT(vao, attribute.location);
glVertexArrayVertexAttribLOffsetEXT(vao, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.stride, attribute.offset);
}
#endif
void Mesh::bindImplementationDefault() {
for(const Attribute& attribute: attributes)
vertexAttribPointer(attribute);
#ifndef MAGNUM_TARGET_GLES
for(const IntegerAttribute& attribute: integerAttributes)
vertexAttribPointer(attribute);
for(const LongAttribute& attribute: longAttributes)
vertexAttribPointer(attribute);
#endif
}
#ifndef MAGNUM_TARGET_GLES
@ -176,6 +212,14 @@ void Mesh::bindImplementationVAO() {
void Mesh::unbindImplementationDefault() {
for(const Attribute& attribute: attributes)
glDisableVertexAttribArray(attribute.location);
#ifndef MAGNUM_TARGET_GLES
for(const IntegerAttribute& attribute: integerAttributes)
glDisableVertexAttribArray(attribute.location);
for(const LongAttribute& attribute: longAttributes)
glDisableVertexAttribArray(attribute.location);
#endif
}
#ifndef MAGNUM_TARGET_GLES

197
src/Mesh.h

@ -20,6 +20,7 @@
*/
#include <vector>
#include <Utility/Debug.h>
#include "AbstractShaderProgram.h"
#include "TypeTraits.h"
@ -30,7 +31,7 @@ class Buffer;
class Context;
/**
@brief Base class for managing non-indexed meshes
@brief Non-indexed mesh
@section Mesh-configuration Mesh configuration
@ -38,8 +39,8 @@ To properly configure mesh, you have to set primitive either in constructor or
using setPrimitive() and call setVertexCount(). Then create vertex buffers,
and them with vertex data. You can also use MeshTools::interleave() to
conveniently set vertex count and buffer data. At last assign them to mesh and
given shader locations using addVertexBuffer(), addInterleavedVertexBuffer()
or addVertexBufferStride().
@ref AbstractShaderProgram::Attribute "shader attributes" using
addVertexBuffer(), addInterleavedVertexBuffer() or addVertexBufferStride().
Note that the buffer is not managed (e.g. deleted on destruction) by the mesh,
so you have to manage it on your own. On the other hand it allows you to use
@ -49,6 +50,12 @@ shader) or store more than only vertex data in one buffer.
Example usage -- filling buffer with position data, configuring the mesh and
assigning the buffer to mesh to use with custom shader:
@code
class MyShader: public AbstractShaderProgram {
public:
typedef Attribute<0, Point3D> Position;
// ...
};
Buffer* buffer;
Mesh* mesh;
@ -59,11 +66,11 @@ buffer->setData(positions, Buffer::Usage::StaticDraw);
mesh->setPrimitve(Mesh::Primitive::Triangles)
->setVertexCount(30)
->addVertexBuffer(buffer, MyShader::Position);
->addVertexBuffer(buffer, MyShader::Position());
@endcode
Example usage -- creating a plane mesh and assigning buffer with interleaved
vertex attributes for use with phong shader:
vertex attributes for use with Shaders::PhongShader:
@code
Buffer* buffer;
Mesh* mesh;
@ -71,7 +78,22 @@ Mesh* mesh;
Primitives::Plane plane;
MeshTools::interleave(mesh, buffer, Buffer::Usage::StaticDraw, *plane.positions(0), *plane.normals(0));
mesh->setPrimitive(plane.primitive())
->addInterleavedVertexBuffer(buffer, 0, Shaders::PhongShader::Position, Shaders::PhongShader::Normal);
->addInterleavedVertexBuffer(buffer, 0, Shaders::PhongShader::Position(), Shaders::PhongShader::Normal());
@endcode
Example usage -- passing color attribute as normalized unsigned byte with BGRA
component ordering (e.g. directly from @ref Trade::TgaImporter "TGA file"):
@code
class MyShader: public AbstractShaderProgram {
public:
typedef Attribute<1, Color4<GLfloat>> Color;
// ...
};
Buffer* buffer;
Mesh* mesh;
mesh->addVertexBuffer(buffer, MyShader::Color(Type::UsignedByte, MyShader::Color::Normalized|MyShader::Color::BGRA));
@endcode
@section Mesh-drawing Rendering meshes
@ -91,16 +113,6 @@ calls to @fn_gl{BindBuffer} and @fn_gl{BindVertexArray}. See documentation of
addVertexBuffer(), addInterleavedVertexBuffer(), addVertexBufferStride() for
more information.
@requires_gles30 Integer attributes are not supported in OpenGL ES 2.0.
@requires_gl30 %Extension @extension{EXT,gpu_shader4} (for integer attributes)
@requires_gl Double attributes are supported only on Desktop OpenGL.
@requires_gl41 %Extension @extension{ARB,vertex_attrib_64bit} (for double attributes)
@todo The attributes can be specified with different type than in shader - how?
@todo Support for normalized values (e.g. for color as char[4] passed to
shader as floating-point vec4)
@todo Support for packed unsigned integer types for attributes (OpenGL 3.3, @extension{ARB,vertex_type_2_10_10_10_rev})
@todo Support for indirect draw buffer (OpenGL 4.0, @extension{ARB,draw_indirect})
@todo Redo in a way that allows glMultiDrawArrays, glDrawArraysInstanced etc.
*/
@ -394,18 +406,15 @@ class MAGNUM_EXPORT Mesh {
* addVertexBuffer()/addInterleavedVertexBuffer() afterwards.
* @see MeshTools::interleave()
*/
inline Mesh* setVertexCount(GLsizei vertexCount) {
_vertexCount = vertexCount;
attributes.clear();
return this;
}
Mesh* setVertexCount(GLsizei vertexCount);
/**
* @brief Add buffer with non-interleaved vertex attributes for use with given shader
*
* Attribute list is combination of attribute definitions (specified
* in implementation of given shader) and offsets between attribute
* arrays.
* Attribute list is combination of
* @ref AbstractShaderProgram::Attribute "attribute definitions"
* (specified in implementation of given shader) and offsets between
* attribute arrays.
*
* See @ref Mesh-configuration "class documentation" for simple usage
* example. For more involved example imagine that you have buffer
@ -419,17 +428,17 @@ class MAGNUM_EXPORT Mesh {
* Buffer* buffer;
* mesh->addVertexBuffer(buffer,
* 35, // skip other data
* Shaders::PhongShader::Position, // position array
* Shaders::PhongShader::Position(), // position array
* sizeof(Vector2)*mesh->vertexCount(), // skip texture coordinate array
* Shaders::PhongShader::Normal); // normal array
* Shaders::PhongShader::Normal()); // normal array
* @endcode
*
* Vou can also achieve the same effect by calling this function more
* times with absolute offsets:
* @code
* mesh->addVertexBuffer(buffer, 35, Shaders::PhongShader::Position);
* mesh->addVertexBuffer(buffer, 35, Shaders::PhongShader::Position());
* ->addVertexBuffer(buffer, 35 + (sizeof(Shaders::PhongShader::Position::Type) + sizeof(Vector2))*
* mesh->vertexCount(), Shaders::PhongShader::Normal);
* mesh->vertexCount(), Shaders::PhongShader::Normal());
* @endcode
*
* @attention Non-zero vertex count must be set before calling this
@ -446,6 +455,8 @@ class MAGNUM_EXPORT Mesh {
* if @extension{APPLE,vertex_array_object} is available
*/
template<class ...T> inline Mesh* addVertexBuffer(Buffer* buffer, const T&... attributes) {
CORRADE_ASSERT(_vertexCount != 0, "Mesh: vertex count must be set before binding attributes", this);
addVertexBufferInternal(buffer, 0, attributes...);
return this;
}
@ -454,7 +465,8 @@ class MAGNUM_EXPORT Mesh {
* @brief Add buffer with interleaved vertex attributes for use with given shader
*
* Parameter @p offset is offset of the interleaved array from the
* beginning, attribute list is combination of attribute definitions
* beginning, attribute list is combination of
* @ref AbstractShaderProgram::Attribute "attribute definitions"
* (specified in implementation of given shader) and offsets between
* attributes.
*
@ -470,32 +482,30 @@ class MAGNUM_EXPORT Mesh {
* Mesh* mesh;
* Buffer* buffer;
* mesh->addInterleavedVertexBuffer(buffer,
* 35, // skip other data
* sizeof(GLfloat), // skip vertex weight
* Shaders::PhongShader::Position, // vertex position
* sizeof(Vector2), // skip texture coordinates
* Shaders::PhongShader::Normal); // vertex normal
* 35, // skip other data
* sizeof(GLfloat), // skip vertex weight
* Shaders::PhongShader::Position(), // vertex position
* sizeof(Vector2), // skip texture coordinates
* Shaders::PhongShader::Normal()); // vertex normal
* @endcode
*
* You can also achieve the same effect by calling addVertexBufferStride()
* more times with absolute offset from the beginning and stride
* between vertex attributes:
* @code
* GLsizei stride = // size of one vertex
* GLsizei stride = // size of one vertex
* sizeof(GLfloat) +
* sizeof(Shaders::PhongShader::Position::Type) +
* sizeof(Vector2) +
* sizeof(Shaders::PhongShader::Normal::Type);
*
* mesh->addVertexBufferStride(buffer, 35 + sizeof(GLfloat),
* stride, Shaders::PhongShader::Position);
* stride, Shaders::PhongShader::Position());
* ->addVertexBufferStride(buffer, 35 + sizeof(GLfloat) +
* sizeof(Shaders::PhongShader::Position::Type) + sizeof(Vector2),
* stride, Shaders::PhongShader::Normal);
* stride, Shaders::PhongShader::Normal());
* @endcode
*
* @attention Non-zero vertex count must be set before calling this
* function.
* @attention The buffer passed as parameter is not managed by the
* mesh, you must ensure it will exist for whole lifetime of the
* mesh and delete it afterwards.
@ -536,20 +546,41 @@ class MAGNUM_EXPORT Mesh {
virtual void draw();
private:
#ifndef DOXYGEN_GENERATING_OUTPUT
struct MAGNUM_LOCAL Attribute {
Buffer* buffer;
GLuint location;
GLint count;
Type type;
GLint size;
GLenum type;
bool normalized;
GLintptr offset;
GLsizei stride;
};
struct MAGNUM_LOCAL IntegerAttribute {
Buffer* buffer;
GLuint location;
GLint size;
GLenum type;
GLintptr offset;
GLsizei stride;
};
struct MAGNUM_LOCAL LongAttribute {
Buffer* buffer;
GLuint location;
GLint size;
GLenum type;
GLintptr offset;
GLsizei stride;
};
#endif
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context);
/* 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) {
addVertexAttribute(buffer, location, TypeTraits<T>::count(), TypeTraits<T>::type(), offset, 0);
template<GLuint location, class T, class ...U> inline void addVertexBufferInternal(Buffer* buffer, GLintptr offset, const AbstractShaderProgram::Attribute<location, T>& attribute, const U&... attributes) {
addVertexAttribute(buffer, attribute, offset, 0);
/* Add size of this attribute array to offset for next attribute */
addVertexBufferInternal(buffer, offset+TypeTraits<T>::count()*TypeTraits<T>::size()*_vertexCount, attributes...);
@ -570,8 +601,8 @@ class MAGNUM_EXPORT Mesh {
inline static GLsizei strideOfInterleaved() { return 0; }
/* Adding interleaved vertex attributes */
template<GLuint location, class T, class ...U> inline void addInterleavedVertexBufferInternal(Buffer* buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute<location, T>&, const U&... attributes) {
addVertexAttribute(buffer, location, TypeTraits<T>::count(), TypeTraits<T>::type(), offset, stride);
template<GLuint location, class T, class ...U> inline void addInterleavedVertexBufferInternal(Buffer* buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute<location, T>& attribute, const U&... attributes) {
addVertexAttribute(buffer, attribute, offset, stride);
/* Add size of this attribute to offset for next attribute */
addInterleavedVertexBufferInternal(buffer, offset+TypeTraits<T>::count()*TypeTraits<T>::size(), stride, attributes...);
@ -582,7 +613,51 @@ class MAGNUM_EXPORT Mesh {
}
inline void addInterleavedVertexBufferInternal(Buffer*, GLsizei, GLintptr) {}
void MAGNUM_EXPORT addVertexAttribute(Buffer* buffer, GLuint location, GLint count, Type type, GLintptr offset, GLsizei stride);
template<GLuint location, class T> inline void addVertexAttribute(typename std::enable_if<std::is_same<typename TypeTraits<T>::AttributeType, GLfloat>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
for(GLuint i = 0; i != Implementation::Attribute<T>::vectorCount(); ++i) {
attributes.push_back({
buffer,
location+i,
Implementation::Attribute<T>::size(attribute.dataOptions()),
static_cast<GLenum>(attribute.dataType()),
!!(attribute.dataOptions() & AbstractShaderProgram::Attribute<location, T>::DataOption::Normalized),
offset,
stride
});
}
(this->*attributePointerImplementation)(attributes.back());
}
#ifndef MAGNUM_TARGET_GLES
template<GLuint location, class T> inline void addVertexAttribute(typename std::enable_if<std::is_integral<typename TypeTraits<T>::AttributeType>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
integerAttributes.push_back({
buffer,
location,
Implementation::Attribute<T>::size(),
static_cast<GLenum>(attribute.dataType()),
offset,
stride
});
(this->*attributeIPointerImplementation)(integerAttributes.back());
}
template<GLuint location, class T> inline void addVertexAttribute(typename std::enable_if<std::is_same<typename TypeTraits<T>::AttributeType, GLdouble>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute<location, T>& attribute, GLintptr offset, GLsizei stride) {
for(GLuint i = 0; i != Implementation::Attribute<T>::vectorCount(); ++i) {
longAttributes.push_back({
buffer,
location+i,
Implementation::Attribute<T>::size(),
static_cast<GLenum>(attribute.dataType()),
offset,
stride
});
(this->*attributeLPointerImplementation)(longAttributes.back());
}
}
#endif
static void MAGNUM_LOCAL bindVAO(GLuint vao);
@ -593,6 +668,10 @@ class MAGNUM_EXPORT Mesh {
}
void MAGNUM_LOCAL vertexAttribPointer(const Attribute& attribute);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL vertexAttribPointer(const IntegerAttribute& attribute);
void MAGNUM_LOCAL vertexAttribPointer(const LongAttribute& attribute);
#endif
typedef void(Mesh::*CreateImplementation)();
void MAGNUM_LOCAL createImplementationDefault();
@ -608,13 +687,27 @@ class MAGNUM_EXPORT Mesh {
#endif
static MAGNUM_LOCAL DestroyImplementation destroyImplementation;
typedef void(Mesh::*BindAttributeImplementation)(const Attribute&);
void MAGNUM_LOCAL bindAttributeImplementationDefault(const Attribute& attribute);
typedef void(Mesh::*AttributePointerImplementation)(const Attribute&);
void MAGNUM_LOCAL attributePointerImplementationDefault(const Attribute& attribute);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL attributePointerImplementationVAO(const Attribute& attribute);
void MAGNUM_LOCAL attributePointerImplementationDSA(const Attribute& attribute);
#endif
static AttributePointerImplementation attributePointerImplementation;
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL bindAttributeImplementationVAO(const Attribute& attribute);
void MAGNUM_LOCAL bindAttributeImplementationDSA(const Attribute& attribute);
typedef void(Mesh::*AttributeIPointerImplementation)(const IntegerAttribute&);
void MAGNUM_LOCAL attributePointerImplementationDefault(const IntegerAttribute& attribute);
void MAGNUM_LOCAL attributePointerImplementationVAO(const IntegerAttribute& attribute);
void MAGNUM_LOCAL attributePointerImplementationDSA(const IntegerAttribute& attribute);
static AttributeIPointerImplementation attributeIPointerImplementation;
typedef void(Mesh::*AttributeLPointerImplementation)(const LongAttribute&);
void MAGNUM_LOCAL attributePointerImplementationDefault(const LongAttribute& attribute);
void MAGNUM_LOCAL attributePointerImplementationVAO(const LongAttribute& attribute);
void MAGNUM_LOCAL attributePointerImplementationDSA(const LongAttribute& attribute);
static AttributeLPointerImplementation attributeLPointerImplementation;
#endif
static MAGNUM_LOCAL BindAttributeImplementation bindAttributeImplementation;
typedef void(Mesh::*BindImplementation)();
void MAGNUM_LOCAL bindImplementationDefault();
@ -635,6 +728,8 @@ class MAGNUM_EXPORT Mesh {
GLsizei _vertexCount;
std::vector<Attribute> attributes;
std::vector<IntegerAttribute> integerAttributes;
std::vector<LongAttribute> longAttributes;
};
}

7
src/Shaders/PhongShader.cpp

@ -22,9 +22,6 @@
namespace Magnum { namespace Shaders {
const PhongShader::Attribute<0, Point3D> PhongShader::Position;
const PhongShader::Attribute<1, Vector3> PhongShader::Normal;
PhongShader::PhongShader() {
Corrade::Utility::Resource rs("MagnumShaders");
Version v = Context::current()->isVersionSupported(Version::GL320) ? Version::GL320 : Version::GL210;
@ -32,8 +29,8 @@ PhongShader::PhongShader() {
attachShader(Shader::fromData(v, Shader::Type::Fragment, rs.get("PhongShader.frag")));
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::explicit_attrib_location>()) {
bindAttributeLocation(Position.Location, "position");
bindAttributeLocation(Normal.Location, "normal");
bindAttributeLocation(Position::Location, "position");
bindAttributeLocation(Normal::Location, "normal");
}
link();

4
src/Shaders/PhongShader.h

@ -35,8 +35,8 @@ otherwise falls back to GLSL 1.20.
*/
class SHADERS_EXPORT PhongShader: public AbstractShaderProgram {
public:
static const Attribute<0, Point3D> Position; /**< @brief Vertex position */
static const Attribute<1, Vector3> Normal; /**< @brief Normal direction */
typedef Attribute<0, Point3D> Position; /**< @brief Vertex position */
typedef Attribute<1, Vector3> Normal; /**< @brief Normal direction */
PhongShader();

Loading…
Cancel
Save