Browse Source

MeshTools: deprecate mesh/buffer-modifying vertex/index tools.

The point of this change is to allow greater flexibility and reduce
confusion.

When instanced meshes are implemented, MeshTools::interleave() can be
used for creating interleaved buffers with per-instance data and then
the call to Mesh::setCount() will be harmful and/or confusing, becuase
the user would in fact want to call Mesh::setInstanceCount() instead.
Similarly, MeshTools::compressIndices() can be used to create index
buffer for more than one mesh.

GL 4.4 has ARB_buffer_storage, which (in relatively distant future) will
mean that the current way of Buffer::setData() will be deprecated in
favor of Buffer::setStorage(), similarly as Texture::setStorage()
replaced Texture::setImage(). Thus any function which calls
Buffer::setData() internally is not future-proof.

The old MeshTools::compressIndices() and MeshTools::interleave()
overloads are marked as deprecated and will be removed in future
release.
pull/51/head
Vladimír Vondruš 12 years ago
parent
commit
51a14b9e0b
  1. 22
      src/Magnum/DebugTools/Implementation/AbstractShapeRenderer.cpp
  2. 3
      src/Magnum/DebugTools/ObjectRenderer.cpp
  3. 89
      src/Magnum/Mesh.h
  4. 43
      src/Magnum/MeshTools/Compile.cpp
  5. 47
      src/Magnum/MeshTools/CompressIndices.cpp
  6. 35
      src/Magnum/MeshTools/CompressIndices.h
  7. 84
      src/Magnum/MeshTools/Interleave.h
  8. 33
      src/Magnum/MeshTools/Test/CompressIndicesTest.cpp
  9. 23
      src/Magnum/MeshTools/Test/InterleaveTest.cpp

22
src/Magnum/DebugTools/Implementation/AbstractShapeRenderer.cpp

@ -59,8 +59,17 @@ template<> void create<2>(Trade::MeshData2D& data, Resource<Mesh>& meshResource,
/* Index buffer, if needed, if not, resource key doesn't have to be set */
if(data.isIndexed()) {
CORRADE_INTERNAL_ASSERT(indexBufferResource.key() != ResourceKey());
Containers::Array<char> indexData;
Mesh::IndexType indexType;
UnsignedInt indexStart, indexEnd;
std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(data.indices());
Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray);
MeshTools::compressIndices(*mesh, *indexBuffer, BufferUsage::StaticDraw, data.indices());
indexBuffer->setData(indexData, BufferUsage::StaticDraw);
mesh->setCount(data.indices().size())
.setIndexBuffer(*indexBuffer, 0, indexType, indexStart, indexEnd);
ResourceManager::instance().set(indexBufferResource.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
/* The mesh is not indexed, set proper vertex count */
@ -82,8 +91,17 @@ template<> void create<3>(Trade::MeshData3D& data, Resource<Mesh>& meshResource,
/* Index buffer, if needed, if not, resource key doesn't have to be set */
if(data.isIndexed()) {
CORRADE_INTERNAL_ASSERT(indexBufferResource.key() != ResourceKey());
Containers::Array<char> indexData;
Mesh::IndexType indexType;
UnsignedInt indexStart, indexEnd;
std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(data.indices());
Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray);
MeshTools::compressIndices(*mesh, *indexBuffer, BufferUsage::StaticDraw, data.indices());
indexBuffer->setData(indexData, BufferUsage::StaticDraw);
mesh->setCount(data.indices().size())
.setIndexBuffer(*indexBuffer, 0, indexType, indexStart, indexEnd);
ResourceManager::instance().set(indexBufferResource.key(), indexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
/* The mesh is not indexed, set proper vertex count */

3
src/Magnum/DebugTools/ObjectRenderer.cpp

@ -26,6 +26,7 @@
#include "ObjectRenderer.h"
#include "Magnum/Buffer.h"
#include "Magnum/Mesh.h"
#include "Magnum/DebugTools/ResourceManager.h"
#include "Magnum/MeshTools/Interleave.h"
#include "Magnum/SceneGraph/AbstractCamera.h"
@ -159,7 +160,7 @@ template<UnsignedInt dimensions> ObjectRenderer<dimensions>::ObjectRenderer(Scen
Buffer* indexBuffer = new Buffer(Buffer::Target::ElementArray);
Mesh* mesh = new Mesh;
MeshTools::interleave(*mesh, *vertexBuffer, BufferUsage::StaticDraw, Renderer<dimensions>::positions, Renderer<dimensions>::colors);
vertexBuffer->setData(MeshTools::interleave(Renderer<dimensions>::positions, Renderer<dimensions>::colors), BufferUsage::StaticDraw);
ResourceManager::instance().set(this->vertexBuffer.key(), vertexBuffer, ResourceDataState::Final, ResourcePolicy::Manual);
indexBuffer->setData(Renderer<dimensions>::indices, BufferUsage::StaticDraw);

89
src/Magnum/Mesh.h

@ -127,16 +127,15 @@ You have to specify at least primitive and vertex/index count using
data, add them to the mesh and specify
@ref AbstractShaderProgram::Attribute "shader attribute" layout inside the
buffers using @ref addVertexBuffer(). You can also use
@ref MeshTools::interleave() conveniently fill interleaved vertex buffer.
The function itself calls @ref setCount(), so you don't have to, but you still
have to specify the primitive using @ref setPrimitive() and the layout using
@ref addVertexBuffer().
@ref MeshTools::interleave() to conveniently interleave vertex data.
If you want indexed mesh, fill your index buffer with data and specify its
layout using @ref setIndexBuffer(). You can also use @ref MeshTools::compressIndices()
to conveniently compress the indices, fill the index buffer and configure the
mesh. It will call @ref setCount() and @ref setIndexBuffer(), so you don't have
to do anything else.
to conveniently compress the indices based on the range used.
There is also @ref MeshTools::compile() function which operates directly on
@ref Trade::MeshData2D / @ref Trade::MeshData3D and returns fully configured
mesh and vertex/index buffers for use with stock shaders.
Note that neither vertex buffers nor index buffer is managed (e.g. deleted on
destruction) by the mesh, so you have to manage them on your own and ensure
@ -159,19 +158,19 @@ class MyShader: public AbstractShaderProgram {
// ...
};
Buffer vertexBuffer;
Mesh mesh;
// Fill vertex buffer with position data
static constexpr Vector3 positions[30] = {
// ...
};
Buffer vertexBuffer;
vertexBuffer.setData(positions, BufferUsage::StaticDraw);
// Set primitive and vertex count, add the buffer and specify its layout
// Configure the mesh, add vertex buffer
Mesh mesh;
mesh.setPrimitive(MeshPrimitive::Triangles)
.setCount(30)
.addVertexBuffer(vertexBuffer, 0, MyShader::Position());
.addVertexBuffer(vertexBuffer, 0, MyShader::Position{});
@endcode
@subsubsection Mesh-configuration-examples-nonindexed-phong Interleaved vertex data
@ -179,17 +178,16 @@ mesh.setPrimitive(MeshPrimitive::Triangles)
@code
// Non-indexed primitive with positions and normals
Trade::MeshData3D plane = Primitives::Plane::solid();
Buffer vertexBuffer;
Mesh mesh;
// Fill vertex buffer with interleaved position and normal data
MeshTools::interleave(mesh, buffer, BufferUsage::StaticDraw,
plane.positions(0), plane.normals(0));
Buffer vertexBuffer;
vertexBuffer.setData(MeshTools::interleave(plane.positions(0), plane.normals(0)), BufferUsage::StaticDraw);
// Set primitive and specify layout of interleaved vertex buffer, vertex count
// has been already set by MeshTools::interleave()
// Configure the mesh, add vertex buffer
Mesh mesh;
mesh.setPrimitive(plane.primitive())
.addVertexBuffer(buffer, 0, Shaders::Phong::Position(), Shaders::Phong::Normal());
.setCount(plane.positions(0).size())
.addVertexBuffer(buffer, 0, Shaders::Phong::Position{}, Shaders::Phong::Normal{});
@endcode
@subsubsection Mesh-configuration-examples-indexed-phong Indexed mesh
@ -202,48 +200,60 @@ class MyShader: public AbstractShaderProgram {
// ...
};
Buffer vertexBuffer, indexBuffer;
Mesh mesh;
// Fill vertex buffer with position data
static constexpr Vector3 positions[300] = {
// ...
};
Buffer vertexBuffer;
vertexBuffer.setData(positions, BufferUsage::StaticDraw);
// Fill index buffer with index data
static constexpr GLubyte indices[75] = {
// ...
};
Buffer indexBuffer;
indexBuffer.setData(indices, BufferUsage::StaticDraw);
// Set primitive, index count, specify the buffers
// Configure the mesh, add both vertex and index buffer
Mesh mesh;
mesh.setPrimitive(MeshPrimitive::Triangles)
.setCount(75)
.addVertexBuffer(vertexBuffer, 0, MyShader::Position())
.addVertexBuffer(vertexBuffer, 0, MyShader::Position{})
.setIndexBuffer(indexBuffer, 0, Mesh::IndexType::UnsignedByte, 176, 229);
@endcode
Or using @ref MeshTools::interleave() and @ref MeshTools::compressIndices():
@code
// Indexed primitive
Trade::MeshData3D cube = Primitives::Cube::solid();
Buffer vertexBuffer, indexBuffer;
Mesh mesh;
// Fill vertex buffer with interleaved position and normal data
MeshTools::interleave(mesh, vertexBuffer, BufferUsage::StaticDraw,
cube.positions(0), cube.normals(0));
Buffer vertexBuffer;
vertexBuffer.setData(MeshTools::interleave(cube.positions(0), cube.normals(0)), BufferUsage::StaticDraw);
// Fill index buffer with compressed index data
MeshTools::compressIndices(mesh, indexBuffer, BufferUsage::StaticDraw,
cube.indices());
// Compress index data
Containers::Array<char> indexData;
Mesh::IndexType indexType;
UnsignedInt indexStart, indexEnd;
std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(cube.indices());
// Set primitive and specify layout of interleaved vertex buffer. Index count
// and index buffer has been already specified by MeshTools::compressIndices().
// Fill index buffer
Buffer indexBuffer;
indexBuffer.setData(data);
// Configure the mesh, add both vertex and index buffer
Mesh mesh;
mesh.setPrimitive(plane.primitive())
.addVertexBuffer(vertexBuffer, 0, Shaders::Phong::Position(), Shaders::Phong::Normal());
.setCount(cube.indices().size())
.addVertexBuffer(vertexBuffer, 0, Shaders::Phong::Position{}, Shaders::Phong::Normal{})
.setIndexBuffer(indexBuffer, 0, indexType, indexStart, indexEnd);
@endcode
Or, if you plan to use the mesh with stock shaders, you can just use
@ref MeshTools::compile().
@subsubsection Mesh-configuration-examples-data-options Specific formats of vertex data
@code
@ -255,34 +265,39 @@ class MyShader: public AbstractShaderProgram {
// ...
};
// Initial mesh configuration
Mesh mesh;
mesh.setPrimitive(...)
.setCount(30);
// Fill position buffer with positions specified as two-component XY (i.e.,
// no Z component, which is meant to be always 0)
Buffer positionBuffer;
Vector2 positions[30] = {
// ...
};
Buffer positionBuffer;
positionBuffer.setData(positions, BufferUsage::StaticDraw);
// Specify layout of positions buffer -- only two components, unspecified Z
// component will be automatically set to 0
mesh.addVertexBuffer(positionBuffer, 0,
MyShader::Position(MyShader::Position::Components::Two));
MyShader::Position{MyShader::Position::Components::Two});
// Fill color buffer with colors specified as four-byte BGRA (e.g. directly
// from TGA file)
Buffer colorBuffer;
GLubyte colors[4*30] = {
// ...
};
Buffer colorBuffer;
colorBuffer.setData(colors, BufferUsage::StaticDraw);
// Specify layout of color buffer -- BGRA, each component unsigned byte and we
// want to normalize them from [0, 255] to [0.0f, 1.0f]
mesh.addVertexBuffer(colorBuffer, 0, MyShader::Color(
mesh.addVertexBuffer(colorBuffer, 0, MyShader::Color{
MyShader::Color::Components::BGRA,
MyShader::Color::DataType::UnsignedByte,
MyShader::Color::DataOption::Normalized));
MyShader::Color::DataOption::Normalized});
@endcode
@section Mesh-drawing Rendering meshes

43
src/Magnum/MeshTools/Compile.cpp

@ -25,6 +25,7 @@
#include "Compile.h"
#include "Magnum/Buffer.h"
#include "Magnum/Math/Vector3.h"
#include "Magnum/MeshTools/CompressIndices.h"
#include "Magnum/MeshTools/Interleave.h"
@ -51,9 +52,7 @@ std::tuple<Mesh, std::unique_ptr<Buffer>, std::unique_ptr<Buffer>> compile(const
std::unique_ptr<Buffer> vertexBuffer{new Buffer{Buffer::Target::Array}};
/* Interleave positions */
std::size_t vertexCount;
Containers::Array<char> data;
std::tie(vertexCount, std::ignore, data) = MeshTools::interleave(
Containers::Array<char> data = MeshTools::interleave(
meshData.positions(0),
stride - sizeof(Shaders::Generic2D::Position::Type));
mesh.addVertexBuffer(*vertexBuffer, 0,
@ -73,16 +72,23 @@ std::tuple<Mesh, std::unique_ptr<Buffer>, std::unique_ptr<Buffer>> compile(const
}
/* Fill vertex buffer with interleaved data */
vertexBuffer->setData(data, BufferUsage::StaticDraw);
vertexBuffer->setData(data, usage);
/* Fill index buffer */
/* If indexed, fill index buffer and configure indexed mesh */
std::unique_ptr<Buffer> indexBuffer;
if(meshData.isIndexed()) {
Containers::Array<char> indexData;
Mesh::IndexType indexType;
UnsignedInt indexStart, indexEnd;
std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(meshData.indices());
indexBuffer.reset(new Buffer{Buffer::Target::ElementArray});
MeshTools::compressIndices(mesh, *indexBuffer, usage, meshData.indices());
indexBuffer->setData(data, usage);
mesh.setCount(meshData.indices().size())
.setIndexBuffer(*indexBuffer, 0, indexType, indexStart, indexEnd);
/* Else set proper vertex count */
} else mesh.setCount(vertexCount);
/* Else set vertex count */
} else mesh.setCount(meshData.positions(0).size());
return std::make_tuple(std::move(mesh), std::move(vertexBuffer), std::move(indexBuffer));
}
@ -106,9 +112,7 @@ std::tuple<Mesh, std::unique_ptr<Buffer>, std::unique_ptr<Buffer>> compile(const
std::unique_ptr<Buffer> vertexBuffer{new Buffer{Buffer::Target::Array}};
/* Interleave positions */
std::size_t vertexCount;
Containers::Array<char> data;
std::tie(vertexCount, std::ignore, data) = MeshTools::interleave(
Containers::Array<char> data = MeshTools::interleave(
meshData.positions(0),
stride - sizeof(Shaders::Generic3D::Position::Type));
mesh.addVertexBuffer(*vertexBuffer, 0,
@ -140,16 +144,23 @@ std::tuple<Mesh, std::unique_ptr<Buffer>, std::unique_ptr<Buffer>> compile(const
}
/* Fill vertex buffer with interleaved data */
vertexBuffer->setData(data, BufferUsage::StaticDraw);
vertexBuffer->setData(data, usage);
/* Fill index buffer */
/* If indexed, fill index buffer and configure indexed mesh */
std::unique_ptr<Buffer> indexBuffer;
if(meshData.isIndexed()) {
Containers::Array<char> indexData;
Mesh::IndexType indexType;
UnsignedInt indexStart, indexEnd;
std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(meshData.indices());
indexBuffer.reset(new Buffer{Buffer::Target::ElementArray});
MeshTools::compressIndices(mesh, *indexBuffer, usage, meshData.indices());
indexBuffer->setData(data, usage);
mesh.setCount(meshData.indices().size())
.setIndexBuffer(*indexBuffer, 0, indexType, indexStart, indexEnd);
/* Else set proper vertex count */
} mesh.setCount(vertexCount);
/* Else set vertex count */
} mesh.setCount(meshData.positions(0).size());
return std::make_tuple(std::move(mesh), std::move(vertexBuffer), std::move(indexBuffer));
}

47
src/Magnum/MeshTools/CompressIndices.cpp

@ -41,50 +41,53 @@ template<> constexpr Mesh::IndexType indexType<UnsignedByte>() { return Mesh::In
template<> constexpr Mesh::IndexType indexType<UnsignedShort>() { return Mesh::IndexType::UnsignedShort; }
template<> constexpr Mesh::IndexType indexType<UnsignedInt>() { return Mesh::IndexType::UnsignedInt; }
template<class T> inline std::tuple<std::size_t, Mesh::IndexType, Containers::Array<char>> compress(const std::vector<UnsignedInt>& indices) {
template<class T> inline std::pair<Containers::Array<char>, Mesh::IndexType> compress(const std::vector<UnsignedInt>& indices) {
Containers::Array<char> buffer(indices.size()*sizeof(T));
for(std::size_t i = 0; i != indices.size(); ++i) {
T index = static_cast<T>(indices[i]);
std::memcpy(buffer.begin()+i*sizeof(T), &index, sizeof(T));
}
return std::make_tuple(indices.size(), indexType<T>(), std::move(buffer));
return {std::move(buffer), indexType<T>()};
}
std::tuple<std::size_t, Mesh::IndexType, Containers::Array<char>> compressIndicesInternal(const std::vector<UnsignedInt>& indices, UnsignedInt max) {
switch(Math::log(256, max)) {
}
std::tuple<Containers::Array<char>, Mesh::IndexType, UnsignedInt, UnsignedInt> compressIndices(const std::vector<UnsignedInt>& indices) {
/** @todo Performance hint when range can be represented by smaller value? */
auto minmax = std::minmax_element(indices.begin(), indices.end());
std::pair<Containers::Array<char>, Mesh::IndexType> typeData;
switch(Math::log(256, *minmax.second)) {
case 0:
return compress<UnsignedByte>(indices);
typeData = compress<UnsignedByte>(indices);
break;
case 1:
return compress<UnsignedShort>(indices);
typeData = compress<UnsignedShort>(indices);
break;
case 2:
case 3:
return compress<UnsignedInt>(indices);
typeData = compress<UnsignedInt>(indices);
break;
default:
CORRADE_ASSERT(false, "MeshTools::compressIndices(): no type able to index" << max << "elements.", {});
CORRADE_ASSERT(false, "MeshTools::compressIndices(): no type able to index" << *minmax.second << "elements.", {});
}
}
}
std::tuple<std::size_t, Mesh::IndexType, Containers::Array<char>> compressIndices(const std::vector<UnsignedInt>& indices) {
return compressIndicesInternal(indices, *std::max_element(indices.begin(), indices.end()));
return std::make_tuple(std::move(typeData.first), typeData.second, *minmax.first, *minmax.second);
}
#ifdef MAGNUM_BUILD_DEPRECATED
void compressIndices(Mesh& mesh, Buffer& buffer, BufferUsage usage, const std::vector<UnsignedInt>& indices) {
auto minmax = std::minmax_element(indices.begin(), indices.end());
/** @todo Performance hint when range can be represented by smaller value? */
std::size_t indexCount;
Mesh::IndexType indexType;
Containers::Array<char> data;
std::tie(indexCount, indexType, data) = compressIndicesInternal(indices, *minmax.second);
Mesh::IndexType type;
UnsignedInt start, end;
std::tie(data, type, start, end) = compressIndices(indices);
mesh.setCount(indices.size())
.setIndexBuffer(buffer, 0, indexType, *minmax.first, *minmax.second);
buffer.setData(data, usage);
mesh.setCount(indices.size())
.setIndexBuffer(buffer, 0, type, start, end);
}
#endif
}}

35
src/Magnum/MeshTools/CompressIndices.h

@ -39,24 +39,34 @@ namespace Magnum { namespace MeshTools {
/**
@brief Compress vertex indices
@param indices Index array
@return Index count, type and compressed index array
@return Index range, type and compressed index array
This function takes index array and outputs them compressed to smallest
possible size. For example when your indices have maximum number 463, it's
wasteful to store them in array of 32bit integers, array of 16bit integers is
sufficient. Example usage:
sufficient.
Example usage:
@code
std::size_t indexCount;
std::vector<UnsignedInt> indices;
Containers::Array<char> indexData;
Mesh::IndexType indexType;
Containers::Array<char> data;
std::tie(indexCount, indexType, data) = MeshTools::compressIndices(indices);
@endcode
UnsignedInt indexStart, indexEnd;
std::tie(indexData, indexType, indexStart, indexEnd) = MeshTools::compressIndices(indices);
Buffer indexBuffer;
indexBuffer.setData(indexData, BufferUsage::StaticDraw);
See also @ref compressIndices(Mesh&, Buffer&, BufferUsage, const std::vector<UnsignedInt>&),
which writes the compressed data directly into index buffer of given mesh.
Mesh mesh;
mesh.setCount(indices.size())
.setIndexBuffer(indexBuffer, 0, indexType, indexStart, indexEnd);
@endcode
@todo Extract IndexType out of Mesh class
*/
std::tuple<std::size_t, Mesh::IndexType, Containers::Array<char>> MAGNUM_MESHTOOLS_EXPORT compressIndices(const std::vector<UnsignedInt>& indices);
std::tuple<Containers::Array<char>, Mesh::IndexType, UnsignedInt, UnsignedInt> MAGNUM_MESHTOOLS_EXPORT compressIndices(const std::vector<UnsignedInt>& indices);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief Compress vertex indices and write them to index buffer
@param mesh Output mesh
@ -64,14 +74,17 @@ std::tuple<std::size_t, Mesh::IndexType, Containers::Array<char>> MAGNUM_MESHTOO
@param usage Index buffer usage
@param indices Index array
@deprecated Use general-purpose
@ref Magnum::MeshTools::compressIndices(const std::vector<UnsignedInt>&) "compressIndices(const std::vector<UnsignedInt>&)"
instead.
The same as @ref compressIndices(const std::vector<UnsignedInt>&), but this
function writes the output to given buffer and calls @ref Mesh::setCount() and
@ref Mesh::setIndexBuffer(), thus you don't need to do anything else for mesh
index configuration.
@see @ref MeshTools::interleave(), @ref MeshTools::compile()
*/
void MAGNUM_MESHTOOLS_EXPORT compressIndices(Mesh& mesh, Buffer& buffer, BufferUsage usage, const std::vector<UnsignedInt>& indices);
#endif
}}

84
src/Magnum/MeshTools/Interleave.h

@ -30,12 +30,16 @@
*/
#include <cstring>
#include <vector>
#include <limits>
#include <tuple>
#include <Corrade/Containers/Array.h>
#include <Corrade/Utility/Assert.h>
#include "Magnum/Mesh.h"
#include "Magnum/Magnum.h"
#ifdef MAGNUM_BUILD_DEPRECATED
#include <tuple>
#include "Magnum/Buffer.h"
#include "Magnum/Mesh.h"
#endif
namespace Magnum { namespace MeshTools {
@ -94,20 +98,21 @@ template<class T, class ...U> void writeInterleaved(std::size_t stride, char* st
@brief %Interleave vertex attributes
This function takes list of attribute arrays and returns them interleaved, so
data for each attribute are in continuous place in memory. Returned tuple
contains attribute count, stride and data array. Deleting the data array is up
to the user.
data for each attribute are in continuous place in memory.
Size of the data buffer can be computed from attribute count and stride, as
shown below. Example usage:
Example usage:
@code
std::vector<Vector4> positions;
MeshPrimitive primitive;
std::vector<Vector3> positions;
std::vector<Vector2> textureCoordinates;
std::size_t attributeCount;
std::size_t stride;
Containers::Array<char> data;
std::tie(attributeCount, stride, data) = MeshTools::interleave(positions, textureCoordinates);
// ...
Buffer vertexBuffer;
vertexBuffer.setData(MeshTools::interleave(positions, textureCoordinates), BufferUsage::StaticDraw);
Mesh mesh;
mesh.setPrimitive(primitive)
.setCount(positions.count())
.addVertexBuffer(vertexBuffer, 0, MyShader::Position{}, MyShader::TextureCoordinates{});
@endcode
It's often desirable to align data for one vertex on 32bit boundaries. To
@ -116,10 +121,8 @@ achieve that, you can specify gaps between the attributes:
std::vector<Vector4> positions;
std::vector<UnsignedShort> weights;
std::vector<Color3ub> vertexColors;
std::size_t attributeCount;
std::size_t stride;
Containers::Array<char> data;
std::tie(attributeCount, stride, data) = MeshTools::interleave(positions, weights, 2, textureCoordinates, 1);
auto data = MeshTools::interleave(positions, weights, 2, textureCoordinates, 1);
@endcode
All gap bytes are set zero. This way vertex stride is 24 bytes, without gaps it
would be 21 bytes, causing possible performance loss.
@ -131,13 +134,13 @@ would be 21 bytes, causing possible performance loss.
for) and function `size()` returning count of elements. In most cases it
will be `std::vector` or `std::array`.
See also @ref interleave(Mesh&, Buffer&, BufferUsage, const T&...),
which writes the interleaved array directly into buffer of given mesh or
@ref interleaveInto() which writes the data into existing buffer instead of
creating new one.
@see @ref interleaveInto()
@todo remove `std::enable_if` when deprecated overloads are removed
*/
/* enable_if to avoid clash with overloaded function below */
template<class T, class ...U> typename std::enable_if<!std::is_same<T, Mesh>::value, std::tuple<std::size_t, std::size_t, Containers::Array<char>>>::type interleave(const T& first, const U&... next) {
template<class T, class ...U> typename std::enable_if<!std::is_same<T, Mesh>::value, Containers::Array<char>>::type
interleave(const T& first, const U&... next)
{
/* Compute buffer size and stride */
const std::size_t attributeCount = Implementation::AttributeCount{}(first, next...);
const std::size_t stride = Implementation::Stride{}(first, next...);
@ -147,10 +150,10 @@ template<class T, class ...U> typename std::enable_if<!std::is_same<T, Mesh>::va
Containers::Array<char> data = Containers::Array<char>::zeroInitialized(attributeCount*stride);
Implementation::writeInterleaved(stride, data.begin(), first, next...);
return std::make_tuple(attributeCount, stride, std::move(data));
return data;
/* Otherwise return nullptr */
} else return std::make_tuple(0, stride, nullptr);
} else return nullptr;
}
/**
@ -165,18 +168,17 @@ parameters.
arrays have the same size. The passed buffer must also be large enough to
contain the interleaved data.
*/
template<class T, class ...U> std::tuple<std::size_t, std::size_t> interleaveInto(Containers::ArrayReference<char> buffer, const T& first, const U&... next) {
template<class T, class ...U> void interleaveInto(Containers::ArrayReference<char> buffer, const T& first, const U&... next) {
/* Verify expected buffer size */
const std::size_t attributeCount = Implementation::AttributeCount{}(first, next...);
const std::size_t stride = Implementation::Stride{}(first, next...);
CORRADE_ASSERT(attributeCount*stride <= buffer.size(), "MeshTools::interleaveInto(): the data buffer is too small, expected" << attributeCount*stride << "but got" << buffer.size(), {});
CORRADE_ASSERT(attributeCount*stride <= buffer.size(), "MeshTools::interleaveInto(): the data buffer is too small, expected" << attributeCount*stride << "but got" << buffer.size(), );
/* Write data */
Implementation::writeInterleaved(stride, buffer.begin(), first, next...);
return std::make_tuple(attributeCount, stride);
}
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief %Interleave vertex attributes, write them to array buffer and configure the mesh
@param mesh Output mesh
@ -184,6 +186,10 @@ template<class T, class ...U> std::tuple<std::size_t, std::size_t> interleaveInt
@param usage Vertex buffer usage
@param attributes Attribute arrays and gaps
@deprecated Use general-purpose
@ref Magnum::MeshTools::interleave(const T&...) "interleave(const T&...)"
instead.
The same as @ref interleave(const T&, const U&...), but this function also
writes the output to given array buffer. If given mesh is not indexed, it also
updates vertex count in the mesh accordingly, so you don't have to call
@ -193,20 +199,19 @@ updates vertex count in the mesh accordingly, so you don't have to call
@ref Mesh::addVertexBuffer() on the mesh afterwards.
@see @ref compressIndices(), @ref compile()
@todo rework so Mesh & Buffer doesn't need to be included in header
*/
template<class ...T> void interleave(Mesh& mesh, Buffer& buffer, BufferUsage usage, const T&... attributes) {
Containers::Array<char> data;
std::size_t attributeCount;
std::tie(attributeCount, std::ignore, data) = interleave(attributes...);
if(!mesh.isIndexed()) mesh.setCount(attributeCount);
buffer.setData(data, usage);
template<class ...T> CORRADE_DEPRECATED("Use interleave(const T&...) instead") void interleave(Mesh& mesh, Buffer& buffer, BufferUsage usage, const T&... attributes) {
if(!mesh.isIndexed()) mesh.setCount(Implementation::AttributeCount{}(attributes...));
buffer.setData(interleave(attributes...), usage);
}
/**
@brief Write vertex attribute to array buffer and configure the mesh
@deprecated Use general-purpose
@ref Magnum::MeshTools::interleave(const T&...) "interleave(const T&...)"
instead.
Simplified specialization of the above function for only one attribute array,
equivalent to the following:
@code
@ -214,10 +219,11 @@ buffer.setData(attribute, usage);
if(!mesh.isIndexed()) mesh.setVertexCount(attribute.size());
@endcode
*/
template<class T> typename std::enable_if<!std::is_convertible<T, std::size_t>::value, void>::type interleave(Mesh& mesh, Buffer& buffer, BufferUsage usage, const T& attribute) {
template<class T> CORRADE_DEPRECATED("Use interleave(const T&...) instead") typename std::enable_if<!std::is_convertible<T, std::size_t>::value, void>::type interleave(Mesh& mesh, Buffer& buffer, BufferUsage usage, const T& attribute) {
if(!mesh.isIndexed()) mesh.setCount(attribute.size());
buffer.setData(attribute, usage);
}
#endif
}}

33
src/Magnum/MeshTools/Test/CompressIndicesTest.cpp

@ -47,27 +47,29 @@ CompressIndicesTest::CompressIndicesTest() {
}
void CompressIndicesTest::compressChar() {
std::size_t indexCount;
Mesh::IndexType indexType;
Containers::Array<char> data;
std::tie(indexCount, indexType, data) = MeshTools::compressIndices(
Mesh::IndexType type;
UnsignedInt start, end;
std::tie(data, type, start, end) = MeshTools::compressIndices(
std::vector<UnsignedInt>{1, 2, 3, 0, 4});
CORRADE_COMPARE(indexCount, 5);
CORRADE_VERIFY(indexType == Mesh::IndexType::UnsignedByte);
CORRADE_COMPARE(start, 0);
CORRADE_COMPARE(end, 4);
CORRADE_COMPARE(type, Mesh::IndexType::UnsignedByte);
CORRADE_COMPARE(std::vector<char>(data.begin(), data.end()),
(std::vector<char>{ 0x01, 0x02, 0x03, 0x00, 0x04 }));
}
void CompressIndicesTest::compressShort() {
std::size_t indexCount;
Mesh::IndexType indexType;
Containers::Array<char> data;
std::tie(indexCount, indexType, data) = MeshTools::compressIndices(
Mesh::IndexType type;
UnsignedInt start, end;
std::tie(data, type, start, end) = MeshTools::compressIndices(
std::vector<UnsignedInt>{1, 256, 0, 5});
CORRADE_COMPARE(indexCount, 4);
CORRADE_VERIFY(indexType == Mesh::IndexType::UnsignedShort);
CORRADE_COMPARE(start, 0);
CORRADE_COMPARE(end, 256);
CORRADE_COMPARE(type, Mesh::IndexType::UnsignedShort);
if(!Utility::Endianness::isBigEndian()) {
CORRADE_COMPARE(std::vector<char>(data.begin(), data.end()),
(std::vector<char>{ 0x01, 0x00,
@ -84,14 +86,15 @@ void CompressIndicesTest::compressShort() {
}
void CompressIndicesTest::compressInt() {
std::size_t indexCount;
Mesh::IndexType indexType;
Containers::Array<char> data;
std::tie(indexCount, indexType, data) = MeshTools::compressIndices(
Mesh::IndexType type;
UnsignedInt start, end;
std::tie(data, type, start, end) = MeshTools::compressIndices(
std::vector<UnsignedInt>{65536, 3, 2});
CORRADE_COMPARE(indexCount, 3);
CORRADE_VERIFY(indexType == Mesh::IndexType::UnsignedInt);
CORRADE_COMPARE(start, 2);
CORRADE_COMPARE(end, 65536);
CORRADE_COMPARE(type, Mesh::IndexType::UnsignedInt);
if(!Utility::Endianness::isBigEndian()) {
CORRADE_COMPARE(std::vector<char>(data.begin(), data.end()),

23
src/Magnum/MeshTools/Test/InterleaveTest.cpp

@ -87,16 +87,11 @@ void InterleaveTest::strideGaps() {
}
void InterleaveTest::write() {
std::size_t attributeCount;
std::size_t stride;
Containers::Array<char> data;
std::tie(attributeCount, stride, data) = MeshTools::interleave(
const Containers::Array<char> data = MeshTools::interleave(
std::vector<Byte>{0, 1, 2},
std::vector<Int>{3, 4, 5},
std::vector<Short>{6, 7, 8});
CORRADE_COMPARE(attributeCount, std::size_t(3));
CORRADE_COMPARE(stride, std::size_t(7));
if(!Utility::Endianness::isBigEndian()) {
CORRADE_COMPARE(std::vector<char>(data.begin(), data.end()), (std::vector<char>{
0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00,
@ -113,17 +108,11 @@ void InterleaveTest::write() {
}
void InterleaveTest::writeGaps() {
std::size_t attributeCount;
std::size_t stride;
Containers::Array<char> data;
std::tie(attributeCount, stride, data) = MeshTools::interleave(
const Containers::Array<char> data = MeshTools::interleave(
std::vector<Byte>{0, 1, 2}, 3,
std::vector<Int>{3, 4, 5},
std::vector<Short>{6, 7, 8}, 2);
CORRADE_COMPARE(attributeCount, std::size_t(3));
CORRADE_COMPARE(stride, std::size_t(12));
if(!Utility::Endianness::isBigEndian()) {
/* byte, _____________gap, int___________________, short_____, _______gap */
CORRADE_COMPARE(std::vector<char>(data.begin(), data.end()), (std::vector<char>{
@ -142,8 +131,6 @@ void InterleaveTest::writeGaps() {
}
void InterleaveTest::interleaveInto() {
std::size_t attributeCount;
std::size_t stride;
auto data = Containers::Array<char>::from(
0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77,
0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77,
@ -151,11 +138,7 @@ void InterleaveTest::interleaveInto() {
0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77, 0x11, 0x33, 0x55, 0x77
);
std::tie(attributeCount, stride) = MeshTools::interleaveInto(data,
2, std::vector<Int>{4, 5, 6, 7}, 1, std::vector<Short>{0, 1, 2, 3}, 3);
CORRADE_COMPARE(attributeCount, std::size_t{4});
CORRADE_COMPARE(stride, std::size_t{12});
MeshTools::interleaveInto(data, 2, std::vector<Int>{4, 5, 6, 7}, 1, std::vector<Short>{0, 1, 2, 3}, 3);
if(!Utility::Endianness::isBigEndian()) {
/* _______gap, int___________________, _gap, short_____, _____________gap */

Loading…
Cancel
Save