Browse Source

doc: reworked the plugins documentation.

pull/205/head
Vladimír Vondruš 8 years ago
parent
commit
fd942a7eb0
  1. 268
      doc/plugins.dox
  2. 1
      doc/snippets/CMakeLists.txt
  3. 65
      doc/snippets/plugins.cpp

268
doc/plugins.dox

@ -30,157 +30,90 @@ namespace Magnum {
@tableofcontents @tableofcontents
@m_footernavigation @m_footernavigation
The base Magnum library contains math support, scene graph implementation and The base Magnum libraries contain math support, scene graph implementation and
is able to interact with graphics and audio hardware. However, the base library are able to interact with graphics and audio hardware. However, they don't
doesn't provide any functions for dealing with specific file formats, as there provide any functions for dealing with specific file formats on their own, as
are simply too many formats to have them included directly in the library. there are simply too many formats to include all of them directly. Instead, the
Instead, the library provides plugin API and you can load plugin which will libraries provide plugin APIs using which you can load a plugin that's able to
then be able to read or write the particular file format. 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 "Magnum repository" contains a few basic plugins for opening The @ref building "Magnum repository" contains a few basic plugins for opening
the some formats, such as TGA images or WAV audio files. These plugins are simple formats, such as TGA images or WAV audio files. These plugins are
included because the file formats are so simple that no external library is included because the file formats are so simple that no external library is
needed for loading their contents and thus they are suitable for quick demos needed for loading their contents and thus they are suitable for quick demos
and prototyping without dealing with additional dependencies. and prototyping without needing to deal with additional dependencies.
Additional plugins (such as importers for PNG and JPEG images, FreeType fonts Additional plugins (such as importers for PNG and JPEG images, TrueType fonts
etc.) are available in @ref building-plugins "Magnum Plugins" repository. etc.) are available in the @ref building-plugins "Magnum Plugins" repository.
Majority of these plugins depends on external libraries, thus some of them Majority of these plugins depends on external libraries, thus not all of them
might not be available on all platforms. might be available on all platforms.
@section plugins-types Plugin interfaces @section plugins-types Plugin interfaces
Magnum contains these 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, - @ref Trade::AbstractImporter --- importers for general 2D and 3D scene,
mesh, material, texture and image data. See `*Importer` classes in mesh, material, texture and image data. See `*Importer` classes in the
@ref Trade namespace for available importer plugins. These are installed in @ref Trade namespace for available importer plugins.
`MAGNUM_PLUGINS_IMPORTER_DIR` directory.
- @ref Trade::AbstractImageConverter --- conversion among various image - @ref Trade::AbstractImageConverter --- conversion among various image
formats. See `*ImageConverter` classes in @ref Trade namespace for list of formats. See `*ImageConverter` classes in the @ref Trade namespace for
available image converter plugins. These are installed in available image converter plugins.
`MAGNUM_PLUGINS_IMAGECONVERTER_DIR` directory.
- @ref Text::AbstractFont --- font loading and glyph layouting. See `*Font` - @ref Text::AbstractFont --- font loading and glyph layouting. See `*Font`
classes in @ref Text namespace for available font plugins. These are classes in the @ref Text namespace for available font plugins.
installed in `MAGNUM_PLUGINS_FONT_DIR` directory.
- @ref Text::AbstractFontConverter --- font and glyph cache conversion. See - @ref Text::AbstractFontConverter --- font and glyph cache conversion. See
`*FontConverter` classes in @ref Text namespace for available font `*FontConverter` classes in the @ref Text namespace for available font
converter plugins. These are installed in `MAGNUM_PLUGINS_FONTCONVERTER_DIR` converter plugins.
directory.
- @ref Audio::AbstractImporter --- importers for audio formats. See - @ref Audio::AbstractImporter --- importers for audio formats. See
`*Importer` classes in @ref Audio namespace for available audio importer `*Importer` classes in the @ref Audio namespace for available audio
plugins. These are installed in `MAGNUM_PLUGINS_AUDIOIMPORTER_DIR` importer plugins.
directory.
@section plugins-loading Loading and instantiating the plugins
To load the plugins, you need to instantiate @ref Corrade::PluginManager::Manager
for given plugin interface, for example @ref Trade::AbstractImporter. You must
set particular plugin directory, from which the manager will load and
instantiate the plugins. To save you from hardcoding the value into your
application source, the plugin directory is provided as `MAGNUM_PLUGINS_DIR`
CMake variable. The default is set to Magnum install location, but you can
change it through CMake to anything else. The `MAGNUM_PLUGINS_IMPORTER_DIR`,
`MAGNUM_PLUGINS_IMAGECONVERTER_DIR`, `MAGNUM_PLUGINS_FONT_DIR`,
`MAGNUM_PLUGINS_FONTCONVERTER_DIR`, `MAGNUM_PLUGINS_AUDIOIMPORTER_DIR`
variables depend on `MAGNUM_PLUGINS_DIR`, so if you modify that variable, the
changes will be reflected in these variables too. See @ref cmake for additional
information.
You can provide the variable to your sources using CMake configuration file.
Create `configure.h.cmake` file in your source directory with contents similar
to these:
@code{.cpp}
#define MAGNUM_PLUGINS_IMPORTER_DIR "${MAGNUM_PLUGINS_IMPORTER_DIR}"
@endcode
In case you are using multi-configuration build system (such as Visual Studio
or XCode), CMake cannot provide separate plugin directory for debug and release
build and you have to select between `MAGNUM_PLUGINS_*_DIR` and
`MAGNUM_PLUGINS_*_DEBUG_DIR` based on @ref corrade-cmake "CORRADE_IS_DEBUG_BUILD"
preprocessor variable. This will ensure that you use debug plugin directory for
debug build on multi-configuration build sytems and fall back to autodetection
for the rest:
@code{.cpp}
#ifdef CORRADE_IS_DEBUG_BUILD
#define MAGNUM_PLUGINS_IMPORTER_DIR "${MAGNUM_PLUGINS_IMPORTER_DEBUG_DIR}"
#else
#define MAGNUM_PLUGINS_IMPORTER_DIR "${MAGNUM_PLUGINS_IMPORTER_DIR}"
#endif
@endcode
However, if you want to use only one (debug/release) plugin version for both @section plugins-loading Loading and instantiating plugins
debug and release configurations of the application, you need to edit
`MAGNUM_PLUGINS_DIR` or `MAGNUM_PLUGINS_DEBUG_DIR` using CMake and point them
to directory containing desired plugin version.
Then process the file in your `CMakeLists.txt`. The result To load a plugin, you need to instantiate @ref Corrade::PluginManager::Manager
(`${MAGNUM_PLUGINS_IMPORTER_DIR}` / `${MAGNUM_PLUGINS_IMPORTER_DEBUG_DIR}` gets for given plugin interface, for example for the @ref Trade::AbstractImporter.
replaced with the actual value) is put into build directory, so don't forget to In order to find plugins on the filesystem, plugin interfaces have a bunch of
add it to include path: plugin search paths hardcoded --- see documentation of the
@ref Trade::AbstractImporter::pluginSearchPaths() "pluginSearchPaths()"
@code{.cmake} functions provided by each plugin interface. It usually just works, but you can
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake also pass a plugin directory to the manager constructor explicitly.
${CMAKE_CURRENT_BINARY_DIR}/configure.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
@endcode
Then you can instantiate the manager, load particular plugin and create an Once the plugin manager is instantiated, you can start creating instances of
instance of it. Keep in mind that the manager instance must exist for whole particular plugins. Keep in mind that the manager instance has to exist for
lifetime of all plugin instances created from it. whole lifetime of all plugin instances created using it.
@code{.cpp} @snippet plugins.cpp loading
#include "configure.h"
// ...
{
PluginManager::Manager<Trade::AbstractImporter> manager{MAGNUM_PLUGINS_IMPORTER_DIR};
std::unique_ptr<Trade::AbstractImporter> tgaImporter = manager.loadAndInstantiate("TgaImporter");
if(!tgaImporter) {
Error() << "Cannot load importer plugin from" << manager.pluginDirectory();
std::exit(1);
}
// Use the plugin...
// At the end of the scope the tgaImporter instance gets deleted and then
// the manager automatically unloads the plugin on destruction
}
@endcode
@section plugins-dependencies Plugin dependencies @section plugins-dependencies Plugin dependencies
Some plugins have dependencies, for example the @ref Text::MagnumFont "MagnumFont" Some plugins have dependencies, for example the @ref Trade::OpenGexImporter "OpenGexImporter"
plugin needs to load the glyph atlas using @ref Trade::TgaImporter "TgaImporter" plugin uses @ref Trade::AnyImageImporter "AnyImageImporter" to load texture
plugin. The dependency loading is done automatically, but you need to create data. The dependency loading is done automatically, but in some cases it's
instance of corresponding plugin manager in particular plugin dir so the across plugin types (for example the @ref Text::MagnumFont "MagnumFont" plugin
dependency can be found. Example: depends on the @ref Trade::TgaImporter "TgaImporter" plugin, which is of a
different type) --- there you need to create manager instances for all required
@code{.cpp} plugin interfaces:
PluginManager::Manager<Trade::AbstractImporter> importerManager(MAGNUM_PLUGINS_IMPORTER_DIR);
PluginManager::Manager<Text::AbstractFont> fontManager(MAGNUM_PLUGINS_FONT_DIR);
// As a side effect TgaImporter is loaded by importerManager @snippet plugins.cpp dependencies
fontManager.load("MagnumFont");
@endcode
@section plugins-static Static plugins @section plugins-static Static plugins
By default all plugins are built as dynamic ones, i.e. they are separate By default, on desktop systems at least, all plugins are built as dynamic ones,
binary which gets linked in at runtime. This is good for reducing memory i.e. they are a separate binary which gets linked in at runtime. This is good
consumption, as the code is loaded in memory only for the time it is needed. for reducing memory consumption, as the code is loaded in memory only for the
However, if you want to port to platform which does not support dynamic linking time it is actually needed. However, if you need to port to a platform which
or you simply want to have the plugin loaded at all times, you can use static does not support dynamic linking or you simply want to have the plugin loaded
plugins. at all times, you can use static plugins.
The plugins are built as static if `BUILD_STATIC` CMake parameter is enabled The plugins are built as static if the `BUILD_PLUGINS_STATIC` CMake parameter
(see @ref building and @ref building-plugins for more information). The actual is enabled (see @ref building and @ref building-plugins for more information).
usage is basically the same as above, but you need to explicitly find the The actual usage in the code is basically the same as above, but you need to
plugin and link it into the executable in your `CMakeLists.txt`. See @ref cmake explicitly find the plugin and link it into the executable. If you use CMake,
and @ref cmake-plugins for additional information. it would look like this:
@code{.cmake} @code{.cmake}
find_package(MagnumPlugins REQUIRED PngImporter) find_package(MagnumPlugins REQUIRED PngImporter)
@ -189,35 +122,88 @@ add_executable(MyApp ...)
target_link_libraries(MyApp ... MagnumPlugins::PngImporter) target_link_libraries(MyApp ... MagnumPlugins::PngImporter)
@endcode @endcode
The only user-visible behavioral change will be that The only user-visible behavioral change in the code will be that
@ref Corrade::PluginManager::AbstractManager::load() "PluginManager::Manager::load()" @ref Corrade::PluginManager::AbstractManager::load() "PluginManager::Manager::load()"
will return @ref Corrade::PluginManager::LoadState::Static "PluginManager::LoadState::Static" will return @ref Corrade::PluginManager::LoadState::Static "PluginManager::LoadState::Static"
instead of @ref Corrade::PluginManager::LoadState::Loaded "PluginManager::LoadState::Loaded", 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 but there is no need to change the above code, as it will work for both dynamic
and static case. and static case.
It's needed to register the static plugin with @ref CORRADE_PLUGIN_IMPORT() in The static plugin needs to be explicitly registered so the plugin manager is
some function which will be executed before you use the plugin, otherwise the aware it's there. If you use CMake 3.1 and newer it's done automatically.
plugin will not be found. See the macro documentation for information about Otherwise, you can achieve the same if you explicitly @cpp #include @ce the
automatic importing and namespace issues. 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 thing
--- 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 choose among different
performance / portability / feature tradeoffs --- choose a plugin with no
external dependencies or on the other hand pick the fastest possible
implementation.
The decision what plugin to use is usually done in the buildsystem or during
the deploy. To make this simpler in the code itself, all plugins that support a
particular format provide a common *alias*. In the 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.
@code{.cpp} So far, the following plugins have the "any format" ability:
int main(int argc, char** argv) {
CORRADE_PLUGIN_IMPORT(TgaImporter)
// ... - @ref Trade::AnyImageImporter "AnyImageImporter" --- imports any image
} format
@endcode - @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 modules:
@snippet plugins.cpp configuration
@section plugins-develop Developing your own plugins @section plugins-develop Developing your own plugins
See class documentation of particular plugin interfaces for more information See class documentation of particular plugin interfaces for more information
about subclassing. The Corrade's @ref plugin-management "plugin management tutorial" about subclassing. The Corrade's @ref plugin-management "plugin management tutorial"
contains more information about plugin compilation and registering. contains more information about plugin compilation and registering.
If you want to develop a plugin which depends on another, you need to find the
original plugin, add its include dirs to include path and link to it, similarly
to how static plugins are found above. See @ref cmake and @ref cmake-plugins
for more information.
*/ */
} }

1
doc/snippets/CMakeLists.txt

@ -34,6 +34,7 @@ if(CORRADE_TARGET_EMSCRIPTEN AND NOT TARGET_GLES2)
endif() endif()
add_library(snippets STATIC add_library(snippets STATIC
plugins.cpp
Magnum.cpp Magnum.cpp
MagnumMeshTools.cpp MagnumMeshTools.cpp
MagnumShaders.cpp MagnumShaders.cpp

65
doc/snippets/plugins.cpp

@ -0,0 +1,65 @@
#include <Corrade/PluginManager/Manager.h>
#include <Corrade/Utility/ConfigurationGroup.h>
#include "Magnum/Text/AbstractFont.h"
#include "Magnum/Trade/AbstractImporter.h"
/* [static-import] */
/* No need to do this if you use CMake */
#include <MagnumPlugins/TgaImporter/importStaticPlugin.cpp>
/* [static-import] */
using namespace Magnum;
int main() {
/* [loading] */
{
PluginManager::Manager<Trade::AbstractImporter> manager;
std::unique_ptr<Trade::AbstractImporter> importer =
manager.loadAndInstantiate("TgaImporter");
if(!importer) Fatal{} << "Cannot load the TgaImporter plugin";
// Use the plugin...
/* At the end of the scope the importer instance gets deleted and then
the manager automatically unloads the plugin on destruction */
}
/* [loading] */
{
/* [dependencies] */
PluginManager::Manager<Trade::AbstractImporter> importerManager;
PluginManager::Manager<Text::AbstractFont> fontManager;
// As a side effect TgaImporter is loaded by importerManager
fontManager.load("MagnumFont");
/* [dependencies] */
}
{
/* [aliases] */
PluginManager::Manager<Text::AbstractFont> fontManager;
fontManager.setPreferredPlugins("TrueTypeFont", {"HarfBuzzFont", "FreeTypeFont"});
/* [aliases] */
}
{
PluginManager::Manager<Trade::AbstractImporter> manager;
/* [anyimporter] */
std::unique_ptr<Trade::AbstractImporter> importer =
manager.instantiate("AnyImageImporter");
importer->openFile("texture.dds"); /* Delegates to the DdsImporter plugin */
/* [anyimporter] */
}
{
PluginManager::Manager<Trade::AbstractImporter> manager;
/* [configuration] */
std::unique_ptr<Trade::AbstractImporter> importer =
manager.instantiate("AssimpImporter");
importer->configuration().group("postprocess")->setValue("PreTransformVertices", true);
/* [configuration] */
}
}
Loading…
Cancel
Save