When look­ing at the changel­og for the lat­est ver­sion, it’s hard to be­lieve that on­ly six months passed since the last re­lease, 2018.04. The list is — as usu­al — very long, so I’m on­ly cher­ry-pick­ing the most in­ter­est­ing bits. Scroll way down for the full de­tailed change lists.

An­i­ma­tion im­port and play­back This long-await­ed fea­ture fi­nal­ly man­aged to rise to the top of the pri­or­i­ty list and so the new re­lease con­tains a brand-new An­i­ma­tion names­pace. Some de­sign ideas are bor­rowed from Ozz-An­i­ma­tion, with one end goal be­ing high-per­for­mance play­back of an­i­ma­tions im­port­ed from glTF files (with oth­er for­mats com­ing lat­er). The oth­er goal is be­ing able to quick­ly it­er­ate on hand-craft­ed an­i­ma­tions of ar­bi­trary val­ues when writ­ing a game­play or UI tran­si­tions. Animation :: Track < Float , Color3 > breathe {{ { 0.0f , 0x3bd267_srgbf }, { 0.9f , 0xacecbe_srgbf }, { 1.8f , 0x3bd267_srgbf } }, Math :: lerp }; Color3 color = breathe . at ( 0.7f ); Hand-craft a col­or tran­si­tion an­i­ma­tion track … The an­i­ma­tion li­brary sup­ports in­ter­leaved or sep­a­rate keyframe da­ta for cache-op­ti­mized da­ta ac­cess; float s, std::chrono, frame in­dex (or just any­thing) for rep­re­sent­ing time, and yes, you can al­so an­i­mate strings, enum val­ues, bool s or even the state of an­oth­er an­i­ma­tion — and why not an­i­mat­ing a time val­ue to make the play­back non-lin­ear! There’s a set of builtin in­ter­po­la­tion modes — con­stant, lin­ear, spher­i­cal lin­ear and spline-based; but you can al­so sup­ply your own in­ter­po­la­tor func­tion if you need some ease-in/ease-out, or, for ex­am­ple, un­pack a quater­nion from a 10–10–10–2 rep­re­sen­ta­tion first. At the mo­ment the An­i­ma­tion li­brary is marked as ex­per­i­men­tal as its API is not set in stone yet. There’s a lot to ex­plain, so stay tuned for de­tailed in­tro­duc­to­ry blog­posts (and ex­am­ples) for all fea­tures. For a brief over­view, check the An­i­ma­tion::Track and An­i­ma­tion::Play­er class docs. Animation :: Player < nanoseconds , Float > player ; player . addWithCallback ( breathe , []( Float , const Color3 & c , Flat2D & shader ) { shader . setColor ( c ); }, shader ); player . setPlayCount ( 0 ) // repeat ∞ times . play ( … ); … and then use it to an­i­mate shad­er col­or An­i­ma­tion im­port is done through the new Trade::An­i­ma­tion­Da­ta class and at the mo­ment the Trade::Ab­strac­tIm­porter in­ter­faces han­dle just ba­sic ob­ject trans­for­ma­tion. Skin­ning and mor­ph­ing will need some more-or-less break­ing changes to some Trade APIs and so these fea­tures are sched­uled for next re­leas­es. Along with that, the goal for the Trade li­brary is al­low­ing ze­ro-copy as­set im­port — for ex­am­ple play­ing back an an­i­ma­tion di­rect­ly from a mem­o­ry-mapped glTF file, with no da­ta copies in be­tween. See mosra/mag­num#240 for fur­ther work in this area. The fun barely started! I had to stop adding new fea­tures be­cause the re­lease would oth­er­wise nev­er make it out. There’s al­ready more in the buf­fer — builtin eas­ing func­tions, in­ter­po­la­tor chain­ing and more. See mosra/mag­num#101 help want­ed for de­tails. There’s lot of small and self-con­tained things to work on, so if you feel brave and want to help, let us know!

Mag­num Play­er While the An­i­ma­tion API it­self doesn’t have any ded­i­cat­ed ex­am­ple yet, there’s now a new app, Mag­num Play­er, that can play back a scene file you throw at it. The fi­nal goal for this app will be show­cas­ing the full Mag­num fea­ture set — de­bug­ging and in­tro­spec­tion tools, ma­te­ri­al tweak­ing etc. Check out the on­line ver­sion be­low — it sup­ports mul­ti-file drag&drop, so sim­ply drop a glTF file on it to play it. If you don’t have any glTF file handy, there’s the of­fi­cial Khronos glTF sam­ple mod­el re­pos­i­to­ry on GitHub. Sketch­fab al­so has 1000s of mod­els down­load­able as glTF. Mag­num Play­er we­bgl2 A view­er and play­er for an­i­mat­ed glTF scenes. Drag&drop a file to load it.

HiD­PI sup­port Long gone are the days of a stan­dard 1024×768 res­o­lu­tion and fixed 96 DPI — dense screens are now a com­mon fea­ture for high­er-end lap­tops and desk­tops. In the 2018.10 re­lease, Mag­num is DPI-aware on mac­OS, iOS, Lin­ux and Em­scripten. The us­abil­i­ty goal is that re­quest­ing an 800×600 win­dow will make it the same phys­i­cal size as an 800×600 win­dow would have on a 96 DPI screen — so ba­si­cal­ly with no ex­tra in­volve­ment from the us­er. For web and mo­bile, Mag­num sim­ply en­sures that for giv­en can­vas / screen size you’ll get all the pix­els that are there, with no scal­ing on top. If you have a HiD­PI screen, check out the We­bGL demos on the Show­case page — ev­ery­thing should be nice­ly crisp. This top­ic is way more com­plex than it might seem, see DPI aware­ness for a de­tailed over­view of DPI-aware­ness on all plat­forms and what that means for you as a de­vel­op­er. Un­for­tu­nate­ly out-of-the-box Win­dows sup­port didn’t make it to the re­lease (though you are able to force ar­bi­trary scal­ing with a --magnum-dpi-scaling pa­ram­e­ter). Full An­droid sup­port and ad­vanced things like DPI change events when drag­ging a win­dow across dif­fer­ent­ly dense mon­i­tors are al­so wait­ing to be done, see mosra/mag­num#243 help want­ed for de­tails.

Lit­tle big de­tails GL :: Mesh mesh = MeshTools :: compile ( Primitives :: gradientVertical2D ( 0x2f83cc_srgbf , 0x3bd267_srgbf )); We’re still un­sure if the up­com­ing Vulkan back­end will be able to do sim­i­lar amount of work in such a terse ex­pres­sion. That could be both a bad and a good thing. Yes, it’s now pos­si­ble to get a GL::Mesh di­rect­ly from Trade::Mesh­Da­ta with a sin­gle click — just use the brand new Mesh­Tools::com­pile() reim­ple­men­ta­tion and it’ll drag all GL::Buf­fer in­stances along with it­self, with­out you need­ing to man­age them. Of course there are flex­i­bil­i­ty trade­offs, so when us­ing the mesh APIs di­rect­ly, you have the op­tion of GL::Mesh::ad­dVer­texBuffer() ei­ther tak­ing a non-own­ing ref­er­ence to the buf­fer or ful­ly tak­ing over its own­er­ship. There’s a new Con­tain­ers::Sco­pe­dEx­it class that sim­ply calls a passed ex­it / close / de­stroy func­tion on giv­en val­ue at the end of scope. Very use­ful when in­ter­act­ing with low-lev­el C APIs and much eas­i­er than wrestling with std::unique_p­tr, try­ing to con­vince it to do the same. int fd = open ( "file.dat" , O_RDONLY ); Containers :: ScopedExit e { fd , close }; If you ev­er need to it­er­ate on a ar­ray of in­ter­leaved val­ues and take al­ways the third val­ue, there’s now Con­tain­ers::StridedAr­rayView that ab­stracts it away. It’s used in­ter­nal­ly by the An­i­ma­tion::Track­View APIs to al­low for both flex­i­ble and cache-ef­fi­cient lay­out of keyframe da­ta. There’s a new Util­i­ty::for­mat() fam­i­ly of func­tions for Python-style type-safe string for­mat­ting. The rea­son I’m adding this is be­cause std::os­tream (and to some ex­tent printf()) is no­to­ri­ous­ly in­ef­fi­cient, neg­a­tive­ly af­fect­ing ex­e­cutable size es­pe­cial­ly on asm.js / We­bAssem­bly tar­gets. How­ev­er the full im­ple­men­ta­tion didn’t make it in­to the re­lease, on­ly the sur­face APIs, Mag­num is not port­ed away from streams just yet — there will be a de­tailed post about all this lat­er 😉 std :: string s = Utility :: formatString ( "path {{ fill: #{:6x}; stroke: #{:6x}; }}" , 0x33ff00 , 0x00aa55 ); // path { fill: #33ff00; stroke: #00aa55; } More of an in­ter­nal thing, the De­bug­Tools::Com­pareIm­age util­i­ty got a Com­pareIm­ageToFile coun­ter­part, to­geth­er with oth­er com­bi­na­tions. In sub­se­quent up­dates, these will get used for fuzzy shad­er out­put ver­i­fi­ca­tion — very im­por­tant for im­ple­ment­ing PBR shaders that are lat­er on the roadmap.

Pro­to­typ­ing Shown above is a new Prim­i­tives::gra­di­en­t2D() func­tion (to­geth­er with its 3D coun­ter­part), use­ful for sim­ple back­drops. The Shaders::Phong shad­er got a long-re­quest­ed sup­port for mul­ti­ple lights and there’s now al­pha mask­ing sup­port in both Shaders::Phong and Shaders::Flat — use­ful for quick’n’dirty pro­to­typ­ing when you don’t want to both­er your­self with depth sort­ing or OIT.

As­set man­age­ment im­prove­ments Since the TinyGlt­fIm­porter plug­in ini­tial re­lease in 2018.04, it’s re­ceiv­ing an end­less stream of up­dates. While the big­gest new fea­ture is an­i­ma­tion im­port, it al­so re­ceived sup­port for mul­ti-prim­i­tive mesh­es, name map­ping for all da­ta, cam­era as­pect ra­tio im­port and var­i­ous con­for­mance fix­es and per­for­mance im­prove­ments. It’s now eas­i­er to ac­cess its in­ter­nal state, in case you want to parse cus­tom glTF prop­er­ties or ac­cess da­ta that the im­porter does not sup­port yet. To sup­port load­ing da­ta from mem­o­ry, from AAssetManager on An­droid or for ex­am­ple voa drag&drop on Em­scripten, all scene and im­age im­porters now sup­port file load­ing call­backs. For you it means you can con­tin­ue load­ing as­sets as usu­al — us­ing their file­names — and on­ly set up a dif­fer­ent file call­back for each plat­form. The im­ple­men­ta­tion was done in a way that makes all ex­ist­ing (and fu­ture) plug­ins im­plic­it­ly work with file call­backs, more­over the TinyGlt­fIm­porter, As­simpIm­porter and OpenGex­Im­porter al­so use pro­vid­ed file call­backs for ex­ter­nal da­ta ref­er­enced from scene files (such as im­ages or da­ta buf­fers). There’s fi­nal­ly a JpegIm­age­Con­vert­er plug­in for com­press­ing JPEG files, us­ing a lib­JPEG im­ple­men­ta­tion of your choice — be it the vanil­la im­ple­men­ta­tion, lib­jpeg-tur­bo or, for ex­am­ple, MozJPEG. Sim­i­lar­ly, the stb_im­age-based StbIm­age­Con­vert­er got up­dat­ed to sup­port JPEG out­put as well — and you can load ei­ther of them us­ing the JpegImageConverter alias. Both plug­ins sup­port spec­i­fy­ing the out­put qual­i­ty via a run­time set­ting; more en­cod­ing op­tions may be added in the fu­ture. std :: unique_ptr < Trade :: AbstractImageConverter > converter = manager . loadAndInstantiate ( "JpegImageConverter" ); converter -> configuration () -> setValue ( "jpegQuality" , 0.95f ); Among oth­er things, the Stb­True­Type­Font was up­dat­ed to a new ver­sion of stb_truetype , gain­ing OTF sup­port, and you can now load it (along with the oth­er Harf­Buz­z­Font and FreeType­Font im­ple­men­ta­tions) via the gener­ic OpenTypeFont alias.

Not all roads led to Rome Mag­num is now over eight years old and it be­came ap­par­ent that some ear­ly func­tion­al­i­ty didn’t stand the test of time — ei­ther be­cause it de­pend­ed on a now-out­dat­ed tool­kit, be­cause the re­quired time in­vest­ment for con­tin­ued main­te­nance was not worth it or sim­ply be­cause it was a de­sign ex­per­i­ment that failed. The fol­low­ing li­braries are now marked as dep­re­cat­ed, are not built by de­fault (in case they ev­er were) and will be com­plete­ly re­moved in about six months time. The Shapes ob­so­lete li­brary, to­geth­er with DebugTools::ShapeRenderer ob­so­lete and the BulletIntegration::convertShape() ob­so­lete func­tion. Failed de­sign ex­per­i­ment that couldn’t ev­er be made per­for­mant (and abus­ing % op­er­a­tors for col­li­sion queries was just plain wrong). Re­lat­ed ge­om­e­try al­go­rithms were moved to Math::Dis­tance and Math::In­ter­sec­tion names­paces. If you need a full-fledged physics li­brary, please have look at Bul­let, which has Mag­num in­te­gra­tion in Bul­let­Inte­gra­tion (to­geth­er with de­bug draw im­ple­ment­ed in Bul­let­Inte­gra­tion::De­bug­Draw), or at Box2D, which has a Mag­num ex­am­ple as well.

The Platform::GlutApplication ob­so­lete ap­pli­ca­tion. It’s based on an out­dat­ed GLUT tool­kit, has porta­bil­i­ty is­sues and doesn’t make sense on the path for­ward to Vulkan. Con­sid­er switch­ing to ei­ther Plat­form::Sdl2Ap­pli­ca­tion or Plat­form::GlfwAp­pli­ca­tion.

The ColladaImporter ob­so­lete plug­in, be­cause it’s based on an out­dat­ed Qt4 tool­kit. More­over, due to the sheer com­plex­i­ty of the COL­LA­DA for­mat and poor con­for­mance of var­i­ous ex­porters it’s not fea­si­ble to main­tain a builtin im­porter any­more. Con­sid­er ei­ther us­ing As­simpIm­porter for COL­LA­DA im­port or switch­ing to bet­ter-de­signed and bet­ter-sup­port­ed for­mats such as glTF or OpenGEX us­ing TinyGlt­fIm­porter or OpenGex­Im­porter. There’s al­so the of­fi­cial COL­LADA2GLTF con­vert­er. Visual Studio 2017 With a heavy heart I have to say that re­cent up­dates of MSVC 2017 were re­gress­ing in­stead of im­prov­ing with their C++11 con­for­mance, crash­ing with In­ter­nal Com­pil­er Er­ror on code in­volv­ing constexpr . While we man­aged to re­pro­duce and work around all re­port­ed is­sues so far, it may hap­pen that your code trig­gers some new cor­ner case. Try to up­date to the lat­est ver­sion first and if the prob­lem per­sists, let us know. Thank you and sor­ry for the bumps. Note that MSVC 2015 is not af­fect­ed by these.

New ex­am­ples Two new ex­am­ples were con­trib­uted by our great com­mu­ni­ty, name­ly an in­te­gra­tion of the Box2D physics en­gine and an ad­vanced depth-aware mouse in­ter­ac­tion ex­am­ple. Both are port­ed to We­bGL and you can play with them right now: Box2D Ex­am­ple we­bgl1 physics in­stanc­ing Builds a pyra­mid out of cubes and al­lows you to de­stroy it af­ter. Mouse In­ter­ac­tion Ex­am­ple we­bgl2 Blender-in­spired depth-aware pan­ning, zoom­ing and ro­ta­tion for easy scene nav­i­ga­tion.

HTTPS 🔒 The Mag­num web­site is nev­er stor­ing any cook­ies or do­ing us­er track­ing (and doesn’t plan to be do­ing that), so there’s no need to be wor­ried about your da­ta be­ing com­pro­mised. Nev­er­the­less, it’s now served over HTTPS, with a cer­tifi­cate from Let’s En­crypt. Some trade­offs were made as it’s ei­ther full se­cu­ri­ty or sup­port­ing the not-most-re­cent browsers (but not both), so if you ex­pe­ri­ence any is­sues, please let us know. Some­times a hard kick is all it takes to get things done.