|
|
|
|
/*
|
|
|
|
|
This file is part of Magnum.
|
|
|
|
|
|
|
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019
|
|
|
|
|
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.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
namespace Magnum {
|
|
|
|
|
/** @page plugins Loading and using plugins
|
|
|
|
|
@brief Extending Magnum with additional functionality
|
|
|
|
|
|
|
|
|
|
@tableofcontents
|
|
|
|
|
@m_footernavigation
|
|
|
|
|
@m_keywords{Plugins}
|
|
|
|
|
|
|
|
|
|
The base Magnum libraries contain math support, scene graph implementation and
|
|
|
|
|
are able to interact with graphics and audio hardware. However, they don't
|
|
|
|
|
provide any functions for dealing with specific file formats on their own, as
|
|
|
|
|
there are simply too many formats to include all of them directly. Instead, the
|
|
|
|
|
libraries provide plugin APIs using which you can load a plugin that's able to
|
|
|
|
|
understand a particular file format. Plugins are distributed as additional
|
|
|
|
|
libraries and loaded either dynamically from the filesystem or, in case of
|
|
|
|
|
embedded systems that don't support dynamic loading, built statically into the
|
|
|
|
|
executable. Depending on the target platform requirements, different set of
|
|
|
|
|
plugins can be deployed for different platforms.
|
|
|
|
|
|
|
|
|
|
The @ref building "core Magnum repository" contains a few basic plugins for
|
|
|
|
|
opening simple formats, such as TGA images or WAV audio files. These plugins
|
|
|
|
|
are included because the file formats are so simple that no 3rd party libraries
|
|
|
|
|
are needed for loading their contents and thus they are suitable for quick
|
|
|
|
|
demos and prototyping without needing to deal with additional dependencies.
|
|
|
|
|
|
|
|
|
|
Additional plugins (such as importers for PNG and JPEG images, glTF scenes,
|
|
|
|
|
TrueType fonts etc.) are available in the @ref building-plugins "Magnum Plugins"
|
|
|
|
|
repository. Majority of these plugins depends on external libraries, thus not
|
|
|
|
|
all of them might be available on all platforms.
|
|
|
|
|
|
|
|
|
|
@section plugins-types Plugin interfaces
|
|
|
|
|
|
|
|
|
|
Plugin functionality is exposed via an interface that's common for all plugins
|
|
|
|
|
of given type. Magnum provides these plugin interfaces:
|
|
|
|
|
|
|
|
|
|
- @ref Trade::AbstractImporter --- importers for general 2D and 3D scene,
|
|
|
|
|
mesh, material, texture and image data. See `*Importer` classes in the
|
|
|
|
|
@ref Trade namespace for available importer plugins.
|
|
|
|
|
- @ref Trade::AbstractImageConverter --- conversion among various image
|
|
|
|
|
formats. See `*ImageConverter` classes in the @ref Trade namespace for
|
|
|
|
|
available image converter plugins.
|
|
|
|
|
- @ref Trade::AbstractSceneConverter --- conversion among various scene
|
|
|
|
|
formats, mesh optimization etc. See `*SceneConverter` classes in the
|
|
|
|
|
@ref Trade namespace for available scene converter plugins.
|
|
|
|
|
- @ref Text::AbstractFont --- font loading and glyph layout. See `*Font`
|
|
|
|
|
classes in the @ref Text namespace for available font plugins.
|
|
|
|
|
- @ref Text::AbstractFontConverter --- font and glyph cache conversion. See
|
|
|
|
|
`*FontConverter` classes in the @ref Text namespace for available font
|
|
|
|
|
converter plugins.
|
|
|
|
|
- @ref Audio::AbstractImporter --- importers for audio formats. See
|
|
|
|
|
`*Importer` classes in the @ref Audio namespace for available audio
|
|
|
|
|
importer plugins.
|
|
|
|
|
|
|
|
|
|
@section plugins-loading Loading and instantiating plugins
|
|
|
|
|
|
|
|
|
|
To load a plugin, you need to instantiate @ref Corrade::PluginManager::Manager
|
|
|
|
|
for given plugin interface, for example for the @ref Trade::AbstractImporter.
|
|
|
|
|
In order to find plugins on the filesystem, plugin interfaces have a bunch of
|
|
|
|
|
plugin search paths hardcoded --- see documentation of the
|
|
|
|
|
@ref Trade::AbstractImporter::pluginSearchPaths() "pluginSearchPaths()"
|
|
|
|
|
functions provided by each plugin interface. It usually just works, but you can
|
|
|
|
|
also pass a plugin directory to the manager constructor explicitly.
|
|
|
|
|
|
|
|
|
|
Once the plugin manager is instantiated, you can start creating instances of
|
|
|
|
|
particular plugins. Keep in mind that the manager instance has to exist for
|
|
|
|
|
whole lifetime of all plugin instances created using it.
|
|
|
|
|
|
|
|
|
|
@snippet plugins.cpp loading
|
|
|
|
|
|
|
|
|
|
@section plugins-dependencies Plugin dependencies
|
|
|
|
|
|
|
|
|
|
Some plugins have dependencies, for example the @ref Trade::TinyGltfImporter "TinyGltfImporter"
|
|
|
|
|
plugin uses @ref Trade::AnyImageImporter "AnyImageImporter" to load texture
|
|
|
|
|
data. The dependency loading is done automatically, but in some cases it's
|
|
|
|
|
across plugin types (for example the @ref Text::MagnumFont "MagnumFont" plugin
|
|
|
|
|
depends on the @ref Trade::TgaImporter "TgaImporter" plugin, which is of a
|
|
|
|
|
different type) --- there you need to create manager instances for all required
|
|
|
|
|
plugin interfaces:
|
|
|
|
|
|
|
|
|
|
@snippet plugins.cpp dependencies
|
|
|
|
|
|
|
|
|
|
@section plugins-static Static plugins
|
|
|
|
|
|
|
|
|
|
By default, on desktop systems at least, all plugins are built as dynamic ones,
|
|
|
|
|
i.e. they are a separate binary which gets linked in at runtime. This is good
|
|
|
|
|
for reducing memory consumption, as the code is loaded in memory only for the
|
|
|
|
|
time it is actually needed. However, if you need to port to a platform which
|
|
|
|
|
does not support dynamic linking or you simply want to have the plugin loaded
|
|
|
|
|
at all times, you can use static plugins.
|
|
|
|
|
|
|
|
|
|
The plugins are built as static if the `BUILD_PLUGINS_STATIC` CMake parameter
|
|
|
|
|
is enabled (see @ref building and @ref building-plugins for more information).
|
|
|
|
|
The actual usage in the code is basically the same as above, but you need to
|
|
|
|
|
explicitly find the plugin and link it into the executable. If you use CMake,
|
|
|
|
|
it would look like this:
|
|
|
|
|
|
|
|
|
|
@code{.cmake}
|
|
|
|
|
find_package(MagnumPlugins REQUIRED
|
|
|
|
|
TinyGltfImporter
|
|
|
|
|
StbTrueTypeFont)
|
|
|
|
|
|
|
|
|
|
add_executable(my-app my-app.cpp)
|
|
|
|
|
target_link_libraries(my-app PRIVATE
|
|
|
|
|
MagnumPlugins::TinyGltfImporter
|
|
|
|
|
MagnumPlugins::StbTrueTypeFont)
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The only user-visible behavioral change in the code will be that
|
|
|
|
|
@ref Corrade::PluginManager::AbstractManager::load() "PluginManager::Manager::load()"
|
|
|
|
|
will return @ref Corrade::PluginManager::LoadState::Static "PluginManager::LoadState::Static"
|
|
|
|
|
instead of @ref Corrade::PluginManager::LoadState::Loaded "PluginManager::LoadState::Loaded",
|
|
|
|
|
but there is no need to change the above code, as it will work for both dynamic
|
|
|
|
|
and static case.
|
|
|
|
|
|
|
|
|
|
The static plugin needs to be explicitly registered so the plugin manager is
|
|
|
|
|
aware it's there. If you use CMake, it's done automatically. Otherwise, you can
|
|
|
|
|
achieve the same if you explicitly @cpp #include @ce the static plugin import
|
|
|
|
|
file (named `importStaticPlugin.cpp`, residing in plugin's include directory)
|
|
|
|
|
in a source file that gets compiled into your main application. The static
|
|
|
|
|
import file contains just a simple call to @ref CORRADE_PLUGIN_IMPORT(), see
|
|
|
|
|
its documentation for further information.
|
|
|
|
|
|
|
|
|
|
@snippet plugins.cpp static-import
|
|
|
|
|
|
|
|
|
|
@section plugins-aliases Plugin aliases and "any" plugins
|
|
|
|
|
|
|
|
|
|
There's usually more than one plugin available to achieve a particular goal ---
|
|
|
|
|
for example in order to open a PNG file, you can choose among
|
|
|
|
|
@ref Trade::PngImporter "PngImporter", @ref Trade::StbImageImporter "StbImageImporter"
|
|
|
|
|
or @ref Trade::DevIlImageImporter "DevIlImageImporter" plugins. Rather than
|
|
|
|
|
this being an unnecessary redundancy, it allows you to pick a particular
|
|
|
|
|
performance / portability / feature tradeoff --- a plugin with no external
|
|
|
|
|
dependencies for a web build or, on the other hand, the fastest possible
|
|
|
|
|
implementation for a tool that does heavy image processing.
|
|
|
|
|
|
|
|
|
|
To make this simpler in the code and defer the decision to the buildsystem or
|
|
|
|
|
app deployment, all plugins that support a particular format provide a common
|
|
|
|
|
*alias* --- in case of PNG images, you can just load a @cpp "PngImporter" @ce
|
|
|
|
|
plugin and if @ref Trade::PngImporter "PngImporter" is not available, it will
|
|
|
|
|
pick up any of the other candidates.
|
|
|
|
|
|
|
|
|
|
For greater control you can also use
|
|
|
|
|
@ref Corrade::PluginManager::AbstractManager::setPreferredPlugins() "setPreferredPlugins()",
|
|
|
|
|
giving a prioritized candidate list for a particular alias. This is especially
|
|
|
|
|
useful in case of font plugins, where you can get advanced layout capabilities
|
|
|
|
|
if the @ref Text::HarfBuzzFont "HarfBuzzFont" plugin is available or at least a
|
|
|
|
|
faster and smoother glyph rendering if you can get the @ref Text::FreeTypeFont "FreeTypeFont"
|
|
|
|
|
plugin. If none of the suggestions is available, it falls back to whatever is
|
|
|
|
|
left (which can be, for example, the @ref Text::StbTrueTypeFont "StbTrueTypeFont"
|
|
|
|
|
plugin).
|
|
|
|
|
|
|
|
|
|
@snippet plugins.cpp aliases
|
|
|
|
|
|
|
|
|
|
To make your life even simpler, there are various "any format" plugins ---
|
|
|
|
|
these detect format based on file extension, map it to a plugin alias and then
|
|
|
|
|
proxy the rest of the work to a corresponding plugin:
|
|
|
|
|
|
|
|
|
|
@snippet plugins.cpp anyimporter
|
|
|
|
|
|
|
|
|
|
Besides convenience for the end user, this allows for example the scene
|
|
|
|
|
importer plugins to load any image formats without needing to have a knowledge
|
|
|
|
|
about them or having an explicit dependency on multitude of image importer
|
|
|
|
|
plugins.
|
|
|
|
|
|
|
|
|
|
So far, the following plugins have the "any format" ability:
|
|
|
|
|
|
|
|
|
|
- @ref Trade::AnyImageImporter "AnyImageImporter" --- imports any image
|
|
|
|
|
format
|
|
|
|
|
- @ref Trade::AnyImageConverter "AnyImageConverter" --- converts to any image
|
|
|
|
|
format
|
|
|
|
|
- @ref Trade::AnySceneImporter "AnySceneImporter" --- imports any scene
|
|
|
|
|
format
|
|
|
|
|
- @ref Audio::AnyImporter "AnyImporter" --- imports any audio format
|
|
|
|
|
|
|
|
|
|
@section plugins-configuration Plugin-specific configuration
|
|
|
|
|
|
|
|
|
|
Because it's not possible for a general statically typed plugin API to expose
|
|
|
|
|
all possible knobs and switches that a file format could support, the plugins
|
|
|
|
|
have a possibility to supply additional configuration via the
|
|
|
|
|
@ref Corrade::PluginManager::AbstractPlugin::configuration() "configuration()"
|
|
|
|
|
function. For example, in the @ref Trade-AssimpImporter-configuration "AssimpImporter"
|
|
|
|
|
plugin you can toggle various postprocessing steps that are applied to loaded
|
|
|
|
|
scene files:
|
|
|
|
|
|
|
|
|
|
@snippet plugins.cpp configuration
|
|
|
|
|
|
|
|
|
|
Besides affecting a single plugin instance, you can also change the
|
|
|
|
|
configuration globally via @ref Corrade::PluginManager::PluginMetadata::configuration() "PluginManager::PluginMetadata::configuration()".
|
|
|
|
|
That will affect all plugin instances created after. Resetting the global
|
|
|
|
|
configuration back to the initial state can be done by recreating the plugin
|
|
|
|
|
manager.
|
|
|
|
|
|
|
|
|
|
@section plugins-direct Direct usage of plugins
|
|
|
|
|
|
|
|
|
|
@todoc and also check that this is not already mentioned above
|
|
|
|
|
|
|
|
|
|
@section plugins-develop Developing your own plugins
|
|
|
|
|
|
|
|
|
|
See class documentation of particular plugin interfaces for more information
|
|
|
|
|
about subclassing. The Corrade's @ref plugin-management "plugin management tutorial"
|
|
|
|
|
contains more information about plugin compilation and registering.
|
|
|
|
|
*/
|
|
|
|
|
}
|