mirror of https://github.com/mosra/magnum.git
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
12 KiB
262 lines
12 KiB
/* |
|
This file is part of Magnum. |
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
|
2020, 2021, 2022, 2023, 2024 |
|
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. |
|
*/ |
|
}
|
|
|