#ifndef Magnum_Trade_AbstractImporter_h #define Magnum_Trade_AbstractImporter_h /* This file is part of Magnum. Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Vladimír Vondruš 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::AbstractImporter */ #include #include #include #include #include "Magnum/Magnum.h" #include "Magnum/Trade/Trade.h" #include "Magnum/Trade/visibility.h" #ifdef MAGNUM_BUILD_DEPRECATED #include "MagnumExternal/Optional/OptionalWrapper.h" #endif namespace Magnum { namespace Trade { /** @brief Importer file loading callback policy @see @ref AbstractImporter::setFileCallback(), @ref Trade-AbstractImporter-usage-callbacks */ enum class ImporterFileCallbackPolicy: UnsignedByte { /** * The requested file is used only during a call of given function and the * memory view is not referenced anymore once the function exits. * * This can be the case for example when importing image data using * @ref AbstractImporter::image2D() --- imported data are copied into the * returned @ref ImageData2D object and the original file is not needed * anymore. Note, however, that this might not be the case for all * importers --- see documentation of a particular plugin for concrete * info. */ LoadTemporary, /** * The requested file may be used for loading most or all data in the next * steps, so the importer expects the memory view to be valid for as long * as data import functions are called on it, but at most until the * importer is destroyed, @ref AbstractImporter::close() is called or * another file is opened. * * This can be the case for example when importing mesh data using * @ref AbstractImporter::mesh3D() --- all vertex data might be combined in * a single binary file and each mesh occupies only a portion of it. Note, * however, that this might not be the case for all importers --- see * documentation of a particular plugin for concrete info. */ LoadPernament, /** * A file that has been previously loaded by this callback can be closed * now (and its memory freed). This is just a hint, it's not *required* for * the callback to close it. This policy is also only ever called with a * file that was previously opened with the same callback, so it's possible * to completely ignore it and just return the cached value. * * This can be the case for example when an importer is done parsing a text * file into an internal representation and the original data are no longer * needed (and, for example, other files need to be loaded and they could * repurpose the unused memory). */ Close }; /** @brief Base for importer plugins Provides interface for importing 2D/3D scene, camera, light, animation, mesh, material, texture and image data. @section Trade-AbstractImporter-usage Usage Importers are most commonly implemented as plugins. For example, loading an image from the filesystem using the @ref AnyImageImporter plugin can be done like this, completely with all error handling: @snippet MagnumTrade.cpp AbstractImporter-usage See @ref plugins for more information about general plugin usage and `*Importer` classes in the @ref Trade namespace for available importer plugins. @subsection Trade-AbstractImporter-usage-callbacks Loading data from memory Besides loading data directly from the filesystem using @ref openFile() like shown above, it's possible to use @ref openData() to import data from memory. Note that the particular importer implementation must support @ref Feature::OpenData for this method to work. Complex scene files often reference other files such as images and in that case you may want to intercept those references and load them in a custom way as well. For importers that advertise support for this with @ref Feature::FileCallback this is done by specifying a file loading callback using @ref setFileCallback(). The callback gets a filename, @ref ImporterFileCallbackPolicy and an user pointer as parameters; returns a non-owning view on the loaded data or a @ref Corrade::Containers::NullOpt "Containers::NullOpt" to indicate the file loading failed. For example, loading a scene from memory-mapped files could look like below. Note that the file loading callback affects @ref openFile() as well --- you don't have to load the top-level file manually and pass it to @ref openData(), any importer supporting the callback feature handles that correctly. @snippet MagnumTrade.cpp AbstractImporter-usage-callbacks For importers that don't support @ref Feature::FileCallback directly, the base @ref openFile() implementation will use the file callback to pass the loaded data through to @ref openData(), in case the importer supports at least @ref Feature::OpenData. If the importer supports neither @ref Feature::FileCallback nor @ref Feature::OpenData, @ref setFileCallback() doesn't allow the callbacks to be set. @subsection Trade-AbstractImporter-usage-state Internal importer state Some importers, especially ones that make use of well-known external libraries, expose internal state through various accessors: - @ref importerState() can expose a pointer to the global importer state for currently opened file - @ref AbstractMaterialData::importerState() can expose importer state for given material imported by @ref material() - @ref AnimationData::importerState() can expose importer state for given animation imported by @ref animation() - @ref CameraData::importerState() can expose importer state for a camera importer by @ref camera() - @ref ImageData::importerState() can expose importer state for an image imported by @ref image1D(), @ref image2D() or @ref image3D() - @ref LightData::importerState() can expose importer state for a light imported by @ref light() - @ref MeshData3D::importerState() can expose importer state for a mesh imported by @ref mesh2D() or @ref mesh3D() - @ref ObjectData3D::importerState() can expose importer state for an object imported by @ref object2D() or @ref object3D() - @ref SceneData::importerState() can expose importer state for a scene imported by @ref scene() - @ref TextureData::importerState() can expose importer state for a texture imported by @ref texture() Besides exposing internal state, importers that support the @ref Feature::OpenState feature can also attach to existing importer state using @ref openState(). See documentation of a particular importer for details about concrete types returned and accepted by these functions. @subsection Trade-AbstractImporter-usage-casting Polymorphic imported data types Some data access functions return @ref std::unique_ptr instead of @ref Corrade::Containers::Optional because the result might be a particular subclass of given type. Those functions are @ref material(), @ref object2D() and @ref object3D(). You can cast the abstract base to a concrete type depending on its reported type, for example: @snippet MagnumTrade.cpp AbstractImporter-usage-cast Another option is making use of the @ref std::static_pointer_cast() family of utilities, but note that in that case your @ref std::unique_ptr will be *moved into* a @ref std::shared_ptr instance and that might not be desirable. @section Trade-AbstractImporter-subclassing Subclassing The plugin needs to implement the @ref doFeatures(), @ref doIsOpened() functions, at least one of @ref doOpenData() / @ref doOpenFile() / @ref doOpenState() functions, function @ref doClose() and one or more tuples of data access functions, based on what features are supported in given format. In order to support @ref Feature::FileCallback, the importer needs to properly use the callbacks to both load the top-level file in @ref doOpenFile() and also load any external files when needed. The @ref doOpenFile() can delegate back into the base implementation, but it should remember at least the base file path to pass correct paths to subsequent file callbacks. The @ref doSetFileCallback() can be overriden in case it's desired to respond to file loading callback setup, but doesn't have to be. For multi-data formats the file opening shouldn't take long and all parsing should be done in the data parsing functions instead, because the user might want to import only some data. This is obviously not the case for single-data formats like images, as the file contains all the data the user wants to import. You don't need to do most of the redundant sanity checks, these things are checked by the implementation: - The @ref doOpenData(), @ref doOpenFile() and @ref doOpenState() functions are called after the previous file was closed, function @ref doClose() is called only if there is any file opened. - The @ref doOpenData() function is called only if @ref Feature::OpenData is supported. - The @ref doOpenState() function is called only if @ref Feature::OpenState is supported. - The @ref doSetFileCallback() function is called only if @ref Feature::FileCallback is supported and there is no file opened. - All `do*()` implementations working on an opened file are called only if there is any file opened. - All `do*()` implementations taking data ID as parameter are called only if the ID is from valid range. @attention @ref Corrade::Containers::Array instances returned from the plugin should *not* use anything else than the default deleter, otherwise this can cause dangling function pointer call on array destruction if the plugin gets unloaded before the array is destroyed. @attention Similarly for interpolator functions passed through @ref Animation::TrackView instances to @ref AnimationData --- to avoid dangling pointers, be sure to always include an interpolator returned from @ref animationInterpolatorFor(), which guarantees the function is *not* instantiated in the plugin binary. Avoid using @ref Animation::interpolatorFor() (or indirectly it by specifying just @ref Animation::Interpolation), as it doesn't have such guarantee. */ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagingPlugin { public: /** * @brief Features supported by this importer * * @see @ref Features, @ref features() */ enum class Feature: UnsignedByte { /** Opening files from raw data using @ref openData() */ OpenData = 1 << 0, /** Opening already loaded state using @ref openState() */ OpenState = 1 << 1, /** * Specifying callbacks for loading additional files referenced * from the main file using @ref setFileCallback(). If the importer * doesn't expose this feature, the format is either single-file or * loading via callbacks is not supported. * * See @ref Trade-AbstractImporter-usage-callbacks and particular * importer documentation for more information. */ FileCallback = 1 << 2 }; /** * @brief Set of features supported by this importer * * @see @ref features() */ typedef Containers::EnumSet Features; /** * @brief Plugin interface * * @code{.cpp} * "cz.mosra.magnum.Trade.AbstractImporter/0.3" * @endcode */ static std::string pluginInterface(); #ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT /** * @brief Plugin search paths * * First looks in `magnum/importers/` or `magnum-d/importers/` next to * the executable and as a fallback in `magnum/importers/` or * `magnum-d/importers/` in the runtime install location (`lib[64]/` on * Unix-like systems, `bin/` on Windows). The system-wide plugin search * directory is configurable using the `MAGNUM_PLUGINS_DIR` CMake * variables, see @ref building for more information. * * Not defined on platforms without * @ref CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT "dynamic plugin support". */ static std::vector pluginSearchPaths(); #endif /** @brief Default constructor */ explicit AbstractImporter(); /** @brief Constructor with access to plugin manager */ explicit AbstractImporter(PluginManager::Manager& manager); /** @brief Plugin manager constructor */ explicit AbstractImporter(PluginManager::AbstractManager& manager, const std::string& plugin); /** @brief Features supported by this importer */ Features features() const { return doFeatures(); } /** * @brief File opening callback function * * @see @ref Trade-AbstractImporter-usage-callbacks */ auto fileCallback() const -> Containers::Optional>(*)(const std::string&, ImporterFileCallbackPolicy, void*) { return _fileCallback; } /** * @brief File opening callback user data * * @see @ref Trade-AbstractImporter-usage-callbacks */ void* fileCallbackUserData() const { return _fileCallbackUserData; } /** * @brief Set file opening callback * * In case the importer supports @ref Feature::FileCallback, files * opened through @ref openFile() will be loaded through the provided * callback. Besides that, all external files referenced by the * top-level file will be loaded through the callback function as well, * usually on demand. The callback function gets a filename, * @ref ImporterFileCallbackPolicy and the @p userData pointer as input * and returns a non-owning view on the loaded data as output or a * @ref Corrade::Containers::NullOpt if loading failed --- because * empty files might also be valid in some circumstances, @cpp nullptr @ce * can't be used to indicate a failure. * * In case the importer doesn't support @ref Feature::FileCallback but * supports at least @ref Feature::OpenData, a file opened through * @ref openFile() will be internally loaded through the provided * callback and then passed to @ref openData(). First the file is * loaded with @ref ImporterFileCallbackPolicy::LoadTemporary passed to * the callback, then the returned memory view is passed to * @ref openData() (sidestepping the potential @ref openFile() * implementation of that particular importer) and after that the * callback is called again with @ref ImporterFileCallbackPolicy::Close * because the semantics of @ref openData() don't require the data to * be alive after. In case you need a different behavior, use * @ref openData() directly. * * In case @p callback is @cpp nullptr @ce, the current callback (if * any) is reset. This function expects that the importer supports * either @ref Feature::FileCallback or @ref Feature::OpenData. If an * importer supports neither, callbacks can't be used. * * It's expected that this function is called *before* a file is * opened. It's also expected that the loaded data are kept in scope * for as long as the importer needs them, based on the value of * @ref ImporterFileCallbackPolicy. Documentation of particular * importers provides more information about the expected callback * behavior. * * Following is an example of setting up a file loading callback for * fetching compiled-in resources from @ref Corrade::Utility::Resource. * See the overload below for a more convenient type-safe way to pass * the user data pointer. * * @snippet MagnumTrade.cpp AbstractImporter-setFileCallback * * @see @ref Trade-AbstractImporter-usage-callbacks */ void setFileCallback(Containers::Optional>(*callback)(const std::string&, ImporterFileCallbackPolicy, void*), void* userData = nullptr); /** * @brief Set file opening callback * * Equivalent to calling the above with a lambda wrapper that casts * @cpp void* @ce back to @cpp T* @ce and dereferences it in order to * pass it to @p callback. Example usage: * * @snippet MagnumTrade.cpp AbstractImporter-setFileCallback-template * * @see @ref Trade-AbstractImporter-usage-callbacks */ #ifdef DOXYGEN_GENERATING_OUTPUT template void setFileCallback(Containers::Optional>(*callback)(const std::string&, ImporterFileCallbackPolicy, T&), T& userData); #else /* Otherwise the user would be forced to use the + operator to convert a lambda to a function pointer and (besides being weird and annoying) it's also not portable because it doesn't work on MSVC 2015 and older versions of MSVC 2017. */ template void setFileCallback(Callback callback, T& userData); #endif /** @brief Whether any file is opened */ bool isOpened() const { return doIsOpened(); } /** * @brief Open raw data * * Closes previous file, if it was opened, and tries to open given raw * data. Available only if @ref Feature::OpenData is supported. Returns * @cpp true @ce on success, @cpp false @ce otherwise. * @see @ref features(), @ref openFile() */ bool openData(Containers::ArrayView data); /** * @brief Open already loaded state * @param state Pointer to importer-specific state * @param filePath Base file directory for opening external data like * textures and materials. * * Closes previous file, if it was opened, and tries to open given * state. Available only if @ref Feature::OpenState is supported. Returns * @cpp true @ce on success, @cpp false @ce otherwise. * * See documentation of a particular plugin for more information about * type and contents of the @p state parameter. * @see @ref features(), @ref openData() */ bool openState(const void* state, const std::string& filePath = {}); /** * @brief Open file * * Closes previous file, if it was opened, and tries to open given * file. Returns @cpp true @ce on success, @cpp false @ce otherwise. * If file loading callbacks are set via @ref setFileCallback() and * @ref Feature::OpenData is supported, this function uses the callback * to load the file and passes the memory view to @ref openData() * instead. See @ref setFileCallback() for more information. * @see @ref features(), @ref openData() */ bool openFile(const std::string& filename); /** @brief Close file */ void close(); /** @{ @name Data accessors * Each function tuple provides access to given data. */ /** * @brief Default scene * * When there is more than one scene, returns ID of the default one. * If there is no default scene, returns @cpp -1 @ce. * * @note The function is not const, because the value will probably * be lazy-populated. */ Int defaultScene(); /** @brief Scene count */ UnsignedInt sceneCount() const; /** * @brief Scene ID for given name * * If no scene for given name exists, returns @cpp -1 @ce. * @see @ref sceneName() */ Int sceneForName(const std::string& name); /** * @brief Scene name * @param id Scene ID, from range [0, @ref sceneCount()). * * @see @ref sceneForName() */ std::string sceneName(UnsignedInt id); /** * @brief Scene * @param id Scene ID, from range [0, @ref sceneCount()). * * Returns given scene or @ref Containers::NullOpt if import failed. */ Containers::Optional scene(UnsignedInt id); /** @brief Animation count */ UnsignedInt animationCount() const; /** * @brief Animation ID for given name * * If no animation for given name exists, returns @cpp -1 @ce. * @see @ref animationName() */ Int animationForName(const std::string& name); /** * @brief Animation name * @param id Animation ID, from range [0, @ref animationCount()). * * @see @ref animationForName() */ std::string animationName(UnsignedInt id); /** * @brief Animation * @param id Animation ID, from range [0, @ref animationCount()). * * Returns given animation or @ref Containers::NullOpt if importing * failed. */ Containers::Optional animation(UnsignedInt id); /** @brief Light count */ UnsignedInt lightCount() const; /** * @brief Light ID for given name * * If no light for given name exists, returns @cpp -1 @ce. * @see @ref lightName() */ Int lightForName(const std::string& name); /** * @brief Light name * @param id Light ID, from range [0, @ref lightCount()). * * @see @ref lightForName() */ std::string lightName(UnsignedInt id); /** * @brief Light * @param id Light ID, from range [0, @ref lightCount()). * * Returns given light or @ref Containers::NullOpt if importing failed. */ Containers::Optional light(UnsignedInt id); /** @brief Camera count */ UnsignedInt cameraCount() const; /** * @brief Camera ID for given name * * If no camera for given name exists, returns @cpp -1 @ce. * @see @ref cameraName() */ Int cameraForName(const std::string& name); /** * @brief Camera name * @param id Camera ID, from range [0, @ref cameraCount()). * * @see @ref cameraForName() */ std::string cameraName(UnsignedInt id); /** * @brief Camera * @param id Camera ID, from range [0, @ref cameraCount()). * * Returns given camera or @ref Containers::NullOpt if importing failed. */ Containers::Optional camera(UnsignedInt id); /** @brief Two-dimensional object count */ UnsignedInt object2DCount() const; /** * @brief Two-dimensional object ID for given name * * If no scene for given name exists, returns @cpp -1 @ce. * @see @ref object2DName() */ Int object2DForName(const std::string& name); /** * @brief Two-dimensional object name * @param id Object ID, from range [0, @ref object2DCount()). * * @see @ref object2DForName() */ std::string object2DName(UnsignedInt id); /** * @brief Two-dimensional object * @param id Object ID, from range [0, @ref object2DCount()). * * Returns given object or @cpp nullptr @ce if importing failed. */ std::unique_ptr object2D(UnsignedInt id); /** @brief Three-dimensional object count */ UnsignedInt object3DCount() const; /** * @brief Three-dimensional object ID for given name * * If no scene for given name exists, returns @cpp -1 @ce. * @see @ref object3DName() */ Int object3DForName(const std::string& name); /** * @brief Three-dimensional object name * @param id Object ID, from range [0, @ref object3DCount()). * * @see @ref object3DForName() */ std::string object3DName(UnsignedInt id); /** * @brief Three-dimensional object * @param id Object ID, from range [0, @ref object3DCount()). * * Returns given object or @cpp nullptr @ce if importing failed. */ std::unique_ptr object3D(UnsignedInt id); /** @brief Two-dimensional mesh count */ UnsignedInt mesh2DCount() const; /** * @brief Two-dimensional mesh ID for given name * * If no mesh for given name exists, returns @cpp -1 @ce. * @see @ref mesh2DName() */ Int mesh2DForName(const std::string& name); /** * @brief Two-dimensional mesh name * @param id Mesh ID, from range [0, @ref mesh2DCount()). * * @see @ref mesh2DForName() */ std::string mesh2DName(UnsignedInt id); /** * @brief Two-dimensional mesh * @param id Mesh ID, from range [0, @ref mesh2DCount()). * * Returns given mesh or @ref Containers::NullOpt if importing failed. */ Containers::Optional mesh2D(UnsignedInt id); /** @brief Three-dimensional mesh count */ UnsignedInt mesh3DCount() const; /** * @brief Three-dimensional mesh ID for given name * * If no mesh for given name exists, returns @cpp -1 @ce. * @see @ref mesh3DName() */ Int mesh3DForName(const std::string& name); /** * @brief Three-dimensional mesh name * @param id Mesh ID, from range [0, @ref mesh3DCount()). * * @see @ref mesh3DForName() */ std::string mesh3DName(UnsignedInt id); /** * @brief Three-dimensional mesh * @param id Mesh ID, from range [0, @ref mesh3DCount()). * * Returns given mesh or @ref Containers::NullOpt if importing failed. */ Containers::Optional mesh3D(UnsignedInt id); /** @brief Material count */ UnsignedInt materialCount() const; /** * @brief Material ID for given name * * If no material for given name exists, returns @cpp -1 @ce. * @see @ref materialName() */ Int materialForName(const std::string& name); /** * @brief Material name * @param id Material ID, from range [0, @ref materialCount()). * * @see @ref materialForName() */ std::string materialName(UnsignedInt id); /** * @brief Material * @param id Material ID, from range [0, @ref materialCount()). * * Returns given material or @cpp nullptr @ce if importing failed. */ std::unique_ptr material(UnsignedInt id); /** @brief Texture count */ UnsignedInt textureCount() const; /** * @brief Texture ID for given name * * If no texture for given name exists, returns @cpp -1 @ce. * @see @ref textureName() */ Int textureForName(const std::string& name); /** * @brief Texture name * @param id Texture ID, from range [0, @ref textureCount()). * * @see @ref textureForName() */ std::string textureName(UnsignedInt id); /** * @brief Texture * @param id Texture ID, from range [0, @ref textureCount()). * * Returns given texture or @ref Containers::NullOpt if importing failed. */ Containers::Optional texture(UnsignedInt id); /** @brief One-dimensional image count */ UnsignedInt image1DCount() const; /** * @brief One-dimensional image ID for given name * * If no image for given name exists, returns @cpp -1 @ce. * @see @ref image1DName() */ Int image1DForName(const std::string& name); /** * @brief One-dimensional image name * @param id Image ID, from range [0, @ref image1DCount()). * * @see @ref image1DForName() */ std::string image1DName(UnsignedInt id); /** * @brief One-dimensional image * @param id Image ID, from range [0, @ref image1DCount()). * * Returns given image or @ref Containers::NullOpt if importing failed. */ Containers::Optional image1D(UnsignedInt id); /** @brief Two-dimensional image count */ UnsignedInt image2DCount() const; /** * @brief Two-dimensional image ID for given name * * If no image for given name exists, returns @cpp -1 @ce. * @see @ref image2DName() */ Int image2DForName(const std::string& name); /** * @brief Two-dimensional image name * @param id Image ID, from range [0, @ref image2DCount()). * * @see @ref image2DForName() */ std::string image2DName(UnsignedInt id); /** * @brief Two-dimensional image * @param id Image ID, from range [0, @ref image2DCount()). * * Returns given image or @ref Containers::NullOpt if importing failed. */ Containers::Optional image2D(UnsignedInt id); /** @brief Three-dimensional image count */ UnsignedInt image3DCount() const; /** * @brief Three-dimensional image ID for given name * * If no image for given name exists, returns @cpp -1 @ce. * @see @ref image3DName() */ Int image3DForName(const std::string& name); /** * @brief Three-dimensional image name * @param id Image ID, from range [0, @ref image3DCount()). * * @see @ref image3DForName() */ std::string image3DName(UnsignedInt id); /** * @brief Three-dimensional image * @param id Image ID, from range [0, @ref image3DCount()). * * Returns given image or @ref Containers::NullOpt if importing failed. */ Containers::Optional image3D(UnsignedInt id); /*@}*/ /** * @brief Plugin-specific access to internal importer state * * The importer might provide access to its internal data structures * for currently opened document through this function. See * documentation of a particular plugin for more information about * returned type and contents. Returns @cpp nullptr @ce by default. * @see @ref AbstractMaterialData::importerState(), * @ref AnimationData::importerState(), @ref CameraData::importerState(), * @ref ImageData::importerState(), @ref LightData::importerState(), * @ref MeshData2D::importerState(), @ref MeshData3D::importerState(), * @ref ObjectData2D::importerState(), @ref ObjectData3D::importerState(), * @ref SceneData::importerState(), @ref TextureData::importerState() */ const void* importerState() const; protected: /** * @brief Implementation for @ref openFile() * * If @ref Feature::OpenData is supported, default implementation opens * the file and calls @ref Magnum::Trade::AbstractImporter::doOpenData() "doOpenData()" * with its contents. It is allowed to call this function from your * @ref Magnum::Trade::AbstractImporter::doOpenFile() "doOpenFile()" * implementation --- in particular, this implementation will also * correctly handle callbacks set through @ref setFileCallback(). * * This function is not called when file callbacks are set through * @ref setFileCallback() and @ref Feature::FileCallback is not * supported --- instead, file is loaded though the callback and data * passed through to @ref Magnum::Trade::AbstractImporter::doOpenData() "doOpenData()". */ virtual void doOpenFile(const std::string& filename); private: /** @brief Implementation for @ref features() */ virtual Features doFeatures() const = 0; /** * @brief Implementation for @ref setFileCallback() * * Useful when the importer needs to modify some internal state on * callback setup. Default implementation does nothing and this * function doesn't need to be implemented --- the callback function * and user data pointer are available through @ref fileCallback() and * @ref fileCallbackUserData(). */ virtual void doSetFileCallback(Containers::Optional>(*callback)(const std::string&, ImporterFileCallbackPolicy, void*), void* userData); /** @brief Implementation for @ref isOpened() */ virtual bool doIsOpened() const = 0; /** @brief Implementation for @ref openData() */ virtual void doOpenData(Containers::ArrayView data); /** @brief Implementation for @ref openState() */ virtual void doOpenState(const void* state, const std::string& filePath); /** @brief Implementation for @ref close() */ virtual void doClose() = 0; /** * @brief Implementation for @ref defaultScene() * * Default implementation returns @cpp -1 @ce. */ virtual Int doDefaultScene(); /** * @brief Implementation for @ref sceneCount() * * Default implementation returns @cpp 0 @ce. */ virtual UnsignedInt doSceneCount() const; /** * @brief Implementation for @ref sceneForName() * * Default implementation returns @cpp -1 @ce. */ virtual Int doSceneForName(const std::string& name); /** * @brief Implementation for @ref sceneName() * * Default implementation returns empty string. */ virtual std::string doSceneName(UnsignedInt id); /** @brief Implementation for @ref scene() */ virtual Containers::Optional doScene(UnsignedInt id); /** * @brief Implementation for @ref animationCount() * * Default implementation returns @cpp 0 @ce. */ virtual UnsignedInt doAnimationCount() const; /** * @brief Implementation for @ref animationForName() * * Default implementation returns @cpp -1 @ce. */ virtual Int doAnimationForName(const std::string& name); /** * @brief Implementation for @ref animationName() * * Default implementation returns empty string. */ virtual std::string doAnimationName(UnsignedInt id); /** @brief Implementation for @ref animation() */ virtual Containers::Optional doAnimation(UnsignedInt id); /** * @brief Implementation for @ref lightCount() * * Default implementation returns @cpp 0 @ce. */ virtual UnsignedInt doLightCount() const; /** * @brief Implementation for @ref lightForName() * * Default implementation returns @cpp -1 @ce. */ virtual Int doLightForName(const std::string& name); /** * @brief Implementation for @ref lightName() * * Default implementation returns empty string. */ virtual std::string doLightName(UnsignedInt id); /** @brief Implementation for @ref light() */ virtual Containers::Optional doLight(UnsignedInt id); /** * @brief Implementation for @ref cameraCount() * * Default implementation returns @cpp 0 @ce. */ virtual UnsignedInt doCameraCount() const; /** * @brief Implementation for @ref cameraForName() * * Default implementation returns @cpp -1 @ce. */ virtual Int doCameraForName(const std::string& name); /** * @brief Implementation for @ref cameraName() * * Default implementation returns empty string. */ virtual std::string doCameraName(UnsignedInt id); /** @brief Implementation for @ref camera() */ virtual Containers::Optional doCamera(UnsignedInt id); /** * @brief Implementation for @ref object2DCount() * * Default implementation returns @cpp 0 @ce. */ virtual UnsignedInt doObject2DCount() const; /** * @brief Implementation for @ref object2DForName() * * Default implementation returns @cpp -1 @ce. */ virtual Int doObject2DForName(const std::string& name); /** * @brief Implementation for @ref object2DName() * * Default implementation returns empty string. */ virtual std::string doObject2DName(UnsignedInt id); /** @brief Implementation for @ref object2D() */ virtual std::unique_ptr doObject2D(UnsignedInt id); /** * @brief Implementation for @ref object3DCount() * * Default implementation returns @cpp 0 @ce. */ virtual UnsignedInt doObject3DCount() const; /** * @brief Implementation for @ref object3DForName() * * Default implementation returns @cpp -1 @ce. */ virtual Int doObject3DForName(const std::string& name); /** * @brief Implementation for @ref object3DName() * * Default implementation returns empty string. */ virtual std::string doObject3DName(UnsignedInt id); /** @brief Implementation for @ref object3D() */ virtual std::unique_ptr doObject3D(UnsignedInt id); /** * @brief Implementation for @ref mesh2DCount() * * Default implementation returns @cpp 0 @ce. */ virtual UnsignedInt doMesh2DCount() const; /** * @brief Implementation for @ref mesh2DForName() * * Default implementation returns @cpp -1 @ce. */ virtual Int doMesh2DForName(const std::string& name); /** * @brief Implementation for @ref mesh2DName() * * Default implementation returns empty string. */ virtual std::string doMesh2DName(UnsignedInt id); /** @brief Implementation for @ref mesh2D() */ virtual Containers::Optional doMesh2D(UnsignedInt id); /** * @brief Implementation for @ref mesh3DCount() * * Default implementation returns @cpp 0 @ce. */ virtual UnsignedInt doMesh3DCount() const; /** * @brief Implementation for @ref mesh3DForName() * * Default implementation returns @cpp -1 @ce. */ virtual Int doMesh3DForName(const std::string& name); /** * @brief Implementation for @ref mesh3DName() * * Default implementation returns empty string. */ virtual std::string doMesh3DName(UnsignedInt id); /** @brief Implementation for @ref mesh3D() */ virtual Containers::Optional doMesh3D(UnsignedInt id); /** * @brief Implementation for @ref materialCount() * * Default implementation returns @cpp 0 @ce. */ virtual UnsignedInt doMaterialCount() const; /** * @brief Implementation for @ref materialForName() * * Default implementation returns @cpp -1 @ce. */ virtual Int doMaterialForName(const std::string& name); /** * @brief Implementation for @ref materialName() * * Default implementation returns empty string. */ virtual std::string doMaterialName(UnsignedInt id); /** @brief Implementation for @ref material() */ virtual std::unique_ptr doMaterial(UnsignedInt id); /** * @brief Implementation for @ref textureCount() * * Default implementation returns @cpp 0 @ce. */ virtual UnsignedInt doTextureCount() const; /** * @brief Implementation for @ref textureForName() * * Default implementation returns @cpp -1 @ce. */ virtual Int doTextureForName(const std::string& name); /** * @brief Implementation for @ref textureName() * * Default implementation returns empty string. */ virtual std::string doTextureName(UnsignedInt id); /** @brief Implementation for @ref texture() */ virtual Containers::Optional doTexture(UnsignedInt id); /** * @brief Implementation for @ref image1DCount() * * Default implementation returns @cpp 0 @ce. */ virtual UnsignedInt doImage1DCount() const; /** * @brief Implementation for @ref image1DForName() * * Default implementation returns @cpp -1 @ce. */ virtual Int doImage1DForName(const std::string& name); /** * @brief Implementation for @ref image1DName() * * Default implementation returns empty string. */ virtual std::string doImage1DName(UnsignedInt id); /** @brief Implementation for @ref image1D() */ virtual Containers::Optional doImage1D(UnsignedInt id); /** * @brief Implementation for @ref image2DCount() * * Default implementation returns @cpp 0 @ce. */ virtual UnsignedInt doImage2DCount() const; /** * @brief Implementation for @ref image2DForName() * * Default implementation returns @cpp -1 @ce. */ virtual Int doImage2DForName(const std::string& name); /** * @brief Implementation for @ref image2DName() * * Default implementation returns empty string. */ virtual std::string doImage2DName(UnsignedInt id); /** @brief Implementation for @ref image2D() */ virtual Containers::Optional doImage2D(UnsignedInt id); /** * @brief Implementation for @ref image3DCount() * * Default implementation returns @cpp 0 @ce. */ virtual UnsignedInt doImage3DCount() const; /** * @brief Implementation for @ref image3DForName() * * Default implementation returns @cpp -1 @ce. */ virtual Int doImage3DForName(const std::string& name); /** * @brief Implementation for @ref image3DName() * * Default implementation returns empty string. */ virtual std::string doImage3DName(UnsignedInt id); /** @brief Implementation for @ref image3D() */ virtual Containers::Optional doImage3D(UnsignedInt id); /** @brief Implementation for @ref importerState() */ virtual const void* doImporterState() const; private: Containers::Optional>(*_fileCallback)(const std::string&, ImporterFileCallbackPolicy, void*){}; void* _fileCallbackUserData{}; /* Used by the templated version only */ struct FileCallbackTemplate { void(*callback)(); void* userData; } _fileCallbackTemplate{}; }; #ifndef DOXYGEN_GENERATING_OUTPUT template void AbstractImporter::setFileCallback(Callback callback, T& userData) { /* Don't try to wrap a null function pointer. Need to cast first because MSVC (even 2017) can't apply ! to a lambda. Ugh. */ const auto callbackPtr = static_cast>(*)(const std::string&, ImporterFileCallbackPolicy, T&)>(callback); if(!callbackPtr) return setFileCallback(nullptr); _fileCallbackTemplate = { reinterpret_cast(callbackPtr), &userData }; setFileCallback([](const std::string& filename, const ImporterFileCallbackPolicy flags, void* const userData) { auto& s = *reinterpret_cast(userData); return reinterpret_cast>(*)(const std::string&, ImporterFileCallbackPolicy, T&)>(s.callback)(filename, flags, *static_cast(s.userData)); }, &_fileCallbackTemplate); } #endif CORRADE_ENUMSET_OPERATORS(AbstractImporter::Features) /** @debugoperatorclassenum{AbstractImporter,AbstractImporter::Feature} */ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, AbstractImporter::Feature value); /** @debugoperatorclassenum{AbstractImporter,AbstractImporter::Features} */ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, AbstractImporter::Features value); /** @debugoperatorenum{ImporterFileCallbackPolicy} */ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, ImporterFileCallbackPolicy value); }} #endif