From ba9a2c3963c068403463a21baaa7e65a7fdd1a29 Mon Sep 17 00:00:00 2001 From: Squareys Date: Wed, 22 Jun 2016 18:14:29 +0200 Subject: [PATCH] WIP --- src/MagnumPlugins/ObjImporter/ObjImporter.cpp | 250 ++++++------------ src/MagnumPlugins/ObjImporter/ObjImporter.h | 5 +- 2 files changed, 92 insertions(+), 163 deletions(-) diff --git a/src/MagnumPlugins/ObjImporter/ObjImporter.cpp b/src/MagnumPlugins/ObjImporter/ObjImporter.cpp index 9470ca177..0848af68e 100644 --- a/src/MagnumPlugins/ObjImporter/ObjImporter.cpp +++ b/src/MagnumPlugins/ObjImporter/ObjImporter.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -38,42 +39,76 @@ #include "Magnum/Math/Color.h" #include "Magnum/Trade/MeshData3D.h" +#if defined(CORRADE_TARGET_NACL_NEWLIB) || defined(CORRADE_TARGET_ANDROID) +#include +#endif + +using namespace Corrade::Containers; + namespace Magnum { namespace Trade { -struct ObjImporter::File { +struct ImporterState { std::unordered_map meshesForName; std::vector meshNames; std::vector> meshes; - std::unique_ptr in; + + std::optional primitive; + std::vector positions; + std::vector> textureCoordinates; + std::vector> normals; + std::vector positionIndices; + std::vector textureCoordinateIndices; + std::vector normalIndices; }; namespace { -void ignoreLine(std::istream& in) { - in.ignore(std::numeric_limits::max(), '\n'); +int findNext(const ArrayView& pos, char c) { + for(int i = 0; i < pos.size(); ++i) { + if(pos[i] == c) { + return i; + } + } + return -1; } -template Math::Vector extractFloatData(const std::string& str, Float* extra = nullptr) { - std::vector 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; +ArrayView skipWhitespaces(const ArrayView& pos) { + for(int i = 0; i < pos.size(); ++i) { + if(pos[i] != ' ' && pos[i] != '\t') { + return pos.suffix(i); + } } + return ArrayView{}; +} - Math::Vector output; - - for(std::size_t i = 0; i != size; ++i) - output[i] = std::stof(data[i]); +ArrayView ignoreLine(const ArrayView& pos) { + return pos.suffix(findNext(pos, '\n')); +} - if(data.size() == size+1) { - /* This should be obvious from the first if, but add this just to make - Clang Analyzer happy */ - CORRADE_INTERNAL_ASSERT(extra); +std::tuple> nextLine(const ArrayView& pos) { + int i = 0; + for(; i < pos.size(); ++i) { + if(pos[i] == '\n') { + break; + } + } + std::string str = pos.prefix(i).data(); + return std::make_tuple(str, pos.suffix(i+1)); +} - *extra = std::stof(data.back()); +std::tuple> nextWord(const ArrayView& pos) { + int i = 0; + for(; i < pos.size(); ++i) { + if(pos[i] == ' ') { + break; + } } + std::string str = pos.prefix(i).data(); + return std::make_tuple(str, pos.suffix(i+1)); +} + +std::tuple> asFloat(const ArrayView& pos) { - return output; } template void reindex(const std::vector& indices, std::vector& data) { @@ -96,26 +131,14 @@ 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) { - std::unique_ptr in{new std::ifstream{filename, std::ios::binary}}; - if(!in->good()) { - Error() << "Trade::ObjImporter::openFile(): cannot open file" << filename; - return; - } +bool ObjImporter::doIsOpened() const { return _in; } - _file.reset(new File); - _file->in = std::move(in); - parseMeshNames(); -} +void ObjImporter::doClose() { _in = nullptr; } void ObjImporter::doOpenData(Containers::ArrayView data) { - _file.reset(new File); - _file->in.reset(new std::istringstream{{data.begin(), data.size()}}); - + _in = Containers::Array{data.size()}; + std::copy(data.begin(), data.end(), _in.begin()); + _state.reset(new ImporterState); parseMeshNames(); } @@ -125,144 +148,33 @@ void ObjImporter::parseMeshNames() { UnsignedInt positionIndexOffset = 1; UnsignedInt normalIndexOffset = 1; UnsignedInt textureCoordinateIndexOffset = 1; - _file->meshes.emplace_back(0, 0, positionIndexOffset, normalIndexOffset, textureCoordinateIndexOffset); + _state->meshes.emplace_back(0, 0, positionIndexOffset, normalIndexOffset, textureCoordinateIndexOffset); - /* The first mesh doesn't have name by default but we might find it later, - so we need to track whether there are any data before first name */ - bool thisIsFirstMeshAndItHasNoData = true; - _file->meshNames.emplace_back(); + _state->meshNames.emplace_back(); - while(_file->in->good()) { - /* The previous object might end at the beginning of this line */ - const std::streampos end = _file->in->tellg(); + ArrayView pos = _in; + while(!pos.empty()) { /* Comment line */ - if(_file->in->peek() == '#') { - ignoreLine(*_file->in); + if(pos[0] == '#') { + pos = ignoreLine(pos); continue; } /* Parse the keyword */ std::string keyword; - *_file->in >> keyword; + std::tie(keyword, pos) = nextWord(pos); /* Mesh name */ if(keyword == "o") { - std::string name; - std::getline(*_file->in, name); - name = Utility::String::trim(name); - - /* This is the name of first mesh */ - if(thisIsFirstMeshAndItHasNoData) { - thisIsFirstMeshAndItHasNoData = false; - - /* Update its name and add it to name map */ - if(!name.empty()) - _file->meshesForName.emplace(name, _file->meshes.size() - 1); - _file->meshNames.back() = std::move(name); - - /* Update its begin offset to be more precise */ - std::get<0>(_file->meshes.back()) = _file->in->tellg(); - - /* Otherwise this is a name of new mesh */ - } else { - /* Set end of the previous one */ - std::get<1>(_file->meshes.back()) = end; - - /* Save name and offset of the new one. The end offset will be - updated later. */ - if(!name.empty()) - _file->meshesForName.emplace(name, _file->meshes.size()); - _file->meshNames.emplace_back(std::move(name)); - _file->meshes.emplace_back(_file->in->tellg(), 0, positionIndexOffset, textureCoordinateIndexOffset, normalIndexOffset); - } - - continue; - - /* If there are any data/indices before the first name, it means that - the first object is unnamed. We need to check for them. */ - - /* Vertex data, update index offset for the following meshes */ - } else if(keyword == "v") { - ++positionIndexOffset; - thisIsFirstMeshAndItHasNoData = false; - } else if(keyword == "vt") { - ++textureCoordinateIndexOffset; - thisIsFirstMeshAndItHasNoData = false; - } else if(keyword == "vn") { - ++normalIndexOffset; - thisIsFirstMeshAndItHasNoData = false; - - /* Index data, just mark that we found something for first unnamed - object */ - } else if(thisIsFirstMeshAndItHasNoData) for(const std::string& data: {"p", "l", "f"}) { - if(keyword == data) { - thisIsFirstMeshAndItHasNoData = false; - break; - } - } - - /* Ignore the rest of the line */ - ignoreLine(*_file->in); - } - - /* Set end of the last object */ - _file->in->clear(); - _file->in->seekg(0, std::ios::end); - std::get<1>(_file->meshes.back()) = _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]; -} - -Containers::Optional ObjImporter::doMesh3D(UnsignedInt id) { - /* Seek the file, set mesh parsing parameters */ - std::streampos begin, end; - UnsignedInt positionIndexOffset, textureCoordinateIndexOffset, normalIndexOffset; - std::tie(begin, end, positionIndexOffset, textureCoordinateIndexOffset, normalIndexOffset) = _file->meshes[id]; - _file->in->seekg(begin); - - Containers::Optional primitive; - std::vector positions; - std::vector> textureCoordinates; - std::vector> normals; - std::vector positionIndices; - std::vector textureCoordinateIndices; - std::vector normalIndices; - - try { while(_file->in->good() && _file->in->tellg() < end) { - /* Ignore comments */ - if(_file->in->peek() == '#') { - ignoreLine(*_file->in); + // TODO 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); + const Vector3 data = extractFloatData<3>(pos, &extra); if(!Math::TypeTraits::equals(extra, 1.0f)) { Error() << "Trade::ObjImporter::mesh3D(): homogeneous coordinates are not supported"; return Containers::NullOpt; @@ -374,13 +286,27 @@ Containers::Optional ObjImporter::doMesh3D(UnsignedInt id) { return Containers::NullOpt; } - }} catch(std::exception) { - Error() << "Trade::ObjImporter::mesh3D(): error while converting numeric data"; - return Containers::NullOpt; - } catch(...) { - /* Error message already printed */ - return Containers::NullOpt; + /* Ignore the rest of the line */ + pos = ignoreLine(pos); } +} + +UnsignedInt ObjImporter::doMesh3DCount() const { return _state->meshes.size(); } + +Int ObjImporter::doMesh3DForName(const std::string& name) { + const auto it = _state->meshesForName.find(name); + return it == _state->meshesForName.end() ? -1 : it->second; +} + +std::string ObjImporter::doMesh3DName(UnsignedInt id) { + return _state->meshNames[id]; +} + +std::optional ObjImporter::doMesh3D(UnsignedInt id) { + /* Seek the file, set mesh parsing parameters */ + std::streampos begin, end; + UnsignedInt positionIndexOffset, textureCoordinateIndexOffset, normalIndexOffset; + std::tie(begin, end, positionIndexOffset, textureCoordinateIndexOffset, normalIndexOffset) = _state->meshes[id]; /* There should be at least indexed position data */ if(positions.empty() || positionIndices.empty()) { diff --git a/src/MagnumPlugins/ObjImporter/ObjImporter.h b/src/MagnumPlugins/ObjImporter/ObjImporter.h index 81ec77dce..f1c1b1fa4 100644 --- a/src/MagnumPlugins/ObjImporter/ObjImporter.h +++ b/src/MagnumPlugins/ObjImporter/ObjImporter.h @@ -33,6 +33,8 @@ #include "MagnumPlugins/ObjImporter/configure.h" +#include + #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_OBJIMPORTER_BUILD_STATIC #if defined(ObjImporter_EXPORTS) || defined(ObjImporterObjects_EXPORTS) @@ -100,7 +102,8 @@ class MAGNUM_OBJIMPORTER_EXPORT ObjImporter: public AbstractImporter { MAGNUM_OBJIMPORTER_LOCAL void parseMeshNames(); - std::unique_ptr _file; + Containers::Array _in; + std::unique_ptr _state; }; }}