Au­tode­tect­ed plug­in paths Un­til now, in or­der to load a dy­nam­ic plug­in, one had to spec­i­fy a path where to look for them. That was as flex­i­ble as it could get, yes, but in most cas­es the plug­ins would be in one or two com­mon places and so the plug­in us­age usu­al­ly in­volved just prop­a­gat­ing a well-known path from CMake via configure_file() . Well, not any­more! Ev­ery plug­in in­ter­face now has a few plug­in search paths pre­de­fined, which will “just work” in most cas­es. For ex­am­ple, in case of *Im­porter plug­ins, the plug­ins are first searched in a magnum/importers/ sub­di­rec­to­ry next to the ex­e­cutable (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 lo­ca­tion de­pend­ing on CMAKE_INSTALL_PREFIX ). See doc­u­men­ta­tion of var­i­ous plu­g­in­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­i­bil­i­ty was not tak­en away, though — it’s still pos­si­ble to pass the plug­in di­rec­to­ry to the con­struc­tor the same as be­fore, if you need to.

Plug­in alias pri­or­i­ties There’s usu­al­ly more than one plug­in avail­able to achieve a par­tic­u­lar goal — for ex­am­ple in or­der to open a PNG file, you can choose among PngIm­porter, Dev­Il­Im­ageIm­porter or StbIm­ageIm­porter. Rather than this be­ing an un­nec­es­sary re­dun­dan­cy, it al­lows you to pick a par­tic­u­lar per­for­mance / porta­bil­i­ty / fea­ture-set trade­off — a plug­in with no ex­ter­nal de­pen­den­cies for a web build or, on the oth­er hand, the fastest pos­si­ble im­ple­men­ta­tion for a tool that does heavy im­age pro­cess­ing. To make this sim­pler in the code and de­fer the de­ci­sion to the buildsys­tem or app de­ploy­ment, all plug­ins that sup­port a par­tic­u­lar for­mat pro­vide a com­mon alias — in case of PNG im­ages, you can just load a "PngImporter" plug­in and if PngIm­porter is not avail­able, it will pick up any of the oth­er can­di­dates. For greater con­trol you can now use set­Pre­ferred­Plu­g­ins(), giv­ing a pri­or­i­tized can­di­date list for a par­tic­u­lar alias. This is es­pe­cial­ly use­ful with font plug­ins, where you can get ad­vanced lay­out ca­pa­bil­i­ties if the Harf­Buz­z­Font plug­in is avail­able or at least a faster and smoother glyph ren­der­ing if you can get the FreeType­Font plug­in. If none of the sug­ges­tions is avail­able, it falls back to what­ev­er is left (which can be, for ex­am­ple, the Stb­True­Type­Font plug­in). PluginManager :: Manager < Text :: AbstractFont > manager ; manager . setPreferredPlugins ( "TrueTypeFont" , { "HarfBuzzFont" , "FreeTypeFont" }); This of course works al­so in com­bi­na­tion with the Any­Im­porter plug­ins — the fol­low­ing snip­pet will use Dev­IL in­stead of the builtin DdsIm­porter to de­code a DXT-com­pressed tex­ture in­to plain RG­BA on load: PluginManager :: Manager < Trade :: AbstractImporter > manager ; manager . setPreferredPlugins ( "DdsImporter" , { "DevIlImageImporter" }); std :: unique_ptr < Trade :: AbstractImporter > importer = manager . loadAndInstantiate ( "AnyImageImporter" ); importer -> openFile ( "texture.dds" );

Plug­in-spe­cif­ic con­fig­u­ra­tion Be­cause it’s not pos­si­ble for a gen­er­al stat­i­cal­ly typed plug­in API to ex­pose all pos­si­ble knobs and switch­es that a file for­mat could sup­port, the plug­ins have a pos­si­bil­i­ty to sup­ply ad­di­tion­al con­fig­u­ra­tion via the con­fig­u­ra­tion() func­tion. For ex­am­ple, in the As­simpIm­porter plug­in you can tog­gle var­i­ous post­pro­cess­ing steps that are ap­plied to load­ed scene files: std :: unique_ptr < Trade :: AbstractImporter > importer = manager . loadAndInstantiate ( "AssimpImporter" ); importer -> configuration (). group ( "postprocess" ) -> setValue ( "PreTransformVertices" , true ); This is just the first spring flow­er, ex­pect more func­tion­al­i­ty be­ing ex­posed through plug­in-spe­cif­ic con­fig­u­ra­tion in the fu­ture — abil­i­ty to con­trol out­put qual­i­ty of im­age con­vert­ers, con­trol­ling ad­vanced text lay­out­ing func­tion­al­i­ty of font plug­ins, …

Au­tomag­ic im­port of stat­ic plug­ins There are plat­forms on which us­ing dlopen() and equiv­a­lents is ei­ther straight im­pos­si­ble or too an­noy­ing. For such cas­es there are stat­ic plug­ins. If you are us­ing CMake, all you need to do is list the re­quired plug­ins in a find_package() call (which was not need­ed for dy­nam­ic plug­ins) and then target_link_libraries() them to your fi­nal ex­e­cutable: 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 sin­gle bit of your C++ code, a CMake target_sources() com­mand does all the mag­ic be­hind. If you’re not us­ing CMake but for ex­am­ple Vis­ual Stu­dio with Vcp­kg, you need to ex­plic­it­ly #include the “stat­ic plug­in im­port” file in­stead: /* No need to do this if you use CMake */ #include <MagnumPlugins/TinyGltfImporter/importStaticPlugin.cpp> #include <MagnumPlugins/StbTrueTypeFont/importStaticPlugin.cpp>