Browse Source

GL: allow to construct DynamicAttribute from VertexFormat.

pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
13c071a1aa
  1. 18
      doc/snippets/MagnumTrade.cpp
  2. 58
      src/Magnum/GL/Attribute.cpp
  3. 33
      src/Magnum/GL/Attribute.h
  4. 2
      src/Magnum/GL/CMakeLists.txt
  5. 149
      src/Magnum/GL/Test/AttributeTest.cpp
  6. 2
      src/Magnum/GL/Test/CMakeLists.txt
  7. 6
      src/Magnum/Trade/MeshData.h

18
doc/snippets/MagnumTrade.cpp

@ -277,17 +277,17 @@ GL::Mesh mesh{data.primitive()};
GL::Buffer vertices; GL::Buffer vertices;
vertices.setData(data.vertexData()); vertices.setData(data.vertexData());
/* Set up the position attribute */ /* Set up the position and normal attributes */
Shaders::Phong::Position position;
auto positionFormat = data.attributeFormat(Trade::MeshAttribute::Position);
if(positionFormat == VertexFormat::Vector2)
position = {Shaders::Phong::Position::Components::Two};
else if(positionFormat == VertexFormat::Vector3)
position = {Shaders::Phong::Position::Components::Three};
else Fatal{} << "Huh?";
mesh.addVertexBuffer(vertices, mesh.addVertexBuffer(vertices,
data.attributeOffset(Trade::MeshAttribute::Position), data.attributeOffset(Trade::MeshAttribute::Position),
data.attributeStride(Trade::MeshAttribute::Position), position); data.attributeStride(Trade::MeshAttribute::Position),
GL::DynamicAttribute{Shaders::Phong::Position{},
data.attributeFormat(Trade::MeshAttribute::Position)});
mesh.addVertexBuffer(vertices,
data.attributeOffset(Trade::MeshAttribute::Normal),
data.attributeStride(Trade::MeshAttribute::Normal),
GL::DynamicAttribute{Shaders::Phong::Normal{},
data.attributeFormat(Trade::MeshAttribute::Normal)});
// Set up other attributes ... // Set up other attributes ...

58
src/Magnum/GL/Attribute.cpp

@ -28,6 +28,8 @@
#include <Corrade/Utility/Assert.h> #include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Debug.h> #include <Corrade/Utility/Debug.h>
#include "Magnum/VertexFormat.h"
namespace Magnum { namespace GL { namespace Magnum { namespace GL {
Debug& operator<<(Debug& debug, const DynamicAttribute::Kind value) { Debug& operator<<(Debug& debug, const DynamicAttribute::Kind value) {
@ -467,4 +469,60 @@ Debug& operator<<(Debug& debug, const Attribute<Math::Vector<4, Float>>::DataTyp
} }
DynamicAttribute::DynamicAttribute(const Kind kind, UnsignedInt location, const VertexFormat format, GLint maxComponents): _kind{kind}, _location{location}, _components{Components(vertexFormatComponentCount(format))} {
/* Translate component type to a GL-specific value */
switch(vertexFormatComponentFormat(format)) {
#define _c(format) \
case VertexFormat::format: \
_dataType = DataType::format; \
break;
_c(UnsignedByte)
_c(Byte)
_c(UnsignedShort)
_c(Short)
_c(UnsignedInt)
_c(Int)
_c(Float)
#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2))
_c(Half)
#endif
#ifndef MAGNUM_TARGET_GLES
_c(Double)
#endif
#undef _c
/* Nothing else expected to be returned from
vertexFormatComponentFormat() */
default: CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
/* If the type is normalized, switch the type to GenericNormalized (if not
already), and check that the attribute isn't expected to be integral or
long */
if(isVertexFormatNormalized(format)) {
CORRADE_ASSERT(kind == Kind::Generic || kind == Kind::GenericNormalized,
"GL::DynamicAttribute: can't use" << format << "for a" << kind << "attribute", );
_kind = Kind::GenericNormalized;
/* Otherwise check that non-normalized types aren't used for attributes
that are expected to be normalized. Float is an exception. */
} else if(_dataType != DataType::Float) {
CORRADE_ASSERT(kind != Kind::GenericNormalized,
"GL::DynamicAttribute: can't use" << format << "for a normalized attribute", );
/* Finally, float data types can't be used for integer attributes */
} else {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(kind != Kind::Integral,
"GL::DynamicAttribute: can't use" << format << "for an integral attribute", );
#endif
}
#ifndef CORRADE_NO_DEBUG
/* Should pass also if maxComponents is GL_BGRA */
CORRADE_ASSERT(GLint(_components) <= maxComponents,
"GL::DynamicAttribute: can't use" << format << "for a" << maxComponents << Debug::nospace << "-component attribute", );
#else
static_cast<void>(maxComponents);
#endif
}
}} }}

33
src/Magnum/GL/Attribute.h

@ -346,7 +346,7 @@ location and base type. Note that unlike the compile-time specification, this
class doesn't do any sanity verification and leaves most of the responsibility class doesn't do any sanity verification and leaves most of the responsibility
on the user. on the user.
*/ */
class DynamicAttribute { class MAGNUM_GL_EXPORT DynamicAttribute {
public: public:
/** /**
* @brief Attribute kind * @brief Attribute kind
@ -543,6 +543,31 @@ class DynamicAttribute {
*/ */
template<UnsignedInt location_, class T> constexpr /*implicit*/ DynamicAttribute(const Attribute<location_, T>& attribute); template<UnsignedInt location_, class T> constexpr /*implicit*/ DynamicAttribute(const Attribute<location_, T>& attribute);
/**
* @brief Construct from a generic mesh attribute type
* @m_since_latest
*
* The @p type is expected to be compatible with @p kind --- i.e.,
* normalized or floating-point for @ref Kind::GenericNormalized,
* non-normalized for @ref Kind::Integral / @ref Kind::Long and
* integral for @ref Kind::Integral.
*/
explicit DynamicAttribute(Kind kind, UnsignedInt location, VertexFormat format): DynamicAttribute{kind, location, format, 4} {}
/**
* @brief Construct from a compile-time attribute with a generic mesh attribute type override
* @m_since_latest
*
* Extracts kind and location from passed @ref Attribute type and calls
* @ref DynamicAttribute(Kind, UnsignedInt, VertexFormat). Expects that
* @p type's component count is not larger than the component count
* defined in the @p Attribute type. Note that only the
* compile-time-defined properties of the @p Attribute type are used,
* the instance-specific data type, options and component count is
* ignored.
*/
template<UnsignedInt location_, class T> explicit DynamicAttribute(const Attribute<location_, T>&, VertexFormat format);
/** @brief Attribute kind */ /** @brief Attribute kind */
constexpr Kind kind() const { return _kind; } constexpr Kind kind() const { return _kind; }
@ -556,6 +581,10 @@ class DynamicAttribute {
constexpr DataType dataType() const { return _dataType; } constexpr DataType dataType() const { return _dataType; }
private: private:
/* Used by the constructor taking Attribute, defined in cpp to avoid
a dependency on <Magnum/Mesh.h> for the assertion */
explicit DynamicAttribute(Kind kind, UnsignedInt location, VertexFormat format, GLint maxComponents);
Kind _kind; Kind _kind;
UnsignedInt _location; UnsignedInt _location;
Components _components; Components _components;
@ -892,6 +921,8 @@ template<class T> struct Attribute<Math::Matrix4<T>>: Attribute<Math::Matrix<4,
template<UnsignedInt location_, class T> constexpr DynamicAttribute::DynamicAttribute(const Attribute<location_, T>& attribute): _kind{Implementation::kindFor<location_, T>(attribute.dataOptions())}, _location{location_}, _components{Components(GLint(attribute.components()))}, _dataType{DataType(GLenum(attribute.dataType()))} {} template<UnsignedInt location_, class T> constexpr DynamicAttribute::DynamicAttribute(const Attribute<location_, T>& attribute): _kind{Implementation::kindFor<location_, T>(attribute.dataOptions())}, _location{location_}, _components{Components(GLint(attribute.components()))}, _dataType{DataType(GLenum(attribute.dataType()))} {}
template<UnsignedInt location_, class T> DynamicAttribute::DynamicAttribute(const Attribute<location_, T>& attribute, const VertexFormat format): DynamicAttribute{Implementation::kindFor<location_, T>(attribute.dataOptions()), location_, format, GLint(Implementation::Attribute<T>::DefaultComponents)} {}
}} }}
#endif #endif

2
src/Magnum/GL/CMakeLists.txt

@ -27,7 +27,6 @@ set(MagnumGL_SRCS
AbstractObject.cpp AbstractObject.cpp
AbstractQuery.cpp AbstractQuery.cpp
AbstractShaderProgram.cpp AbstractShaderProgram.cpp
Attribute.cpp
Buffer.cpp Buffer.cpp
Context.cpp Context.cpp
DefaultFramebuffer.cpp DefaultFramebuffer.cpp
@ -56,6 +55,7 @@ set(MagnumGL_SRCS
set(MagnumGL_GracefulAssert_SRCS set(MagnumGL_GracefulAssert_SRCS
AbstractFramebuffer.cpp AbstractFramebuffer.cpp
AbstractTexture.cpp AbstractTexture.cpp
Attribute.cpp
CubeMapTexture.cpp CubeMapTexture.cpp
Mesh.cpp Mesh.cpp
MeshView.cpp MeshView.cpp

149
src/Magnum/GL/Test/AttributeTest.cpp

@ -27,6 +27,7 @@
#include <Corrade/TestSuite/Tester.h> #include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h> #include <Corrade/Utility/DebugStl.h>
#include "Magnum/VertexFormat.h"
#include "Magnum/GL/Attribute.h" #include "Magnum/GL/Attribute.h"
namespace Magnum { namespace GL { namespace Test { namespace { namespace Magnum { namespace GL { namespace Test { namespace {
@ -53,6 +54,23 @@ struct AttributeTest: TestSuite::Tester {
void attributeMatrixNxNd(); void attributeMatrixNxNd();
void attributeMatrixMxNd(); void attributeMatrixMxNd();
void attributeFromGenericFormat();
#ifndef MAGNUM_TARGET_GLES2
void attributeFromGenericFormatIntegral();
#endif
#ifndef MAGNUM_TARGET_GLES
void attributeFromGenericFormatLong();
#endif
void attributeFromGenericFormatEnableNormalized();
void attributeFromGenericFormatUnexpectedForNormalizedKind();
#ifndef MAGNUM_TARGET_GLES2
void attributeFromGenericFormatUnexpectedForIntegralKind();
#endif
#ifndef MAGNUM_TARGET_GLES
void attributeFromGenericFormatUnexpectedForLongKind();
#endif
void attributeFromGenericFormatTooManyComponents();
void debugComponents1(); void debugComponents1();
void debugComponents2(); void debugComponents2();
void debugComponents3(); void debugComponents3();
@ -98,6 +116,23 @@ AttributeTest::AttributeTest() {
&AttributeTest::attributeMatrixNxNd, &AttributeTest::attributeMatrixNxNd,
&AttributeTest::attributeMatrixMxNd, &AttributeTest::attributeMatrixMxNd,
&AttributeTest::attributeFromGenericFormat,
#ifndef MAGNUM_TARGET_GLES2
&AttributeTest::attributeFromGenericFormatIntegral,
#endif
#ifndef MAGNUM_TARGET_GLES
&AttributeTest::attributeFromGenericFormatLong,
#endif
&AttributeTest::attributeFromGenericFormatEnableNormalized,
&AttributeTest::attributeFromGenericFormatUnexpectedForNormalizedKind,
#ifndef MAGNUM_TARGET_GLES2
&AttributeTest::attributeFromGenericFormatUnexpectedForIntegralKind,
#endif
#ifndef MAGNUM_TARGET_GLES
&AttributeTest::attributeFromGenericFormatUnexpectedForLongKind,
#endif
&AttributeTest::attributeFromGenericFormatTooManyComponents,
&AttributeTest::debugComponents1, &AttributeTest::debugComponents1,
&AttributeTest::debugComponents2, &AttributeTest::debugComponents2,
&AttributeTest::debugComponents3, &AttributeTest::debugComponents3,
@ -491,6 +526,120 @@ void AttributeTest::attributeMatrixMxNd() {
#endif #endif
} }
void AttributeTest::attributeFromGenericFormat() {
DynamicAttribute a{DynamicAttribute::Kind::Generic, 3,
VertexFormat::UnsignedShort};
CORRADE_COMPARE(a.kind(), DynamicAttribute::Kind::Generic);
CORRADE_COMPARE(a.location(), 3);
CORRADE_COMPARE(a.components(), DynamicAttribute::Components::One);
CORRADE_COMPARE(a.dataType(), DynamicAttribute::DataType::UnsignedShort);
/* Check that compile-time attribs work too */
DynamicAttribute a2{Attribute<7, Vector3>{},
VertexFormat::UnsignedShort};
CORRADE_COMPARE(a2.kind(), DynamicAttribute::Kind::Generic);
CORRADE_COMPARE(a2.location(), 7);
CORRADE_COMPARE(a2.components(), DynamicAttribute::Components::One);
CORRADE_COMPARE(a2.dataType(), DynamicAttribute::DataType::UnsignedShort);
DynamicAttribute b{DynamicAttribute::Kind::GenericNormalized, 3,
VertexFormat::Vector2bNormalized};
CORRADE_COMPARE(b.kind(), DynamicAttribute::Kind::GenericNormalized);
CORRADE_COMPARE(b.location(), 3);
CORRADE_COMPARE(b.components(), DynamicAttribute::Components::Two);
CORRADE_COMPARE(b.dataType(), DynamicAttribute::DataType::Byte);
DynamicAttribute c{DynamicAttribute::Kind::Generic, 3,
VertexFormat::Vector4ui};
CORRADE_COMPARE(c.kind(), DynamicAttribute::Kind::Generic);
CORRADE_COMPARE(c.location(), 3);
CORRADE_COMPARE(c.components(), DynamicAttribute::Components::Four);
CORRADE_COMPARE(c.dataType(), DynamicAttribute::DataType::UnsignedInt);
/* This one shouldn't fail even though the normalization is (probably?)
ignored. Not exactly sure. */
DynamicAttribute d{DynamicAttribute::Kind::GenericNormalized, 3,
VertexFormat::Float};
CORRADE_COMPARE(d.kind(), DynamicAttribute::Kind::GenericNormalized);
CORRADE_COMPARE(d.location(), 3);
CORRADE_COMPARE(d.components(), DynamicAttribute::Components::One);
CORRADE_COMPARE(d.dataType(), DynamicAttribute::DataType::Float);
}
#ifndef MAGNUM_TARGET_GLES2
void AttributeTest::attributeFromGenericFormatIntegral() {
DynamicAttribute a{DynamicAttribute::Kind::Integral, 3,
VertexFormat::Vector3s};
CORRADE_COMPARE(a.kind(), DynamicAttribute::Kind::Integral);
CORRADE_COMPARE(a.location(), 3);
CORRADE_COMPARE(a.components(), DynamicAttribute::Components::Three);
CORRADE_COMPARE(a.dataType(), DynamicAttribute::DataType::Short);
}
#endif
#ifndef MAGNUM_TARGET_GLES
void AttributeTest::attributeFromGenericFormatLong() {
DynamicAttribute a{DynamicAttribute::Kind::Long, 15,
VertexFormat::Vector2d};
CORRADE_COMPARE(a.kind(), DynamicAttribute::Kind::Long);
CORRADE_COMPARE(a.location(), 15);
CORRADE_COMPARE(a.components(), DynamicAttribute::Components::Two);
CORRADE_COMPARE(a.dataType(), DynamicAttribute::DataType::Double);
}
#endif
void AttributeTest::attributeFromGenericFormatEnableNormalized() {
DynamicAttribute a{DynamicAttribute::Kind::Generic, 3,
VertexFormat::Vector3ubNormalized};
/* Generic is automatically switched to GenericNormalized */
CORRADE_COMPARE(a.kind(), DynamicAttribute::Kind::GenericNormalized);
CORRADE_COMPARE(a.location(), 3);
CORRADE_COMPARE(a.components(), DynamicAttribute::Components::Three);
CORRADE_COMPARE(a.dataType(), DynamicAttribute::DataType::UnsignedByte);
}
void AttributeTest::attributeFromGenericFormatUnexpectedForNormalizedKind() {
std::ostringstream out;
Error redirectError{&out};
DynamicAttribute{DynamicAttribute::Kind::GenericNormalized, 3,
VertexFormat::Int};
CORRADE_COMPARE(out.str(),
"GL::DynamicAttribute: can't use VertexFormat::Int for a normalized attribute\n");
}
#ifndef MAGNUM_TARGET_GLES2
void AttributeTest::attributeFromGenericFormatUnexpectedForIntegralKind() {
std::ostringstream out;
Error redirectError{&out};
DynamicAttribute{DynamicAttribute::Kind::Integral, 3,
VertexFormat::Vector2bNormalized};
DynamicAttribute{DynamicAttribute::Kind::Integral, 3,
VertexFormat::Vector3};
CORRADE_COMPARE(out.str(),
"GL::DynamicAttribute: can't use VertexFormat::Vector2bNormalized for a GL::DynamicAttribute::Kind::Integral attribute\n"
"GL::DynamicAttribute: can't use VertexFormat::Vector3 for an integral attribute\n");
}
#endif
#ifndef MAGNUM_TARGET_GLES
void AttributeTest::attributeFromGenericFormatUnexpectedForLongKind() {
std::ostringstream out;
Error redirectError{&out};
DynamicAttribute{DynamicAttribute::Kind::Long, 3,
VertexFormat::UnsignedShortNormalized};
CORRADE_COMPARE(out.str(),
"GL::DynamicAttribute: can't use VertexFormat::UnsignedShortNormalized for a GL::DynamicAttribute::Kind::Long attribute\n");
}
#endif
void AttributeTest::attributeFromGenericFormatTooManyComponents() {
std::ostringstream out;
Error redirectError{&out};
DynamicAttribute{Attribute<7, Vector2>{}, VertexFormat::Vector3};
CORRADE_COMPARE(out.str(),
"GL::DynamicAttribute: can't use VertexFormat::Vector3 for a 2-component attribute\n");
}
void AttributeTest::debugComponents1() { void AttributeTest::debugComponents1() {
typedef Attribute<3, Float> Attribute; typedef Attribute<3, Float> Attribute;

2
src/Magnum/GL/Test/CMakeLists.txt

@ -23,7 +23,7 @@
# DEALINGS IN THE SOFTWARE. # DEALINGS IN THE SOFTWARE.
# #
corrade_add_test(GLAttributeTest AttributeTest.cpp LIBRARIES MagnumGL) corrade_add_test(GLAttributeTest AttributeTest.cpp LIBRARIES MagnumGLTestLib)
corrade_add_test(GLAbstractShaderProgramTest AbstractShaderProgramTest.cpp LIBRARIES MagnumGL) corrade_add_test(GLAbstractShaderProgramTest AbstractShaderProgramTest.cpp LIBRARIES MagnumGL)
corrade_add_test(GLBufferTest BufferTest.cpp LIBRARIES MagnumGL) corrade_add_test(GLBufferTest BufferTest.cpp LIBRARIES MagnumGL)
corrade_add_test(GLContextTest ContextTest.cpp LIBRARIES MagnumGL) corrade_add_test(GLContextTest ContextTest.cpp LIBRARIES MagnumGL)

6
src/Magnum/Trade/MeshData.h

@ -373,7 +373,11 @@ cases, sometimes you may want to minimize the import time of a large model or
the imported data may be already in a well-optimized layout and format that you the imported data may be already in a well-optimized layout and format that you
want to preserve. The @ref MeshData class internally stores a contiguous blob want to preserve. The @ref MeshData class internally stores a contiguous blob
of data, which you can directly upload, and then use provided metadata to let of data, which you can directly upload, and then use provided metadata to let
the GPU know of the format and layout: the GPU know of the format and layout. Because there's a lot of possible types
of each attribute (floats, packed integers, ...), the @ref GL::DynamicAttribute
can accept a pair of @ref GL::Attribute defined by the shader and the actual
@ref VertexFormat, figuring out all properties such as component count and
element data type without having to explicitly handle all relevant types:
@snippet MagnumTrade.cpp MeshData-usage-advanced @snippet MagnumTrade.cpp MeshData-usage-advanced

Loading…
Cancel
Save