WebXR in C++

~ 3.5 Minute Read.

Web XR in C++… what?

I re­cent­ly had the joy of link­ing javascript to C++ code for a tiny game we’re build­ing at Vhite Rab­bit.

Com­pil­ers like Em­scripten or cheerp – which I didn’t get a chance to try just yet – al­low you to com­pile your C++ or C code to ASM.js or We­bAssem­bly. Since you will want ac­cess to some Web APIs, you will need to link some javascript to your WASM code.

Let’s get in­to some more tech­ni­cal de­tails for those who are in­ter­est­ed:

Link­ing JS in CMake

For em­scripten you can check the doc­u­men­ta­tion here. While that page and the li­braries that come with em­scripten should get you all the way there, I thought it may be help­ful to give a over­view any­way. With a head­er like:

#ifndef WEBXR_H_
#define WEBXR_H_

#ifdef __cplusplus
extern "C" {
#endif

/** Init WebXR rendering */
extern void init_webxr(/* ... */);

#ifdef __cplusplus
}
#endif

#endif

You can link the im­ple­ment­ing javascript li­brary:

mergeInto(LibraryManager.library, {
    init_webxr: function(/* ... */) { }
);

… su­per eas­i­ly by adding ap­pro­pri­ate CMake flags:

if(CORRADE_TARGET_EMSCRIPTEN)
    # "link" the webxr javascript library
    set_property(TARGET your-target APPEND_STRING PROPERTY
        LINK_FLAGS " --js-library library_webxr.js")
endif()

Where CORRADE_TARGET_EMSCRIPTEN is a flag pro­vid­ed by Cor­rade. This works with­out, if you want to un­con­di­tion­al­ly link the js, though. I use the toolchains that are al­so used in Mag­num.

Ad­di­tion­al­ly I rec­om­mend adding prop­er de­bug flags:

# Some handy debug flags
set_property(TARGET your-target APPEND_STRING PROPERTY
    LINK_FLAGS_DEBUG " -s ASSERTIONS=1 -s DEMANGLE_SUPPORT=1")

Work­ing with the heap

To pass da­ta be­tween C++ and JS with em­scripten, you will want to use the heap. While pass­ing small­er da­ta via func­tion ar­gu­ments and re­turn val­ues is triv­ial, you can pass en­tire struc­tures by al­lo­cat­ing heap mem­o­ry:

var yourStruct = Module._malloc(SIZEOF_YOUR_STRUCT);

To then set its val­ues us­ing set­Val­ue 3:

setValue(yourStruct + 0, 42.0, 'double')
setValue(yourStruct + 8, 42.0, 'float')
setValue(yourStruct + 12, 42, 'i64')
setValue(yourStruct + 20, 42, 'i32')
setValue(yourStruct + 24, 42, 'i16')
setValue(yourStruct + 28, 42, 'i8')

Fi­nal­ly, pass­ing the point­er and if you’re done us­ing that heap mem­o­ry, you should be deal­lo­cat­ing it ei­ther in javascript:

Module._free(yourStruct);

or in C/C++ as you would usu­al­ly do (I hope).

I hope this helps some­one out there, I know it would have saved be a minute to have this a lit­tle more con­densed and in one place.

1
This will prob­a­bly be a blog post of its own some­time.
2
I just no­ticed it’s miss­ing an ori­gin tri­al to­ken may not run!
3
In em­scripten’s li­braries you will of­ten see makeSetValue, which is meant to work with the JSON li­brary which stores the off­sets of the mem­bers of all the C structs, though.

Writ­ten in 60 min­utes, ed­it­ed in 5 min­utes.