The new Mag­num mile­stone brings WebGL 2.0 and WebAssembly, VR sup­port, lots of niceties for Win­dows users, iOS port, new ex­per­i­ment­al UI lib­rary, im­proved test­ing cap­ab­il­it­ies, sup­port for over 80 new as­set formats, new ex­amples and much more.

With nearly three years of de­vel­op­ment since the pre­vi­ous re­lease, I’m ex­cited to an­nounce the re­lease of Mag­num 2018.02. Lots of things happened, so I’ll fo­cus on the most prom­in­ent fea­tures, for a de­tailed list fol­low the changelog links at the end. This re­lease also in­tro­duces a new ver­sion­ing scheme. Ori­gin­ally this was meant to be 1.0, but after much thought I de­cided to go with year/month in­stead, as it fits more in­to the rolling re­lease philo­sophy of Mag­num.

Brand new web­site and doc­u­ment­a­tion theme

Un­til very re­cently, Mag­num lacked a cent­ral place with con­sist­ent design for show­cas­ing the fea­tures, provid­ing doc­u­ment­a­tion and keep­ing you up­dated. You can read more in the web­site an­nounce­ment post, be sure to also sub­scribe to the blog Atom feed to not miss any up­dates. The doc­u­ment­a­tion got an over­haul in a sim­il­ar style, with ex­tra ef­fort put in­to be­ing fast, easy-to-read and with first-class search func­tion­al­ity. There’s a blog post ded­ic­ated to ex­plain­ing how the new search works, if you want to learn about the in­ner work­ings.

One not­able non-ob­vi­ous fea­ture is an abil­ity to search us­ing OpenGL or Open­AL API names — very handy in case you are port­ing ex­ist­ing OpenGL code to Mag­num:

OpenGL symbol search

Mag­num wouldn’t be any­thing without the great com­munity that formed around it and com­munity in­volve­ment is im­port­ant also for the web­site con­tent — if you want to share a suc­ces story with Mag­num or have some­thing in­ter­est­ing to say, sub­mit a Guest Post and we’ll be happy to pub­lish it.

If you didn’t no­tice yet, there’s also a Mag­num chat room on Git­ter.im, full of people that are happy to help if you have ques­tions or need a bit of sup­port. You can join simply with your Git­Hub or Twit­ter ac­count.

First-class WebGL 2.0 sup­port, WebAssembly

An area that re­ceived great care is the WebGL port. WebGL 2.0 is now fully sup­por­ted and there is a set of new de­pend­ency-less plu­gins so you can now more eas­ily play au­dio, con­vert im­ages or render text on the web. The StbIm­age­Con­vert­er and Stb­TrueTypeFont plu­gins are one of them. The Bul­letInteg­ra­tion code and ex­ample now runs on the web and the mag­num-info / Mag­num Open­AL Info util­it­ies were por­ted to provide in­form­a­tion about your WebGL im­ple­ment­a­tion as well.

Bullet Physics example screenshot
Bul­let Phys­ics Ex­ample webgl1 phys­ics in­stan­cing
Shows a ro­tat­ing table full of cubes that you can shoot down.
Magnum GL Info screenshot
Mag­num GL Info asm.js fall­back webgl1 webgl2
Text util­ity print­ing info about Mag­num OpenGL cap­ab­il­it­ies. Ver­sions for WebGL 1, asm.js WebGL 1 and WebGL 2.

A bunch of code size op­tim­iz­a­tions is already in place and fur­ther size im­prove­ments are on the roadmap. Com­pil­a­tion to WebAssembly for bet­ter per­form­ance is now pos­sible, which in fact re­placed the un­main­tained NaCl port. See the post about WebAssembly sup­port for more in­form­a­tion.

Vir­tu­al Real­ity, Web­VR

Thanks to years of hard work by @Squareys, Mag­num now provides seam­less in­teg­ra­tion of the Oculus VR SDK in the Ov­rIn­teg­ra­tion lib­rary, to­geth­er with a simple ex­ample that show­cases a ba­sic use. Be­sides that, there’s a live ex­ample show­ing Web­VR in­teg­ra­tion in Em­scripten:

WebXR example screenshot
WebXR Ex­ample webgl1 webxr
A ba­sic demon­stra­tion of how to use the Em­scripten WebXR lib­rary with Mag­num.

Win­dows im­prove­ments

Visu­al Stu­dio 2015, 2017, Win­dows Store/Phone, ANGLE, Vcp­kg

Win­dows sup­port did a huge leap for­ward com­pared to the pre­vi­ous ver­sion. Thanks to big im­prove­ments in C++11 sup­port in re­cent Visu­al Stu­dio ver­sions it’s now pos­sible to build Mag­num with MS­VC 2015 and 2017 and also tar­get the UWP plat­form us­ing the ANGLE OpenGL-to-D3D trans­la­tion lay­er. On the oth­er hand, sup­port for MS­VC 2013 and MinG­W32 (the non-w64 ver­sion) was dropped to sim­pli­fy main­ten­ance ef­forts.

To make de­vel­op­ment and de­pend­ency hand­ling on Win­dows even easi­er, Mag­num now has Vcp­kg pack­ages, which al­low you to in­stall it to­geth­er with all de­pend­en­cies us­ing a single com­mand:

vcpkg install magnum

Pack­ages in­stalled us­ing Vcp­kg can be used straight away in Visu­al Stu­dio — all you need to do is to #include the head­ers you want, the build­sys­tem will do all needed lib­rary link­ing and setup be­hind the scenes auto­mat­ic­ally. (Cool, isn’t it?)

It’s of course also pos­sible to use Vcp­kg-in­stalled pack­ages with CMake. See the doc­u­ment­a­tion for de­tails.

UTF-8 every­where

Among oth­er not­able things is im­proved Uni­code sup­port on Win­dows. In line with the UTF-8 Mani­festo, all Mag­num APIs were de­signed to ex­pect strings and paths en­coded in UTF-8. This is now work­ing prop­erly also on Win­dows — as long as you use Mag­num APIs such as Util­ity::Dir­ect­ory or Trade::Ab­strac­tIm­port­er to ac­cess the filesys­tem, Win­dows wide-char APIs will be used be­hind the scenes to en­sure prop­er path en­cod­ing.

ma­cOS im­prove­ments, iOS port

Mag­num is be­ing used in a pro­ject that’s tightly coupled to Apple plat­forms, which means the code now runs on iOS as well. Plat­form::Sdl2Ap­plic­a­tion was up­dated for Ret­ina sup­port and oth­er iOS-spe­cif­ic fea­tures.

There’s also a new Plat­form::Win­dow­lessI­o­s­Ap­plic­a­tion that’s use­ful for run­ning head­less OpenGL tests on iOS. The Test­Suite lib­rary now provides in­teg­ra­tion with Xcode and XCT­est so you can run tests dir­ectly from the IDE. The cor­rade_ad­d_test() macro is also able to do all the ne­ces­sary boil­er­plate to al­low you to run your tests dir­ectly on an iOS device or sim­u­lat­or simply by run­ning CMake ctest from the com­mand-line.

To make life easi­er for ma­cOS users, there are now Homebrew pack­ages that you can in­stall simply by typ­ing

brew install mosra/magnum/magnum

You can also add all Mag­num pack­ages as a tap, see the doc­u­ment­a­tion for more in­form­a­tion.

Broad­er test­ing cap­ab­il­it­ies

Mag­num was in­volved in a pro­ject that was all about pro­cessing of im­age and spa­tial data. Thanks to that, the Test­Suite lib­rary re­ceived loads of im­prove­ments to make auto­mated test­ing a breeze. The test out­put is now colored to make it easi­er to spot fail­ures and it gained bench­mark­ing cap­ab­il­it­ies so you can com­pare how your al­gorithms per­form against baseline im­ple­ment­a­tions — us­ing CPU time, wall clock time, in­struc­tion counter or any cus­tom meas­ured quant­ity such as amount of al­loc­ated memory.

Starting InvSqrtBenchmark with 4 test cases...
 BENCH [1]   8.24 ± 0.19   ns naive()@499x1000000 (wall time)
 BENCH [2]   8.27 ± 0.19   ns naive()@499x1000000 (CPU time)
 BENCH [3]   0.31 ± 0.01   ns fast()@499x1000000 (wall time)
 BENCH [4]   0.31 ± 0.01   ns fast()@499x1000000 (CPU time)
Finished InvSqrtBenchmark with 0 errors out of 0 checks.

Be­sides the already men­tioned iOS test­ing, there are sim­il­ar im­prove­ments for An­droid — the cor­rade_ad­d_test() can em­ploy adb to up­load the test ex­ecut­able to­geth­er with all bundled files to a device or emu­lat­or, run it there and re­trieve the res­ults just as if you would be run­ning the tests on your loc­al ma­chine.

The test suite is now able to handle in­stanced tests (or, in oth­er words, data-driv­en tests). Lots of at­ten­tion was put in­to fuzzy com­par­is­on — from simple nu­mer­ic com­par­is­on us­ing Test­Suite::Com­pare::Around to com­par­ing im­age data to a ground truth with er­ror thresholds us­ing De­bug­Tools::Com­pareIm­age. Be­cause prop­er visu­al­iz­a­tion of large data is es­sen­tial for pro­ductiv­ity, the lat­ter is able to print AS­CII art visu­al­iz­a­tion of the dif­fer­ence so you can see what’s wrong dir­ectly from your CI log:

Starting ProcessingTest with 1 test cases...
  FAIL [1] process() at …/debugtools-compareimage.cpp on line 77
        Images actual and expected have max delta above threshold, actual 189
        but at most 170 expected. Mean delta 13.5776 is below threshold 96.
        Delta image:
          |                                |
          |                                |
          |         ~8070DNMN8$ZD7         |
          |       ?I0:   :++~.  .I0Z       |
          |      7I   ?$D8ZZ0DZ8,  +?      |
          |     ~+   +I        ,7NZZ$      |
          |     :    ~                     |
          |     .    .                     |
          |     ,    :                     |
          |     ~.   +.         +ID8?.     |
          |      ?.  .Z0:     +0I  :7      |
          |      .$$.  ~D8$Z0DZ.  =Z+      |
          |        =8$DI=,. .:+ZDI$        |
          |           :70DNMND$+.          |
          |                                |
          |                                |
        Top 10 out of 66 pixels above max/mean threshold:
          [16,5] #000000ff, expected #fcfcfcff (Δ = 189)
          [16,27] #fbfbfbff, expected #000000ff (Δ = 188.25)
          [15,27] #f2f2f2ff, expected #000000ff (Δ = 181.5)
          [17,5] #000000ff, expected #f1f1f1ff (Δ = 180.75)
          [15,5] #000000ff, expected #efefefff (Δ = 179.25)
          [17,27] #eeeeeeff, expected #000000ff (Δ = 178.5)
          [22,20] #000000ff, expected #e7e7e7ff (Δ = 173.25)
          [18,23] #060606ff, expected #eaeaeaff (Δ = 171)
          [18,9] #e5e5e5ff, expected #040404ff (Δ = 168.75)
          [21,26] #efefefff, expected #0f0f0fff (Δ = 168)
Finished ProcessingTest with 1 errors out of 1 checks.

Base class for tests re­quir­ing OpenGL con­text is now avail­able in a ded­ic­ated OpenGL­Test­er lib­rary and it gained sup­port for GPU time bench­marks. For easi­er test­ing on OpenGL ES and WebGL, there are now De­bug­Tools::buf­fer­Sub­Data() and De­bug­Tools::tex­ture­SubIm­age() help­er util­it­ies that sup­ple­ment the lack of Buf­fer::data() and Tex­ture::im­age() on those plat­forms.

To en­sure sta­bil­ity and make main­ten­ance easi­er, Mag­num and all its lib­rar­ies are now also com­piled and tested with code cov­er­age on all sup­por­ted plat­forms — see the Build Status page for the whole test­ing mat­rix. This also means that every sub­mit­ted pull re­quest gets auto­mat­ic­ally tested for re­gres­sions, stream­lin­ing the whole re­view pro­cess.

There’s much more to men­tion re­gard­ing test­ing — it’ll be a part of a more de­tailed blog post in the fu­ture, stay tuned!

Ex­per­i­ment­al UI lib­rary

Some years ago I was re­spons­ible for UI ren­der­ing in a pro­ject that fo­cused on visu­al­iz­ing large amounts of tex­tu­al and plot data. The new ex­per­i­ment­al Mag­num::Ui lib­rary builds on the know­ledge gained dur­ing that pro­ject and its design goal is be­ing ale to render huge UIs (such as ed­it­ors) fast while stay­ing fully cus­tom­iz­able and easy to use for quick pro­to­typ­ing.

Due to its heavy use of uni­form buf­fers and in­stan­cing it’s re­quir­ing at least OpenGL ES 3.0 (or WebGL 2.0). The cur­rent state is very ex­per­i­ment­al — it will gradu­ally sta­bil­ize, gain more wid­gets and get doc­u­mented in the next months. You can see how it looks in the UI Wid­get Gal­lery, it was also used to provide some knobs and toggles for the Area Lights demo:

Magnum::Ui Gallery screenshot
Mag­num::Ui Gal­lery webgl2 ui
A gal­lery of vari­ous wid­gets (but­tons, la­bels, in­puts, mod­als) provided by the Mag­num::Ui lib­rary.

As­set man­age­ment im­prove­ments

A large new fea­ture is sup­port for com­pressed im­ages — load­ing them from files, up­load­ing and down­load­ing them from tex­tures; plus there are new in­ter­faces in Trade::Ab­strac­tIm­age­Con­vert­er ready for in­teg­rat­ing vari­ous GPU com­pres­sion lib­rar­ies. To­geth­er with com­pressed im­ages Mag­num gained sup­port for vari­ous pixel stor­age op­tions in the Pixel­Stor­age class to al­low dir­ect ma­nip­u­la­tion of im­age sub-rect­angles, with fur­ther con­veni­ence fea­tures such as Image::slice() planned for the next re­leases.

There’s also a new util­ity called mag­num-im­age­con­vert­er that simply ex­poses all ex­ist­ing *Im­port­er and *Im­age­Con­vert­er plu­gins on a com­mand line. To­geth­er with a new Any­Im­age­Con­vert­er plu­gin it’s able to auto­de­tect source and des­tin­a­tion file formats based on ex­ten­sion, so you can eas­ily use it in your pipeline for data con­ver­sion, for ex­ample:

magnum-imageconverter image.bmp image.png

Many ex­tern­al con­tri­bu­tions went in­to as­set man­age­ment and con­ver­sion — you can now use the As­simpIm­port­er plu­gin to load about 40 new scene formats us­ing the As­simp lib­rary; the Dev­Il­Im­ageIm­port­er plu­gin uses Dev­IL to load 40 new im­age formats. Ini­tial work went in­to cam­era and light prop­erty im­port, with sup­port in the As­simp and OpenGEX im­port­er.

Among the oth­ers there’s a pos­sib­il­ity to load DXT-com­pressed tex­tures us­ing DdsIm­port­er or con­vert im­ages to PNG and EXR us­ing PngIm­age­Con­vert­er and Min­iExrIm­age­Con­vert­er. The StbIm­age­Con­vert­er can now use stb_im­age_write to out­put HDR and BMP formats in ad­di­tion to PNG.

Au­dio lib­rary good­ies

The Au­dio lib­rary re­ceived HRTF sup­port that’s very im­port­ant for im­mers­ive au­dio in VR, be­sides that it sup­ports many new buf­fer formats. The HRTF sup­port is ac­com­pan­ied with a new ex­ample and the whole Au­dio lib­rary was up­dated to work on the web as well:

Audio example screenshot
Au­dio Ex­ample webgl1 au­dio
Loads an OGG file and shows how to play spa­tial­ized au­dio with the Mag­num Au­dio lib­rary.

Many new de­pend­ency-less im­port plu­gins were con­trib­uted — Stb­Vor­bisAu­di­oIm­port­er for load­ing OGG Vor­bis files us­ing stb_­vor­bis, DrWavAu­di­oIm­port­er and Dr­Fla­cAu­di­oIm­port­er for load­ing WAV and FLAC files us­ing dr_wav/dr_­flac. The WavAu­di­oIm­port­er plu­gin that’s main­tained dir­ectly in Mag­num re­ceived vari­ous up­dates, broad­er buf­fer format sup­port and bet­ter er­ror hand­ling.

Full con­trol over ini­tial­iz­a­tion and own­er­ship

While all types in Mag­num are by de­fault ini­tial­ized to a defined value, it’s now pos­sible to over­ride the be­ha­vi­or for great­er flex­ib­il­ity. For ex­ample if you will be over­writ­ing all val­ues in a con­tain­er any­way; to avoid un­ne­ces­sary memory zero­ing in­struc­tions in a tight loop; or to de­fer OpenGL ob­ject ini­tial­iz­a­tion to a point where a con­text is ready without in­tro­du­cing ad­di­tion­al in­dir­ec­tion us­ing point­ers or op­tion­al ob­jects:

/* Generate grid positions */
Containers::Array<Vector3> positions{Containers::NoInit, 16*16};
for(auto& i: positions)
    i = ...;

/* Zero-init the matrix instead of setting it to identity */
Matrix3x3 m{Math::ZeroInit};

/* Defer buffer initialization for later when GL context is ready */
Buffer buffer{NoCreate};

// ...

buffer = Buffer{};

To­geth­er with this it’s now pos­sible to trans­fer own­er­ship of all un­der­ly­ing re­sources — wrap­ping ex­tern­ally al­loc­ated ar­rays and provid­ing cus­tom de­leters, or, on the oth­er hand, us­ing Con­tain­ers::Ar­ray::re­lease() to re­lease own­er­ship of the al­loc­ated memory. There are also two new classes, Con­tain­ers::StaticAr­ray and Con­tain­ers::StaticAr­rayView, for hand­ling stack-al­loc­ated, com­pile-time-sized ar­rays and views on them. New APIs like Con­tain­ers::ar­rayCast() or Con­tain­ers::ar­ray­Size() provide fur­ther con­veni­ence util­it­ies:

/* custom allocator functions */
char* allocate(std::size_t);
void deallocate(char*, std::size_t);

// ...

/* Allocate the data and wrap them in a RAII container */
Containers::Array<char> data{allocate(128), 128, [](char* data, std::size_t size) {
    deallocate(data, size);
}};

/* The allocated array is in fact 16 four-component float vectors */
Containers::ArrayView<Vector4> vectors = Containers::arrayCast<Vector4>(data);
for(Vector4& i: vectors)
    // ...

Math lib­rary ad­di­tions

The Math lib­rary re­ceived a class rep­res­ent­ing Bez­i­er curves and a Frust­um struc­ture. The Math::Geo­metry::In­ter­sec­tion namespace is ex­ten­ded with frust­um cull­ing al­gorithms and fur­ther ad­di­tions are already be­ing worked on.

There’s a new Half type for rep­res­ent­ing 16-bit half-float num­bers. It’s just a stor­age type, provid­ing con­ver­sions from and to float types. In ad­di­tion to the ex­ist­ing _deg/_rad lit­er­als there is a new _h lit­er­al for half-floats and vari­ous lit­er­als for en­ter­ing hexa­decim­al RGB(A) col­ors in lin­ear RGB or sR­GB:

Color3ub a = 0x33b27f_rgb;      // {0x33, 0xb2, 0x7f}
Color4 c = 0x33b27fcc_srgbaf;   // {0.0331048f, 0.445201f, 0.212231f, 0.8f}

There’s much more ad­ded for more con­veni­ence and bet­ter fea­ture par­ity with GLSL, check out the com­plete changelog at the end of the art­icle.

Bet­ter in­ter­op­er­ab­il­ity with 3rd-party code

One of design goals of Mag­num is to be a col­lec­tion of use­ful non-in­trus­ive tools that works well with third-party lib­rar­ies — not be­ing a big mono­lith­ic en­gine that takes over everything and forces a par­tic­u­lar work­flow. With this and the fol­low­ing re­leases this design goal is be­ing pushed fur­ther than ever be­fore.

One com­mon case is that Mag­num is not the only lib­rary ac­cess­ing the OpenGL con­text — for ex­ample it’s only tak­ing care of data visu­al­iz­a­tion in a big­ger ap­plic­a­tion that’s writ­ten in Qt. Be­cause OpenGL is a lot of glob­al state, care must be taken so lib­rar­ies know what state can be trus­ted and what not — that’s handled with Con­text::re­set­State(). It’s also pos­sible to wrap ex­tern­ally cre­ated OpenGL ob­jects us­ing *::wrap() and, con­versely, re­lease their own­er­ship with re­lease(). A re­duced ex­ample show­ing ren­der­ing in­to QQuick­Frame­buf­fer­Ob­ject:

#include <Magnum/Context.h>
#include <Magnum/Framebuffer.h>
#include <Magnum/Mesh.h>
#include <Magnum/Shaders/Phong.h>
#include <QQuickFramebufferObject>

struct MagnumRenderer: QQuickFramebufferObject::Renderer {
    // ...

    QOpenGLFramebufferObject* createFramebufferObject(const QSize& size) override {
        /* Create Qt framebuffer object and wrap it to use with Magnum APIs */
        auto fb = new QOpenGLFramebufferObject(size, ...);
        _fb = Framebuffer::wrap(fb->handle(), {{}, {size.width(), size.height()}});
        return fb;
    }

    void render() override {
        /* Reset Magnum state tracker after Qt did its job */
        Context::resetState(Context::State::ExitExternal);

        /* Clear the framebuffer and draw a mesh */
        _fb.clear(FramebufferClear::Color|FramebufferClear::Depth);
        _mesh.draw(_shader);

        /* Clean up to avoid Magnum state being modified by Qt */
        Context::resetState(Context::State::EnterExternal);
    }

    Framebuffer _fb{NoInit};
    Mesh _mesh;
    Shaders::Phong _shader;
};

Some­times you may need to ac­cess the un­der­ly­ing APIs that Mag­num is wrap­ping — for ex­ample to test out a new fea­ture that hasn’t been ex­posed yet. Both Plat­form::Sdl2Ap­plic­a­tion and Plat­form::GlfwAp­plic­a­tion now provide ac­cess to the un­der­ly­ing toolkit struc­tures. If you need to go even deep­er, you can ditch the *Application classes com­pletely and simply at­tach Mag­num to an ex­ist­ing OpenGL con­text. How to do that with GLFW is shown on a simple tri­angle ren­der­ing ex­ample.

Sim­il­ar thing is with as­set im­port­ers — if you need to ac­cess par­tic­u­lar As­simp fea­ture dir­ectly or parse an OpenGEX ex­ten­sion struc­ture, it’s now avail­able through type-erased importerState() ac­cessors. In case of As­simp it’s also pos­sible to take over an ex­ist­ing As­simp in­stance us­ing open­State(). See re­lated sec­tions in As­simpIm­port­er and OpenGex­Im­port­er plu­gin doc­u­ment­a­tion for de­tails.

Con­ver­sion of math struc­tures from and to ex­tern­al types was ex­ten­ded to all struc­tures in the Math namespace, so with prop­er boil­er­plate head­er in­cluded it is pos­sible to have seam­less in­teg­ra­tion with, for ex­ample, GLM:

glm::gtc::quaternion a{4.0f, 1.0f, 2.0f, 3.0f};

Quaternion q{a};
Debug{} << q.vector();              // {1.0, 2.0, 3.0}

glm::gtc::quaternion b{q.normalized()};

Even more new stuff

The list of new things doesn’t stop here. It’s im­port­ant to note that all ex­ample code is now put in­to pub­lic do­main (or UN­LI­CENSE) to free you from leg­al obstacles when us­ing the code in your apps. There’s a new ex­ample show­ing how to use Par­al­lel Split / Cas­ca­ded Shad­ow Maps and also a simple Ob­ject Pick­ing ex­ample:

Object picking example screenshot
Ob­ject Pick­ing Ex­ample webgl2
Show­cases us­age of mul­tiple frame­buf­fer at­tach­ments to im­ple­ment ob­ject pick­ing.

There’s also a new ex­per­i­ment­al DartInteg­ra­tion lib­rary be­ing worked on — it in­teg­rates the DART Dy­nam­ic An­im­a­tion and Ro­bot­ics Toolkit in­to Mag­num in a sim­il­ar way that’s done with the Bul­let Phys­ics lib­rary. A first draft is already merged with second re­vi­sion be­ing cur­rently in the works. This lib­rary alone de­serves a blog post on its own — stay tuned!

Up­grad­ing from pre­vi­ous ver­sions

Be­cause there was no mile­stone since 2015, great care was taken to main­tain back­wards com­pat­ib­il­ity with the 2015.05 ver­sion. De­pend­ing on how big your up­grade jump is, up­grad­ing to 2018.02 should be largely source com­pat­ible, with de­prec­a­tion warn­ings is­sued for APIs that were re­placed with new func­tion­al­ity.

In con­trast, im­me­di­ately fol­low­ing this re­lease there’s some cleanup work sched­uled — pur­ging of APIs de­prec­ated for a long time and do­ing some re­or­gan­iz­a­tion to make space for new fea­tures, such as Vulkan and SPIR-V sup­port.

Com­plete changelog

If you sur­vived all the way down here, con­grats! There’s much more and it’s not pos­sible to fit everything in this an­nounce­ment. You can find a de­tailed list of changes in ver­sion 2018.02 in the doc­u­ment­a­tion:

Spe­cial thanks

This re­lease wouldn’t be pos­sible without ex­treme ded­ic­a­tion of nu­mer­ous vo­lun­teers:

  • Jonath­an Hale (@Squareys) — Oculus VR in­teg­ra­tion, Web­VR ex­ample, HRTF sup­port in the Au­dio lib­rary; DDS As­simp and Vor­bis im­port­ers, Area Lights ex­ample, GLFW ap­plic­a­tion, frust­um cull­ing and much much more
  • Alice Mar­gatroid (@Alice­mar­gatroid) — multi-chan­nel sup­port in Au­dio lib­rary, stand­ard con­form­ance, huge im­prove­ments in the WAV im­port­er plu­gin, dr_wav and dr_­flac im­port­er plu­gins, Dev­IL im­port­er plu­gin, vari­ous bug re­ports, fea­ture sug­ges­tions and much more
  • Kon­stanti­nos Chatzily­ger­oud­is (@cost­ashatz) — on­go­ing work on the DART in­teg­ra­tion lib­rary and re­lated func­tion­al­ity
  • Bill Robin­son (@wivlaro) — shad­ow map­ping ex­ample, vari­ous bug re­ports and sug­ges­tions
  • Ash­win Ravichandran (@ashrko619) — Bézi­er curve im­ple­ment­a­tion
  • Mi­chael Di­ets­chi (@mdi­etsch) — colored out­put in Win­dows con­sole, nu­mer­ous bug re­ports
  • Ger­hard de Cler­cq — ini­tial Win­dows RT (Store/Phone) port
  • @sig­man78 — ini­tial MS­VC 2017 port, ini­tial ver­sion of Vcp­kg pack­ages
  • Joel Clay (@jclay) — up­dates to Vcp­kg pack­ages

This list is not ex­haust­ive — sorry if I for­got about some­body! Over the time there were many more people re­port­ing is­sues, help­ing with bug­fixes, giv­ing en­cour­aging and con­struct­ive feed­back or just be­ing happy to help each oth­er on the Git­ter chat. Thank you, every­body, and cheers!