From 575bbb1dec7a6d9465c04ef719ba94c80d0d5426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 15 Apr 2022 10:05:20 +0200 Subject: [PATCH] [wip] Trade: ability to feed a whole importer to a scene converter. TOOD: all the TODOs --- src/Magnum/Trade/AbstractSceneConverter.cpp | 109 ++++++++++++++++++++ src/Magnum/Trade/AbstractSceneConverter.h | 76 ++++++++++++++ 2 files changed, 185 insertions(+) diff --git a/src/Magnum/Trade/AbstractSceneConverter.cpp b/src/Magnum/Trade/AbstractSceneConverter.cpp index e3f54f7d8..58117e4bf 100644 --- a/src/Magnum/Trade/AbstractSceneConverter.cpp +++ b/src/Magnum/Trade/AbstractSceneConverter.cpp @@ -39,7 +39,9 @@ #include "Magnum/Trade/ArrayAllocator.h" #include "Magnum/Trade/ImageData.h" #include "Magnum/Trade/MeshData.h" +#include "Magnum/Trade/MaterialData.h" #include "Magnum/Trade/SceneData.h" +#include "Magnum/Trade/TextureData.h" #ifdef MAGNUM_BUILD_DEPRECATED /* needed by deprecated convertToFile() that takes a std::string */ @@ -1224,6 +1226,113 @@ Containers::Optional AbstractSceneConverter::add(const Containers:: // return add(Containers::arrayView(imageLevels), {}); // } +bool AbstractSceneConverter::addImporterContents(AbstractImporter& importer, const SceneConverterContents contents) { + // TODO assert if begin called + // TODO assert if importer opened + // TODO assert about features? or leave that on the called funs + + if(contents & SceneConverterContent::Scenes) { + /* Propagate object names, skip ones that are empty */ + for(UnsignedLong i = 0, iMax = importer.objectCount(); i != iMax; ++i) { + if(const Containers::String name = importer.objectName(i)) + setObjectName(i, name); + } + + for(UnsignedInt i = 0, iMax = importer.sceneCount(); i != iMax; ++i) { + Containers::Optional scene = importer.scene(i); + if(!scene) return false; + + for(UnsignedInt j = 0; j != scene->fieldCount(); ++j) { + // TODO how to filter them to not call the name again and again?! + const Trade::SceneField name = scene->fieldName(j); + if(!isSceneFieldCustom(name)) continue; + if(const Containers::String nameString = importer.sceneFieldName(name)) { + !Debug{}; + setSceneFieldName(name, nameString); + } + } + + if(!scene || !add(*scene, importer.sceneName(i))) + return false; + } + } + + if(contents & SceneConverterContent::Meshes) { + // TODO levels?! + for(UnsignedInt i = 0, iMax = importer.meshCount(); i != iMax; ++i) { + // TODO attribute names, how to filter them to not call the name again + // and again?! + Containers::Optional mesh = importer.mesh(i); + if(!mesh || !add(*mesh, importer.meshName(i))) + return false; + } + } + + if(contents & (SceneConverterContent::Images3D|SceneConverterContent::CompressedImages3D)) { + // TODO levels?! + for(UnsignedInt i = 0, iMax = importer.image3DCount(); i != iMax; ++i) { + // TODO skip what's compressed (and converter doesn't support) and + // vice versa + Containers::Optional image = importer.image3D(i); + if(!image || !add(*image, importer.image3DName(i))) + return false; + } + } + + if(contents & SceneConverterContent::Textures) { + for(UnsignedInt i = 0, iMax = importer.textureCount(); i != iMax; ++i) { + Containers::Optional texture = importer.texture(i); + if(!texture || !add(*texture, importer.textureName(i))) + return false; + } + } + + if(contents & SceneConverterContent::Materials) { + for(UnsignedInt i = 0, iMax = importer.materialCount(); i != iMax; ++i) { + // TODO attribute names, how to filter them to not call the name again + // and again?! + Containers::Optional material = importer.material(i); + if(!material || !add(*material, importer.materialName(i))) + return false; + } + } + + // TODO rest + + return true; +} + +bool AbstractSceneConverter::addSupportedImporterContents(AbstractImporter& importer, const SceneConverterContents contents) { + SceneConverterContents filteredContents; + const SceneConverterFeatures features = this->features(); + #define _c(name) \ + if(features & SceneConverterFeature::Add ## name) \ + filteredContents |= SceneConverterContent::name; + _c(Scenes) + _c(Animations) + _c(Lights) + _c(Cameras) + _c(Skins2D) + _c(Skins3D) + _c(Meshes) + _c(Materials) + _c(Textures) + _c(Images1D) + _c(Images2D) + _c(Images3D) + _c(CompressedImages1D) + _c(CompressedImages2D) + _c(CompressedImages2D) + #undef _c + if(features & SceneConverterFeature::MeshLevels) + filteredContents |= SceneConverterContent::ExtraMeshLevels; + if(features & SceneConverterFeature::ImageLevels) + filteredContents |= SceneConverterContent::ExtraImageLevels; + + // TODO be sure to test this + return addImporterContents(importer, filteredContents & contents); +} + Debug& operator<<(Debug& debug, const SceneConverterFeature value) { debug << "Trade::SceneConverterFeature" << Debug::nospace; diff --git a/src/Magnum/Trade/AbstractSceneConverter.h b/src/Magnum/Trade/AbstractSceneConverter.h index 4fb95a359..67faf671f 100644 --- a/src/Magnum/Trade/AbstractSceneConverter.h +++ b/src/Magnum/Trade/AbstractSceneConverter.h @@ -311,6 +311,49 @@ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, SceneConverterFlag value); */ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, SceneConverterFlags value); +/** +@brief Contents to use for scene conversion +@m_since_latest + +@see @ref SceneConverterContents, + @ref AbstractSceneConverter::addImporterContents(), + @ref AbstractSceneConverter::addSupportedImporterContents() +*/ +enum class SceneConverterContent: UnsignedInt { + Scenes = 1 << 0, // TODO ... and default scene? + Animations = 1 << 1, + Lights = 1 << 2, + Cameras = 1 << 3, + Skins2D = 1 << 4, + Skins3D = 1 << 5, + Meshes = 1 << 6, + Materials = 1 << 7, + Textures = 1 << 8, + Images1D = 1 << 9, + Images2D = 1 << 10, + Images3D = 1 << 11, + CompressedImages1D = 1 << 12, + CompressedImages2D = 1 << 13, + CompressedImages3D = 1 << 14, + ExtraMeshLevels = 1 << 15, // TODO what to do here? just the first one if not? + ExtraImageLevels = 1 << 16 + // TODO Names ?! or, rather, NoNames?! + // TODO or have that as a global flag, IgnoreNames, for smaller output? + + // TODO what about scene parts? "only mesh and material assignment", "no custom fields", ...? i guess better done separately +}; + +/** +@brief Parts to import for scene conversion +@m_since_latest + +@see @ref AbstractSceneConverter::addImporterContents(), + @ref AbstractSceneConverter::addSupportedImporterContents() +*/ +typedef Containers::EnumSet SceneConverterContents; + +CORRADE_ENUMSET_OPERATORS(SceneConverterContents) + #ifdef MAGNUM_BUILD_DEPRECATED namespace Implementation { /* Could be a concrete type as it's always only char, but that would mean @@ -1687,6 +1730,39 @@ class MAGNUM_TRADE_EXPORT AbstractSceneConverter: public PluginManager::Abstract // Containers::Optional add(std::initializer_list imageLevels); // #endif + /** + * @brief Add importer contents + * @m_since_latest + * + * Convenience function for querying @p importer for particular data + * and feeding them to various `add*()` and `set*()` functions. + * + * Expects that a conversion is currently in progress and for every + * @ref SceneConverterContent in @p contents a corresponding feature is + * supported. + * @see @ref addSupportedImporterContents() + */ + bool addImporterContents(AbstractImporter& importer, SceneConverterContents contents); + // TODO mention that Count gets updated after (?!) + // TODO document behavior if something fails -- continue or abruptly fail? uhhh + // take this as a convenience feature and if more detailed behavior is + // needed, use the functions directly?! + + // TODO some doAddImporter() thing for e.g. glTF JSON + // being directly reused (or not)? or not at all? + // seems like needless pain, honestly :( + // TODO or maybe if it would just get some importer-specific extras + // and leave the rest on the base implementation? + + /** + * @brief Add supported importer contents + * @m_since_latest + * + * Filters @p contents based on supported @ref features() and delegates + * to @ref addImporterContents(). + */ + bool addSupportedImporterContents(AbstractImporter& importer, SceneConverterContents contents = ~SceneConverterContents{}); + protected: /** * @brief Implementation for @ref convertToFile(const MeshData&, Containers::StringView)