mirror of https://github.com/mosra/magnum.git
30 changed files with 1599 additions and 1 deletions
@ -0,0 +1,53 @@ |
|||||||
|
# |
||||||
|
# This file is part of Magnum. |
||||||
|
# |
||||||
|
# Copyright © 2010, 2011, 2012, 2013, 2014 |
||||||
|
# Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
# |
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
# copy of this software and associated documentation files (the "Software"), |
||||||
|
# to deal in the Software without restriction, including without limitation |
||||||
|
# the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
# and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
# Software is furnished to do so, subject to the following conditions: |
||||||
|
# |
||||||
|
# The above copyright notice and this permission notice shall be included |
||||||
|
# in all copies or substantial portions of the Software. |
||||||
|
# |
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
# DEALINGS IN THE SOFTWARE. |
||||||
|
# |
||||||
|
|
||||||
|
add_library(ObjImporterObjects OBJECT ObjImporter.cpp) |
||||||
|
if(NOT BUILD_STATIC OR BUILD_STATIC_PIC) |
||||||
|
set_target_properties(ObjImporterObjects PROPERTIES COMPILE_FLAGS "${CMAKE_SHARED_LIBRARY_CXX_FLAGS}") |
||||||
|
endif() |
||||||
|
|
||||||
|
add_plugin(ObjImporter ${MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR} |
||||||
|
ObjImporter.conf |
||||||
|
$<TARGET_OBJECTS:ObjImporterObjects> |
||||||
|
pluginRegistration.cpp) |
||||||
|
target_link_libraries(ObjImporter Magnum MagnumMeshTools) |
||||||
|
|
||||||
|
install(FILES ObjImporter.h DESTINATION ${MAGNUM_PLUGINS_INCLUDE_INSTALL_DIR}/ObjImporter) |
||||||
|
|
||||||
|
if(BUILD_TESTS) |
||||||
|
add_library(ObjImporterTestLib STATIC $<TARGET_OBJECTS:ObjImporterObjects>) |
||||||
|
target_link_libraries(ObjImporterTestLib Magnum MagnumMeshTools) |
||||||
|
|
||||||
|
# On Windows we need to install first and then run the tests to avoid "DLL |
||||||
|
# not found" hell, thus we need to install this too |
||||||
|
if(WIN32 AND NOT CMAKE_CROSSCOMPILING) |
||||||
|
install(TARGETS ObjImporterTestLib |
||||||
|
RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR} |
||||||
|
LIBRARY DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR} |
||||||
|
ARCHIVE DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) |
||||||
|
endif() |
||||||
|
|
||||||
|
add_subdirectory(Test) |
||||||
|
endif() |
||||||
@ -0,0 +1,408 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014 |
||||||
|
Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "ObjImporter.h" |
||||||
|
|
||||||
|
#include <fstream> |
||||||
|
#include <limits> |
||||||
|
#include <sstream> |
||||||
|
#include <unordered_map> |
||||||
|
#include <Corrade/Containers/Array.h> |
||||||
|
#include <Corrade/Utility/String.h> |
||||||
|
|
||||||
|
#include "Magnum/Math/Vector3.h" |
||||||
|
#include "Magnum/Trade/MeshData3D.h" |
||||||
|
#include <Magnum/Mesh.h> |
||||||
|
#include <Magnum/MeshTools/CombineIndexedArrays.h> |
||||||
|
#include <Magnum/MeshTools/Duplicate.h> |
||||||
|
|
||||||
|
namespace Magnum { namespace Trade { |
||||||
|
|
||||||
|
struct ObjImporter::File { |
||||||
|
std::unordered_map<std::string, UnsignedInt> meshesForName; |
||||||
|
std::vector<std::string> meshNames; |
||||||
|
std::vector<std::pair<std::streampos, std::streampos>> meshes; |
||||||
|
std::unique_ptr<std::istream> in; |
||||||
|
}; |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
void ignoreLine(std::istream& in) { |
||||||
|
in.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); |
||||||
|
} |
||||||
|
|
||||||
|
template<std::size_t size> Math::Vector<size, Float> extractFloatData(std::string str, Float* extra = nullptr) { |
||||||
|
std::vector<std::string> data = Utility::String::splitWithoutEmptyParts(str, ' '); |
||||||
|
if(data.size() < size || data.size() > size + (extra ? 1 : 0)) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): invalid float array size"; |
||||||
|
throw 0; |
||||||
|
} |
||||||
|
|
||||||
|
Math::Vector<size, Float> output; |
||||||
|
for(std::size_t i = 0; i != size; ++i) |
||||||
|
output[i] = std::stof(data[i]); |
||||||
|
|
||||||
|
if(data.size() == size+1) *extra = std::stof(data.back()); |
||||||
|
|
||||||
|
return output; |
||||||
|
} |
||||||
|
|
||||||
|
template<class T> void reindex(const std::vector<UnsignedInt>& indices, std::vector<T>& data) { |
||||||
|
/* Check that indices are in range */ |
||||||
|
for(UnsignedInt i: indices) if(i >= data.size()) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): index out of range"; |
||||||
|
throw 0; |
||||||
|
} |
||||||
|
|
||||||
|
data = MeshTools::duplicate(indices, data); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
ObjImporter::ObjImporter() = default; |
||||||
|
|
||||||
|
ObjImporter::ObjImporter(PluginManager::AbstractManager& manager, std::string plugin): AbstractImporter(manager, std::move(plugin)) {} |
||||||
|
|
||||||
|
ObjImporter::~ObjImporter() = default; |
||||||
|
|
||||||
|
auto ObjImporter::doFeatures() const -> Features { return Feature::OpenData; } |
||||||
|
|
||||||
|
void ObjImporter::doClose() { _file.reset(); } |
||||||
|
|
||||||
|
bool ObjImporter::doIsOpened() const { return !!_file; } |
||||||
|
|
||||||
|
void ObjImporter::doOpenFile(const std::string& filename) { |
||||||
|
/* Open file in *text* mode (to avoid \r handling) */ |
||||||
|
std::unique_ptr<std::istream> in{new std::ifstream{filename}}; |
||||||
|
if(!in->good()) { |
||||||
|
Error() << "Trade::ObjImporter::openFile(): cannot open file" << filename; |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
_file.reset(new File); |
||||||
|
_file->in = std::move(in); |
||||||
|
parseMeshNames(); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporter::doOpenData(Containers::ArrayReference<const unsigned char> data) { |
||||||
|
/* Open file in *text* mode (to avoid \r handling) */ |
||||||
|
_file.reset(new File); |
||||||
|
_file->in.reset(new std::istringstream{{reinterpret_cast<const char*>(data.begin()), data.size()}}); |
||||||
|
|
||||||
|
parseMeshNames(); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporter::parseMeshNames() { |
||||||
|
bool hasData = false; |
||||||
|
std::string name; |
||||||
|
std::streampos begin = 0; |
||||||
|
while(_file->in->good()) { |
||||||
|
/* The previous object ends at the beginning of this line */ |
||||||
|
const std::streampos end = _file->in->tellg(); |
||||||
|
|
||||||
|
/* Comment line */ |
||||||
|
if(_file->in->peek() == '#') { |
||||||
|
ignoreLine(*_file->in); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
/* Parse the keyword */ |
||||||
|
std::string keyword; |
||||||
|
*_file->in >> keyword; |
||||||
|
|
||||||
|
/* Object name */ |
||||||
|
if(keyword == "o") { |
||||||
|
/* If there was any previous object, this is name of new object,
|
||||||
|
save the previous one */ |
||||||
|
if(hasData) { |
||||||
|
if(!name.empty()) _file->meshesForName.emplace(name, _file->meshes.size()); |
||||||
|
_file->meshNames.emplace_back(std::move(name)); |
||||||
|
_file->meshes.emplace_back(begin, end); |
||||||
|
|
||||||
|
/* Otherwise it's the name of first object (there weren't any data
|
||||||
|
before) */ |
||||||
|
} else hasData = true; |
||||||
|
|
||||||
|
/* Get name of new object, the object then starts at the next line */ |
||||||
|
std::getline(*_file->in, name); |
||||||
|
name = Utility::String::trim(name); |
||||||
|
begin = _file->in->tellg(); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
/* If there are any data before the first name, it means that the first
|
||||||
|
object can be unnamed */ |
||||||
|
if(!hasData) for(const std::string& data: {"v", "vt", "vn", "p", "l", "f"}) { |
||||||
|
if(keyword == data) { |
||||||
|
hasData = true; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* Ignore the rest of the line */ |
||||||
|
ignoreLine(*_file->in); |
||||||
|
} |
||||||
|
|
||||||
|
/* Add also the last object */ |
||||||
|
_file->in->clear(); |
||||||
|
_file->in->seekg(0, std::ios::end); |
||||||
|
if(!name.empty()) _file->meshesForName.emplace(name, _file->meshes.size()); |
||||||
|
_file->meshNames.emplace_back(std::move(name)); |
||||||
|
_file->meshes.emplace_back(begin, _file->in->tellg()); |
||||||
|
} |
||||||
|
|
||||||
|
UnsignedInt ObjImporter::doMesh3DCount() const { return _file->meshes.size(); } |
||||||
|
|
||||||
|
Int ObjImporter::doMesh3DForName(const std::string& name) { |
||||||
|
const auto it = _file->meshesForName.find(name); |
||||||
|
return it == _file->meshesForName.end() ? -1 : it->second; |
||||||
|
} |
||||||
|
|
||||||
|
std::string ObjImporter::doMesh3DName(UnsignedInt id) { |
||||||
|
return _file->meshNames[id]; |
||||||
|
} |
||||||
|
|
||||||
|
std::optional<MeshData3D> ObjImporter::doMesh3D(UnsignedInt id) { |
||||||
|
/* Seek the file */ |
||||||
|
std::streampos begin, end; |
||||||
|
std::tie(begin, end) = _file->meshes[id]; |
||||||
|
_file->in->seekg(begin); |
||||||
|
|
||||||
|
std::optional<MeshPrimitive> primitive; |
||||||
|
std::vector<Vector3> positions; |
||||||
|
std::vector<std::vector<Vector2>> textureCoordinates; |
||||||
|
std::vector<std::vector<Vector3>> normals; |
||||||
|
std::vector<UnsignedInt> positionIndices; |
||||||
|
std::vector<UnsignedInt> textureCoordinateIndices; |
||||||
|
std::vector<UnsignedInt> normalIndices; |
||||||
|
|
||||||
|
try { while(_file->in->good() && _file->in->tellg() < end) { |
||||||
|
/* Ignore comments */ |
||||||
|
if(_file->in->peek() == '#') { |
||||||
|
ignoreLine(*_file->in); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
/* Get the line */ |
||||||
|
std::string line; |
||||||
|
std::getline(*_file->in, line); |
||||||
|
line = Utility::String::trim(line); |
||||||
|
|
||||||
|
/* Ignore empty lines */ |
||||||
|
if(line.empty()) continue; |
||||||
|
|
||||||
|
/* Split the line into keyword and contents */ |
||||||
|
const std::size_t keywordEnd = line.find(' '); |
||||||
|
const std::string keyword = line.substr(0, keywordEnd); |
||||||
|
const std::string contents = keywordEnd != std::string::npos ? |
||||||
|
Utility::String::ltrim(line.substr(keywordEnd+1)) : ""; |
||||||
|
|
||||||
|
/* Vertex position */ |
||||||
|
if(keyword == "v") { |
||||||
|
Float extra{1.0f}; |
||||||
|
const Vector3 data = extractFloatData<3>(contents, &extra); |
||||||
|
if(!Math::TypeTraits<Float>::equals(extra, 1.0f)) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): homogeneous coordinates are not supported"; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
positions.push_back(data); |
||||||
|
|
||||||
|
/* Texture coordinate */ |
||||||
|
} else if(keyword == "vt") { |
||||||
|
Float extra{0.0f}; |
||||||
|
const auto data = extractFloatData<2>(contents, &extra); |
||||||
|
if(!Math::TypeTraits<Float>::equals(extra, 0.0f)) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): 3D texture coordinates are not supported"; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
if(textureCoordinates.empty()) textureCoordinates.push_back({}); |
||||||
|
textureCoordinates.front().push_back(data); |
||||||
|
|
||||||
|
/* Normal */ |
||||||
|
} else if(keyword == "vn") { |
||||||
|
if(normals.empty()) normals.push_back({}); |
||||||
|
normals.front().push_back(extractFloatData<3>(contents)); |
||||||
|
|
||||||
|
/* Indices */ |
||||||
|
} else if(keyword == "p" || keyword == "l" || keyword == "f") { |
||||||
|
const std::vector<std::string> indexTuples = Utility::String::splitWithoutEmptyParts(contents, ' '); |
||||||
|
|
||||||
|
/* Points */ |
||||||
|
if(keyword == "p") { |
||||||
|
/* Check that we don't mix the primitives in one mesh */ |
||||||
|
if(primitive && primitive != MeshPrimitive::Points) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): mixed primitive" << *primitive << "and" << MeshPrimitive::Points; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
/* Check vertex count per primitive */ |
||||||
|
if(indexTuples.size() != 1) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): wrong index count for point"; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
primitive = MeshPrimitive::Points; |
||||||
|
|
||||||
|
/* Lines */ |
||||||
|
} else if(keyword == "l") { |
||||||
|
/* Check that we don't mix the primitives in one mesh */ |
||||||
|
if(primitive && primitive != MeshPrimitive::Lines) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): mixed primitive" << *primitive << "and" << MeshPrimitive::Lines; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
/* Check vertex count per primitive */ |
||||||
|
if(indexTuples.size() != 2) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): wrong index count for line"; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
primitive = MeshPrimitive::Lines; |
||||||
|
|
||||||
|
/* Faces */ |
||||||
|
} else if(keyword == "f") { |
||||||
|
/* Check that we don't mix the primitives in one mesh */ |
||||||
|
if(primitive && primitive != MeshPrimitive::Triangles) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): mixed primitive" << *primitive << "and" << MeshPrimitive::Triangles; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
/* Check vertex count per primitive */ |
||||||
|
if(indexTuples.size() < 3) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): wrong index count for triangle"; |
||||||
|
return std::nullopt; |
||||||
|
} else if(indexTuples.size() != 3) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): polygons are not supported"; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
primitive = MeshPrimitive::Triangles; |
||||||
|
|
||||||
|
} else CORRADE_ASSERT_UNREACHABLE(); |
||||||
|
|
||||||
|
for(const std::string& indexTuple: indexTuples) { |
||||||
|
std::vector<std::string> indices = Utility::String::split(indexTuple, '/'); |
||||||
|
if(indices.size() > 3) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): invalid index data"; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
/* Indices in OBJ file start from 1 */ |
||||||
|
|
||||||
|
/* Position indices */ |
||||||
|
positionIndices.push_back(std::stoul(indices[0])-1); |
||||||
|
|
||||||
|
/* Texture coordinates */ |
||||||
|
if(indices.size() == 2 || (indices.size() == 3 && !indices[1].empty())) |
||||||
|
textureCoordinateIndices.push_back(std::stoul(indices[1])-1); |
||||||
|
|
||||||
|
/* Normal indices */ |
||||||
|
if(indices.size() == 3) |
||||||
|
normalIndices.push_back(std::stoul(indices[2])-1); |
||||||
|
} |
||||||
|
|
||||||
|
/* Ignore unsupported keywords, error out on unknown keywords */ |
||||||
|
} else if(![&keyword](){ |
||||||
|
/* Using lambda to emulate for-else construct like in Python */ |
||||||
|
for(const std::string expected: {"mtllib", "usemtl", "g", "s"}) |
||||||
|
if(keyword == expected) return true; |
||||||
|
return false; |
||||||
|
}()) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): unknown keyword" << keyword; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
}} catch(std::exception) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): error while converting numeric data"; |
||||||
|
return std::nullopt; |
||||||
|
} catch(...) { |
||||||
|
/* Error message already printed */ |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
/* There should be at least indexed position data */ |
||||||
|
if(positions.empty() || positionIndices.empty()) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): incomplete position data"; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
/* If there are index data, there should be also vertex data (and also the other way) */ |
||||||
|
if(normals.empty() != normalIndices.empty()) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): incomplete normal data"; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
if(textureCoordinates.empty() != textureCoordinateIndices.empty()) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): incomplete texture coordinate data"; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
/* All index arrays should have the same length */ |
||||||
|
if(!normalIndices.empty() && normalIndices.size() != positionIndices.size()) { |
||||||
|
CORRADE_INTERNAL_ASSERT(normalIndices.size() < positionIndices.size()); |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): some normal indices are missing"; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
if(!textureCoordinates.empty() && textureCoordinateIndices.size() != positionIndices.size()) { |
||||||
|
CORRADE_INTERNAL_ASSERT(textureCoordinateIndices.size() < positionIndices.size()); |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): some texture coordinate indices are missing"; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
/* Merge index arrays, if there aren't just the positions */ |
||||||
|
std::vector<UnsignedInt> indices; |
||||||
|
if(!normalIndices.empty() || !textureCoordinateIndices.empty()) { |
||||||
|
std::vector<std::reference_wrapper<std::vector<UnsignedInt>>> arrays; |
||||||
|
arrays.reserve(3); |
||||||
|
arrays.push_back(positionIndices); |
||||||
|
if(!normalIndices.empty()) arrays.push_back(normalIndices); |
||||||
|
if(!textureCoordinateIndices.empty()) arrays.push_back(textureCoordinateIndices); |
||||||
|
indices = MeshTools::combineIndexArrays(arrays); |
||||||
|
|
||||||
|
/* Reindex data arrays */ |
||||||
|
try { |
||||||
|
reindex(positionIndices, positions); |
||||||
|
if(!normalIndices.empty()) reindex(normalIndices, normals.front()); |
||||||
|
if(!textureCoordinateIndices.empty()) reindex(textureCoordinateIndices, textureCoordinates.front()); |
||||||
|
} catch(...) { |
||||||
|
/* Error message already printed */ |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
|
||||||
|
/* Otherwise just use the original position index array. Don't forget to
|
||||||
|
check range */ |
||||||
|
} else { |
||||||
|
indices = std::move(positionIndices); |
||||||
|
for(UnsignedInt i: indices) if(i >= positions.size()) { |
||||||
|
Error() << "Trade::ObjImporter::mesh3D(): index out of range"; |
||||||
|
return std::nullopt; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return MeshData3D(*primitive, std::move(indices), {std::move(positions)}, std::move(normals), std::move(textureCoordinates)); |
||||||
|
} |
||||||
|
|
||||||
|
}} |
||||||
@ -0,0 +1,86 @@ |
|||||||
|
#ifndef Magnum_Trade_ObjImporter_h |
||||||
|
#define Magnum_Trade_ObjImporter_h |
||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014 |
||||||
|
Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
/** @file
|
||||||
|
* @brief Class @ref Magnum::Trade::ObjImporter |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "Magnum/Trade/AbstractImporter.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace Trade { |
||||||
|
|
||||||
|
/**
|
||||||
|
@brief OBJ importer plugin |
||||||
|
|
||||||
|
Supported features: |
||||||
|
- multiple objects |
||||||
|
- vertex positions, normals and 2D texture coordinates |
||||||
|
- triangles, lines and points |
||||||
|
|
||||||
|
Polygons (quads etc.), automatic normal generation and material properties are |
||||||
|
currently not supported. |
||||||
|
|
||||||
|
This plugin is built if `WITH_OBJIMPORTER` is enabled when building %Magnum. To |
||||||
|
use dynamic plugin, you need to load `%ObjImporter` plugin from |
||||||
|
`MAGNUM_PLUGINS_IMPORTER_DIR`. To use static plugin or use this as a dependency |
||||||
|
of another plugin, you need to request `%ObjImporter` component of `%Magnum` |
||||||
|
package in CMake and link to `${MAGNUM_OBJIMPORTER_LIBRARIES}`. See |
||||||
|
@ref building, @ref cmake and @ref plugins for more information. |
||||||
|
*/ |
||||||
|
class ObjImporter: public AbstractImporter { |
||||||
|
public: |
||||||
|
/** @brief Default constructor */ |
||||||
|
explicit ObjImporter(); |
||||||
|
|
||||||
|
/** @brief Plugin manager constructor */ |
||||||
|
explicit ObjImporter(PluginManager::AbstractManager& manager, std::string plugin); |
||||||
|
|
||||||
|
~ObjImporter(); |
||||||
|
|
||||||
|
private: |
||||||
|
struct File; |
||||||
|
|
||||||
|
Features doFeatures() const override; |
||||||
|
|
||||||
|
bool doIsOpened() const override; |
||||||
|
void doOpenData(Containers::ArrayReference<const unsigned char> data) override; |
||||||
|
void doOpenFile(const std::string& filename) override; |
||||||
|
void doClose() override; |
||||||
|
|
||||||
|
UnsignedInt doMesh3DCount() const override; |
||||||
|
Int doMesh3DForName(const std::string& name) override; |
||||||
|
std::string doMesh3DName(UnsignedInt id) override; |
||||||
|
std::optional<MeshData3D> doMesh3D(UnsignedInt id) override; |
||||||
|
|
||||||
|
void parseMeshNames(); |
||||||
|
|
||||||
|
std::unique_ptr<File> _file; |
||||||
|
}; |
||||||
|
|
||||||
|
}} |
||||||
|
|
||||||
|
#endif |
||||||
@ -0,0 +1,31 @@ |
|||||||
|
# |
||||||
|
# This file is part of Magnum. |
||||||
|
# |
||||||
|
# Copyright © 2010, 2011, 2012, 2013, 2014 |
||||||
|
# Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
# |
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
# copy of this software and associated documentation files (the "Software"), |
||||||
|
# to deal in the Software without restriction, including without limitation |
||||||
|
# the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
# and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
# Software is furnished to do so, subject to the following conditions: |
||||||
|
# |
||||||
|
# The above copyright notice and this permission notice shall be included |
||||||
|
# in all copies or substantial portions of the Software. |
||||||
|
# |
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
# DEALINGS IN THE SOFTWARE. |
||||||
|
# |
||||||
|
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/configure.h) |
||||||
|
|
||||||
|
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) |
||||||
|
|
||||||
|
corrade_add_test(ObjImporterTest Test.cpp LIBRARIES ObjImporterTestLib) |
||||||
@ -0,0 +1,737 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014 |
||||||
|
Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <sstream> |
||||||
|
#include <Corrade/TestSuite/Tester.h> |
||||||
|
#include <Corrade/Utility/Directory.h> |
||||||
|
|
||||||
|
#include "Magnum/Mesh.h" |
||||||
|
#include "Magnum/Math/Vector3.h" |
||||||
|
#include "Magnum/Trade/MeshData3D.h" |
||||||
|
#include "MagnumPlugins/ObjImporter/ObjImporter.h" |
||||||
|
|
||||||
|
#include "configure.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace Trade { namespace Test { |
||||||
|
|
||||||
|
class ObjImporterTest: public TestSuite::Tester { |
||||||
|
public: |
||||||
|
explicit ObjImporterTest(); |
||||||
|
|
||||||
|
void pointMesh(); |
||||||
|
void lineMesh(); |
||||||
|
void triangleMesh(); |
||||||
|
void mixedPrimitives(); |
||||||
|
|
||||||
|
void positionsOnly(); |
||||||
|
void textureCoordinates(); |
||||||
|
void normals(); |
||||||
|
void textureCoordinatesNormals(); |
||||||
|
|
||||||
|
void emptyFile(); |
||||||
|
void unnamedMesh(); |
||||||
|
void namedMesh(); |
||||||
|
void moreMeshes(); |
||||||
|
void unnamedFirstMesh(); |
||||||
|
|
||||||
|
void wrongFloat(); |
||||||
|
void wrongInteger(); |
||||||
|
void unmergedIndexOutOfRange(); |
||||||
|
void mergedIndexOutOfRange(); |
||||||
|
void zeroIndex(); |
||||||
|
|
||||||
|
void explicitOptionalPositionCoordinate(); |
||||||
|
void explicitOptionalTextureCoordinate(); |
||||||
|
void unsupportedOptionalPositionCoordinate(); |
||||||
|
void unsupportedOptionalTextureCoordinate(); |
||||||
|
|
||||||
|
void shortFloatData(); |
||||||
|
void longFloatData(); |
||||||
|
void longOptionalFloatData(); |
||||||
|
|
||||||
|
void longIndexData(); |
||||||
|
void wrongPointIndexData(); |
||||||
|
void wrongLineIndexData(); |
||||||
|
void wrongTriangleIndexData(); |
||||||
|
void polygonIndexData(); |
||||||
|
|
||||||
|
void missingPositionData(); |
||||||
|
void missingNormalData(); |
||||||
|
void missingTextureCoordinateData(); |
||||||
|
void missingPositionIndices(); |
||||||
|
void missingNormalIndices(); |
||||||
|
void missingTextureCoordinateIndices(); |
||||||
|
|
||||||
|
void wrongTextureCoordinateIndexCount(); |
||||||
|
void wrongNormalIndexCount(); |
||||||
|
|
||||||
|
void unsupportedKeyword(); |
||||||
|
void unknownKeyword(); |
||||||
|
}; |
||||||
|
|
||||||
|
ObjImporterTest::ObjImporterTest() { |
||||||
|
addTests({&ObjImporterTest::pointMesh, |
||||||
|
&ObjImporterTest::lineMesh, |
||||||
|
&ObjImporterTest::triangleMesh, |
||||||
|
&ObjImporterTest::mixedPrimitives, |
||||||
|
|
||||||
|
&ObjImporterTest::positionsOnly, |
||||||
|
&ObjImporterTest::textureCoordinates, |
||||||
|
&ObjImporterTest::normals, |
||||||
|
&ObjImporterTest::textureCoordinatesNormals, |
||||||
|
|
||||||
|
&ObjImporterTest::emptyFile, |
||||||
|
&ObjImporterTest::unnamedMesh, |
||||||
|
&ObjImporterTest::namedMesh, |
||||||
|
&ObjImporterTest::moreMeshes, |
||||||
|
&ObjImporterTest::unnamedFirstMesh, |
||||||
|
|
||||||
|
&ObjImporterTest::wrongFloat, |
||||||
|
&ObjImporterTest::wrongInteger, |
||||||
|
&ObjImporterTest::unmergedIndexOutOfRange, |
||||||
|
&ObjImporterTest::mergedIndexOutOfRange, |
||||||
|
&ObjImporterTest::zeroIndex, |
||||||
|
|
||||||
|
&ObjImporterTest::explicitOptionalPositionCoordinate, |
||||||
|
&ObjImporterTest::explicitOptionalTextureCoordinate, |
||||||
|
&ObjImporterTest::unsupportedOptionalPositionCoordinate, |
||||||
|
&ObjImporterTest::unsupportedOptionalTextureCoordinate, |
||||||
|
|
||||||
|
&ObjImporterTest::shortFloatData, |
||||||
|
&ObjImporterTest::longFloatData, |
||||||
|
&ObjImporterTest::longOptionalFloatData, |
||||||
|
|
||||||
|
&ObjImporterTest::longIndexData, |
||||||
|
&ObjImporterTest::wrongPointIndexData, |
||||||
|
&ObjImporterTest::wrongLineIndexData, |
||||||
|
&ObjImporterTest::wrongTriangleIndexData, |
||||||
|
|
||||||
|
&ObjImporterTest::missingPositionData, |
||||||
|
&ObjImporterTest::missingNormalData, |
||||||
|
&ObjImporterTest::missingTextureCoordinateData, |
||||||
|
&ObjImporterTest::missingPositionIndices, |
||||||
|
&ObjImporterTest::missingNormalIndices, |
||||||
|
&ObjImporterTest::missingTextureCoordinateIndices, |
||||||
|
|
||||||
|
&ObjImporterTest::wrongTextureCoordinateIndexCount, |
||||||
|
&ObjImporterTest::wrongNormalIndexCount, |
||||||
|
|
||||||
|
&ObjImporterTest::unsupportedKeyword, |
||||||
|
&ObjImporterTest::unknownKeyword}); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::pointMesh() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "pointMesh.obj"))); |
||||||
|
CORRADE_COMPARE(importer.mesh3DCount(), 1); |
||||||
|
|
||||||
|
const std::optional<MeshData3D> data = importer.mesh3D(0); |
||||||
|
CORRADE_VERIFY(data); |
||||||
|
CORRADE_COMPARE(data->primitive(), MeshPrimitive::Points); |
||||||
|
CORRADE_COMPARE(data->positionArrayCount(), 1); |
||||||
|
CORRADE_COMPARE(data->positions(0), (std::vector<Vector3>{ |
||||||
|
{0.5f, 2.0f, 3.0f}, |
||||||
|
{0.0f, 1.5f, 1.0f}, |
||||||
|
{2.0f, 3.0f, 5.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(data->indices(), (std::vector<UnsignedInt>{ |
||||||
|
0, 2, 1, 0 |
||||||
|
})); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::lineMesh() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "lineMesh.obj"))); |
||||||
|
CORRADE_COMPARE(importer.mesh3DCount(), 1); |
||||||
|
|
||||||
|
const std::optional<MeshData3D> data = importer.mesh3D(0); |
||||||
|
CORRADE_VERIFY(data); |
||||||
|
CORRADE_COMPARE(data->primitive(), MeshPrimitive::Lines); |
||||||
|
CORRADE_COMPARE(data->positionArrayCount(), 1); |
||||||
|
CORRADE_COMPARE(data->positions(0), (std::vector<Vector3>{ |
||||||
|
{0.5f, 2.0f, 3.0f}, |
||||||
|
{0.0f, 1.5f, 1.0f}, |
||||||
|
{2.0f, 3.0f, 5.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(data->indices(), (std::vector<UnsignedInt>{ |
||||||
|
0, 1, 1, 2 |
||||||
|
})); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::triangleMesh() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "triangleMesh.obj"))); |
||||||
|
CORRADE_COMPARE(importer.mesh3DCount(), 1); |
||||||
|
|
||||||
|
const std::optional<MeshData3D> data = importer.mesh3D(0); |
||||||
|
CORRADE_VERIFY(data); |
||||||
|
CORRADE_COMPARE(data->primitive(), MeshPrimitive::Triangles); |
||||||
|
CORRADE_COMPARE(data->positionArrayCount(), 1); |
||||||
|
CORRADE_COMPARE(data->positions(0), (std::vector<Vector3>{ |
||||||
|
{0.5f, 2.0f, 3.0f}, |
||||||
|
{0.0f, 1.5f, 1.0f}, |
||||||
|
{2.0f, 3.0f, 5.0f}, |
||||||
|
{2.5f, 0.0f, 1.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(data->indices(), (std::vector<UnsignedInt>{ |
||||||
|
0, 1, 2, 3, 1, 0 |
||||||
|
})); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::mixedPrimitives() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "mixedPrimitives.obj"))); |
||||||
|
CORRADE_COMPARE(importer.mesh3DCount(), 1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(0)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): mixed primitive MeshPrimitive::Points and MeshPrimitive::Lines\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::positionsOnly() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "triangleMesh.obj"))); |
||||||
|
CORRADE_COMPARE(importer.mesh3DCount(), 1); |
||||||
|
|
||||||
|
const std::optional<MeshData3D> data = importer.mesh3D(0); |
||||||
|
CORRADE_VERIFY(data); |
||||||
|
CORRADE_COMPARE(data->positionArrayCount(), 1); |
||||||
|
CORRADE_VERIFY(!data->hasNormals()); |
||||||
|
CORRADE_VERIFY(!data->hasTextureCoords2D()); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::textureCoordinates() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "textureCoordinates.obj"))); |
||||||
|
CORRADE_COMPARE(importer.mesh3DCount(), 1); |
||||||
|
|
||||||
|
const std::optional<MeshData3D> data = importer.mesh3D(0); |
||||||
|
CORRADE_VERIFY(data); |
||||||
|
CORRADE_COMPARE(data->primitive(), MeshPrimitive::Lines); |
||||||
|
CORRADE_COMPARE(data->positionArrayCount(), 1); |
||||||
|
CORRADE_VERIFY(!data->hasNormals()); |
||||||
|
CORRADE_COMPARE(data->textureCoords2DArrayCount(), 1); |
||||||
|
CORRADE_COMPARE(data->positions(0), (std::vector<Vector3>{ |
||||||
|
{0.5f, 2.0f, 3.0f}, |
||||||
|
{0.0f, 1.5f, 1.0f}, |
||||||
|
{0.5f, 2.0f, 3.0f}, |
||||||
|
{0.0f, 1.5f, 1.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(data->textureCoords2D(0), (std::vector<Vector2>{ |
||||||
|
{1.0f, 0.5f}, |
||||||
|
{1.0f, 0.5f}, |
||||||
|
{0.5f, 1.0f}, |
||||||
|
{0.5f, 1.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(data->indices(), (std::vector<UnsignedInt>{ |
||||||
|
0, 1, 2, 3, 1, 0 |
||||||
|
})); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::normals() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "normals.obj"))); |
||||||
|
CORRADE_COMPARE(importer.mesh3DCount(), 1); |
||||||
|
|
||||||
|
const std::optional<MeshData3D> data = importer.mesh3D(0); |
||||||
|
CORRADE_VERIFY(data); |
||||||
|
CORRADE_COMPARE(data->primitive(), MeshPrimitive::Lines); |
||||||
|
CORRADE_COMPARE(data->positionArrayCount(), 1); |
||||||
|
CORRADE_VERIFY(!data->hasTextureCoords2D()); |
||||||
|
CORRADE_COMPARE(data->normalArrayCount(), 1); |
||||||
|
CORRADE_COMPARE(data->positions(0), (std::vector<Vector3>{ |
||||||
|
{0.5f, 2.0f, 3.0f}, |
||||||
|
{0.0f, 1.5f, 1.0f}, |
||||||
|
{0.5f, 2.0f, 3.0f}, |
||||||
|
{0.0f, 1.5f, 1.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(data->normals(0), (std::vector<Vector3>{ |
||||||
|
{1.0f, 0.5f, 3.5f}, |
||||||
|
{1.0f, 0.5f, 3.5f}, |
||||||
|
{0.5f, 1.0f, 0.5f}, |
||||||
|
{0.5f, 1.0f, 0.5f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(data->indices(), (std::vector<UnsignedInt>{ |
||||||
|
0, 1, 2, 3, 1, 0 |
||||||
|
})); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::textureCoordinatesNormals() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "textureCoordinatesNormals.obj"))); |
||||||
|
CORRADE_COMPARE(importer.mesh3DCount(), 1); |
||||||
|
|
||||||
|
const std::optional<MeshData3D> data = importer.mesh3D(0); |
||||||
|
CORRADE_VERIFY(data); |
||||||
|
CORRADE_COMPARE(data->primitive(), MeshPrimitive::Lines); |
||||||
|
CORRADE_COMPARE(data->positionArrayCount(), 1); |
||||||
|
CORRADE_COMPARE(data->textureCoords2DArrayCount(), 1); |
||||||
|
CORRADE_COMPARE(data->normalArrayCount(), 1); |
||||||
|
CORRADE_COMPARE(data->positions(0), (std::vector<Vector3>{ |
||||||
|
{0.5f, 2.0f, 3.0f}, |
||||||
|
{0.0f, 1.5f, 1.0f}, |
||||||
|
{0.5f, 2.0f, 3.0f}, |
||||||
|
{0.0f, 1.5f, 1.0f}, |
||||||
|
{0.0f, 1.5f, 1.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(data->textureCoords2D(0), (std::vector<Vector2>{ |
||||||
|
{1.0f, 0.5f}, |
||||||
|
{1.0f, 0.5f}, |
||||||
|
{0.5f, 1.0f}, |
||||||
|
{0.5f, 1.0f}, |
||||||
|
{0.5f, 1.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(data->normals(0), (std::vector<Vector3>{ |
||||||
|
{1.0f, 0.5f, 3.5f}, |
||||||
|
{0.5f, 1.0f, 0.5f}, |
||||||
|
{0.5f, 1.0f, 0.5f}, |
||||||
|
{1.0f, 0.5f, 3.5f}, |
||||||
|
{0.5f, 1.0f, 0.5f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(data->indices(), (std::vector<UnsignedInt>{ |
||||||
|
0, 1, 2, 3, 1, 0, 4, 2 |
||||||
|
})); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::emptyFile() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "emptyFile.obj"))); |
||||||
|
CORRADE_COMPARE(importer.mesh3DCount(), 1); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::unnamedMesh() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "emptyFile.obj"))); |
||||||
|
CORRADE_COMPARE(importer.mesh3DCount(), 1); |
||||||
|
CORRADE_COMPARE(importer.mesh3DName(0), ""); |
||||||
|
CORRADE_COMPARE(importer.mesh3DForName(""), -1); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::namedMesh() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "namedMesh.obj"))); |
||||||
|
CORRADE_COMPARE(importer.mesh3DCount(), 1); |
||||||
|
CORRADE_COMPARE(importer.mesh3DName(0), "MyMesh"); |
||||||
|
CORRADE_COMPARE(importer.mesh3DForName("MyMesh"), 0); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::moreMeshes() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "moreMeshes.obj"))); |
||||||
|
CORRADE_COMPARE(importer.mesh3DCount(), 3); |
||||||
|
|
||||||
|
CORRADE_COMPARE(importer.mesh3DName(0), "PointMesh"); |
||||||
|
CORRADE_COMPARE(importer.mesh3DForName("PointMesh"), 0); |
||||||
|
const std::optional<MeshData3D> data = importer.mesh3D(0); |
||||||
|
CORRADE_VERIFY(data); |
||||||
|
CORRADE_COMPARE(data->primitive(), MeshPrimitive::Points); |
||||||
|
CORRADE_COMPARE(data->positionArrayCount(), 1); |
||||||
|
CORRADE_COMPARE(data->positions(0), (std::vector<Vector3>{ |
||||||
|
{0.5f, 2.0f, 3.0f}, |
||||||
|
{0.0f, 1.5f, 1.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(data->indices(), (std::vector<UnsignedInt>{ |
||||||
|
0, 1 |
||||||
|
})); |
||||||
|
|
||||||
|
CORRADE_COMPARE(importer.mesh3DName(1), "LineMesh"); |
||||||
|
CORRADE_COMPARE(importer.mesh3DForName("LineMesh"), 1); |
||||||
|
const std::optional<MeshData3D> data1 = importer.mesh3D(1); |
||||||
|
CORRADE_VERIFY(data1); |
||||||
|
CORRADE_COMPARE(data1->primitive(), MeshPrimitive::Lines); |
||||||
|
CORRADE_COMPARE(data1->positionArrayCount(), 1); |
||||||
|
CORRADE_COMPARE(data1->positions(0), (std::vector<Vector3>{ |
||||||
|
{0.5f, 2.0f, 3.0f}, |
||||||
|
{0.0f, 1.5f, 1.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(data1->indices(), (std::vector<UnsignedInt>{ |
||||||
|
0, 1, 1, 0 |
||||||
|
})); |
||||||
|
|
||||||
|
CORRADE_COMPARE(importer.mesh3DName(2), "TriangleMesh"); |
||||||
|
CORRADE_COMPARE(importer.mesh3DForName("TriangleMesh"), 2); |
||||||
|
const std::optional<MeshData3D> data2 = importer.mesh3D(2); |
||||||
|
CORRADE_VERIFY(data2); |
||||||
|
CORRADE_COMPARE(data2->primitive(), MeshPrimitive::Triangles); |
||||||
|
CORRADE_COMPARE(data2->positionArrayCount(), 1); |
||||||
|
CORRADE_COMPARE(data2->positions(0), (std::vector<Vector3>{ |
||||||
|
{0.5f, 2.0f, 3.0f}, |
||||||
|
{0.0f, 1.5f, 1.0f}, |
||||||
|
{2.0f, 3.0f, 5.5f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(data2->indices(), (std::vector<UnsignedInt>{ |
||||||
|
0, 1, 2, 2, 1, 0 |
||||||
|
})); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::unnamedFirstMesh() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "unnamedFirstMesh.obj"))); |
||||||
|
CORRADE_COMPARE(importer.mesh3DCount(), 2); |
||||||
|
|
||||||
|
CORRADE_COMPARE(importer.mesh3DName(0), ""); |
||||||
|
CORRADE_COMPARE(importer.mesh3DForName(""), -1); |
||||||
|
|
||||||
|
CORRADE_COMPARE(importer.mesh3DName(1), "SecondMesh"); |
||||||
|
CORRADE_COMPARE(importer.mesh3DForName("SecondMesh"), 1); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::wrongFloat() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongNumbers.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("WrongFloat"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): error while converting numeric data\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::wrongInteger() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongNumbers.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("WrongInteger"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): error while converting numeric data\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::unmergedIndexOutOfRange() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongNumbers.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("PositionIndexOutOfRange"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): index out of range\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::mergedIndexOutOfRange() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongNumbers.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("TextureIndexOutOfRange"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): index out of range\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::zeroIndex() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongNumbers.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("ZeroIndex"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): index out of range\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::explicitOptionalPositionCoordinate() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "optionalCoordinates.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("SupportedPositionW"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
const std::optional<MeshData3D> data = importer.mesh3D(id); |
||||||
|
CORRADE_VERIFY(data); |
||||||
|
CORRADE_COMPARE(data->positionArrayCount(), 1); |
||||||
|
CORRADE_COMPARE(data->positions(0), (std::vector<Vector3>{ |
||||||
|
{1.5f, 2.0f, 3.0f} |
||||||
|
})); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::explicitOptionalTextureCoordinate() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "optionalCoordinates.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("SupportedTextureW"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
const std::optional<MeshData3D> data = importer.mesh3D(id); |
||||||
|
CORRADE_VERIFY(data); |
||||||
|
CORRADE_COMPARE(data->textureCoords2DArrayCount(), 1); |
||||||
|
CORRADE_COMPARE(data->textureCoords2D(0), (std::vector<Vector2>{ |
||||||
|
{0.5f, 0.7f} |
||||||
|
})); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::unsupportedOptionalPositionCoordinate() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "optionalCoordinates.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("UnsupportedPositionW"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): homogeneous coordinates are not supported\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::unsupportedOptionalTextureCoordinate() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "optionalCoordinates.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("UnsupportedTextureW"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): 3D texture coordinates are not supported\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::shortFloatData() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongNumberCount.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("ShortFloat"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): invalid float array size\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::longFloatData() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongNumberCount.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("LongFloat"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): invalid float array size\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::longOptionalFloatData() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongNumberCount.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("LongOptionalFloat"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): invalid float array size\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::longIndexData() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongNumberCount.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("InvalidIndices"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): invalid index data\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::wrongPointIndexData() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongNumberCount.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("WrongPointIndices"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): wrong index count for point\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::wrongLineIndexData() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongNumberCount.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("WrongLineIndices"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): wrong index count for line\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::wrongTriangleIndexData() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongNumberCount.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("WrongTriangleIndices"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): wrong index count for triangle\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::polygonIndexData() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongNumberCount.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("PolygonIndices"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): polygons are not supported\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::missingPositionData() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "missingData.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("MissingPositionData"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): incomplete position data\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::missingPositionIndices() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "missingData.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("MissingPositionIndices"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): incomplete position data\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::missingNormalData() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "missingData.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("MissingNormalData"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): incomplete normal data\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::missingNormalIndices() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "missingData.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("MissingNormalIndices"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): incomplete normal data\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::missingTextureCoordinateData() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "missingData.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("MissingTextureData"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): incomplete texture coordinate data\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::missingTextureCoordinateIndices() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "missingData.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("MissingTextureIndices"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): incomplete texture coordinate data\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::wrongNormalIndexCount() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongIndexCount.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("ShortNormalIndices"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): some normal indices are missing\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::wrongTextureCoordinateIndexCount() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "wrongIndexCount.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("ShortTextureIndices"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): some texture coordinate indices are missing\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::unsupportedKeyword() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "keywords.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("UnsupportedKeyword"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
/* Everything should be parsed properly */ |
||||||
|
const std::optional<MeshData3D> data = importer.mesh3D(id); |
||||||
|
CORRADE_VERIFY(data); |
||||||
|
CORRADE_COMPARE(data->primitive(), MeshPrimitive::Points); |
||||||
|
CORRADE_COMPARE(data->positionArrayCount(), 1); |
||||||
|
CORRADE_COMPARE(data->positions(0), (std::vector<Vector3>{ |
||||||
|
{0.0f, 1.0f, 2.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(data->indices(), std::vector<UnsignedInt>{0}); |
||||||
|
} |
||||||
|
|
||||||
|
void ObjImporterTest::unknownKeyword() { |
||||||
|
ObjImporter importer; |
||||||
|
CORRADE_VERIFY(importer.openFile(Utility::Directory::join(OBJIMPORTER_TEST_DIR, "keywords.obj"))); |
||||||
|
const Int id = importer.mesh3DForName("UnknownKeyword"); |
||||||
|
CORRADE_VERIFY(id > -1); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error::setOutput(&out); |
||||||
|
CORRADE_VERIFY(!importer.mesh3D(id)); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::ObjImporter::mesh3D(): unknown keyword bleh\n"); |
||||||
|
} |
||||||
|
|
||||||
|
}}} |
||||||
|
|
||||||
|
CORRADE_TEST_MAIN(Magnum::Trade::Test::ObjImporterTest) |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
/* |
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014 |
||||||
|
Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#define OBJIMPORTER_TEST_DIR "${CMAKE_CURRENT_SOURCE_DIR}" |
||||||
@ -0,0 +1 @@ |
|||||||
|
# Nothinng to see here |
||||||
@ -0,0 +1,7 @@ |
|||||||
|
o UnsupportedKeyword |
||||||
|
g VertexGroup |
||||||
|
v 0 1 2 |
||||||
|
p 1 |
||||||
|
|
||||||
|
o UnknownKeyword |
||||||
|
bleh |
||||||
@ -0,0 +1,8 @@ |
|||||||
|
# Positions |
||||||
|
v 0.5 2 3 |
||||||
|
v 0 1.5 1 |
||||||
|
v 2 3 5.0 |
||||||
|
|
||||||
|
# Lines |
||||||
|
l 1 2 |
||||||
|
l 2 3 |
||||||
@ -0,0 +1,23 @@ |
|||||||
|
o MissingPositionData |
||||||
|
p 1 |
||||||
|
|
||||||
|
o MissingPositionIndices |
||||||
|
v 1 2 3 |
||||||
|
|
||||||
|
o MissingNormalData |
||||||
|
v 1 2 3 |
||||||
|
p 1//1 |
||||||
|
|
||||||
|
o MissingNormalIndices |
||||||
|
v 1 2 3 |
||||||
|
vn 1 2 3 |
||||||
|
p 1 |
||||||
|
|
||||||
|
o MissingTextureData |
||||||
|
v 1 2 3 |
||||||
|
p 1/1 |
||||||
|
|
||||||
|
o MissingTextureIndices |
||||||
|
v 1 2 3 |
||||||
|
vt 1 2 |
||||||
|
p 1 |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
# Positions |
||||||
|
v 0.5 2 3 |
||||||
|
v 0 1.5 1 |
||||||
|
v 2 3 5.0 |
||||||
|
|
||||||
|
# Points |
||||||
|
p 1 |
||||||
|
p 3 |
||||||
|
p 2 |
||||||
|
|
||||||
|
# Lines |
||||||
|
l 1 2 |
||||||
|
l 2 3 |
||||||
@ -0,0 +1,21 @@ |
|||||||
|
# Points |
||||||
|
o PointMesh |
||||||
|
v 0.5 2 3 |
||||||
|
v 0 1.5 1 |
||||||
|
p 1 |
||||||
|
p 2 |
||||||
|
|
||||||
|
# Lines |
||||||
|
o LineMesh |
||||||
|
v 0.5 2 3 |
||||||
|
v 0 1.5 1 |
||||||
|
l 1 2 |
||||||
|
l 2 1 |
||||||
|
|
||||||
|
# Triangles |
||||||
|
o TriangleMesh |
||||||
|
v 0.5 2 3 |
||||||
|
v 0 1.5 1 |
||||||
|
v 2 3 5.5 |
||||||
|
f 1 2 3 |
||||||
|
f 3 2 1 |
||||||
@ -0,0 +1,2 @@ |
|||||||
|
# Named mesh |
||||||
|
o MyMesh |
||||||
@ -0,0 +1,12 @@ |
|||||||
|
# Positions |
||||||
|
v 0.5 2 3 |
||||||
|
v 0 1.5 1 |
||||||
|
|
||||||
|
# Normals (don't have to be normalized) |
||||||
|
vn 1 0.5 3.5 |
||||||
|
vn 0.5 1 0.5 |
||||||
|
|
||||||
|
# Lines |
||||||
|
l 1//1 2//1 |
||||||
|
l 1//2 2//2 |
||||||
|
l 2//1 1//1 |
||||||
@ -0,0 +1,17 @@ |
|||||||
|
o SupportedPositionW |
||||||
|
v 1.5 2 3 1.0 |
||||||
|
p 1 |
||||||
|
|
||||||
|
o SupportedTextureW |
||||||
|
v 1.5 2 3 |
||||||
|
vt 0.5 0.7 0.0 |
||||||
|
p 1/1 |
||||||
|
|
||||||
|
o UnsupportedPositionW |
||||||
|
v 1.5 2 3 0.8 |
||||||
|
p 1 |
||||||
|
|
||||||
|
o UnsupportedTextureW |
||||||
|
v 1.5 2 3 |
||||||
|
vt 0.5 0.7 0.5 |
||||||
|
p 1/1 |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
# Positions |
||||||
|
v 0.5 2 3 |
||||||
|
v 0 1.5 1 |
||||||
|
v 2 3 5.0 |
||||||
|
|
||||||
|
# Points |
||||||
|
p 1 |
||||||
|
p 3 |
||||||
|
p 2 |
||||||
|
p 1 |
||||||
@ -0,0 +1,12 @@ |
|||||||
|
# Positions |
||||||
|
v 0.5 2 3 |
||||||
|
v 0 1.5 1 |
||||||
|
|
||||||
|
# Texture coordinates |
||||||
|
vt 1 0.5 |
||||||
|
vt 0.5 1 |
||||||
|
|
||||||
|
# Lines |
||||||
|
l 1/1 2/1 |
||||||
|
l 1/2 2/2 |
||||||
|
l 2/1 1/1 |
||||||
@ -0,0 +1,17 @@ |
|||||||
|
# Positions |
||||||
|
v 0.5 2 3 |
||||||
|
v 0 1.5 1 |
||||||
|
|
||||||
|
# Texture coordinates |
||||||
|
vt 1 0.5 |
||||||
|
vt 0.5 1 |
||||||
|
|
||||||
|
# Normals |
||||||
|
vn 1 0.5 3.5 |
||||||
|
vn 0.5 1 0.5 |
||||||
|
|
||||||
|
# Lines |
||||||
|
l 1/1/1 2/1/2 |
||||||
|
l 1/2/2 2/2/1 |
||||||
|
l 2/1/2 1/1/1 |
||||||
|
l 2/2/2 1/2/2 |
||||||
@ -0,0 +1,9 @@ |
|||||||
|
# Positions |
||||||
|
v 0.5 2 3 |
||||||
|
v 0 1.5 1 |
||||||
|
v 2 3 5.0 |
||||||
|
v 2.5 0 1 |
||||||
|
|
||||||
|
# Triangles |
||||||
|
f 1 2 3 |
||||||
|
f 4 2 1 |
||||||
@ -0,0 +1,2 @@ |
|||||||
|
v 1 2 3 |
||||||
|
o SecondMesh |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
o ShortNormalIndices |
||||||
|
v 1 2 3 |
||||||
|
vn 1 2 3 |
||||||
|
p 1//1 |
||||||
|
p 1 |
||||||
|
p 1//1 |
||||||
|
|
||||||
|
o ShortTextureIndices |
||||||
|
v 1 2 3 |
||||||
|
vt 1 2 |
||||||
|
p 1/1 |
||||||
|
p 1 |
||||||
|
p 1/1 |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
o ShortFloat |
||||||
|
v 0.5 1.0 |
||||||
|
|
||||||
|
o LongFloat |
||||||
|
v 0.5 1 2 |
||||||
|
vn 0.5 1.0 2.3 7.4 |
||||||
|
|
||||||
|
o LongOptionalFloat |
||||||
|
v 0.5 1 2 0.0 3.5 |
||||||
|
|
||||||
|
o InvalidIndices |
||||||
|
v 1 2 3 |
||||||
|
p 1/1/1/1 |
||||||
|
|
||||||
|
o WrongPointIndices |
||||||
|
v 1 2 3 |
||||||
|
p 1 1 |
||||||
|
|
||||||
|
o WrongLineIndices |
||||||
|
v 1 2 3 |
||||||
|
l 1 |
||||||
|
|
||||||
|
o WrongTriangleIndices |
||||||
|
v 1 2 3 |
||||||
|
f 1 1 |
||||||
|
|
||||||
|
o PolygonIndices |
||||||
|
v 1 2 3 |
||||||
|
f 1 1 1 1 |
||||||
@ -0,0 +1,20 @@ |
|||||||
|
o WrongFloat |
||||||
|
v 1 bleh 2 |
||||||
|
p 1 |
||||||
|
|
||||||
|
o WrongInteger |
||||||
|
v 1 0 2 |
||||||
|
p bleh |
||||||
|
|
||||||
|
o PositionIndexOutOfRange |
||||||
|
v 1 0 2 |
||||||
|
p 2 |
||||||
|
|
||||||
|
o TextureIndexOutOfRange |
||||||
|
v 1 0 2 |
||||||
|
vt 0 1 |
||||||
|
p 1/2 |
||||||
|
|
||||||
|
o ZeroIndex |
||||||
|
v 1 0 2 |
||||||
|
p 0 |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014 |
||||||
|
Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "MagnumPlugins/ObjImporter/ObjImporter.h" |
||||||
|
|
||||||
|
CORRADE_PLUGIN_REGISTER(ObjImporter, Magnum::Trade::ObjImporter, |
||||||
|
"cz.mosra.magnum.Trade.AbstractImporter/0.3") |
||||||
Loading…
Reference in new issue