I made a brief de­tour on the way to Vulkan sup­port and equipped Mag­num with fea­tures that make plu­gin work­flow nicer and open up new pos­sib­il­it­ies.

Auto­de­tec­ted plu­gin paths

Un­til now, in or­der to load a dy­nam­ic plu­gin, one had to spe­cify a path where to look for them. That was as flex­ible as it could get, yes, but in most cases the plu­gins would be in one or two com­mon places and so the plu­gin us­age usu­ally in­volved just propagat­ing a well-known path from CMake via configure_file().

Well, not any­more!

Every plu­gin in­ter­face now has a few plu­gin search paths pre­defined, which will “just work” in most cases. For ex­ample, in case of *Im­port­er plu­gins, the plu­gins are first searched in a magnum/importers/ sub­dir­ect­ory next to the ex­ecut­able (which is a com­mon case when de­ploy­ing on Win­dows) and as a fall­back in /usr/lib/magnum/importers (or any oth­er sys­tem-wide loc­a­tion de­pend­ing on CMAKE_INSTALL_PREFIX). See doc­u­ment­a­tion of vari­ous plu­gin­Search­Paths() func­tions for de­tails.

With this change in place, load­ing a mod­el from a glTF file is now just a mat­ter of this:

PluginManager::Manager<Trade::AbstractImporter> manager;
std::unique_ptr<Trade::AbstractImporter> importer =
    manager.loadAndInstantiate("GltfImporter");

importer->openFile("cave.gltf");
Containers::Optional<Trade::MeshData3D> data =
    importer->mesh3D(importer->mesh3DForName("treasure-chest"));

The flex­ib­il­ity was not taken away, though — it’s still pos­sible to pass the plu­gin dir­ect­ory to the con­struct­or the same as be­fore, if you need to.

Plu­gin ali­as pri­or­it­ies

There’s usu­ally more than one plu­gin avail­able to achieve a par­tic­u­lar goal — for ex­ample in or­der to open a PNG file, you can choose among PngIm­port­er, Dev­Il­Im­ageIm­port­er or StbIm­ageIm­port­er. Rather than this be­ing an un­ne­ces­sary re­dund­ancy, it al­lows you to pick a par­tic­u­lar per­form­ance / port­ab­il­ity / fea­ture-set tradeoff — a plu­gin with no ex­tern­al de­pend­en­cies for a web build or, on the oth­er hand, the fast­est pos­sible im­ple­ment­a­tion for a tool that does heavy im­age pro­cessing.

To make this sim­pler in the code and de­fer the de­cision to the build­sys­tem or app de­ploy­ment, all plu­gins that sup­port a par­tic­u­lar format provide a com­mon ali­as — in case of PNG im­ages, you can just load a "PngImporter" plu­gin and if PngIm­port­er is not avail­able, it will pick up any of the oth­er can­did­ates.

For great­er con­trol you can now use set­Pre­ferred­Plu­gins(), giv­ing a pri­or­it­ized can­did­ate list for a par­tic­u­lar ali­as. This is es­pe­cially use­ful with font plu­gins, where you can get ad­vanced lay­out cap­ab­il­it­ies if the Harf­BuzzFont plu­gin is avail­able or at least a faster and smooth­er glyph ren­der­ing if you can get the Free­TypeFont plu­gin. If none of the sug­ges­tions is avail­able, it falls back to whatever is left (which can be, for ex­ample, the Stb­TrueTypeFont plu­gin).

PluginManager::Manager<Text::AbstractFont> manager;
manager.setPreferredPlugins("TrueTypeFont", {"HarfBuzzFont", "FreeTypeFont"});

This of course works also in com­bin­a­tion with the Any­Im­port­er plu­gins — the fol­low­ing snip­pet will use Dev­IL in­stead of the built­in DdsIm­port­er to de­code a DXT-com­pressed tex­ture in­to plain RGBA on load:

PluginManager::Manager<Trade::AbstractImporter> manager;
manager.setPreferredPlugins("DdsImporter", {"DevIlImageImporter"});
std::unique_ptr<Trade::AbstractImporter> importer =
    manager.loadAndInstantiate("AnyImageImporter");
importer->openFile("texture.dds");

Plu­gin-spe­cif­ic con­fig­ur­a­tion

Be­cause it’s not pos­sible for a gen­er­al stat­ic­ally typed plu­gin API to ex­pose all pos­sible knobs and switches that a file format could sup­port, the plu­gins have a pos­sib­il­ity to sup­ply ad­di­tion­al con­fig­ur­a­tion via the con­fig­ur­a­tion() func­tion. For ex­ample, in the As­simpIm­port­er plu­gin you can toggle vari­ous post­pro­cessing steps that are ap­plied to loaded scene files:

std::unique_ptr<Trade::AbstractImporter> importer =
    manager.loadAndInstantiate("AssimpImporter");
importer->configuration().group("postprocess")->setValue("PreTransformVertices", true);

This is just the first spring flower, ex­pect more func­tion­al­ity be­ing ex­posed through plu­gin-spe­cif­ic con­fig­ur­a­tion in the fu­ture — abil­ity to con­trol out­put qual­ity of im­age con­vert­ers, con­trolling ad­vanced text lay­out­ing func­tion­al­ity of font plu­gins, …

Auto­ma­gic im­port of stat­ic plu­gins

There are plat­forms on which us­ing dlopen() and equi­val­ents is either straight im­possible or too an­noy­ing. For such cases there are stat­ic plu­gins. If you are us­ing CMake, all you need to do is list the re­quired plu­gins in a find_package() call (which was not needed for dy­nam­ic plu­gins) and then target_link_libraries() them to your fi­nal ex­ecut­able:

find_package(MagnumPlugins REQUIRED
    TinyGltfImporter
    StbTrueTypeFont)

add_executable(my-app my-app.cpp)
target_link_libraries(my-app PRIVATE
    MagnumPlugins::TinyGltfImporter
    MagnumPlugins::StbTrueTypeFont)

That’s all, you don’t need to change a single bit of your C++ code, a CMake target_sources() com­mand does all the ma­gic be­hind. If you’re not us­ing CMake but for ex­ample Visu­al Stu­dio with Vcp­kg, you need to ex­pli­citly #include the “stat­ic plu­gin im­port” file in­stead:

/* No need to do this if you use CMake */
#include <MagnumPlugins/TinyGltfImporter/importStaticPlugin.cpp>
#include <MagnumPlugins/StbTrueTypeFont/importStaticPlugin.cpp>

Now, where do I get this?

If you are already hap­pily us­ing Mag­num, just grab latest master re­vi­sions and don’t for­get to up­date your loc­al cop­ies of FindCorrade.cmake, FindMagnum.cmake and FindMagnumPlugins.cmake mod­ules to make the new fea­tures work.

If you are not us­ing Mag­num yet, wel­come! We prob­ably already have a pack­age for your plat­form to get you star­ted in no time. Head over to the Get­ting Star­ted guide and have fun!

There’s more!

Thanks to an ex­cep­tion­al first-time con­tri­bu­tion from @Nussknack­er­XXL and help from @Squareys there’s now a fresh Tiny­Glt­fIm­port­er plu­gin for im­port­ing both text and bin­ary glTF 2.0 files. Be­sides that — and be­sides the on­go­ing Vulkan work — a lot of ef­fort went in­to the doc­u­ment­a­tion, see for ex­ample the new ex­tens­ive An­droid de­vel­op­ment guide.