You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

262 lines
13 KiB

/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021, 2022, 2023, 2024, 2025, 2026
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, image and animation 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.
- @ref ShaderTools::AbstractConverter --- shader conversion, compilation,
optimization and validation. See `*Converter` classes in the
@ref ShaderTools namespace for available shader converter 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 @relativeref{Trade,TinyGltfImporter}
plugin uses @relativeref{Trade,AnyImageImporter} to load texture data. The
dependency loading is done automatically, but in some cases it's across
different plugin interfaces (for example the @relativeref{Text,MagnumFont}
*font* plugin depends on the @relativeref{Trade,TgaImporter} *importer* plugin)
--- there you need to create manager instances for all required plugin
interfaces and connect them together using
@relativeref{Corrade::PluginManager::Manager,registerExternalManager()}:
@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 `MAGNUM_BUILD_PLUGINS_STATIC` CMake
option 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
@relativeref{Corrade,PluginManager::AbstractManager::load()} will return
@relativeref{Corrade,PluginManager::LoadState::Static} instead of
@relativeref{Corrade::PluginManager,LoadState::Loaded}, but there is no need to
change anything in the C++ code --- it will work for both dynamic and static
case.
@m_class{m-block m-warning}
@par Using static plugins with custom buildsystems
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 through the
@cmake target_link_libraries() @ce call. Otherwise, besides linking the
plugin library itself, you have to 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
executable:
@par
@snippet plugins.cpp static-import
@par
The static import file contains a call to @ref CORRADE_PLUGIN_IMPORT(),
executed in a global constructor, which will do the required registration
automatically during application startup.
@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 or its contents and then proxy the
rest of the work to a concrete plugin suited for given format:
@snippet plugins.cpp anyimporter
Besides convenience for the end user, this allows the scene importer plugins to
load arbitrary image formats without having to explicitly deal with and depend
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 Trade::AnySceneConverter "AnySceneConverter" --- converts to any scene
format
- @ref ShaderTools::AnyConverter "AnyShaderConverter" --- converts shaders of
any formats
- @ref Audio::AnyImporter "AnyAudioImporter" --- imports any audio format
@section plugins-configuration Editing 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. Plugins that offer such possibility then show how the default
configuration looks like and document the purpose of each option. For example,
in case of the @relativeref{Trade,AssimpImporter} plugin you can toggle various
import options and postprocessing steps --- this is how a subset of its
@ref Trade-AssimpImporter-configuration "default configuration file" looks
like:
@code{.ini}
[configuration]
mergeAnimationClips=false
[configuration/postprocess]
PreTransformVertices=false
@endcode
@m_class{m-noindent}
and this is how you can edit it using @relativeref{Corrade,Utility::Configuration}:
@snippet plugins.cpp configuration
Besides affecting a single plugin instance, you can also change the
configuration globally via @relativeref{Corrade,PluginManager::PluginMetadata::configuration()}.
That will affect all subsequently created plugin instances. Resetting the global
configuration back to the initial state can be done by recreating the plugin
manager.
A special case is the "Any" plugins @ref plugins-aliases "described above" ---
these don't contain any implicit configuration on their own, but will propagate
anything you set to the concrete plugin implementation. So you could do the
above with @cpp "AnySceneImporter" @ce as well, and if @relativeref{Trade,AssimpImporter} would end up being used, it correctly
receives the options you have set.
@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.
*/
}