Browse Source

Trade: support mesh level import in AbstractImporter.

Similar to image mip level import, but this is largely left to be
importer-specific. For example PLY defines per-face data and sometimes
one might want to import them as-is, without them being turned into a
per-vertex property.
pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
9425c23d0a
  1. 33
      src/Magnum/Trade/AbstractImporter.cpp
  2. 55
      src/Magnum/Trade/AbstractImporter.h
  3. 120
      src/Magnum/Trade/Test/AbstractImporterTest.cpp

33
src/Magnum/Trade/AbstractImporter.cpp

@ -462,6 +462,16 @@ UnsignedInt AbstractImporter::meshCount() const {
UnsignedInt AbstractImporter::doMeshCount() const { return 0; } UnsignedInt AbstractImporter::doMeshCount() const { return 0; }
UnsignedInt AbstractImporter::meshLevelCount(const UnsignedInt id) {
CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::meshLevelCount(): no file opened", {});
CORRADE_ASSERT(id < doMeshCount(), "Trade::AbstractImporter::meshLevelCount(): index" << id << "out of range for" << doMeshCount() << "entries", {});
const UnsignedInt out = doMeshLevelCount(id);
CORRADE_ASSERT(out, "Trade::AbstractImporter::meshLevelCount(): implementation reported zero levels", {});
return out;
}
UnsignedInt AbstractImporter::doMeshLevelCount(UnsignedInt) { return 1; }
Int AbstractImporter::meshForName(const std::string& name) { Int AbstractImporter::meshForName(const std::string& name) {
CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::meshForName(): no file opened", {}); CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::meshForName(): no file opened", {});
return doMeshForName(name); return doMeshForName(name);
@ -477,10 +487,21 @@ std::string AbstractImporter::meshName(const UnsignedInt id) {
std::string AbstractImporter::doMeshName(UnsignedInt) { return {}; } std::string AbstractImporter::doMeshName(UnsignedInt) { return {}; }
Containers::Optional<MeshData> AbstractImporter::mesh(const UnsignedInt id) { Containers::Optional<MeshData> AbstractImporter::mesh(const UnsignedInt id, const UnsignedInt level) {
CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::mesh(): no file opened", {}); CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::mesh(): no file opened", {});
CORRADE_ASSERT(id < doMeshCount(), "Trade::AbstractImporter::mesh(): index" << id << "out of range for" << doMeshCount() << "entries", {}); CORRADE_ASSERT(id < doMeshCount(), "Trade::AbstractImporter::mesh(): index" << id << "out of range for" << doMeshCount() << "entries", {});
Containers::Optional<MeshData> mesh = doMesh(id); #ifndef CORRADE_NO_ASSERT
/* Check for the range only if requested level is nonzero, as
meshLevelCount() is expected to return >= 1. This is done to prevent
random assertions and messages from a doMeshLevelCount() to be printed
(which are unlikely, but let's be consistent with what image*D() does). */
if(level) {
const UnsignedInt levelCount = doMeshLevelCount(id);
CORRADE_ASSERT(levelCount, "Trade::AbstractImporter::mesh(): implementation reported zero levels", {});
CORRADE_ASSERT(level < levelCount, "Trade::AbstractImporter::mesh(): level" << level << "out of range for" << levelCount << "entries", {});
}
#endif
Containers::Optional<MeshData> mesh = doMesh(id, level);
CORRADE_ASSERT(!mesh || ( CORRADE_ASSERT(!mesh || (
(!mesh->_indexData.deleter() || mesh->_indexData.deleter() == Implementation::nonOwnedArrayDeleter || mesh->_indexData.deleter() == ArrayAllocator<char>::deleter) && (!mesh->_indexData.deleter() || mesh->_indexData.deleter() == Implementation::nonOwnedArrayDeleter || mesh->_indexData.deleter() == ArrayAllocator<char>::deleter) &&
(!mesh->_vertexData.deleter() || mesh->_vertexData.deleter() == Implementation::nonOwnedArrayDeleter || mesh->_vertexData.deleter() == ArrayAllocator<char>::deleter) && (!mesh->_vertexData.deleter() || mesh->_vertexData.deleter() == Implementation::nonOwnedArrayDeleter || mesh->_vertexData.deleter() == ArrayAllocator<char>::deleter) &&
@ -489,15 +510,15 @@ Containers::Optional<MeshData> AbstractImporter::mesh(const UnsignedInt id) {
return mesh; return mesh;
} }
Containers::Optional<MeshData> AbstractImporter::doMesh(UnsignedInt) { Containers::Optional<MeshData> AbstractImporter::doMesh(UnsignedInt, UnsignedInt) {
CORRADE_ASSERT(false, "Trade::AbstractImporter::mesh(): not implemented", {}); CORRADE_ASSERT(false, "Trade::AbstractImporter::mesh(): not implemented", {});
} }
Containers::Optional<MeshData> AbstractImporter::mesh(const std::string& name) { Containers::Optional<MeshData> AbstractImporter::mesh(const std::string& name, const UnsignedInt level) {
CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::mesh(): no file opened", {}); CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::mesh(): no file opened", {});
const Int id = doMeshForName(name); const Int id = doMeshForName(name);
if(id == -1) return {}; if(id == -1) return {};
return mesh(id); /* not doMesh(), so we get the checks also */ return mesh(id, level); /* not doMesh(), so we get the checks also */
} }
MeshAttribute AbstractImporter::meshAttributeForName(const std::string& name) { MeshAttribute AbstractImporter::meshAttributeForName(const std::string& name) {
@ -602,7 +623,7 @@ Containers::Optional<MeshData3D> AbstractImporter::mesh3D(const UnsignedInt id)
} }
Containers::Optional<MeshData3D> AbstractImporter::doMesh3D(const UnsignedInt id) { Containers::Optional<MeshData3D> AbstractImporter::doMesh3D(const UnsignedInt id) {
Containers::Optional<MeshData> out = doMesh(id); Containers::Optional<MeshData> out = doMesh(id, 0);
if(out) return MeshData3D{*out}; if(out) return MeshData3D{*out};
return Containers::NullOpt; return Containers::NullOpt;
} }

55
src/Magnum/Trade/AbstractImporter.h

@ -245,9 +245,9 @@ checked by the implementation:
there is any file opened. there is any file opened.
- All `do*()` implementations taking data ID as parameter are called only if - All `do*()` implementations taking data ID as parameter are called only if
the ID is from valid range. the ID is from valid range.
- For `doImage*()` and @p level parameter being nonzero, implementations are - For @ref doMesh() and `doImage*()` and @p level parameter being nonzero,
called only if it is from valid range. Level zero is always expected to be implementations are called only if it is from valid range. Level zero is
present and thus no check is done in that case. always expected to be present and thus no check is done in that case.
@m_class{m-block m-warning} @m_class{m-block m-warning}
@ -760,16 +760,27 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi
* @m_since_latest * @m_since_latest
* *
* Expects that a file is opened. * Expects that a file is opened.
* @see @ref meshLevelCount()
*/ */
UnsignedInt meshCount() const; UnsignedInt meshCount() const;
/**
* @brief Mesh level count
* @param id Mesh ID, from range [0, @ref meshCount()).
* @m_since_latest
*
* Always returns at least one level, import failures are deferred to
* @ref mesh(). Expects that a file is opened.
*/
UnsignedInt meshLevelCount(UnsignedInt id);
/** /**
* @brief Mesh ID for given name * @brief Mesh ID for given name
* @m_since_latest * @m_since_latest
* *
* If no mesh for given name exists, returns @cpp -1 @ce. Expects that * If no mesh for given name exists, returns @cpp -1 @ce. Expects that
* a file is opened. * a file is opened.
* @see @ref meshName(), @ref mesh(const std::string&) * @see @ref meshName(), @ref mesh(const std::string&, UnsignedInt)
*/ */
Int meshForName(const std::string& name); Int meshForName(const std::string& name);
@ -786,24 +797,30 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi
/** /**
* @brief Mesh * @brief Mesh
* @param id Mesh ID, from range [0, @ref meshCount()). * @param id Mesh ID, from range [0, @ref meshCount()).
* @param level Mesh level, from range [0, @ref meshLevelCount())
* @m_since_latest * @m_since_latest
* *
* Returns given mesh or @ref Containers::NullOpt if importing failed. * Returns given mesh or @ref Containers::NullOpt if importing failed.
* Expects that a file is opened. * The @p level parameter allows access to additional data and is
* @see @ref mesh(const std::string&) * largely left as importer-specific --- for example allowing access to
* per-instance, per-face or per-edge data. Expects that a file is
* opened.
* @see @ref mesh(const std::string&, UnsignedInt),
* @ref MeshPrimitive::Instances, @ref MeshPrimitive::Faces,
* @ref MeshPrimitive::Edges
*/ */
Containers::Optional<MeshData> mesh(UnsignedInt id); Containers::Optional<MeshData> mesh(UnsignedInt id, UnsignedInt level = 0);
/** /**
* @brief Mesh for given name * @brief Mesh for given name
* @m_since_latest * @m_since_latest
* *
* A convenience API combining @ref meshForName() and * A convenience API combining @ref meshForName() and
* @ref mesh(UnsignedInt). Returns @ref Containers::NullOpt either if * @ref mesh(UnsignedInt, UnsignedInt). Returns
* @ref meshForName() returns @cpp -1 @ce or if importing fails. * @ref Containers::NullOpt either if @ref meshForName() returns
* Expects that a file is opened. * @cpp -1 @ce or if importing fails. Expects that a file is opened.
*/ */
Containers::Optional<MeshData> mesh(const std::string& name); Containers::Optional<MeshData> mesh(const std::string& name, UnsignedInt level = 0);
/** /**
* @brief Mesh attribute for given name * @brief Mesh attribute for given name
@ -1403,6 +1420,20 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi
*/ */
virtual UnsignedInt doMeshCount() const; virtual UnsignedInt doMeshCount() const;
/**
* @brief Implementation for @ref meshLevelCount()
* @m_since_latest
*
* Default implementation returns @cpp 1 @ce. Similarly to all other
* `*Count()` functions, this function isn't expected to fail --- if an
* import error occus, this function should return @cpp 1 @ce and the
* error state should be returned from @ref mesh() instead.
*
* Deliberately not @cpp const @ce to allow plugins cache decoded
* data.
*/
virtual UnsignedInt doMeshLevelCount(UnsignedInt id);
/** /**
* @brief Implementation for @ref meshForName() * @brief Implementation for @ref meshForName()
* @m_since_latest * @m_since_latest
@ -1423,7 +1454,7 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi
* @brief Implementation for @ref mesh() * @brief Implementation for @ref mesh()
* @m_since_latest * @m_since_latest
*/ */
virtual Containers::Optional<MeshData> doMesh(UnsignedInt id); virtual Containers::Optional<MeshData> doMesh(UnsignedInt id, UnsignedInt level);
/** /**
* @brief Implementation for @ref meshAttributeForName() * @brief Implementation for @ref meshAttributeForName()

120
src/Magnum/Trade/Test/AbstractImporterTest.cpp

@ -171,6 +171,10 @@ struct AbstractImporterTest: TestSuite::Tester {
#endif #endif
void meshCountNotImplemented(); void meshCountNotImplemented();
void meshCountNoFile(); void meshCountNoFile();
void meshLevelCountNotImplemented();
void meshLevelCountNoFile();
void meshLevelCountOutOfRange();
void meshLevelCountZero();
void meshForNameNotImplemented(); void meshForNameNotImplemented();
void meshForNameNoFile(); void meshForNameNoFile();
void meshNameNotImplemented(); void meshNameNotImplemented();
@ -179,6 +183,7 @@ struct AbstractImporterTest: TestSuite::Tester {
void meshNotImplemented(); void meshNotImplemented();
void meshNoFile(); void meshNoFile();
void meshOutOfRange(); void meshOutOfRange();
void meshLevelOutOfRange();
void meshNonOwningDeleters(); void meshNonOwningDeleters();
void meshGrowableDeleters(); void meshGrowableDeleters();
void meshCustomIndexDataDeleter(); void meshCustomIndexDataDeleter();
@ -420,6 +425,10 @@ AbstractImporterTest::AbstractImporterTest() {
#endif #endif
&AbstractImporterTest::meshCountNotImplemented, &AbstractImporterTest::meshCountNotImplemented,
&AbstractImporterTest::meshCountNoFile, &AbstractImporterTest::meshCountNoFile,
&AbstractImporterTest::meshLevelCountNotImplemented,
&AbstractImporterTest::meshLevelCountNoFile,
&AbstractImporterTest::meshLevelCountOutOfRange,
&AbstractImporterTest::meshLevelCountZero,
&AbstractImporterTest::meshForNameNotImplemented, &AbstractImporterTest::meshForNameNotImplemented,
&AbstractImporterTest::meshForNameNoFile, &AbstractImporterTest::meshForNameNoFile,
&AbstractImporterTest::meshNameNotImplemented, &AbstractImporterTest::meshNameNotImplemented,
@ -428,6 +437,7 @@ AbstractImporterTest::AbstractImporterTest() {
&AbstractImporterTest::meshNotImplemented, &AbstractImporterTest::meshNotImplemented,
&AbstractImporterTest::meshNoFile, &AbstractImporterTest::meshNoFile,
&AbstractImporterTest::meshOutOfRange, &AbstractImporterTest::meshOutOfRange,
&AbstractImporterTest::meshLevelOutOfRange,
&AbstractImporterTest::meshNonOwningDeleters, &AbstractImporterTest::meshNonOwningDeleters,
&AbstractImporterTest::meshGrowableDeleters, &AbstractImporterTest::meshGrowableDeleters,
&AbstractImporterTest::meshCustomIndexDataDeleter, &AbstractImporterTest::meshCustomIndexDataDeleter,
@ -2239,6 +2249,10 @@ void AbstractImporterTest::mesh() {
void doClose() override {} void doClose() override {}
UnsignedInt doMeshCount() const override { return 8; } UnsignedInt doMeshCount() const override { return 8; }
UnsignedInt doMeshLevelCount(UnsignedInt id) override {
if(id == 7) return 3;
else return {};
}
Int doMeshForName(const std::string& name) override { Int doMeshForName(const std::string& name) override {
if(name == "eighth") return 7; if(name == "eighth") return 7;
else return -1; else return -1;
@ -2247,10 +2261,10 @@ void AbstractImporterTest::mesh() {
if(id == 7) return "eighth"; if(id == 7) return "eighth";
else return {}; else return {};
} }
Containers::Optional<MeshData> doMesh(UnsignedInt id) override { Containers::Optional<MeshData> doMesh(UnsignedInt id, UnsignedInt level) override {
/* Verify that initializer list is converted to an array with /* Verify that initializer list is converted to an array with
the default deleter and not something disallowed */ the default deleter and not something disallowed */
if(id == 7) return MeshData{MeshPrimitive::Points, nullptr, {MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3, nullptr}}, &state}; if(id == 7 && level == 2) return MeshData{MeshPrimitive::Points, nullptr, {MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3, nullptr}}, &state};
else return {}; else return {};
} }
} importer; } importer;
@ -2260,11 +2274,11 @@ void AbstractImporterTest::mesh() {
CORRADE_COMPARE(importer.meshName(7), "eighth"); CORRADE_COMPARE(importer.meshName(7), "eighth");
{ {
auto data = importer.mesh(7); auto data = importer.mesh(7, 2);
CORRADE_VERIFY(data); CORRADE_VERIFY(data);
CORRADE_COMPARE(data->importerState(), &state); CORRADE_COMPARE(data->importerState(), &state);
} { } {
auto data = importer.mesh("eighth"); auto data = importer.mesh("eighth", 2);
CORRADE_VERIFY(data); CORRADE_VERIFY(data);
CORRADE_COMPARE(data->importerState(), &state); CORRADE_COMPARE(data->importerState(), &state);
} { } {
@ -2289,8 +2303,8 @@ void AbstractImporterTest::meshDeprecatedFallback() {
if(id == 7) return "eighth"; if(id == 7) return "eighth";
else return {}; else return {};
} }
Containers::Optional<MeshData> doMesh(UnsignedInt id) override { Containers::Optional<MeshData> doMesh(UnsignedInt id, UnsignedInt level) override {
if(id == 7) return MeshData{MeshPrimitive::Points, nullptr, {MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3, nullptr}}, &state}; if(id == 7 && level == 0) return MeshData{MeshPrimitive::Points, nullptr, {MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3, nullptr}}, &state};
else return {}; else return {};
} }
} importer; } importer;
@ -2336,6 +2350,70 @@ void AbstractImporterTest::meshCountNoFile() {
CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::meshCount(): no file opened\n"); CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::meshCount(): no file opened\n");
} }
void AbstractImporterTest::meshLevelCountNotImplemented() {
struct: AbstractImporter {
ImporterFeatures doFeatures() const override { return {}; }
bool doIsOpened() const override { return true; }
void doClose() override {}
UnsignedInt doMeshCount() const override { return 8; }
} importer;
CORRADE_COMPARE(importer.meshLevelCount(7), 1);
}
void AbstractImporterTest::meshLevelCountNoFile() {
struct: AbstractImporter {
ImporterFeatures doFeatures() const override { return {}; }
bool doIsOpened() const override { return false; }
void doClose() override {}
} importer;
std::ostringstream out;
Error redirectError{&out};
importer.meshLevelCount(7);
CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::meshLevelCount(): no file opened\n");
}
void AbstractImporterTest::meshLevelCountOutOfRange() {
struct: AbstractImporter {
ImporterFeatures doFeatures() const override { return {}; }
bool doIsOpened() const override { return true; }
void doClose() override {}
UnsignedInt doMeshCount() const override { return 8; }
} importer;
std::ostringstream out;
Error redirectError{&out};
importer.meshLevelCount(8);
CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::meshLevelCount(): index 8 out of range for 8 entries\n");
}
void AbstractImporterTest::meshLevelCountZero() {
struct: AbstractImporter {
ImporterFeatures doFeatures() const override { return {}; }
bool doIsOpened() const override { return true; }
void doClose() override {}
UnsignedInt doMeshCount() const override { return 8; }
Int doMeshForName(const std::string&) override { return 0; }
UnsignedInt doMeshLevelCount(UnsignedInt) override { return 0; }
} importer;
std::ostringstream out;
Error redirectError{&out};
importer.meshLevelCount(7);
/* This should print a similar message instead of a confusing
"level 1 out of range for 0 entries" */
importer.mesh(7, 1);
importer.mesh("", 1);
CORRADE_COMPARE(out.str(),
"Trade::AbstractImporter::meshLevelCount(): implementation reported zero levels\n"
"Trade::AbstractImporter::mesh(): implementation reported zero levels\n"
"Trade::AbstractImporter::mesh(): implementation reported zero levels\n");
}
void AbstractImporterTest::meshForNameNotImplemented() { void AbstractImporterTest::meshForNameNotImplemented() {
struct: AbstractImporter { struct: AbstractImporter {
ImporterFeatures doFeatures() const override { return {}; } ImporterFeatures doFeatures() const override { return {}; }
@ -2451,6 +2529,26 @@ void AbstractImporterTest::meshOutOfRange() {
CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::mesh(): index 8 out of range for 8 entries\n"); CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::mesh(): index 8 out of range for 8 entries\n");
} }
void AbstractImporterTest::meshLevelOutOfRange() {
struct: AbstractImporter {
ImporterFeatures doFeatures() const override { return {}; }
bool doIsOpened() const override { return true; }
void doClose() override {}
UnsignedInt doMeshCount() const override { return 8; }
Int doMeshForName(const std::string&) override { return 0; }
UnsignedInt doMeshLevelCount(UnsignedInt) override { return 3; }
} importer;
std::ostringstream out;
Error redirectError{&out};
importer.mesh(7, 3);
importer.mesh("", 3);
CORRADE_COMPARE(out.str(),
"Trade::AbstractImporter::mesh(): level 3 out of range for 3 entries\n"
"Trade::AbstractImporter::mesh(): level 3 out of range for 3 entries\n");
}
void AbstractImporterTest::meshNonOwningDeleters() { void AbstractImporterTest::meshNonOwningDeleters() {
struct: AbstractImporter { struct: AbstractImporter {
ImporterFeatures doFeatures() const override { return {}; } ImporterFeatures doFeatures() const override { return {}; }
@ -2458,7 +2556,7 @@ void AbstractImporterTest::meshNonOwningDeleters() {
void doClose() override {} void doClose() override {}
UnsignedInt doMeshCount() const override { return 1; } UnsignedInt doMeshCount() const override { return 1; }
Containers::Optional<MeshData> doMesh(UnsignedInt) override { Containers::Optional<MeshData> doMesh(UnsignedInt, UnsignedInt) override {
return MeshData{MeshPrimitive::Triangles, return MeshData{MeshPrimitive::Triangles,
Containers::Array<char>{indexData, 1, Implementation::nonOwnedArrayDeleter}, MeshIndexData{MeshIndexType::UnsignedByte, indexData}, Containers::Array<char>{indexData, 1, Implementation::nonOwnedArrayDeleter}, MeshIndexData{MeshIndexType::UnsignedByte, indexData},
Containers::Array<char>{nullptr, 0, Implementation::nonOwnedArrayDeleter}, Containers::Array<char>{nullptr, 0, Implementation::nonOwnedArrayDeleter},
@ -2483,7 +2581,7 @@ void AbstractImporterTest::meshGrowableDeleters() {
void doClose() override {} void doClose() override {}
UnsignedInt doMeshCount() const override { return 1; } UnsignedInt doMeshCount() const override { return 1; }
Containers::Optional<MeshData> doMesh(UnsignedInt) override { Containers::Optional<MeshData> doMesh(UnsignedInt, UnsignedInt) override {
Containers::Array<char> indexData; Containers::Array<char> indexData;
Containers::arrayAppend<ArrayAllocator>(indexData, '\xab'); Containers::arrayAppend<ArrayAllocator>(indexData, '\xab');
Containers::Array<Vector3> vertexData; Containers::Array<Vector3> vertexData;
@ -2511,7 +2609,7 @@ void AbstractImporterTest::meshCustomIndexDataDeleter() {
UnsignedInt doMeshCount() const override { return 1; } UnsignedInt doMeshCount() const override { return 1; }
Int doMeshForName(const std::string&) override { return 0; } Int doMeshForName(const std::string&) override { return 0; }
Containers::Optional<MeshData> doMesh(UnsignedInt) override { Containers::Optional<MeshData> doMesh(UnsignedInt, UnsignedInt) override {
return MeshData{MeshPrimitive::Triangles, Containers::Array<char>{data, 1, [](char*, std::size_t) {}}, MeshIndexData{MeshIndexType::UnsignedByte, data}}; return MeshData{MeshPrimitive::Triangles, Containers::Array<char>{data, 1, [](char*, std::size_t) {}}, MeshIndexData{MeshIndexType::UnsignedByte, data}};
} }
@ -2536,7 +2634,7 @@ void AbstractImporterTest::meshCustomVertexDataDeleter() {
UnsignedInt doMeshCount() const override { return 1; } UnsignedInt doMeshCount() const override { return 1; }
Int doMeshForName(const std::string&) override { return 0; } Int doMeshForName(const std::string&) override { return 0; }
Containers::Optional<MeshData> doMesh(UnsignedInt) override { Containers::Optional<MeshData> doMesh(UnsignedInt, UnsignedInt) override {
return MeshData{MeshPrimitive::Triangles, Containers::Array<char>{nullptr, 0, [](char*, std::size_t) {}}, {MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3, nullptr}}}; return MeshData{MeshPrimitive::Triangles, Containers::Array<char>{nullptr, 0, [](char*, std::size_t) {}}, {MeshAttributeData{MeshAttribute::Position, VertexFormat::Vector3, nullptr}}};
} }
} importer; } importer;
@ -2559,7 +2657,7 @@ void AbstractImporterTest::meshCustomAttributesDeleter() {
UnsignedInt doMeshCount() const override { return 1; } UnsignedInt doMeshCount() const override { return 1; }
Int doMeshForName(const std::string&) override { return 0; } Int doMeshForName(const std::string&) override { return 0; }
Containers::Optional<MeshData> doMesh(UnsignedInt) override { Containers::Optional<MeshData> doMesh(UnsignedInt, UnsignedInt) override {
return MeshData{MeshPrimitive::Triangles, nullptr, Containers::Array<MeshAttributeData>{&positions, 1, [](MeshAttributeData*, std::size_t) {}}}; return MeshData{MeshPrimitive::Triangles, nullptr, Containers::Array<MeshAttributeData>{&positions, 1, [](MeshAttributeData*, std::size_t) {}}};
} }

Loading…
Cancel
Save