Bug 1198518: [webvr] add support for OSVR. r=kip
☠☠ backed out by 59d3baba3cf0 ☠ ☠
authorGeorgiy Frolov <georgiy@sensics.com>
Wed, 23 Mar 2016 11:59:01 -0400
changeset 331907 2da4c57f45951fe964d32c6ca78a6c1dfe02f2a9
parent 331906 85a2d1e3cf9548108ec1124f001a1abe9ace1f03
child 331908 0d41311af46d5b3c2606361018e2d1100161cf44
push id1146
push userCallek@gmail.com
push dateMon, 25 Jul 2016 16:35:44 +0000
treeherdermozilla-release@a55778f9cd5a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskip
bugs1198518
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1198518: [webvr] add support for OSVR. r=kip
gfx/thebes/gfxPrefs.h
gfx/vr/VRManager.cpp
gfx/vr/gfxVR.cpp
gfx/vr/gfxVR.h
gfx/vr/gfxVROSVR.cpp
gfx/vr/gfxVROSVR.h
gfx/vr/moz.build
gfx/vr/osvr/ClientKit/ClientKitC.h
gfx/vr/osvr/ClientKit/ContextC.h
gfx/vr/osvr/ClientKit/DisplayC.h
gfx/vr/osvr/ClientKit/Export.h
gfx/vr/osvr/ClientKit/InterfaceC.h
gfx/vr/osvr/ClientKit/InterfaceCallbackC.h
gfx/vr/osvr/ClientKit/InterfaceStateC.h
gfx/vr/osvr/ClientKit/SystemCallbackC.h
gfx/vr/osvr/ClientKit/TransformsC.h
gfx/vr/osvr/Util/APIBaseC.h
gfx/vr/osvr/Util/AnnotationMacrosC.h
gfx/vr/osvr/Util/BoolC.h
gfx/vr/osvr/Util/ChannelCountC.h
gfx/vr/osvr/Util/ClientCallbackTypesC.h
gfx/vr/osvr/Util/ClientOpaqueTypesC.h
gfx/vr/osvr/Util/ClientReportTypesC.h
gfx/vr/osvr/Util/Export.h
gfx/vr/osvr/Util/ImagingReportTypesC.h
gfx/vr/osvr/Util/MatrixConventionsC.h
gfx/vr/osvr/Util/PlatformConfig.h
gfx/vr/osvr/Util/Pose3C.h
gfx/vr/osvr/Util/QuaternionC.h
gfx/vr/osvr/Util/QuatlibInteropC.h
gfx/vr/osvr/Util/RadialDistortionParametersC.h
gfx/vr/osvr/Util/RenderingTypesC.h
gfx/vr/osvr/Util/ReturnCodesC.h
gfx/vr/osvr/Util/StdInt.h
gfx/vr/osvr/Util/TimeValueC.h
gfx/vr/osvr/Util/Vec2C.h
gfx/vr/osvr/Util/Vec3C.h
modules/libpref/init/all.js
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -197,16 +197,17 @@ private:
   DECL_GFX_PREF(Live, "browser.viewport.desktopWidth",         DesktopViewportWidth, int32_t, 980);
 
   DECL_GFX_PREF(Live, "dom.ipc.plugins.asyncdrawing.enabled",  PluginAsyncDrawingEnabled, bool, false);
   DECL_GFX_PREF(Live, "dom.meta-viewport.enabled",             MetaViewportEnabled, bool, false);
   DECL_GFX_PREF(Once, "dom.vr.enabled",                        VREnabled, bool, false);
   DECL_GFX_PREF(Once, "dom.vr.oculus.enabled",                 VROculusEnabled, bool, true);
   DECL_GFX_PREF(Once, "dom.vr.oculus050.enabled",              VROculus050Enabled, bool, true);
   DECL_GFX_PREF(Once, "dom.vr.cardboard.enabled",              VRCardboardEnabled, bool, false);
+  DECL_GFX_PREF(Once, "dom.vr.osvr.enabled",                   VROSVREnabled, bool, false);
   DECL_GFX_PREF(Once, "dom.vr.add-test-devices",               VRAddTestDevices, int32_t, 1);
   DECL_GFX_PREF(Live, "dom.vr.poseprediction.enabled",         VRPosePredictionEnabled, bool, false);
   DECL_GFX_PREF(Live, "dom.w3c_pointer_events.enabled",        PointerEventsEnabled, bool, false);
   DECL_GFX_PREF(Live, "dom.w3c_touch_events.enabled",          TouchEventsEnabled, int32_t, 0);
 
   DECL_GFX_PREF(Live, "general.smoothScroll",                  SmoothScrollEnabled, bool, true);
   DECL_GFX_PREF(Live, "general.smoothScroll.currentVelocityWeighting",
                 SmoothScrollCurrentVelocityWeighting, float, 0.25);
--- a/gfx/vr/VRManager.cpp
+++ b/gfx/vr/VRManager.cpp
@@ -13,16 +13,17 @@
 
 #include "gfxPrefs.h"
 #include "gfxVR.h"
 #if defined(XP_WIN)
 #include "gfxVROculus.h"
 #endif
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
 #include "gfxVROculus050.h"
+#include "gfxVROSVR.h"
 #endif
 #include "gfxVRCardboard.h"
 
 
 namespace mozilla {
 namespace gfx {
 
 static StaticRefPtr<VRManager> sVRManagerSingleton;
@@ -62,16 +63,22 @@ VRManager::VRManager()
 
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
   if (useOculus050) {
     mgr = VRHMDManagerOculus050::Create();
     if (mgr) {
       mManagers.AppendElement(mgr);
     }
   }
+  // OSVR is cross platform compatible
+  mgr = VRHMDManagerOSVR::Create();
+  if (mgr){
+      mManagers.AppendElement(mgr);
+  }
+
 #endif
 
   mgr = VRHMDManagerCardboard::Create();
   if (mgr) {
     mManagers.AppendElement(mgr);
   }
 }
 
--- a/gfx/vr/gfxVR.cpp
+++ b/gfx/vr/gfxVR.cpp
@@ -12,16 +12,17 @@
 
 #include "gfxPrefs.h"
 #include "gfxVR.h"
 #if defined(XP_WIN)
 #include "gfxVROculus.h"
 #endif
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
 #include "gfxVROculus050.h"
+#include "gfxVROSVR.h"
 #endif
 #include "gfxVRCardboard.h"
 
 #include "mozilla/unused.h"
 #include "mozilla/layers/Compositor.h"
 #include "mozilla/layers/TextureHost.h"
 
 #ifndef M_PI
--- a/gfx/vr/gfxVR.h
+++ b/gfx/vr/gfxVR.h
@@ -24,16 +24,17 @@ class CompositingRenderTarget;
 }
 
 namespace gfx {
 
 enum class VRHMDType : uint16_t {
   Oculus,
   Cardboard,
   Oculus050,
+  OSVR,
   NumHMDTypes
 };
 
 enum class VRStateValidFlags : uint16_t {
   State_None = 0,
   State_Position = 1 << 1,
   State_Orientation = 1 << 2,
   // State_All used for validity checking during IPC serialization
new file mode 100644
--- /dev/null
+++ b/gfx/vr/gfxVROSVR.cpp
@@ -0,0 +1,622 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <math.h>
+
+#include "prlink.h"
+#include "prmem.h"
+#include "prenv.h"
+#include "gfxPrefs.h"
+#include "nsString.h"
+#include "mozilla/Preferences.h"
+
+#include "mozilla/gfx/Quaternion.h"
+
+#ifdef XP_WIN
+#include "../layers/d3d11/CompositorD3D11.h"
+#include "../layers/d3d11/TextureD3D11.h"
+#endif
+
+#include "gfxVROSVR.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+using namespace mozilla::layers;
+using namespace mozilla::gfx;
+using namespace mozilla::gfx::impl;
+
+namespace {
+// need to typedef functions that will be used in the code below
+extern "C" {
+typedef OSVR_ClientContext (*pfn_osvrClientInit)(
+  const char applicationIdentifier[], uint32_t flags);
+typedef OSVR_ReturnCode (*pfn_osvrClientShutdown)(OSVR_ClientContext ctx);
+typedef OSVR_ReturnCode (*pfn_osvrClientUpdate)(OSVR_ClientContext ctx);
+typedef OSVR_ReturnCode (*pfn_osvrClientCheckStatus)(OSVR_ClientContext ctx);
+typedef OSVR_ReturnCode (*pfn_osvrClientGetInterface)(
+  OSVR_ClientContext ctx, const char path[], OSVR_ClientInterface* iface);
+typedef OSVR_ReturnCode (*pfn_osvrClientFreeInterface)(
+  OSVR_ClientContext ctx, OSVR_ClientInterface iface);
+typedef OSVR_ReturnCode (*pfn_osvrGetOrientationState)(
+  OSVR_ClientInterface iface, OSVR_TimeValue* timestamp,
+  OSVR_OrientationState* state);
+typedef OSVR_ReturnCode (*pfn_osvrGetPositionState)(OSVR_ClientInterface iface,
+                                                    OSVR_TimeValue* timestamp,
+                                                    OSVR_PositionState* state);
+typedef OSVR_ReturnCode (*pfn_osvrClientGetDisplay)(OSVR_ClientContext ctx,
+                                                    OSVR_DisplayConfig* disp);
+typedef OSVR_ReturnCode (*pfn_osvrClientFreeDisplay)(OSVR_DisplayConfig disp);
+typedef OSVR_ReturnCode (*pfn_osvrClientGetNumEyesForViewer)(
+  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount* eyes);
+typedef OSVR_ReturnCode (*pfn_osvrClientGetViewerEyePose)(
+  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+  OSVR_Pose3* pose);
+typedef OSVR_ReturnCode (*pfn_osvrClientGetDisplayDimensions)(
+  OSVR_DisplayConfig disp, OSVR_DisplayInputCount displayInputIndex,
+  OSVR_DisplayDimension* width, OSVR_DisplayDimension* height);
+typedef OSVR_ReturnCode (
+  *pfn_osvrClientGetViewerEyeSurfaceProjectionClippingPlanes)(
+  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+  OSVR_SurfaceCount surface, double* left, double* right, double* bottom,
+  double* top);
+typedef OSVR_ReturnCode (*pfn_osvrClientGetRelativeViewportForViewerEyeSurface)(
+  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+  OSVR_SurfaceCount surface, OSVR_ViewportDimension* left,
+  OSVR_ViewportDimension* bottom, OSVR_ViewportDimension* width,
+  OSVR_ViewportDimension* height);
+typedef OSVR_ReturnCode (*pfn_osvrClientGetViewerEyeSurfaceProjectionMatrixf)(
+  OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+  OSVR_SurfaceCount surface, float near, float far,
+  OSVR_MatrixConventions flags, float* matrix);
+typedef OSVR_ReturnCode (*pfn_osvrClientCheckDisplayStartup)(
+  OSVR_DisplayConfig disp);
+typedef OSVR_ReturnCode (*pfn_osvrClientSetRoomRotationUsingHead)(
+  OSVR_ClientContext ctx);
+}
+
+static pfn_osvrClientInit osvr_ClientInit = nullptr;
+static pfn_osvrClientShutdown osvr_ClientShutdown = nullptr;
+static pfn_osvrClientUpdate osvr_ClientUpdate = nullptr;
+static pfn_osvrClientCheckStatus osvr_ClientCheckStatus = nullptr;
+static pfn_osvrClientGetInterface osvr_ClientGetInterface = nullptr;
+static pfn_osvrClientFreeInterface osvr_ClientFreeInterface = nullptr;
+static pfn_osvrGetOrientationState osvr_GetOrientationState = nullptr;
+static pfn_osvrGetPositionState osvr_GetPositionState = nullptr;
+static pfn_osvrClientGetDisplay osvr_ClientGetDisplay = nullptr;
+static pfn_osvrClientFreeDisplay osvr_ClientFreeDisplay = nullptr;
+static pfn_osvrClientGetNumEyesForViewer osvr_ClientGetNumEyesForViewer =
+  nullptr;
+static pfn_osvrClientGetViewerEyePose osvr_ClientGetViewerEyePose = nullptr;
+static pfn_osvrClientGetDisplayDimensions osvr_ClientGetDisplayDimensions =
+  nullptr;
+static pfn_osvrClientGetViewerEyeSurfaceProjectionClippingPlanes
+  osvr_ClientGetViewerEyeSurfaceProjectionClippingPlanes = nullptr;
+static pfn_osvrClientGetRelativeViewportForViewerEyeSurface
+  osvr_ClientGetRelativeViewportForViewerEyeSurface = nullptr;
+static pfn_osvrClientGetViewerEyeSurfaceProjectionMatrixf
+  osvr_ClientGetViewerEyeSurfaceProjectionMatrixf = nullptr;
+static pfn_osvrClientCheckDisplayStartup osvr_ClientCheckDisplayStartup =
+  nullptr;
+static pfn_osvrClientSetRoomRotationUsingHead
+  osvr_ClientSetRoomRotationUsingHead = nullptr;
+
+bool
+LoadOSVRRuntime()
+{
+  static PRLibrary* osvrUtilLib = nullptr;
+  static PRLibrary* osvrCommonLib = nullptr;
+  static PRLibrary* osvrClientLib = nullptr;
+  static PRLibrary* osvrClientKitLib = nullptr;
+  //this looks up the path in the about:config setting, from greprefs.js or modules\libpref\init\all.js
+  nsAdoptingCString osvrUtilPath =
+    mozilla::Preferences::GetCString("gfx.vr.osvr.utilLibPath");
+  nsAdoptingCString osvrCommonPath =
+    mozilla::Preferences::GetCString("gfx.vr.osvr.commonLibPath");
+  nsAdoptingCString osvrClientPath =
+    mozilla::Preferences::GetCString("gfx.vr.osvr.clientLibPath");
+  nsAdoptingCString osvrClientKitPath =
+    mozilla::Preferences::GetCString("gfx.vr.osvr.clientKitLibPath");
+
+  //we need all the libs to be valid
+  if ((!osvrUtilPath) || (!osvrCommonPath) || (!osvrClientPath) ||
+      (!osvrClientKitPath)) {
+    return false;
+  }
+
+  osvrUtilLib = PR_LoadLibrary(osvrUtilPath.BeginReading());
+  osvrCommonLib = PR_LoadLibrary(osvrCommonPath.BeginReading());
+  osvrClientLib = PR_LoadLibrary(osvrClientPath.BeginReading());
+  osvrClientKitLib = PR_LoadLibrary(osvrClientKitPath.BeginReading());
+
+  if (!osvrUtilLib) {
+    printf_stderr("[OSVR] Failed to load OSVR Util library!\n");
+    return false;
+  }
+  if (!osvrCommonLib) {
+    printf_stderr("[OSVR] Failed to load OSVR Common library!\n");
+    return false;
+  }
+  if (!osvrClientLib) {
+    printf_stderr("[OSVR] Failed to load OSVR Client library!\n");
+    return false;
+  }
+  if (!osvrClientKitLib) {
+    printf_stderr("[OSVR] Failed to load OSVR ClientKit library!\n");
+    return false;
+  }
+
+// make sure all functions that we'll be using are available
+#define REQUIRE_FUNCTION(_x)                                                   \
+  do {                                                                         \
+    *(void**) & osvr_##_x =                                                    \
+      (void*)PR_FindSymbol(osvrClientKitLib, "osvr" #_x);                      \
+    if (!osvr_##_x) {                                                          \
+      printf_stderr("osvr" #_x " symbol missing\n");                           \
+      goto fail;                                                               \
+    }                                                                          \
+  } while (0)
+
+  REQUIRE_FUNCTION(ClientInit);
+  REQUIRE_FUNCTION(ClientShutdown);
+  REQUIRE_FUNCTION(ClientUpdate);
+  REQUIRE_FUNCTION(ClientCheckStatus);
+  REQUIRE_FUNCTION(ClientGetInterface);
+  REQUIRE_FUNCTION(ClientFreeInterface);
+  REQUIRE_FUNCTION(GetOrientationState);
+  REQUIRE_FUNCTION(GetPositionState);
+  REQUIRE_FUNCTION(ClientGetDisplay);
+  REQUIRE_FUNCTION(ClientFreeDisplay);
+  REQUIRE_FUNCTION(ClientGetNumEyesForViewer);
+  REQUIRE_FUNCTION(ClientGetViewerEyePose);
+  REQUIRE_FUNCTION(ClientGetDisplayDimensions);
+  REQUIRE_FUNCTION(ClientGetViewerEyeSurfaceProjectionClippingPlanes);
+  REQUIRE_FUNCTION(ClientGetRelativeViewportForViewerEyeSurface);
+  REQUIRE_FUNCTION(ClientGetViewerEyeSurfaceProjectionMatrixf);
+  REQUIRE_FUNCTION(ClientCheckDisplayStartup);
+  REQUIRE_FUNCTION(ClientSetRoomRotationUsingHead);
+
+#undef REQUIRE_FUNCTION
+
+  return true;
+
+fail:
+  return false;
+}
+
+} // namespace
+
+mozilla::gfx::VRFieldOfView
+SetFromTanRadians(double left, double right, double bottom, double top)
+{
+  mozilla::gfx::VRFieldOfView fovInfo;
+  fovInfo.leftDegrees = atan(left) * 180.0 / M_PI;
+  fovInfo.rightDegrees = atan(right) * 180.0 / M_PI;
+  fovInfo.upDegrees = atan(top) * 180.0 / M_PI;
+  fovInfo.downDegrees = atan(bottom) * 180.0 / M_PI;
+  return fovInfo;
+}
+
+HMDInfoOSVR::HMDInfoOSVR(OSVR_ClientContext* context,
+                         OSVR_ClientInterface* iface,
+                         OSVR_DisplayConfig* display)
+  : VRHMDInfo(VRHMDType::OSVR, false)
+  , m_ctx(context)
+  , m_iface(iface)
+  , m_display(display)
+{
+
+  MOZ_COUNT_CTOR_INHERITED(HMDInfoOSVR, VRHMDInfo);
+
+  mDeviceInfo.mDeviceName.AssignLiteral("OSVR HMD");
+  mDeviceInfo.mSupportedSensorBits = VRStateValidFlags::State_None;
+  mDeviceInfo.mSupportedSensorBits =
+    VRStateValidFlags::State_Orientation | VRStateValidFlags::State_Position;
+
+  // XXX OSVR display topology allows for more than one viewer
+  // will assume only one viewer for now (most likely stay that way)
+
+  OSVR_EyeCount numEyes;
+  osvr_ClientGetNumEyesForViewer(*m_display, 0, &numEyes);
+
+  for (uint8_t eye = 0; eye < numEyes; eye++) {
+    double left, right, bottom, top;
+    // XXX for now there is only one surface per eye
+    osvr_ClientGetViewerEyeSurfaceProjectionClippingPlanes(
+      *m_display, 0, eye, 0, &left, &right, &bottom, &top);
+    mDeviceInfo.mRecommendedEyeFOV[eye] = mDeviceInfo.mMaximumEyeFOV[eye] =
+      SetFromTanRadians(-left, right, -bottom, top);
+  }
+
+  // XXX Assuming there is only one display input for now
+  // however, it's possible to have more than one (dSight with 2 HDMI inputs)
+  OSVR_DisplayDimension width, height;
+  osvr_ClientGetDisplayDimensions(*m_display, 0, &width, &height);
+
+  SetFOV(mDeviceInfo.mRecommendedEyeFOV[VRDeviceInfo::Eye_Left],
+         mDeviceInfo.mRecommendedEyeFOV[VRDeviceInfo::Eye_Right], 0.01,
+         10000.0);
+}
+
+void
+HMDInfoOSVR::Destroy()
+{
+  // destroy non-owning pointers
+  m_ctx = nullptr;
+  m_iface = nullptr;
+  m_display = nullptr;
+}
+
+bool
+HMDInfoOSVR::SetFOV(const gfx::VRFieldOfView& aFOVLeft,
+                    const gfx::VRFieldOfView& aFOVRight, double zNear,
+                    double zFar)
+{
+  OSVR_EyeCount numEyes;
+  osvr_ClientGetNumEyesForViewer(*m_display, 0, &numEyes);
+  for (uint8_t eye = 0; eye < numEyes; eye++) {
+
+    mDeviceInfo.mEyeFOV[eye] = eye == 0 ? aFOVLeft : aFOVRight;
+
+    OSVR_ViewportDimension l, b, w, h;
+    osvr_ClientGetRelativeViewportForViewerEyeSurface(*m_display, 0, eye, 0, &l,
+                                                      &b, &w, &h);
+    mDeviceInfo.mEyeResolution.width = w;
+    mDeviceInfo.mEyeResolution.height = h;
+    OSVR_Pose3 eyePose;
+    // Viewer eye pose may not be immediately available, update client context until we get it
+    OSVR_ReturnCode ret =
+      osvr_ClientGetViewerEyePose(*m_display, 0, eye, &eyePose);
+    while (ret != OSVR_RETURN_SUCCESS) {
+      osvr_ClientUpdate(*m_ctx);
+      ret = osvr_ClientGetViewerEyePose(*m_display, 0, eye, &eyePose);
+    }
+    mDeviceInfo.mEyeTranslation[eye].x = eyePose.translation.data[0];
+    mDeviceInfo.mEyeTranslation[eye].y = eyePose.translation.data[1];
+    mDeviceInfo.mEyeTranslation[eye].z = eyePose.translation.data[2];
+
+    mDeviceInfo.mEyeProjectionMatrix[eye] =
+      mDeviceInfo.mEyeFOV[eye].ConstructProjectionMatrix(zNear, zFar, true);
+  }
+
+  mConfiguration.hmdType = mDeviceInfo.mType;
+  mConfiguration.value = 0;
+  mConfiguration.fov[VRDeviceInfo::Eye_Left] = aFOVLeft;
+  mConfiguration.fov[VRDeviceInfo::Eye_Right] = aFOVRight;
+
+  return true;
+}
+
+void
+HMDInfoOSVR::FillDistortionConstants(
+  uint32_t whichEye, const IntSize& textureSize, const IntRect& eyeViewport,
+  const Size& destViewport, const Rect& destRect, VRDistortionConstants& values)
+{
+}
+
+bool
+HMDInfoOSVR::KeepSensorTracking()
+{
+  // Tracking is enabled if the device supports tracking and in that
+  // case is enabled automatically unless you cannot connect to it
+  return true;
+}
+
+void
+HMDInfoOSVR::NotifyVsync(const mozilla::TimeStamp& aVsyncTimestamp)
+{
+}
+
+void
+HMDInfoOSVR::ZeroSensor()
+{
+  // recenter pose aka reset yaw
+  osvr_ClientSetRoomRotationUsingHead(*m_ctx);
+}
+
+VRHMDSensorState
+HMDInfoOSVR::GetSensorState()
+{
+
+  //update client context before anything
+  //this usually goes into app's mainloop
+  osvr_ClientUpdate(*m_ctx);
+
+  VRHMDSensorState result;
+  OSVR_TimeValue timestamp;
+  result.Clear();
+
+  OSVR_OrientationState orientation;
+
+  OSVR_ReturnCode ret =
+    osvr_GetOrientationState(*m_iface, &timestamp, &orientation);
+
+  result.timestamp = timestamp.seconds;
+
+  if (ret == OSVR_RETURN_SUCCESS) {
+    result.flags |= VRStateValidFlags::State_Orientation;
+    result.orientation[0] = orientation.data[1];
+    result.orientation[1] = orientation.data[2];
+    result.orientation[2] = orientation.data[3];
+    result.orientation[3] = orientation.data[0];
+  }
+
+  OSVR_PositionState position;
+  ret = osvr_GetPositionState(*m_iface, &timestamp, &position);
+  if (ret == OSVR_RETURN_SUCCESS) {
+    result.flags |= VRStateValidFlags::State_Position;
+    result.position[0] = position.data[0];
+    result.position[1] = position.data[1];
+    result.position[2] = position.data[2];
+  }
+
+  return result;
+}
+
+VRHMDSensorState
+HMDInfoOSVR::GetImmediateSensorState()
+{
+  return GetSensorState();
+}
+
+struct RenderTargetSetOSVR : public VRHMDRenderingSupport::RenderTargetSet
+{
+  RenderTargetSetOSVR(Compositor* aCompositor, const IntSize& aSize,
+                      HMDInfoOSVR* aHMD)
+  {
+
+    size = aSize;
+    currentRenderTarget = 0;
+    mCompositorBackend = aCompositor->GetBackendType();
+
+    const uint32_t numTargets = 2;
+    renderTargets.SetLength(numTargets);
+    for (uint32_t i = 0; i < numTargets; ++i) {
+      renderTargets[i] = aCompositor->CreateRenderTarget(
+        IntRect(0, 0, aSize.width, aSize.height), INIT_MODE_NONE);
+    }
+  }
+
+  bool Valid() const
+  {
+    for (uint32_t i = 0; i < renderTargets.Length(); ++i) {
+      if (!renderTargets[i])
+        return false;
+    }
+    return true;
+  }
+
+  already_AddRefed<CompositingRenderTarget> GetNextRenderTarget() override
+  {
+    currentRenderTarget = (currentRenderTarget + 1) % renderTargets.Length();
+    renderTargets[currentRenderTarget]->ClearOnBind();
+    RefPtr<CompositingRenderTarget> rt = renderTargets[currentRenderTarget];
+    return rt.forget();
+  }
+
+  void Destroy() {}
+
+  ~RenderTargetSetOSVR() {}
+
+  LayersBackend mCompositorBackend;
+};
+
+already_AddRefed<VRHMDRenderingSupport::RenderTargetSet>
+HMDInfoOSVR::CreateRenderTargetSet(layers::Compositor* aCompositor,
+                                   const IntSize& aSize)
+{
+#ifdef XP_WIN
+  if (aCompositor->GetBackendType() == layers::LayersBackend::LAYERS_D3D11) {
+    layers::CompositorD3D11* comp11 =
+      static_cast<layers::CompositorD3D11*>(aCompositor);
+
+    RefPtr<RenderTargetSetOSVR> rts =
+      new RenderTargetSetOSVR(comp11, aSize, this);
+    if (!rts->Valid()) {
+      return nullptr;
+    }
+
+    return rts.forget();
+  }
+#endif
+
+  if (aCompositor->GetBackendType() == layers::LayersBackend::LAYERS_OPENGL) {
+  }
+
+  return nullptr;
+}
+
+void
+HMDInfoOSVR::DestroyRenderTargetSet(RenderTargetSet* aRTSet)
+{
+  RenderTargetSetOSVR* rts = static_cast<RenderTargetSetOSVR*>(aRTSet);
+  rts->Destroy();
+}
+
+void
+HMDInfoOSVR::SubmitFrame(RenderTargetSet* aRTSet, int32_t aInputFrameID)
+{
+  // XXX, add renderManager code to submit frame
+}
+
+already_AddRefed<VRHMDManagerOSVR>
+VRHMDManagerOSVR::Create()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!gfxPrefs::VREnabled() || !gfxPrefs::VROSVREnabled()) {
+    return nullptr;
+  }
+  if (!LoadOSVRRuntime()) {
+    return nullptr;
+  }
+  RefPtr<VRHMDManagerOSVR> manager = new VRHMDManagerOSVR();
+  return manager.forget();
+}
+
+void
+VRHMDManagerOSVR::CheckOSVRStatus()
+{
+  if (mOSVRInitialized) {
+    return;
+  }
+
+  // client context must be initialized first
+  InitializeClientContext();
+
+  // update client context
+  osvr_ClientUpdate(m_ctx);
+
+  // initialize interface and display if they are not initialized yet
+  InitializeInterface();
+  InitializeDisplay();
+
+  // OSVR is fully initialized now
+  if (mClientContextInitialized && mDisplayConfigInitialized &&
+      mInterfaceInitialized) {
+    mOSVRInitialized = true;
+  }
+}
+
+void
+VRHMDManagerOSVR::InitializeClientContext()
+{
+  // already initialized
+  if (mClientContextInitialized) {
+    return;
+  }
+
+  // first time creating
+  if (!m_ctx) {
+    // get client context
+    m_ctx = osvr_ClientInit("com.osvr.webvr", 0);
+    // update context
+    osvr_ClientUpdate(m_ctx);
+    // verify we are connected
+    if (OSVR_RETURN_SUCCESS == osvr_ClientCheckStatus(m_ctx)) {
+      mClientContextInitialized = true;
+    }
+  }
+  // client context exists but not up and running yet
+  else {
+    // update context
+    osvr_ClientUpdate(m_ctx);
+    if (OSVR_RETURN_SUCCESS == osvr_ClientCheckStatus(m_ctx)) {
+      mClientContextInitialized = true;
+    }
+  }
+}
+
+void
+VRHMDManagerOSVR::InitializeInterface()
+{
+  // already initialized
+  if (mInterfaceInitialized) {
+    return;
+  }
+  //Client context must be initialized before getting interface
+  if (mClientContextInitialized) {
+    // m_iface will remain nullptr if no interface is returned
+    if (OSVR_RETURN_SUCCESS ==
+        osvr_ClientGetInterface(m_ctx, "/me/head", &m_iface)) {
+      mInterfaceInitialized = true;
+    }
+  }
+}
+
+void
+VRHMDManagerOSVR::InitializeDisplay()
+{
+  // display is fully configured
+  if (mDisplayConfigInitialized) {
+    return;
+  }
+
+  //Client context must be initialized before getting interface
+  if (mClientContextInitialized) {
+    // first time creating display object
+    if (m_display == nullptr) {
+
+      OSVR_ReturnCode ret = osvr_ClientGetDisplay(m_ctx, &m_display);
+
+      if (ret == OSVR_RETURN_SUCCESS) {
+        osvr_ClientUpdate(m_ctx);
+        // display object may have been created but not fully startup
+        if (OSVR_RETURN_SUCCESS == osvr_ClientCheckDisplayStartup(m_display)) {
+          mDisplayConfigInitialized = true;
+        }
+      }
+
+      // Typically once we get Display object, pose data is available after
+      // clientUpdate but sometimes it takes ~ 200 ms to get
+      // a succesfull connection, so we might have to run a few update cycles
+    } else {
+
+      if (OSVR_RETURN_SUCCESS == osvr_ClientCheckDisplayStartup(m_display)) {
+        mDisplayConfigInitialized = true;
+      }
+    }
+  }
+}
+
+bool
+VRHMDManagerOSVR::Init()
+{
+
+  // OSVR server should be running in the background
+  // It would load plugins and take care of detecting HMDs
+  if (!mOSVRInitialized) {
+    nsIThread* thread = nullptr;
+    NS_GetCurrentThread(&thread);
+    mOSVRThread = already_AddRefed<nsIThread>(thread);
+
+    // initialize client context
+    InitializeClientContext();
+    // try to initialize interface
+    InitializeInterface();
+    // try to initialize display object
+    InitializeDisplay();
+    // verify all components are initialized
+    CheckOSVRStatus();
+  }
+
+  return mOSVRInitialized;
+}
+
+void
+VRHMDManagerOSVR::Destroy()
+{
+  if (mOSVRInitialized) {
+    MOZ_ASSERT(NS_GetCurrentThread() == mOSVRThread);
+    mOSVRThread = nullptr;
+    mHMDInfo = nullptr;
+    mOSVRInitialized = false;
+  }
+  // client context may not have been initialized
+  if (m_ctx) {
+    osvr_ClientFreeDisplay(m_display);
+  }
+  // osvr checks that m_ctx or m_iface are not null
+  osvr_ClientFreeInterface(m_ctx, m_iface);
+  osvr_ClientShutdown(m_ctx);
+}
+
+void
+VRHMDManagerOSVR::GetHMDs(nsTArray<RefPtr<VRHMDInfo>>& aHMDResult)
+{
+  // make sure context, interface and display are initialized
+  CheckOSVRStatus();
+
+  if (!mOSVRInitialized) {
+    return;
+  }
+
+  mHMDInfo = new HMDInfoOSVR(&m_ctx, &m_iface, &m_display);
+
+  if (mHMDInfo) {
+    aHMDResult.AppendElement(mHMDInfo);
+  }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/vr/gfxVROSVR.h
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_VR_OSVR_H
+#define GFX_VR_OSVR_H
+
+#include "nsTArray.h"
+#include "mozilla/RefPtr.h"
+#include "nsThreadUtils.h"
+
+#include "mozilla/gfx/2D.h"
+#include "mozilla/EnumeratedArray.h"
+
+#include "gfxVR.h"
+
+#include <osvr/ClientKit/ClientKitC.h>
+#include <osvr/ClientKit/DisplayC.h>
+
+namespace mozilla {
+namespace gfx {
+namespace impl {
+
+class HMDInfoOSVR : public VRHMDInfo, public VRHMDRenderingSupport
+{
+public:
+  explicit HMDInfoOSVR(OSVR_ClientContext* context, OSVR_ClientInterface* iface,
+                       OSVR_DisplayConfig* display);
+
+  bool SetFOV(const VRFieldOfView& aFOVLeft, const VRFieldOfView& aFOVRight,
+              double zNear, double zFar) override;
+
+  VRHMDSensorState GetSensorState() override;
+  VRHMDSensorState GetImmediateSensorState() override;
+  bool KeepSensorTracking() override;
+  void ZeroSensor() override;
+  void NotifyVsync(const TimeStamp& aVsyncTimestamp) override;
+
+  void FillDistortionConstants(uint32_t whichEye, const IntSize& textureSize,
+                               const IntRect& eyeViewport,
+                               const Size& destViewport, const Rect& destRect,
+                               VRDistortionConstants& values) override;
+
+  VRHMDRenderingSupport* GetRenderingSupport() override { return this; }
+
+  void Destroy();
+
+  /* VRHMDRenderingSupport */
+  already_AddRefed<RenderTargetSet> CreateRenderTargetSet(
+    layers::Compositor* aCompositor, const IntSize& aSize) override;
+  void DestroyRenderTargetSet(RenderTargetSet* aRTSet) override;
+  void SubmitFrame(RenderTargetSet* aRTSet, int32_t aInputFrameID) override;
+
+protected:
+  virtual ~HMDInfoOSVR()
+  {
+    Destroy();
+    MOZ_COUNT_DTOR_INHERITED(HMDInfoOSVR, VRHMDInfo);
+  }
+
+  // must match the size of VRDistortionVertex
+  struct DistortionVertex
+  {
+    float pos[2];
+    float texR[2];
+    float texG[2];
+    float texB[2];
+    float genericAttribs[4];
+  };
+
+  OSVR_ClientContext* m_ctx;
+  OSVR_ClientInterface* m_iface;
+  OSVR_DisplayConfig* m_display;
+};
+
+} // namespace impl
+
+class VRHMDManagerOSVR : public VRHMDManager
+{
+public:
+  static already_AddRefed<VRHMDManagerOSVR> Create();
+  virtual bool Init() override;
+  virtual void Destroy() override;
+  virtual void GetHMDs(nsTArray<RefPtr<VRHMDInfo>>& aHMDResult) override;
+
+protected:
+  VRHMDManagerOSVR()
+    : mOSVRInitialized(false)
+    , mClientContextInitialized(false)
+    , mDisplayConfigInitialized(false)
+    , mInterfaceInitialized(false)
+    , m_ctx(nullptr)
+    , m_iface(nullptr)
+    , m_display(nullptr)
+  {
+  }
+
+  RefPtr<impl::HMDInfoOSVR> mHMDInfo;
+  bool mOSVRInitialized;
+  bool mClientContextInitialized;
+  bool mDisplayConfigInitialized;
+  bool mInterfaceInitialized;
+  RefPtr<nsIThread> mOSVRThread;
+
+  OSVR_ClientContext m_ctx;
+  OSVR_ClientInterface m_iface;
+  OSVR_DisplayConfig m_display;
+
+private:
+  // check if all components are initialized
+  // and if not, it will try to initialize them
+  void CheckOSVRStatus();
+  void InitializeClientContext();
+  void InitializeDisplay();
+  void InitializeInterface();
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif /* GFX_VR_OSVR_H */
\ No newline at end of file
--- a/gfx/vr/moz.build
+++ b/gfx/vr/moz.build
@@ -16,16 +16,17 @@ EXPORTS += [
 LOCAL_INCLUDES += [
     '/gfx/thebes',
 ]
 
 UNIFIED_SOURCES += [
     'gfxVR.cpp',
     'gfxVRCardboard.cpp',
     'gfxVROculus.cpp',
+    'gfxVROSVR.cpp',
     'ipc/VRManagerChild.cpp',
     'ipc/VRManagerParent.cpp',
     'VRDeviceProxy.cpp',
     'VRDeviceProxyOrientationFallBack.cpp',
     'VRManager.cpp',
 ]
 
 SOURCES += [
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/ClientKit/ClientKitC.h
@@ -0,0 +1,37 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_ClientKitC_h_GUID_8D7DF104_892D_4CB5_2302_7C6BB5BC985C
+#define INCLUDED_ClientKitC_h_GUID_8D7DF104_892D_4CB5_2302_7C6BB5BC985C
+
+#include <osvr/ClientKit/ContextC.h>
+#include <osvr/ClientKit/InterfaceC.h>
+#include <osvr/ClientKit/InterfaceCallbackC.h>
+#include <osvr/ClientKit/SystemCallbackC.h>
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/ClientKit/ContextC.h
@@ -0,0 +1,96 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @todo Apply annotation macros
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_ContextC_h_GUID_3790F330_2425_4486_4C9F_20C300D7DED3
+#define INCLUDED_ContextC_h_GUID_3790F330_2425_4486_4C9F_20C300D7DED3
+
+/* Internal Includes */
+#include <osvr/ClientKit/Export.h>
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/ReturnCodesC.h>
+#include <osvr/Util/AnnotationMacrosC.h>
+#include <osvr/Util/StdInt.h>
+#include <osvr/Util/ClientOpaqueTypesC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup ClientKit
+    @{
+*/
+
+/** @brief Initialize the library.
+
+    @param applicationIdentifier A null terminated string identifying your
+   application. Reverse DNS format strongly suggested.
+    @param flags initialization options (reserved) - pass 0 for now.
+
+    @returns Client context - will be needed for subsequent calls
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ClientContext osvrClientInit(
+    const char applicationIdentifier[], uint32_t flags OSVR_CPP_ONLY(= 0));
+
+/** @brief Updates the state of the context - call regularly in your mainloop.
+
+    @param ctx Client context
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode osvrClientUpdate(OSVR_ClientContext ctx);
+
+/** @brief Checks to see if the client context is fully started up and connected
+    properly to a server.
+
+    If this reports that the client context is not OK, there may not be a server
+    running, or you may just have to call osvrClientUpdate() a few times to
+    permit startup to finish. The return value of this call will not change from
+    failure to success without calling osvrClientUpdate().
+
+    @param ctx Client context
+
+    @return OSVR_RETURN_FAILURE if not yet fully connected/initialized, or if
+    some other error (null context) occurs.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientCheckStatus(OSVR_ClientContext ctx);
+
+/** @brief Shutdown the library.
+    @param ctx Client context
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientShutdown(OSVR_ClientContext ctx);
+
+/** @} */
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/ClientKit/DisplayC.h
@@ -0,0 +1,506 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2015
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2015 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_DisplayC_h_GUID_8658EDC9_32A2_49A2_5F5C_10F67852AE74
+#define INCLUDED_DisplayC_h_GUID_8658EDC9_32A2_49A2_5F5C_10F67852AE74
+
+/* Internal Includes */
+#include <osvr/ClientKit/Export.h>
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/ReturnCodesC.h>
+#include <osvr/Util/ClientOpaqueTypesC.h>
+#include <osvr/Util/RenderingTypesC.h>
+#include <osvr/Util/MatrixConventionsC.h>
+#include <osvr/Util/Pose3C.h>
+#include <osvr/Util/BoolC.h>
+#include <osvr/Util/RadialDistortionParametersC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+/** @addtogroup ClientKit
+    @{
+    @name Display API
+    @{
+*/
+
+/** @brief Opaque type of a display configuration. */
+typedef struct OSVR_DisplayConfigObject *OSVR_DisplayConfig;
+
+/** @brief Allocates a display configuration object populated with data from the
+    OSVR system.
+
+    Before this call will succeed, your application will need to be correctly
+   and fully connected to an OSVR server. You may consider putting this call in
+   a loop alternating with osvrClientUpdate() until this call succeeds.
+
+    Data provided by a display configuration object:
+
+    - The logical display topology (number and relationship of viewers, eyes,
+        and surfaces), which remains constant throughout the life of the
+        configuration object. (A method of notification of change here is TBD).
+    - Pose data for viewers (not required for rendering) and pose/view data for
+        eyes (used for rendering) which is based on tracker data: if used, these
+        should be queried every frame.
+    - Projection matrix data for surfaces, which while in current practice may
+        be relatively unchanging, we are not guaranteeing them to be constant:
+        these should be queried every frame.
+    - Video-input-relative viewport size/location for a surface: would like this
+        to be variable, but probably not feasible. If you have input, please
+        comment on the dev mailing list.
+    - Per-surface distortion strategy priorities/availabilities: constant. Note
+        the following, though...
+    - Per-surface distortion strategy parameters: variable, request each frame.
+        (Could make constant with a notification if needed?)
+
+    Important note: While most of this data is immediately available if you are
+   successful in getting a display config object, the pose-based data (viewer
+   pose, eye pose, eye view matrix) needs tracker state, so at least one (and in
+   practice, typically more) osvrClientUpdate() must be performed before a new
+   tracker report is available to populate that state. See
+   osvrClientCheckDisplayStartup() to query if all startup data is available.
+
+    @todo Decide if relative viewport should be constant in a display config,
+   and update docs accordingly.
+
+    @todo Decide if distortion params should be constant in a display config,
+   and update docs accordingly.
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed or some other
+    error occurred, in which case the output argument is unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientGetDisplay(OSVR_ClientContext ctx, OSVR_DisplayConfig *disp);
+
+/** @brief Frees a display configuration object. The corresponding context must
+    still be open.
+
+    If you fail to call this, it will be automatically called as part of
+    clean-up when the corresponding context is closed.
+
+    @return OSVR_RETURN_FAILURE if a null config was passed, or if the given
+    display object was already freed.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientFreeDisplay(OSVR_DisplayConfig disp);
+
+/** @brief Checks to see if a display is fully configured and ready, including
+    having received its first pose update.
+
+    Once this first succeeds, it will continue to succeed for the lifetime of
+    the display config object, so it is not necessary to keep calling once you
+    get a successful result.
+
+    @return OSVR_RETURN_FAILURE if a null config was passed, or if the given
+    display config object was otherwise not ready for full use.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientCheckDisplayStartup(OSVR_DisplayConfig disp);
+
+/** @brief A display config can have one or more display inputs to pass pixels
+    over (HDMI/DVI connections, etc): retrieve the number of display inputs in
+   the current configuration.
+
+    @param disp Display config object.
+    @param[out] numDisplayInputs Number of display inputs in the logical display
+    topology, **constant** throughout the active, valid lifetime of a display
+    config object.
+
+    @sa OSVR_DisplayInputCount
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed, in
+   which case the output argument is unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode osvrClientGetNumDisplayInputs(
+    OSVR_DisplayConfig disp, OSVR_DisplayInputCount *numDisplayInputs);
+
+/** @brief Retrieve the pixel dimensions of a given display input for a display
+   config
+
+    @param disp Display config object.
+    @param displayInputIndex The zero-based index of the display input.
+    @param[out] width Width (in pixels) of the display input.
+    @param[out] height Height (in pixels) of the display input.
+
+    The out parameters are **constant** throughout the active, valid lifetime of
+    a display config object.
+
+    @sa OSVR_DisplayDimension
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed, in
+   which case the output arguments are unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode osvrClientGetDisplayDimensions(
+    OSVR_DisplayConfig disp, OSVR_DisplayInputCount displayInputIndex,
+    OSVR_DisplayDimension *width, OSVR_DisplayDimension *height);
+
+/** @brief A display config can have one (or theoretically more) viewers:
+    retrieve the viewer count.
+
+    @param disp Display config object.
+    @param[out] viewers Number of viewers in the logical display topology,
+    **constant** throughout the active, valid lifetime of a display config
+    object.
+
+    @sa OSVR_ViewerCount
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed, in which case
+   the output argument is unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientGetNumViewers(OSVR_DisplayConfig disp, OSVR_ViewerCount *viewers);
+
+/** @brief Get the pose of a viewer in a display config.
+
+    Note that there may not necessarily be any surfaces rendered from this pose
+    (it's the unused "center" eye in a stereo configuration, for instance) so
+    only use this if it makes integration into your engine or existing
+    applications (not originally designed for stereo) easier.
+
+    Will only succeed if osvrClientCheckDisplayStartup() succeeds.
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed or no pose was
+    yet available, in which case the pose argument is unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode osvrClientGetViewerPose(
+    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_Pose3 *pose);
+
+/** @brief Each viewer in a display config can have one or more "eyes" which
+    have a substantially similar pose: get the count.
+
+    @param disp Display config object.
+    @param viewer Viewer ID
+    @param[out] eyes Number of eyes for this viewer in the logical display
+   topology, **constant** throughout the active, valid lifetime of a display
+   config object
+
+    @sa OSVR_EyeCount
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed, in which case
+    the output argument is unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode osvrClientGetNumEyesForViewer(
+    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount *eyes);
+
+/** @brief Get the "viewpoint" for the given eye of a viewer in a display
+   config.
+
+    Will only succeed if osvrClientCheckDisplayStartup() succeeds.
+
+    @param disp Display config object
+    @param viewer Viewer ID
+    @param eye Eye ID
+    @param[out] pose Room-space pose (not relative to pose of the viewer)
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed or no pose was
+    yet available, in which case the pose argument is unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientGetViewerEyePose(OSVR_DisplayConfig disp, OSVR_ViewerCount viewer,
+                           OSVR_EyeCount eye, OSVR_Pose3 *pose);
+
+/** @brief Get the view matrix (inverse of pose) for the given eye of a
+    viewer in a display config - matrix of **doubles**.
+
+    Will only succeed if osvrClientCheckDisplayStartup() succeeds.
+
+    @param disp Display config object
+    @param viewer Viewer ID
+    @param eye Eye ID
+    @param flags Bitwise OR of matrix convention flags (see @ref MatrixFlags)
+    @param[out] mat Pass a double[::OSVR_MATRIX_SIZE] to get the transformation
+    matrix from room space to eye space (not relative to pose of the viewer)
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed or no pose was
+    yet available, in which case the output argument is unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode osvrClientGetViewerEyeViewMatrixd(
+    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+    OSVR_MatrixConventions flags, double *mat);
+
+/** @brief Get the view matrix (inverse of pose) for the given eye of a
+    viewer in a display config - matrix of **floats**.
+
+    Will only succeed if osvrClientCheckDisplayStartup() succeeds.
+
+    @param disp Display config object
+    @param viewer Viewer ID
+    @param eye Eye ID
+    @param flags Bitwise OR of matrix convention flags (see @ref MatrixFlags)
+    @param[out] mat Pass a float[::OSVR_MATRIX_SIZE] to get the transformation
+    matrix from room space to eye space (not relative to pose of the viewer)
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed or no pose was
+    yet available, in which case the output argument is unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode osvrClientGetViewerEyeViewMatrixf(
+    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+    OSVR_MatrixConventions flags, float *mat);
+
+/** @brief Each eye of each viewer in a display config has one or more surfaces
+    (aka "screens") on which content should be rendered.
+
+    @param disp Display config object
+    @param viewer Viewer ID
+    @param eye Eye ID
+    @param[out] surfaces Number of surfaces (numbered [0, surfaces - 1]) for the
+    given viewer and eye. **Constant** throughout the active, valid lifetime of
+    a display config object.
+
+    @sa OSVR_SurfaceCount
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed, in which case
+    the output argument is unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode osvrClientGetNumSurfacesForViewerEye(
+    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+    OSVR_SurfaceCount *surfaces);
+
+/** @brief Get the dimensions/location of the viewport **within the display
+    input** for a surface seen by an eye of a viewer in a display config. (This
+    does not include other video inputs that may be on a single virtual desktop,
+    etc. or explicitly account for display configurations that use multiple
+    video inputs. It does not necessarily indicate that a viewport in the sense
+    of glViewport must be created with these parameters, though the parameter
+    order matches for convenience.)
+
+    @param disp Display config object
+    @param viewer Viewer ID
+    @param eye Eye ID
+    @param surface Surface ID
+    @param[out] left Output: Distance in pixels from the left of the video input
+    to the left of the viewport.
+    @param[out] bottom Output: Distance in pixels from the bottom of the video
+    input to the bottom of the viewport.
+    @param[out] width Output: Width of viewport in pixels.
+    @param[out] height Output: Height of viewport in pixels.
+
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed, in which case
+    the output arguments are unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientGetRelativeViewportForViewerEyeSurface(
+    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+    OSVR_SurfaceCount surface, OSVR_ViewportDimension *left,
+    OSVR_ViewportDimension *bottom, OSVR_ViewportDimension *width,
+    OSVR_ViewportDimension *height);
+
+/** @brief Get the index of the display input for a surface seen by an eye of a
+   viewer in a display config.
+
+    This is the OSVR-assigned display input: it may not (and in practice,
+    usually will not) match any platform-specific display indices. This function
+    exists to associate surfaces with video inputs as enumerated by
+    osvrClientGetNumDisplayInputs().
+
+    @param disp Display config object
+    @param viewer Viewer ID
+    @param eye Eye ID
+    @param surface Surface ID
+    @param[out] displayInput Zero-based index of the display input pixels for
+    this surface are tranmitted over.
+
+    This association is **constant** throughout the active, valid lifetime of a
+    display config object.
+
+    @sa osvrClientGetNumDisplayInputs(),
+    osvrClientGetRelativeViewportForViewerEyeSurface()
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed, in which
+    case the output argument is unmodified.
+ */
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientGetViewerEyeSurfaceDisplayInputIndex(
+    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+    OSVR_SurfaceCount surface, OSVR_DisplayInputCount *displayInput);
+
+/** @brief Get the projection matrix for a surface seen by an eye of a viewer
+    in a display config. (double version)
+
+    @param disp Display config object
+    @param viewer Viewer ID
+    @param eye Eye ID
+    @param surface Surface ID
+    @param near Distance from viewpoint to near clipping plane - must be
+    positive.
+    @param far Distance from viewpoint to far clipping plane - must be positive
+    and not equal to near, typically greater than near.
+    @param flags Bitwise OR of matrix convention flags (see @ref MatrixFlags)
+    @param[out] matrix Output projection matrix: supply an array of 16
+    (::OSVR_MATRIX_SIZE) doubles.
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed, in which case
+    the output argument is unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientGetViewerEyeSurfaceProjectionMatrixd(
+    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+    OSVR_SurfaceCount surface, double near, double far,
+    OSVR_MatrixConventions flags, double *matrix);
+
+/** @brief Get the projection matrix for a surface seen by an eye of a viewer
+    in a display config. (float version)
+
+    @param disp Display config object
+    @param viewer Viewer ID
+    @param eye Eye ID
+    @param surface Surface ID
+    @param near Distance to near clipping plane - must be nonzero, typically
+    positive.
+    @param far Distance to far clipping plane - must be nonzero, typically
+    positive and greater than near.
+    @param flags Bitwise OR of matrix convention flags (see @ref MatrixFlags)
+    @param[out] matrix Output projection matrix: supply an array of 16
+    (::OSVR_MATRIX_SIZE) floats.
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed, in which case
+    the output argument is unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientGetViewerEyeSurfaceProjectionMatrixf(
+    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+    OSVR_SurfaceCount surface, float near, float far,
+    OSVR_MatrixConventions flags, float *matrix);
+
+/** @brief Get the clipping planes (positions at unit distance) for a surface
+   seen by an eye of a viewer
+    in a display config.
+
+    This is only for use in integrations that cannot accept a fully-formulated
+    projection matrix as returned by
+    osvrClientGetViewerEyeSurfaceProjectionMatrixf() or
+    osvrClientGetViewerEyeSurfaceProjectionMatrixd(), and may not necessarily
+    provide the same optimizations.
+
+    As all the planes are given at unit (1) distance, before passing these
+   planes to a consuming function in your application/engine, you will typically
+   divide them by your near clipping plane distance.
+
+    @param disp Display config object
+    @param viewer Viewer ID
+    @param eye Eye ID
+    @param surface Surface ID
+    @param[out] left Distance to left clipping plane
+    @param[out] right Distance to right clipping plane
+    @param[out] bottom Distance to bottom clipping plane
+    @param[out] top Distance to top clipping plane
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed, in which case
+    the output arguments are unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientGetViewerEyeSurfaceProjectionClippingPlanes(
+    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+    OSVR_SurfaceCount surface, double *left, double *right, double *bottom,
+    double *top);
+
+/** @brief Determines if a surface seen by an eye of a viewer in a display
+    config requests some distortion to be performed.
+
+    This simply reports true or false, and does not specify which kind of
+    distortion implementations have been parameterized for this display. For
+    each distortion implementation your application supports, you'll want to
+    call the corresponding priority function to find out if it is available.
+
+    @param disp Display config object
+    @param viewer Viewer ID
+    @param eye Eye ID
+    @param surface Surface ID
+    @param[out] distortionRequested Output parameter: whether distortion is
+    requested. **Constant** throughout the active, valid lifetime of a display
+    config object.
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed, in which case
+    the output argument is unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientDoesViewerEyeSurfaceWantDistortion(OSVR_DisplayConfig disp,
+                                             OSVR_ViewerCount viewer,
+                                             OSVR_EyeCount eye,
+                                             OSVR_SurfaceCount surface,
+                                             OSVR_CBool *distortionRequested);
+
+/** @brief Returns the priority/availability of radial distortion parameters for
+    a surface seen by an eye of a viewer in a display config.
+
+    If osvrClientDoesViewerEyeSurfaceWantDistortion() reports false, then the
+    display does not request distortion of any sort, and thus neither this nor
+    any other distortion strategy priority function will report an "available"
+    priority.
+
+    @param disp Display config object
+    @param viewer Viewer ID
+    @param eye Eye ID
+    @param surface Surface ID
+    @param[out] priority Output: the priority level. Negative values
+    (canonically OSVR_DISTORTION_PRIORITY_UNAVAILABLE) indicate this technique
+    not available, higher values indicate higher preference for the given
+    technique based on the device's description. **Constant** throughout the
+    active, valid lifetime of a display config object.
+
+    @return OSVR_RETURN_FAILURE if invalid parameters were passed, in which case
+    the output argument is unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientGetViewerEyeSurfaceRadialDistortionPriority(
+    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+    OSVR_SurfaceCount surface, OSVR_DistortionPriority *priority);
+
+/** @brief Returns the radial distortion parameters, if known/requested, for a
+    surface seen by an eye of a viewer in a display config.
+
+    Will only succeed if osvrClientGetViewerEyeSurfaceRadialDistortionPriority()
+    reports a non-negative priority.
+
+    @param disp Display config object
+    @param viewer Viewer ID
+    @param eye Eye ID
+    @param surface Surface ID
+    @param[out] params Output: the parameters for radial distortion
+
+    @return OSVR_RETURN_FAILURE if this surface does not have these parameters
+    described, or if invalid parameters were passed, in which case the output
+    argument is unmodified.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientGetViewerEyeSurfaceRadialDistortion(
+    OSVR_DisplayConfig disp, OSVR_ViewerCount viewer, OSVR_EyeCount eye,
+    OSVR_SurfaceCount surface, OSVR_RadialDistortionParameters *params);
+
+/** @}
+    @}
+*/
+
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/ClientKit/Export.h
@@ -0,0 +1,138 @@
+/** @file
+    @brief Automatically-generated export header - do not edit!
+
+    @date 2016
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+// Copyright 2016 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef OSVR_CLIENTKIT_EXPORT_H
+#define OSVR_CLIENTKIT_EXPORT_H
+
+#ifdef OSVR_CLIENTKIT_STATIC_DEFINE
+#  define OSVR_CLIENTKIT_EXPORT
+#  define OSVR_CLIENTKIT_NO_EXPORT
+#endif
+
+/* Per-compiler advance preventative definition */
+#if defined(__BORLANDC__) || defined(__CODEGEARC__) || defined(__HP_aCC) ||    \
+    defined(__PGI) || defined(__WATCOMC__)
+/* Compilers that don't support deprecated, according to CMake. */
+#  ifndef OSVR_CLIENTKIT_DEPRECATED
+#    define OSVR_CLIENTKIT_DEPRECATED
+#  endif
+#endif
+
+/* Check for attribute support */
+#if defined(__INTEL_COMPILER)
+/* Checking before GNUC because Intel implements GNU extensions,
+ * so it chooses to define __GNUC__ as well. */
+#  if __INTEL_COMPILER >= 1200
+/* Intel compiler 12.0 or newer can handle these attributes per CMake */
+#    define OSVR_CLIENTKIT_EXPORT_HEADER_SUPPORTS_ATTRIBUTES
+#  endif
+
+#elif defined(__GNUC__)
+#  if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
+/* GCC 4.2+ */
+#    define OSVR_CLIENTKIT_EXPORT_HEADER_SUPPORTS_ATTRIBUTES
+#  endif
+#endif
+
+/* Per-platform defines */
+#if defined(_MSC_VER)
+/* MSVC on Windows */
+
+#ifndef OSVR_CLIENTKIT_EXPORT
+#  ifdef osvrClientKit_EXPORTS
+      /* We are building this library */
+#    define OSVR_CLIENTKIT_EXPORT __declspec(dllexport)
+#  else
+      /* We are using this library */
+#    define OSVR_CLIENTKIT_EXPORT __declspec(dllimport)
+#  endif
+#endif
+
+#ifndef OSVR_CLIENTKIT_DEPRECATED
+#  define OSVR_CLIENTKIT_DEPRECATED __declspec(deprecated)
+#endif
+
+#elif defined(_WIN32) && defined(__GNUC__)
+/* GCC-compatible on Windows */
+
+#ifndef OSVR_CLIENTKIT_EXPORT
+#  ifdef osvrClientKit_EXPORTS
+      /* We are building this library */
+#    define OSVR_CLIENTKIT_EXPORT __attribute__((dllexport))
+#  else
+      /* We are using this library */
+#    define OSVR_CLIENTKIT_EXPORT __attribute__((dllimport))
+#  endif
+#endif
+
+#ifndef OSVR_CLIENTKIT_DEPRECATED
+#  define OSVR_CLIENTKIT_DEPRECATED __attribute__((__deprecated__))
+#endif
+
+#elif defined(OSVR_CLIENTKIT_EXPORT_HEADER_SUPPORTS_ATTRIBUTES) ||         \
+    (defined(__APPLE__) && defined(__MACH__))
+/* GCC4.2+ compatible (assuming something *nix-like) and Mac OS X */
+/* (The first macro is defined at the top of the file, if applicable) */
+/* see https://gcc.gnu.org/wiki/Visibility */
+
+#ifndef OSVR_CLIENTKIT_EXPORT
+  /* We are building/using this library */
+#  define OSVR_CLIENTKIT_EXPORT __attribute__((visibility("default")))
+#endif
+
+#ifndef OSVR_CLIENTKIT_NO_EXPORT
+#  define OSVR_CLIENTKIT_NO_EXPORT __attribute__((visibility("hidden")))
+#endif
+
+#ifndef OSVR_CLIENTKIT_DEPRECATED
+#  define OSVR_CLIENTKIT_DEPRECATED __attribute__((__deprecated__))
+#endif
+
+#endif
+/* End of platform ifdefs */
+
+/* fallback def */
+#ifndef OSVR_CLIENTKIT_EXPORT
+#  define OSVR_CLIENTKIT_EXPORT
+#endif
+
+/* fallback def */
+#ifndef OSVR_CLIENTKIT_NO_EXPORT
+#  define OSVR_CLIENTKIT_NO_EXPORT
+#endif
+
+/* fallback def */
+#ifndef OSVR_CLIENTKIT_DEPRECATED_EXPORT
+#  define OSVR_CLIENTKIT_DEPRECATED_EXPORT OSVR_CLIENTKIT_EXPORT OSVR_CLIENTKIT_DEPRECATED
+#endif
+
+/* fallback def */
+#ifndef OSVR_CLIENTKIT_DEPRECATED_NO_EXPORT
+#  define OSVR_CLIENTKIT_DEPRECATED_NO_EXPORT OSVR_CLIENTKIT_NO_EXPORT OSVR_CLIENTKIT_DEPRECATED
+#endif
+
+/* Clean up after ourselves */
+#undef OSVR_CLIENTKIT_EXPORT_HEADER_SUPPORTS_ATTRIBUTES
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/ClientKit/InterfaceC.h
@@ -0,0 +1,75 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_InterfaceC_h_GUID_D90BBAA6_AD62_499D_C023_2F6ED8987C17
+#define INCLUDED_InterfaceC_h_GUID_D90BBAA6_AD62_499D_C023_2F6ED8987C17
+
+/* Internal Includes */
+#include <osvr/ClientKit/Export.h>
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/ReturnCodesC.h>
+#include <osvr/Util/AnnotationMacrosC.h>
+#include <osvr/Util/ClientOpaqueTypesC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+/** @addtogroup ClientKit
+@{
+*/
+
+/** @brief Get the interface associated with the given path.
+    @param ctx Client context
+    @param path A resource path (null-terminated string)
+    @param[out] iface The interface object. May be freed when no longer needed,
+   otherwise it will be freed when the context is closed.
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientGetInterface(OSVR_ClientContext ctx, const char path[],
+                       OSVR_ClientInterface *iface);
+
+/** @brief Free an interface object before context closure.
+
+    @param ctx Client context
+    @param iface The interface object
+
+    @returns OSVR_RETURN_SUCCESS unless a null context or interface was passed
+   or the given interface was not found in the context (i.e. had already been
+   freed)
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientFreeInterface(OSVR_ClientContext ctx, OSVR_ClientInterface iface);
+
+/** @} */
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/ClientKit/InterfaceCallbackC.h
@@ -0,0 +1,77 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_InterfaceCallbacksC_h_GUID_8F16E6CB_F998_4ABC_5B6B_4FC1E4B71BC9
+#define INCLUDED_InterfaceCallbacksC_h_GUID_8F16E6CB_F998_4ABC_5B6B_4FC1E4B71BC9
+
+/* Internal Includes */
+#include <osvr/ClientKit/Export.h>
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/ReturnCodesC.h>
+#include <osvr/Util/AnnotationMacrosC.h>
+#include <osvr/Util/ClientOpaqueTypesC.h>
+#include <osvr/Util/ClientCallbackTypesC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+#define OSVR_INTERFACE_CALLBACK_METHOD(TYPE)                                   \
+    /** @brief Register a callback for TYPE reports on an interface */         \
+    OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode osvrRegister##TYPE##Callback(        \
+        OSVR_ClientInterface iface, OSVR_##TYPE##Callback cb, void *userdata);
+
+OSVR_INTERFACE_CALLBACK_METHOD(Pose)
+OSVR_INTERFACE_CALLBACK_METHOD(Position)
+OSVR_INTERFACE_CALLBACK_METHOD(Orientation)
+OSVR_INTERFACE_CALLBACK_METHOD(Velocity)
+OSVR_INTERFACE_CALLBACK_METHOD(LinearVelocity)
+OSVR_INTERFACE_CALLBACK_METHOD(AngularVelocity)
+OSVR_INTERFACE_CALLBACK_METHOD(Acceleration)
+OSVR_INTERFACE_CALLBACK_METHOD(LinearAcceleration)
+OSVR_INTERFACE_CALLBACK_METHOD(AngularAcceleration)
+OSVR_INTERFACE_CALLBACK_METHOD(Button)
+OSVR_INTERFACE_CALLBACK_METHOD(Analog)
+OSVR_INTERFACE_CALLBACK_METHOD(Imaging)
+OSVR_INTERFACE_CALLBACK_METHOD(Location2D)
+OSVR_INTERFACE_CALLBACK_METHOD(Direction)
+OSVR_INTERFACE_CALLBACK_METHOD(EyeTracker2D)
+OSVR_INTERFACE_CALLBACK_METHOD(EyeTracker3D)
+OSVR_INTERFACE_CALLBACK_METHOD(EyeTrackerBlink)
+OSVR_INTERFACE_CALLBACK_METHOD(NaviVelocity)
+OSVR_INTERFACE_CALLBACK_METHOD(NaviPosition)
+
+#undef OSVR_INTERFACE_CALLBACK_METHOD
+
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/ClientKit/InterfaceStateC.h
@@ -0,0 +1,79 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_InterfaceStateC_h_GUID_8F85D178_74B9_4AA9_4E9E_243089411408
+#define INCLUDED_InterfaceStateC_h_GUID_8F85D178_74B9_4AA9_4E9E_243089411408
+
+/* Internal Includes */
+#include <osvr/ClientKit/Export.h>
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/ReturnCodesC.h>
+#include <osvr/Util/AnnotationMacrosC.h>
+#include <osvr/Util/ClientOpaqueTypesC.h>
+#include <osvr/Util/ClientReportTypesC.h>
+#include <osvr/Util/TimeValueC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+#define OSVR_CALLBACK_METHODS(TYPE)                                            \
+    /** @brief Get TYPE state from an interface, returning failure if none     \
+     * exists */                                                               \
+    OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode osvrGet##TYPE##State(                \
+        OSVR_ClientInterface iface, struct OSVR_TimeValue *timestamp,          \
+        OSVR_##TYPE##State *state);
+
+OSVR_CALLBACK_METHODS(Pose)
+OSVR_CALLBACK_METHODS(Position)
+OSVR_CALLBACK_METHODS(Orientation)
+OSVR_CALLBACK_METHODS(Velocity)
+OSVR_CALLBACK_METHODS(LinearVelocity)
+OSVR_CALLBACK_METHODS(AngularVelocity)
+OSVR_CALLBACK_METHODS(Acceleration)
+OSVR_CALLBACK_METHODS(LinearAcceleration)
+OSVR_CALLBACK_METHODS(AngularAcceleration)
+OSVR_CALLBACK_METHODS(Button)
+OSVR_CALLBACK_METHODS(Analog)
+OSVR_CALLBACK_METHODS(Location2D)
+OSVR_CALLBACK_METHODS(Direction)
+OSVR_CALLBACK_METHODS(EyeTracker2D)
+OSVR_CALLBACK_METHODS(EyeTracker3D)
+OSVR_CALLBACK_METHODS(EyeTrackerBlink)
+OSVR_CALLBACK_METHODS(NaviVelocity)
+OSVR_CALLBACK_METHODS(NaviPosition)
+
+#undef OSVR_CALLBACK_METHODS
+
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/ClientKit/SystemCallbackC.h
@@ -0,0 +1,47 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_SystemCallbackC_h_GUID_543F3F04_343E_4389_08A0_DEA988EC23F7
+#define INCLUDED_SystemCallbackC_h_GUID_543F3F04_343E_4389_08A0_DEA988EC23F7
+
+/* Internal Includes */
+#include <osvr/ClientKit/Export.h>
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/ReturnCodesC.h>
+#include <osvr/Util/AnnotationMacrosC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/ClientKit/TransformsC.h
@@ -0,0 +1,75 @@
+/** @file
+    @brief Header controlling the OSVR transformation hierarchy
+
+    Must be c-safe!
+
+    @date 2015
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2015 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_TransformsC_h_GUID_5B5B7438_42D4_4095_E48A_90E2CC13498E
+#define INCLUDED_TransformsC_h_GUID_5B5B7438_42D4_4095_E48A_90E2CC13498E
+
+/* Internal Includes */
+#include <osvr/ClientKit/Export.h>
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/ReturnCodesC.h>
+#include <osvr/Util/ClientOpaqueTypesC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup ClientKit
+    @{
+*/
+
+/** @brief Updates the internal "room to world" transformation (applied to all
+    tracker data for this client context instance) based on the user's head
+    orientation, so that the direction the user is facing becomes -Z to your
+    application. Only rotates about the Y axis (yaw).
+
+    Note that this method internally calls osvrClientUpdate() to get a head pose
+    so your callbacks may be called during its execution!
+
+    @param ctx Client context
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientSetRoomRotationUsingHead(OSVR_ClientContext ctx);
+
+/** @brief Clears/resets the internal "room to world" transformation back to an
+   identity transformation - that is, clears the effect of any other
+   manipulation of the room to world transform.
+
+    @param ctx Client context
+*/
+OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode
+osvrClientClearRoomToWorldTransform(OSVR_ClientContext ctx);
+
+/** @} */
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/APIBaseC.h
@@ -0,0 +1,50 @@
+/** @file
+    @brief Header providing basic C macros for defining API headers.
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_APIBaseC_h_GUID_C5A2E769_2ADC_429E_D250_DF0883E6E5DB
+#define INCLUDED_APIBaseC_h_GUID_C5A2E769_2ADC_429E_D250_DF0883E6E5DB
+
+#ifdef __cplusplus
+#define OSVR_C_ONLY(X)
+#define OSVR_CPP_ONLY(X) X
+#define OSVR_EXTERN_C_BEGIN extern "C" {
+#define OSVR_EXTERN_C_END }
+#define OSVR_INLINE inline
+#else
+#define OSVR_C_ONLY(X) X
+#define OSVR_CPP_ONLY(X)
+#define OSVR_EXTERN_C_BEGIN
+#define OSVR_EXTERN_C_END
+#ifdef _MSC_VER
+#define OSVR_INLINE static __inline
+#else
+#define OSVR_INLINE static inline
+#endif
+#endif
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/AnnotationMacrosC.h
@@ -0,0 +1,232 @@
+/** @file
+    @brief Header containing macros for source-level annotation.
+
+    In theory, supporting MSVC SAL, as well as compatible GCC and
+    Clang attributes. In practice, expanded as time allows and requires.
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_AnnotationMacrosC_h_GUID_48538D9B_35E3_4E9A_D2B0_D83D51DD5900
+#define INCLUDED_AnnotationMacrosC_h_GUID_48538D9B_35E3_4E9A_D2B0_D83D51DD5900
+
+#ifndef OSVR_DISABLE_ANALYSIS
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1700)
+/* Visual C++ (2012 and newer) */
+/* Using SAL attribute format:
+ * http://msdn.microsoft.com/en-us/library/ms182032(v=vs.120).aspx */
+
+#include <sal.h>
+
+#define OSVR_IN _In_
+#define OSVR_IN_PTR _In_
+#define OSVR_IN_OPT _In_opt_
+#define OSVR_IN_STRZ _In_z_
+#define OSVR_IN_READS(NUM_ELEMENTS) _In_reads_(NUM_ELEMENTS)
+
+#define OSVR_OUT _Out_
+#define OSVR_OUT_PTR _Outptr_
+#define OSVR_OUT_OPT _Out_opt_
+
+#define OSVR_INOUT _Inout_
+#define OSVR_INOUT_PTR _Inout_
+
+#define OSVR_RETURN_WARN_UNUSED _Must_inspect_result_
+#define OSVR_RETURN_SUCCESS_CONDITION(X) _Return_type_success_(X)
+
+/* end of msvc section */
+#elif defined(__GNUC__) && (__GNUC__ >= 4)
+/* section for GCC and GCC-alikes */
+
+#if defined(__clang__)
+/* clang-specific section */
+#endif
+
+#define OSVR_FUNC_NONNULL(X) __attribute__((__nonnull__ X))
+#define OSVR_RETURN_WARN_UNUSED __attribute__((warn_unused_result))
+
+/* end of gcc section and compiler detection */
+#endif
+
+/* end of ndef disable analysis */
+#endif
+
+/* Fallback declarations */
+/**
+@defgroup annotation_macros Static analysis annotation macros
+@brief Wrappers for Microsoft's SAL annotations and others
+@ingroup Util
+
+Use of these is optional, but recommended particularly for C APIs,
+as well as any methods handling a buffer with a length.
+@{
+*/
+/** @name Parameter annotations
+
+    These indicate the role and valid values for parameters to functions.
+
+    At most one of these should be placed before a parameter's type name in the
+   function parameter list, in both the declaration and definition. (They must
+   match!)
+   @{
+*/
+/** @def OSVR_IN
+    @brief Indicates a required function parameter that serves only as input.
+*/
+#ifndef OSVR_IN
+#define OSVR_IN
+#endif
+
+/** @def OSVR_IN_PTR
+    @brief Indicates a required pointer (non-null) function parameter that
+    serves only as input.
+*/
+#ifndef OSVR_IN_PTR
+#define OSVR_IN_PTR
+#endif
+
+/** @def OSVR_IN_OPT
+    @brief Indicates a function parameter (pointer) that serves only as input,
+   but is optional and might be NULL.
+*/
+#ifndef OSVR_IN_OPT
+#define OSVR_IN_OPT
+#endif
+
+/** @def OSVR_IN_STRZ
+    @brief Indicates a null-terminated string function parameter that serves
+   only as input.
+*/
+#ifndef OSVR_IN_STRZ
+#define OSVR_IN_STRZ
+#endif
+
+/** @def OSVR_IN_READS(NUM_ELEMENTS)
+    @brief Indicates a buffer containing input with the specified number of
+   elements.
+
+    The specified number of elements is typically the name of another parameter.
+*/
+#ifndef OSVR_IN_READS
+#define OSVR_IN_READS(NUM_ELEMENTS)
+#endif
+
+/** @def OSVR_OUT
+    @brief Indicates a required function parameter that serves only as output.
+    In C code, since this usually means "pointer", you probably want
+   OSVR_OUT_PTR instead.
+*/
+#ifndef OSVR_OUT
+#define OSVR_OUT
+#endif
+
+/** @def OSVR_OUT_PTR
+    @brief Indicates a required pointer (non-null) function parameter that
+    serves only as output.
+*/
+#ifndef OSVR_OUT_PTR
+#define OSVR_OUT_PTR
+#endif
+
+/** @def OSVR_OUT_OPT
+    @brief Indicates a function parameter (pointer) that serves only as output,
+   but is optional and might be NULL
+*/
+#ifndef OSVR_OUT_OPT
+#define OSVR_OUT_OPT
+#endif
+
+/** @def OSVR_INOUT
+    @brief Indicates a required function parameter that is both read and written
+   to.
+
+    In C code, since this usually means "pointer", you probably want
+   OSVR_INOUT_PTR instead.
+*/
+#ifndef OSVR_INOUT
+#define OSVR_INOUT
+#endif
+
+/** @def OSVR_INOUT_PTR
+    @brief Indicates a required pointer (non-null) function parameter that is
+    both read and written to.
+*/
+#ifndef OSVR_INOUT_PTR
+#define OSVR_INOUT_PTR
+#endif
+
+/* End of parameter annotations. */
+/** @} */
+
+/** @name Function annotations
+
+    These indicate particular relevant aspects about a function. Some
+    duplicate the effective meaning of parameter annotations: applying both
+    allows the fullest extent of static analysis tools to analyze the code,
+    and in some compilers, generate warnings.
+
+   @{
+*/
+/** @def OSVR_FUNC_NONNULL(X)
+    @brief Indicates the parameter(s) that must be non-null.
+
+    @param X A parenthesized list of parameters by number (1-based index)
+
+    Should be placed after a function declaration (but before the
+   semicolon). Repeating in the definition is not needed.
+*/
+#ifndef OSVR_FUNC_NONNULL
+#define OSVR_FUNC_NONNULL(X)
+#endif
+
+/** @def OSVR_RETURN_WARN_UNUSED
+    @brief Indicates the function has a return value that must be used (either a
+   security problem or an obvious bug if not).
+
+    Should be placed before the return value (and virtual keyword, if
+   applicable) in both declaration and definition.
+*/
+#ifndef OSVR_RETURN_WARN_UNUSED
+#define OSVR_RETURN_WARN_UNUSED
+#endif
+/* End of function annotations. */
+/** @} */
+
+/** @def OSVR_RETURN_SUCCESS_CONDITION
+    @brief Applied to a typedef, indicates the condition for `return` under
+   which a function returning it should be considered to have succeeded (thus
+   holding certain specifications).
+
+    Should be placed before the typename in a typedef, with the parameter
+   including the keyword `return` to substitute for the return value.
+*/
+#ifndef OSVR_RETURN_SUCCESS_CONDITION
+#define OSVR_RETURN_SUCCESS_CONDITION(X)
+#endif
+
+/* End of annotation group. */
+/** @} */
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/BoolC.h
@@ -0,0 +1,59 @@
+/** @file
+    @brief Header providing a C-safe "bool" type, because we can't depend on
+   Visual Studio providing proper C99 support in external-facing APIs.
+
+    Must be c-safe!
+
+    @date 2015
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2015 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_BoolC_h_GUID_4F97BE90_2758_4BA5_B0FC_0CA92DEBA210
+#define INCLUDED_BoolC_h_GUID_4F97BE90_2758_4BA5_B0FC_0CA92DEBA210
+
+/* Internal Includes */
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/StdInt.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+/** @addtogroup Util
+@{
+*/
+
+/** @brief A pre-C99-safe bool type. Canonical values for true and false are
+ * provided. Interpretation of other values is not defined. */
+typedef uint8_t OSVR_CBool;
+/** @brief Canonical "true" value for OSVR_CBool */
+#define OSVR_TRUE (1)
+/** @brief Canonical "false" value for OSVR_CBool */
+#define OSVR_FALSE (0)
+
+/** @} */
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/ChannelCountC.h
@@ -0,0 +1,57 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2015
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2015 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_ChannelCountC_h_GUID_CF7E5EE7_28B0_4B99_E823_DD701904B5D1
+#define INCLUDED_ChannelCountC_h_GUID_CF7E5EE7_28B0_4B99_E823_DD701904B5D1
+
+/* Internal Includes */
+#include <osvr/Util/StdInt.h>
+#include <osvr/Util/APIBaseC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup PluginKit
+@{
+*/
+
+/** @brief The integer type specifying a number of channels/sensors or a
+channel/sensor index.
+*/
+typedef uint32_t OSVR_ChannelCount;
+
+/** @} */
+
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/ClientCallbackTypesC.h
@@ -0,0 +1,140 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    GENERATED - do not edit by hand!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_ClientCallbackTypesC_h_GUID_4D43A675_C8A4_4BBF_516F_59E6C785E4EF
+#define INCLUDED_ClientCallbackTypesC_h_GUID_4D43A675_C8A4_4BBF_516F_59E6C785E4EF
+
+/* Internal Includes */
+#include <osvr/Util/ClientReportTypesC.h>
+#include <osvr/Util/ImagingReportTypesC.h>
+#include <osvr/Util/ReturnCodesC.h>
+#include <osvr/Util/TimeValueC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup ClientKit
+    @{
+*/
+
+/** @name Report callback types
+    @{
+*/
+
+/* generated file - do not edit! */
+/** @brief C function type for a Pose callback */
+typedef void (*OSVR_PoseCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_PoseReport *report);
+/** @brief C function type for a Position callback */
+typedef void (*OSVR_PositionCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_PositionReport *report);
+/** @brief C function type for a Orientation callback */
+typedef void (*OSVR_OrientationCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_OrientationReport *report);
+/** @brief C function type for a Velocity callback */
+typedef void (*OSVR_VelocityCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_VelocityReport *report);
+/** @brief C function type for a LinearVelocity callback */
+typedef void (*OSVR_LinearVelocityCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_LinearVelocityReport *report);
+/** @brief C function type for a AngularVelocity callback */
+typedef void (*OSVR_AngularVelocityCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_AngularVelocityReport *report);
+/** @brief C function type for a Acceleration callback */
+typedef void (*OSVR_AccelerationCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_AccelerationReport *report);
+/** @brief C function type for a LinearAcceleration callback */
+typedef void (*OSVR_LinearAccelerationCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_LinearAccelerationReport *report);
+/** @brief C function type for a AngularAcceleration callback */
+typedef void (*OSVR_AngularAccelerationCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_AngularAccelerationReport *report);
+/** @brief C function type for a Button callback */
+typedef void (*OSVR_ButtonCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_ButtonReport *report);
+/** @brief C function type for a Analog callback */
+typedef void (*OSVR_AnalogCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_AnalogReport *report);
+/** @brief C function type for a Imaging callback */
+typedef void (*OSVR_ImagingCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_ImagingReport *report);
+/** @brief C function type for a Location2D callback */
+typedef void (*OSVR_Location2DCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_Location2DReport *report);
+/** @brief C function type for a Direction callback */
+typedef void (*OSVR_DirectionCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_DirectionReport *report);
+/** @brief C function type for a EyeTracker2D callback */
+typedef void (*OSVR_EyeTracker2DCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_EyeTracker2DReport *report);
+/** @brief C function type for a EyeTracker3D callback */
+typedef void (*OSVR_EyeTracker3DCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_EyeTracker3DReport *report);
+/** @brief C function type for a EyeTrackerBlink callback */
+typedef void (*OSVR_EyeTrackerBlinkCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_EyeTrackerBlinkReport *report);
+/** @brief C function type for a NaviVelocity callback */
+typedef void (*OSVR_NaviVelocityCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_NaviVelocityReport *report);
+/** @brief C function type for a NaviPosition callback */
+typedef void (*OSVR_NaviPositionCallback)(void *userdata,
+                                     const struct OSVR_TimeValue *timestamp,
+                                     const struct OSVR_NaviPositionReport *report);
+
+/** @} */
+
+/** @} */
+
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/ClientOpaqueTypesC.h
@@ -0,0 +1,69 @@
+/** @file
+    @brief Header declaring opaque types used by @ref Client and @ref ClientKit
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_ClientOpaqueTypesC_h_GUID_24B79ED2_5751_4BA2_1690_BBD250EBC0C1
+#define INCLUDED_ClientOpaqueTypesC_h_GUID_24B79ED2_5751_4BA2_1690_BBD250EBC0C1
+
+/* Internal Includes */
+#include <osvr/Util/APIBaseC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup ClientKit
+    @{
+*/
+/** @brief Opaque handle that should be retained by your application. You need
+    only and exactly one.
+
+    Created by osvrClientInit() at application start.
+
+    You are required to clean up this handle with osvrClientShutdown().
+*/
+typedef struct OSVR_ClientContextObject *OSVR_ClientContext;
+
+/** @brief Opaque handle to an interface used for registering callbacks and
+   getting status.
+
+    You are not required to clean up this handle (it will be automatically
+   cleaned up when the context is), but you can if you are no longer using it,
+   using osvrClientFreeInterface() to inform the context that you no longer need
+   this interface.
+*/
+typedef struct OSVR_ClientInterfaceObject *OSVR_ClientInterface;
+
+/** @} */
+
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/ClientReportTypesC.h
@@ -0,0 +1,348 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_ClientReportTypesC_h_GUID_E79DAB07_78B7_4795_1EB9_CA6EEB274AEE
+#define INCLUDED_ClientReportTypesC_h_GUID_E79DAB07_78B7_4795_1EB9_CA6EEB274AEE
+
+/* Internal Includes */
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/Pose3C.h>
+#include <osvr/Util/StdInt.h>
+
+#include <osvr/Util/Vec2C.h>
+#include <osvr/Util/Vec3C.h>
+#include <osvr/Util/ChannelCountC.h>
+#include <osvr/Util/BoolC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup ClientKit
+    @{
+*/
+
+/** @name State types
+@{
+*/
+/** @brief Type of position state */
+typedef OSVR_Vec3 OSVR_PositionState;
+
+/** @brief Type of orientation state */
+typedef OSVR_Quaternion OSVR_OrientationState;
+
+/** @brief Type of pose state */
+typedef OSVR_Pose3 OSVR_PoseState;
+
+/** @brief Type of linear velocity state */
+typedef OSVR_Vec3 OSVR_LinearVelocityState;
+
+/** @brief The quaternion represents the incremental rotation taking place over
+    a period of dt seconds. Use of dt (which does not necessarily
+    have to be 1, as other velocity/acceleration representations imply) and an
+    incremental quaternion allows device reports to be scaled to avoid aliasing
+*/
+typedef struct OSVR_IncrementalQuaternion {
+    OSVR_Quaternion incrementalRotation;
+    double dt;
+} OSVR_IncrementalQuaternion;
+
+/** @brief Type of angular velocity state: an incremental quaternion, providing
+    the incremental rotation taking place due to velocity over a period of dt
+    seconds.
+*/
+typedef OSVR_IncrementalQuaternion OSVR_AngularVelocityState;
+
+/** @brief Struct for combined velocity state */
+typedef struct OSVR_VelocityState {
+    OSVR_LinearVelocityState linearVelocity;
+    /** @brief Whether the data source reports valid data for
+        #OSVR_VelocityState::linearVelocity */
+    OSVR_CBool linearVelocityValid;
+
+    OSVR_AngularVelocityState angularVelocity;
+    /** @brief Whether the data source reports valid data for
+    #OSVR_VelocityState::angularVelocity */
+    OSVR_CBool angularVelocityValid;
+} OSVR_VelocityState;
+
+/** @brief Type of linear acceleration state */
+typedef OSVR_Vec3 OSVR_LinearAccelerationState;
+
+/** @brief Type of angular acceleration state
+*/
+typedef OSVR_IncrementalQuaternion OSVR_AngularAccelerationState;
+
+/** @brief Struct for combined acceleration state */
+typedef struct OSVR_AccelerationState {
+    OSVR_LinearAccelerationState linearAcceleration;
+    /** @brief Whether the data source reports valid data for
+    #OSVR_AccelerationState::linearAcceleration */
+    OSVR_CBool linearAccelerationValid;
+
+    OSVR_AngularAccelerationState angularAcceleration;
+    /** @brief Whether the data source reports valid data for
+    #OSVR_AccelerationState::angularAcceleration */
+    OSVR_CBool angularAccelerationValid;
+} OSVR_AccelerationState;
+
+/** @brief Type of button state */
+typedef uint8_t OSVR_ButtonState;
+
+/** @brief OSVR_ButtonState value indicating "button down" */
+#define OSVR_BUTTON_PRESSED (1)
+
+/** @brief OSVR_ButtonState value indicating "button up" */
+#define OSVR_BUTTON_NOT_PRESSED (0)
+
+/** @brief Type of analog channel state */
+typedef double OSVR_AnalogState;
+
+/** @} */
+
+/** @name Report types
+    @{
+*/
+/** @brief Report type for a position callback on a tracker interface */
+typedef struct OSVR_PositionReport {
+    /** @brief Identifies the sensor that the report comes from */
+    int32_t sensor;
+    /** @brief The position vector */
+    OSVR_PositionState xyz;
+} OSVR_PositionReport;
+
+/** @brief Report type for an orientation callback on a tracker interface */
+typedef struct OSVR_OrientationReport {
+    /** @brief Identifies the sensor that the report comes from */
+    int32_t sensor;
+    /** @brief The rotation unit quaternion */
+    OSVR_OrientationState rotation;
+} OSVR_OrientationReport;
+
+/** @brief Report type for a pose (position and orientation) callback on a
+    tracker interface
+*/
+typedef struct OSVR_PoseReport {
+    /** @brief Identifies the sensor that the report comes from */
+    int32_t sensor;
+    /** @brief The pose structure, containing a position vector and a rotation
+        quaternion
+    */
+    OSVR_PoseState pose;
+} OSVR_PoseReport;
+
+/** @brief Report type for a velocity (linear and angular) callback on a
+    tracker interface
+*/
+typedef struct OSVR_VelocityReport {
+    /** @brief Identifies the sensor that the report comes from */
+    int32_t sensor;
+    /** @brief The data state - note that not all fields are neccesarily valid,
+        use the `Valid` members to check the status of the other fields.
+    */
+    OSVR_VelocityState state;
+} OSVR_VelocityReport;
+
+/** @brief Report type for a linear velocity callback on a tracker interface
+*/
+typedef struct OSVR_LinearVelocityReport {
+    /** @brief Identifies the sensor that the report comes from */
+    int32_t sensor;
+    /** @brief The state itself */
+    OSVR_LinearVelocityState state;
+} OSVR_LinearVelocityReport;
+
+/** @brief Report type for an angular velocity callback on a tracker interface
+*/
+typedef struct OSVR_AngularVelocityReport {
+    /** @brief Identifies the sensor that the report comes from */
+    int32_t sensor;
+    /** @brief The state itself */
+    OSVR_AngularVelocityState state;
+} OSVR_AngularVelocityReport;
+
+/** @brief Report type for an acceleration (linear and angular) callback on a
+    tracker interface
+*/
+typedef struct OSVR_AccelerationReport {
+    /** @brief Identifies the sensor that the report comes from */
+    int32_t sensor;
+    /** @brief The data state - note that not all fields are neccesarily valid,
+        use the `Valid` members to check the status of the other fields.
+    */
+    OSVR_AccelerationState state;
+} OSVR_AccelerationReport;
+
+/** @brief Report type for a linear acceleration callback on a tracker interface
+*/
+typedef struct OSVR_LinearAccelerationReport {
+    /** @brief Identifies the sensor that the report comes from */
+    int32_t sensor;
+    /** @brief The state itself */
+    OSVR_LinearAccelerationState state;
+} OSVR_LinearAccelerationReport;
+
+/** @brief Report type for an angular acceleration callback on a tracker
+    interface
+*/
+typedef struct OSVR_AngularAccelerationReport {
+    /** @brief Identifies the sensor that the report comes from */
+    int32_t sensor;
+    /** @brief The state itself */
+    OSVR_AngularAccelerationState state;
+} OSVR_AngularAccelerationReport;
+
+/** @brief Report type for a callback on a button interface */
+typedef struct OSVR_ButtonReport {
+    /** @brief Identifies the sensor that the report comes from */
+    int32_t sensor;
+    /** @brief The button state: 1 is pressed, 0 is not pressed. */
+    OSVR_ButtonState state;
+} OSVR_ButtonReport;
+
+/** @brief Report type for a callback on an analog interface */
+typedef struct OSVR_AnalogReport {
+    /** @brief Identifies the sensor/channel that the report comes from */
+    int32_t sensor;
+    /** @brief The analog state. */
+    OSVR_AnalogState state;
+} OSVR_AnalogReport;
+
+/** @brief Type of location within a 2D region/surface, in normalized
+    coordinates (in range [0, 1] in standard OSVR coordinate system)
+*/
+typedef OSVR_Vec2 OSVR_Location2DState;
+
+/** @brief Report type for 2D location */
+typedef struct OSVR_Location2DReport {
+    OSVR_ChannelCount sensor;
+    OSVR_Location2DState location;
+} OSVR_Location2DReport;
+
+/** @brief Type of unit directional vector in 3D with no particular origin */
+typedef OSVR_Vec3 OSVR_DirectionState;
+
+/** @brief Report type for 3D Direction vector */
+typedef struct OSVR_DirectionReport {
+    OSVR_ChannelCount sensor;
+    OSVR_DirectionState direction;
+} OSVR_DirectionReport;
+
+/** @brief Type of eye gaze direction in 3D which contains 3D vector (position)
+    containing gaze base point of the user's respective eye in 3D device
+    coordinates.
+*/
+typedef OSVR_PositionState OSVR_EyeGazeBasePoint3DState;
+
+/** @brief Type of eye gaze position in 2D which contains users's gaze/point of
+    regard in normalized display coordinates (in range [0, 1] in standard OSVR
+    coordinate system)
+*/
+typedef OSVR_Location2DState OSVR_EyeGazePosition2DState;
+
+// typedef OSVR_DirectionState OSVR_EyeGazeBasePoint3DState;
+
+/** @brief Type of 3D vector (direction vector) containing the normalized gaze
+    direction of user's respective eye */
+typedef OSVR_DirectionState OSVR_EyeGazeDirectionState;
+
+/** @brief State for 3D gaze report */
+typedef struct OSVR_EyeTracker3DState {
+    OSVR_CBool directionValid;
+    OSVR_DirectionState direction;
+    OSVR_CBool basePointValid;
+    OSVR_PositionState basePoint;
+} OSVR_EyeTracker3DState;
+
+/** @brief Report type for 3D gaze report */
+typedef struct OSVR_EyeTracker3DReport {
+    OSVR_ChannelCount sensor;
+    OSVR_EyeTracker3DState state;
+} OSVR_EyeTracker3DReport;
+
+/** @brief State for 2D location report */
+typedef OSVR_Location2DState OSVR_EyeTracker2DState;
+
+/** @brief Report type for 2D location report */
+typedef struct OSVR_EyeTracker2DReport {
+    OSVR_ChannelCount sensor;
+    OSVR_EyeTracker2DState state;
+} OSVR_EyeTracker2DReport;
+
+/** @brief State for a blink event */
+typedef OSVR_ButtonState OSVR_EyeTrackerBlinkState;
+
+/** @brief OSVR_EyeTrackerBlinkState value indicating an eyes blink had occurred
+ */
+#define OSVR_EYE_BLINK (1)
+
+/** @brief OSVR_EyeTrackerBlinkState value indicating eyes are not blinking */
+#define OSVR_EYE_NO_BLINK (0)
+
+/** @brief Report type for a blink event */
+typedef struct OSVR_EyeTrackerBlinkReport {
+    OSVR_ChannelCount sensor;
+    OSVR_EyeTrackerBlinkState state;
+} OSVR_EyeTrackerBlinkReport;
+
+/** @brief Report type for an Imaging callback (forward declaration) */
+struct OSVR_ImagingReport;
+
+/** @brief Type of Navigation Velocity state */
+typedef OSVR_Vec2 OSVR_NaviVelocityState;
+
+/** @brief Type of Navigation Position state */
+typedef OSVR_Vec2 OSVR_NaviPositionState;
+
+/** @brief Report type for an navigation velocity callback on a tracker
+ * interface */
+typedef struct OSVR_NaviVelocityReport {
+    OSVR_ChannelCount sensor;
+    /** @brief The 2D vector in world coordinate system, in meters/second */
+    OSVR_NaviVelocityState state;
+} OSVR_NaviVelocityReport;
+
+/** @brief Report type for an navigation position callback on a tracker
+ * interface */
+typedef struct OSVR_NaviPositionReport {
+    OSVR_ChannelCount sensor;
+    /** @brief The 2D vector in world coordinate system, in meters, relative to
+     * starting position */
+    OSVR_NaviPositionState state;
+} OSVR_NaviPositionReport;
+
+/** @} */
+
+/** @} */
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/Export.h
@@ -0,0 +1,138 @@
+/** @file
+    @brief Automatically-generated export header - do not edit!
+
+    @date 2016
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+// Copyright 2016 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef OSVR_UTIL_EXPORT_H
+#define OSVR_UTIL_EXPORT_H
+
+#ifdef OSVR_UTIL_STATIC_DEFINE
+#  define OSVR_UTIL_EXPORT
+#  define OSVR_UTIL_NO_EXPORT
+#endif
+
+/* Per-compiler advance preventative definition */
+#if defined(__BORLANDC__) || defined(__CODEGEARC__) || defined(__HP_aCC) ||    \
+    defined(__PGI) || defined(__WATCOMC__)
+/* Compilers that don't support deprecated, according to CMake. */
+#  ifndef OSVR_UTIL_DEPRECATED
+#    define OSVR_UTIL_DEPRECATED
+#  endif
+#endif
+
+/* Check for attribute support */
+#if defined(__INTEL_COMPILER)
+/* Checking before GNUC because Intel implements GNU extensions,
+ * so it chooses to define __GNUC__ as well. */
+#  if __INTEL_COMPILER >= 1200
+/* Intel compiler 12.0 or newer can handle these attributes per CMake */
+#    define OSVR_UTIL_EXPORT_HEADER_SUPPORTS_ATTRIBUTES
+#  endif
+
+#elif defined(__GNUC__)
+#  if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
+/* GCC 4.2+ */
+#    define OSVR_UTIL_EXPORT_HEADER_SUPPORTS_ATTRIBUTES
+#  endif
+#endif
+
+/* Per-platform defines */
+#if defined(_MSC_VER)
+/* MSVC on Windows */
+
+#ifndef OSVR_UTIL_EXPORT
+#  ifdef osvrUtil_EXPORTS
+      /* We are building this library */
+#    define OSVR_UTIL_EXPORT __declspec(dllexport)
+#  else
+      /* We are using this library */
+#    define OSVR_UTIL_EXPORT __declspec(dllimport)
+#  endif
+#endif
+
+#ifndef OSVR_UTIL_DEPRECATED
+#  define OSVR_UTIL_DEPRECATED __declspec(deprecated)
+#endif
+
+#elif defined(_WIN32) && defined(__GNUC__)
+/* GCC-compatible on Windows */
+
+#ifndef OSVR_UTIL_EXPORT
+#  ifdef osvrUtil_EXPORTS
+      /* We are building this library */
+#    define OSVR_UTIL_EXPORT __attribute__((dllexport))
+#  else
+      /* We are using this library */
+#    define OSVR_UTIL_EXPORT __attribute__((dllimport))
+#  endif
+#endif
+
+#ifndef OSVR_UTIL_DEPRECATED
+#  define OSVR_UTIL_DEPRECATED __attribute__((__deprecated__))
+#endif
+
+#elif defined(OSVR_UTIL_EXPORT_HEADER_SUPPORTS_ATTRIBUTES) ||         \
+    (defined(__APPLE__) && defined(__MACH__))
+/* GCC4.2+ compatible (assuming something *nix-like) and Mac OS X */
+/* (The first macro is defined at the top of the file, if applicable) */
+/* see https://gcc.gnu.org/wiki/Visibility */
+
+#ifndef OSVR_UTIL_EXPORT
+  /* We are building/using this library */
+#  define OSVR_UTIL_EXPORT __attribute__((visibility("default")))
+#endif
+
+#ifndef OSVR_UTIL_NO_EXPORT
+#  define OSVR_UTIL_NO_EXPORT __attribute__((visibility("hidden")))
+#endif
+
+#ifndef OSVR_UTIL_DEPRECATED
+#  define OSVR_UTIL_DEPRECATED __attribute__((__deprecated__))
+#endif
+
+#endif
+/* End of platform ifdefs */
+
+/* fallback def */
+#ifndef OSVR_UTIL_EXPORT
+#  define OSVR_UTIL_EXPORT
+#endif
+
+/* fallback def */
+#ifndef OSVR_UTIL_NO_EXPORT
+#  define OSVR_UTIL_NO_EXPORT
+#endif
+
+/* fallback def */
+#ifndef OSVR_UTIL_DEPRECATED_EXPORT
+#  define OSVR_UTIL_DEPRECATED_EXPORT OSVR_UTIL_EXPORT OSVR_UTIL_DEPRECATED
+#endif
+
+/* fallback def */
+#ifndef OSVR_UTIL_DEPRECATED_NO_EXPORT
+#  define OSVR_UTIL_DEPRECATED_NO_EXPORT OSVR_UTIL_NO_EXPORT OSVR_UTIL_DEPRECATED
+#endif
+
+/* Clean up after ourselves */
+#undef OSVR_UTIL_EXPORT_HEADER_SUPPORTS_ATTRIBUTES
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/ImagingReportTypesC.h
@@ -0,0 +1,91 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2015
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2015 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_ImagingReportTypesC_h_GUID_746A7BF8_B92D_4585_CA72_DC5391DEDF24
+#define INCLUDED_ImagingReportTypesC_h_GUID_746A7BF8_B92D_4585_CA72_DC5391DEDF24
+
+/* Internal Includes */
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/StdInt.h>
+#include <osvr/Util/ChannelCountC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup ClientKit
+    @{
+*/
+typedef uint32_t OSVR_ImageDimension;
+typedef uint8_t OSVR_ImageChannels;
+typedef uint8_t OSVR_ImageDepth;
+
+/** @brief Type for raw buffer access to image data */
+typedef unsigned char OSVR_ImageBufferElement;
+
+typedef enum OSVR_ImagingValueType {
+    OSVR_IVT_UNSIGNED_INT = 0,
+    OSVR_IVT_SIGNED_INT = 1,
+    OSVR_IVT_FLOATING_POINT = 2
+} OSVR_ImagingValueType;
+
+typedef struct OSVR_ImagingMetadata {
+    /** @brief height in pixels */
+    OSVR_ImageDimension height;
+    /** @brief width in pixels */
+    OSVR_ImageDimension width;
+    /** @brief number of channels of data for each pixel */
+    OSVR_ImageChannels channels;
+    /** @brief the depth (size) in bytes of each channel - valid values are 1,
+     * 2, 4, and 8 */
+    OSVR_ImageDepth depth;
+    /** @brief Whether values are unsigned ints, signed ints, or floating point
+     */
+    OSVR_ImagingValueType type;
+
+} OSVR_ImagingMetadata;
+
+typedef struct OSVR_ImagingState {
+    OSVR_ImagingMetadata metadata;
+    OSVR_ImageBufferElement *data;
+} OSVR_ImagingState;
+
+typedef struct OSVR_ImagingReport {
+    OSVR_ChannelCount sensor;
+    OSVR_ImagingState state;
+} OSVR_ImagingReport;
+
+/** @} */
+
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/MatrixConventionsC.h
@@ -0,0 +1,190 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2015
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2015 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_MatrixConventionsC_h_GUID_6FC7A4C6_E6C5_4A96_1C28_C3D21B909681
+#define INCLUDED_MatrixConventionsC_h_GUID_6FC7A4C6_E6C5_4A96_1C28_C3D21B909681
+
+/* Internal Includes */
+#include <osvr/Util/Export.h>
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/StdInt.h>
+#include <osvr/Util/Pose3C.h>
+#include <osvr/Util/ReturnCodesC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @defgroup MatrixConvention Matrix conventions and bit flags
+    @ingroup UtilMath
+*/
+
+/** @brief Type for passing matrix convention flags.
+    @ingroup MatrixConvention
+*/
+typedef uint16_t OSVR_MatrixConventions;
+
+#ifndef OSVR_DOXYGEN_EXTERNAL
+/** @brief Bitmasks for testing matrix conventions.
+    @ingroup MatrixConvention
+*/
+typedef enum OSVR_MatrixMasks {
+    OSVR_MATRIX_MASK_ROWMAJOR = 0x1,
+    OSVR_MATRIX_MASK_ROWVECTORS = 0x2,
+    OSVR_MATRIX_MASK_LHINPUT = 0x4,
+    OSVR_MATRIX_MASK_UNSIGNEDZ = 0x8
+} OSVR_MatrixMasks;
+#endif
+
+/** @defgroup MatrixFlags Matrix flags
+    @ingroup MatrixConvention
+
+    Bit flags for specifying matrix options. Only one option may be specified
+   per enum, with all the specified options combined with bitwise-or `|`.
+
+    Most methods that take matrix flags only obey ::OSVR_MatrixOrderingFlags and
+   ::OSVR_MatrixVectorFlags - the flags that affect memory order. The remaining
+   flags are for use with projection matrix generation API methods.
+
+    @{
+*/
+/** @brief Flag bit controlling output memory order */
+typedef enum OSVR_MatrixOrderingFlags {
+    /** @brief Column-major memory order (default) */
+    OSVR_MATRIX_COLMAJOR = 0x0,
+    /** @brief Row-major memory order */
+    OSVR_MATRIX_ROWMAJOR = OSVR_MATRIX_MASK_ROWMAJOR
+} OSVR_MatrixOrderingFlags;
+
+/** @brief Flag bit controlling expected input to matrices.
+    (Related to ::OSVR_MatrixOrderingFlags - setting one to non-default results
+    in an output change, but setting both to non-default results in effectively
+    no change in the output. If this blows your mind, just ignore this aside and
+    carry on.)
+*/
+typedef enum OSVR_MatrixVectorFlags {
+    /** @brief Matrix transforms column vectors (default) */
+    OSVR_MATRIX_COLVECTORS = 0x0,
+    /** @brief Matrix transforms row vectors */
+    OSVR_MATRIX_ROWVECTORS = OSVR_MATRIX_MASK_ROWVECTORS
+} OSVR_MatrixVectorFlags;
+
+/** @brief Flag bit to indicate coordinate system input to projection matrix */
+typedef enum OSVR_ProjectionMatrixInputFlags {
+    /** @brief Matrix takes vectors from a right-handed coordinate system
+       (default) */
+    OSVR_MATRIX_RHINPUT = 0x0,
+    /** @brief Matrix takes vectors from a left-handed coordinate system */
+    OSVR_MATRIX_LHINPUT = OSVR_MATRIX_MASK_LHINPUT
+
+} OSVR_ProjectionMatrixInputFlags;
+
+/** @brief Flag bit to indicate the desired post-projection Z value convention
+ */
+typedef enum OSVR_ProjectionMatrixZFlags {
+    /** @brief Matrix maps the near and far planes to signed Z values (in the
+        range [-1, 1])  (default)*/
+    OSVR_MATRIX_SIGNEDZ = 0x0,
+    /** @brief Matrix maps the near and far planes to unsigned Z values (in the
+        range [0, 1]) */
+    OSVR_MATRIX_UNSIGNEDZ = OSVR_MATRIX_MASK_UNSIGNEDZ
+} OSVR_ProjectionMatrixZFlags;
+/** @} */ /* end of matrix flags group */
+
+enum {
+    /** @brief Constant for the number of elements in the matrices we use - 4x4.
+        @ingroup MatrixConvention
+    */
+    OSVR_MATRIX_SIZE = 16
+};
+
+/** @addtogroup UtilMath
+    @{
+*/
+/** @brief Set a matrix of doubles based on a Pose3.
+    @param pose The Pose3 to convert
+    @param flags Memory ordering flag - see @ref MatrixFlags
+    @param[out] mat an array of 16 doubles
+*/
+OSVR_UTIL_EXPORT OSVR_ReturnCode osvrPose3ToMatrixd(
+    OSVR_Pose3 const *pose, OSVR_MatrixConventions flags, double *mat);
+
+/** @brief Set a matrix of floats based on a Pose3.
+    @param pose The Pose3 to convert
+    @param flags Memory ordering flag - see @ref MatrixFlags
+    @param[out] mat an array of 16 floats
+*/
+OSVR_UTIL_EXPORT OSVR_ReturnCode osvrPose3ToMatrixf(
+    OSVR_Pose3 const *pose, OSVR_MatrixConventions flags, float *mat);
+/** @} */
+
+OSVR_EXTERN_C_END
+
+#ifdef __cplusplus
+/** @brief Set a matrix based on a Pose3. (C++-only overload - detecting scalar
+ * type) */
+inline OSVR_ReturnCode osvrPose3ToMatrix(OSVR_Pose3 const *pose,
+                                         OSVR_MatrixConventions flags,
+                                         double *mat) {
+    return osvrPose3ToMatrixd(pose, flags, mat);
+}
+
+/** @brief Set a matrix based on a Pose3. (C++-only overload - detecting scalar
+ * type) */
+inline OSVR_ReturnCode osvrPose3ToMatrix(OSVR_Pose3 const *pose,
+                                         OSVR_MatrixConventions flags,
+                                         float *mat) {
+    return osvrPose3ToMatrixf(pose, flags, mat);
+}
+
+/** @brief Set a matrix based on a Pose3. (C++-only overload - detects scalar
+ * and takes array rather than pointer) */
+template <typename Scalar>
+inline OSVR_ReturnCode osvrPose3ToMatrix(OSVR_Pose3 const *pose,
+                                         OSVR_MatrixConventions flags,
+                                         Scalar mat[OSVR_MATRIX_SIZE]) {
+    return osvrPose3ToMatrix(pose, flags, &(mat[0]));
+}
+/** @brief Set a matrix based on a Pose3. (C++-only overload - detects scalar,
+ * takes array, takes pose by reference) */
+template <typename Scalar>
+inline OSVR_ReturnCode osvrPose3ToMatrix(OSVR_Pose3 const &pose,
+                                         OSVR_MatrixConventions flags,
+                                         Scalar mat[OSVR_MATRIX_SIZE]) {
+    return osvrPose3ToMatrix(&pose, flags, &(mat[0]));
+}
+
+#endif
+
+/** @} */
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/PlatformConfig.h
@@ -0,0 +1,88 @@
+/** @file
+    @brief Auto-configured header
+
+    If this filename ends in `.h`, don't edit it: your edits will
+    be lost next time this file is regenerated!
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_PlatformConfig_h_GUID_0D10E644_8114_4294_A839_699F39E1F0E0
+#define INCLUDED_PlatformConfig_h_GUID_0D10E644_8114_4294_A839_699F39E1F0E0
+
+/** @def OSVR_HAVE_STRUCT_TIMEVAL_IN_WINSOCK2_H
+    @brief Does the system have struct timeval in <winsock2.h>?
+*/
+#define OSVR_HAVE_STRUCT_TIMEVAL_IN_WINSOCK2_H
+
+/** @def OSVR_HAVE_STRUCT_TIMEVAL_IN_SYS_TIME_H
+    @brief Does the system have struct timeval in <sys/time.h>?
+*/
+
+/*
+    MinGW and similar environments have both winsock and sys/time.h, so
+    we hide this define for disambiguation at the top level.
+*/
+#ifndef OSVR_HAVE_STRUCT_TIMEVAL_IN_WINSOCK2_H
+/* #undef OSVR_HAVE_STRUCT_TIMEVAL_IN_SYS_TIME_H */
+#endif
+
+#if defined(OSVR_HAVE_STRUCT_TIMEVAL_IN_SYS_TIME_H) ||                         \
+    defined(OSVR_HAVE_STRUCT_TIMEVAL_IN_WINSOCK2_H)
+#define OSVR_HAVE_STRUCT_TIMEVAL
+#endif
+
+/**
+ * Platform-specific variables.
+ *
+ * Prefer testing for specific compiler or platform features instead of relying
+ * on these variables.
+ *
+ */
+//@{
+/* #undef OSVR_AIX */
+/* #undef OSVR_ANDROID */
+/* #undef OSVR_BSDOS */
+/* #undef OSVR_FREEBSD */
+/* #undef OSVR_HPUX */
+/* #undef OSVR_IRIX */
+/* #undef OSVR_LINUX */
+/* #undef OSVR_KFREEBSD */
+/* #undef OSVR_NETBSD */
+/* #undef OSVR_OPENBSD */
+/* #undef OSVR_OFS1 */
+/* #undef OSVR_SCO_SV */
+/* #undef OSVR_UNIXWARE */
+/* #undef OSVR_XENIX */
+/* #undef OSVR_SUNOS */
+/* #undef OSVR_TRU64 */
+/* #undef OSVR_ULTRIX */
+/* #undef OSVR_CYGWIN */
+/* #undef OSVR_MACOSX */
+#define OSVR_WINDOWS
+//@}
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/Pose3C.h
@@ -0,0 +1,70 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_Pose3C_h_GUID_066CFCE2_229C_4194_5D2B_2602CCD5C439
+#define INCLUDED_Pose3C_h_GUID_066CFCE2_229C_4194_5D2B_2602CCD5C439
+
+/* Internal Includes */
+
+/* Internal Includes */
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/Vec3C.h>
+#include <osvr/Util/QuaternionC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup UtilMath
+    @{
+*/
+
+/** @brief A structure defining a 3D (6DOF) rigid body pose: translation and
+    rotation.
+*/
+typedef struct OSVR_Pose3 {
+    /** @brief Position vector */
+    OSVR_Vec3 translation;
+    /** @brief Orientation as a unit quaternion */
+    OSVR_Quaternion rotation;
+} OSVR_Pose3;
+
+/** @brief Set a pose to identity */
+OSVR_INLINE void osvrPose3SetIdentity(OSVR_Pose3 *pose) {
+    osvrQuatSetIdentity(&(pose->rotation));
+    osvrVec3Zero(&(pose->translation));
+}
+/** @} */
+
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/QuaternionC.h
@@ -0,0 +1,92 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_QuaternionC_h_GUID_1470A5FE_8209_41A6_C19E_46077FDF9C66
+#define INCLUDED_QuaternionC_h_GUID_1470A5FE_8209_41A6_C19E_46077FDF9C66
+
+/* Internal Includes */
+#include <osvr/Util/APIBaseC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup UtilMath
+    @{
+*/
+/** @brief A structure defining a quaternion, often a unit quaternion
+ * representing 3D rotation.
+*/
+typedef struct OSVR_Quaternion {
+    /** @brief Internal data - direct access not recommended */
+    double data[4];
+} OSVR_Quaternion;
+
+#define OSVR_QUAT_MEMBER(COMPONENT, INDEX)                                     \
+    /** @brief Accessor for quaternion component COMPONENT */                  \
+    OSVR_INLINE double osvrQuatGet##COMPONENT(OSVR_Quaternion const *q) {      \
+        return q->data[INDEX];                                                 \
+    }                                                                          \
+    /** @brief Setter for quaternion component COMPONENT */                    \
+    OSVR_INLINE void osvrQuatSet##COMPONENT(OSVR_Quaternion *q, double val) {  \
+        q->data[INDEX] = val;                                                  \
+    }
+
+OSVR_QUAT_MEMBER(W, 0)
+OSVR_QUAT_MEMBER(X, 1)
+OSVR_QUAT_MEMBER(Y, 2)
+OSVR_QUAT_MEMBER(Z, 3)
+
+#undef OSVR_QUAT_MEMBER
+
+/** @brief Set a quaternion to the identity rotation */
+OSVR_INLINE void osvrQuatSetIdentity(OSVR_Quaternion *q) {
+    osvrQuatSetW(q, 1);
+    osvrQuatSetX(q, 0);
+    osvrQuatSetY(q, 0);
+    osvrQuatSetZ(q, 0);
+}
+
+/** @} */
+
+OSVR_EXTERN_C_END
+
+#ifdef __cplusplus
+template <typename StreamType>
+inline StreamType &operator<<(StreamType &os, OSVR_Quaternion const &quat) {
+    os << "(" << osvrQuatGetW(&quat) << ", (" << osvrQuatGetX(&quat) << ", "
+       << osvrQuatGetY(&quat) << ", " << osvrQuatGetZ(&quat) << "))";
+    return os;
+}
+#endif
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/QuatlibInteropC.h
@@ -0,0 +1,84 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_QuatlibInteropC_h_GUID_85D92019_F0CC_419C_5F6D_F5A3134AA5D4
+#define INCLUDED_QuatlibInteropC_h_GUID_85D92019_F0CC_419C_5F6D_F5A3134AA5D4
+
+/* Internal Includes */
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/Pose3C.h>
+
+/* Library/third-party includes */
+#include <quat.h>
+
+/* Standard includes */
+#include <string.h>
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup UtilMath
+    @{
+*/
+OSVR_INLINE void osvrQuatToQuatlib(q_type dest, OSVR_Quaternion const *src) {
+    dest[Q_W] = osvrQuatGetW(src);
+    dest[Q_X] = osvrQuatGetX(src);
+    dest[Q_Y] = osvrQuatGetY(src);
+    dest[Q_Z] = osvrQuatGetZ(src);
+}
+
+OSVR_INLINE void osvrQuatFromQuatlib(OSVR_Quaternion *dest, q_type const src) {
+    osvrQuatSetW(dest, src[Q_W]);
+    osvrQuatSetX(dest, src[Q_X]);
+    osvrQuatSetY(dest, src[Q_Y]);
+    osvrQuatSetZ(dest, src[Q_Z]);
+}
+
+OSVR_INLINE void osvrVec3ToQuatlib(q_vec_type dest, OSVR_Vec3 const *src) {
+    memcpy((void *)(dest), (void const *)(src->data), sizeof(double) * 3);
+}
+
+OSVR_INLINE void osvrVec3FromQuatlib(OSVR_Vec3 *dest, q_vec_type const src) {
+    memcpy((void *)(dest->data), (void const *)(src), sizeof(double) * 3);
+}
+
+OSVR_INLINE void osvrPose3ToQuatlib(q_xyz_quat_type *dest,
+                                    OSVR_Pose3 const *src) {
+    osvrVec3ToQuatlib(dest->xyz, &(src->translation));
+    osvrQuatToQuatlib(dest->quat, &(src->rotation));
+}
+
+OSVR_INLINE void osvrPose3FromQuatlib(OSVR_Pose3 *dest,
+                                      q_xyz_quat_type const *src) {
+    osvrVec3FromQuatlib(&(dest->translation), src->xyz);
+    osvrQuatFromQuatlib(&(dest->rotation), src->quat);
+}
+
+/** @} */
+
+OSVR_EXTERN_C_END
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/RadialDistortionParametersC.h
@@ -0,0 +1,62 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2015
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2015 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_RadialDistortionParametersC_h_GUID_925BCEB1_BACA_4DA7_5133_FFF560C72EBD
+#define INCLUDED_RadialDistortionParametersC_h_GUID_925BCEB1_BACA_4DA7_5133_FFF560C72EBD
+
+/* Internal Includes */
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/Vec2C.h>
+#include <osvr/Util/Vec3C.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup UtilMath
+@{
+*/
+
+/** @brief Parameters for a per-color-component radial distortion shader
+*/
+typedef struct OSVR_RadialDistortionParameters {
+    /** @brief Vector of K1 coefficients for the R, G, B channels*/
+    OSVR_Vec3 k1;
+    /** @brief Center of projection for the radial distortion, relative to the
+        bounds of this surface.
+        */
+    OSVR_Vec2 centerOfProjection;
+} OSVR_RadialDistortionParameters;
+
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/RenderingTypesC.h
@@ -0,0 +1,134 @@
+/** @file
+    @brief Header with integer types for Viewer, Eye, and Surface
+   counts/indices, as well as viewport information.
+
+    Must be c-safe!
+
+    @date 2015
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2015 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_RenderingTypesC_h_GUID_6689A6CA_76AC_48AC_A0D0_2902BC95AC35
+#define INCLUDED_RenderingTypesC_h_GUID_6689A6CA_76AC_48AC_A0D0_2902BC95AC35
+
+/* Internal Includes */
+#include <osvr/Util/StdInt.h>
+#include <osvr/Util/APIBaseC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup PluginKit
+@{
+*/
+
+/** @brief A count or index for a display input in a display config.
+*/
+typedef uint8_t OSVR_DisplayInputCount;
+
+/** @brief The integer type used in specification of size or location of a
+    display input, in pixels.
+*/
+typedef int32_t OSVR_DisplayDimension;
+
+/** @brief The integer type specifying a number of viewers in a system.
+
+    A "head" is a viewer (though not all viewers are necessarily heads).
+
+    The count is output from osvrClientGetNumViewers().
+
+    When used as an ID/index, it is zero-based, so values range from 0 to (count
+    - 1) inclusive.
+
+    The most frequent count is 1, though higher values are theoretically
+    possible. If you do not handle higher values, do still check and alert the
+    user if their system reports a higher number, as your application may not
+    behave as the user expects.
+*/
+typedef uint32_t OSVR_ViewerCount;
+
+/** @brief The integer type specifying the number of eyes (viewpoints) of a
+    viewer.
+
+    The count for a given viewer is output from osvrClientGetNumEyesForViewer().
+
+    When used as an ID/index, it is zero-based,so values range from 0 to (count
+    - 1) inclusive, for a given viewer.
+
+    Use as an ID/index is not meaningful except in conjunction with the ID of
+    the corresponding viewer. (that is, there is no overall "eye 0", but "viewer
+    0, eye 0" is meaningful.)
+
+    In practice, the most frequent counts are 1 (e.g. mono) and 2 (e.g. stereo),
+    and for example the latter results in eyes with ID 0 and 1 for the viewer.
+    There is no innate or consistent semantics/meaning ("left" or "right") to
+    indices guaranteed at this time, and applications should not try to infer
+    any.
+*/
+typedef uint8_t OSVR_EyeCount;
+
+/** @brief The integer type specifying the number of surfaces seen by a viewer's
+    eye.
+
+    The count for a given viewer and eye is output from
+    osvrClientGetNumSurfacesForViewerEye(). Note that the count is not
+    necessarily equal between eyes of a viewer.
+
+    When used as an ID/index, it is zero-based, so values range from 0 to (count
+    - 1) inclusive, for a given viewer and eye.
+
+    Use as an ID/index is not meaningful except in conjunction with the IDs of
+    the corresponding viewer and eye. (that is, there is no overall "surface 0",
+    but "viewer 0, eye 0, surface 0" is meaningful.)
+*/
+typedef uint32_t OSVR_SurfaceCount;
+
+/** @brief The integer type used in specification of size or location of a
+    viewport.
+*/
+typedef int32_t OSVR_ViewportDimension;
+
+/** @brief The integer type used to indicate relative priorities of a display
+    distortion strategy. Negative values are defined to mean that strategy is
+    unavailable.
+
+    @sa OSVR_DISTORTION_PRIORITY_UNAVAILABLE
+*/
+typedef int32_t OSVR_DistortionPriority;
+
+/** @brief The constant to return as an OSVR_DistortionPriority if a given
+    strategy is not available for a surface.
+
+    @sa OSVR_DistortionPriority
+*/
+#define OSVR_DISTORTION_PRIORITY_UNAVAILABLE (-1)
+
+/** @} */
+
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/ReturnCodesC.h
@@ -0,0 +1,57 @@
+/** @file
+    @brief Header declaring a type and values for simple C return codes.
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_ReturnCodesC_h_GUID_C81A2FDE_E5BB_4AAA_70A4_C616DD7C141A
+#define INCLUDED_ReturnCodesC_h_GUID_C81A2FDE_E5BB_4AAA_70A4_C616DD7C141A
+
+/* Internal Includes */
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/AnnotationMacrosC.h>
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup PluginKit
+    @{
+*/
+/** @name Return Codes
+    @{
+*/
+/** @brief The "success" value for an OSVR_ReturnCode */
+#define OSVR_RETURN_SUCCESS (0)
+/** @brief The "failure" value for an OSVR_ReturnCode */
+#define OSVR_RETURN_FAILURE (1)
+/** @brief Return type from C API OSVR functions. */
+typedef OSVR_RETURN_SUCCESS_CONDITION(
+    return == OSVR_RETURN_SUCCESS) char OSVR_ReturnCode;
+/** @} */
+
+/** @} */ /* end of group */
+
+OSVR_EXTERN_C_END
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/StdInt.h
@@ -0,0 +1,42 @@
+/** @file
+    @brief Header wrapping the C99 standard `stdint` header.
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_StdInt_h_GUID_C1AAF35C_C704_4DB7_14AC_615730C4619B
+#define INCLUDED_StdInt_h_GUID_C1AAF35C_C704_4DB7_14AC_615730C4619B
+
+/* IWYU pragma: begin_exports */
+
+#if !defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER >= 1600)
+#include <stdint.h>
+#else
+#include "MSStdIntC.h"
+#endif
+
+/* IWYU pragma: end_exports */
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/TimeValueC.h
@@ -0,0 +1,271 @@
+/** @file
+    @brief Header defining a dependency-free, cross-platform substitute for
+   struct timeval
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_TimeValueC_h_GUID_A02C6917_124D_4CB3_E63E_07F2DA7144E9
+#define INCLUDED_TimeValueC_h_GUID_A02C6917_124D_4CB3_E63E_07F2DA7144E9
+
+/* Internal Includes */
+#include <osvr/Util/Export.h>
+#include <osvr/Util/APIBaseC.h>
+#include <osvr/Util/AnnotationMacrosC.h>
+#include <osvr/Util/PlatformConfig.h>
+#include <osvr/Util/StdInt.h>
+#include <osvr/Util/BoolC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @defgroup UtilTime Timestamp interaction
+    @ingroup Util
+
+    This provides a level of interoperability with struct timeval on systems
+    with that facility. It provides a neutral representation with sufficiently
+    large types.
+
+    For C++ code, use of std::chrono or boost::chrono instead is recommended.
+
+    Note that these time values may not necessarily correlate between processes
+   so should not be used to estimate or measure latency, etc.
+
+    @{
+*/
+
+/** @brief The signed integer type storing the seconds in a struct
+    OSVR_TimeValue */
+typedef int64_t OSVR_TimeValue_Seconds;
+/** @brief The signed integer type storing the microseconds in a struct
+    OSVR_TimeValue */
+typedef int32_t OSVR_TimeValue_Microseconds;
+
+/** @brief Standardized, portable parallel to struct timeval for representing
+   both absolute times and time intervals.
+
+   Where interpreted as an absolute time, its meaning is to be considered the
+   same as that of the POSIX struct timeval:
+   time since 00:00 Coordinated Universal Time (UTC), January 1, 1970.
+
+   For best results, please keep normalized. Output of all functions here
+   is normalized.
+   */
+typedef struct OSVR_TimeValue {
+    /** @brief Seconds portion of the time value. */
+    OSVR_TimeValue_Seconds seconds;
+    /** @brief Microseconds portion of the time value. */
+    OSVR_TimeValue_Microseconds microseconds;
+} OSVR_TimeValue;
+
+#ifdef OSVR_HAVE_STRUCT_TIMEVAL
+/** @brief Gets the current time in the TimeValue. Parallel to gettimeofday. */
+OSVR_UTIL_EXPORT void osvrTimeValueGetNow(OSVR_OUT OSVR_TimeValue *dest)
+    OSVR_FUNC_NONNULL((1));
+
+struct timeval; /* forward declaration */
+
+/** @brief Converts from a TimeValue struct to your system's struct timeval.
+
+    @param dest Pointer to an empty struct timeval for your platform.
+    @param src A pointer to an OSVR_TimeValue you'd like to convert from.
+
+    If either parameter is NULL, the function will return without doing
+   anything.
+*/
+OSVR_UTIL_EXPORT void
+osvrTimeValueToStructTimeval(OSVR_OUT struct timeval *dest,
+                             OSVR_IN_PTR const OSVR_TimeValue *src)
+    OSVR_FUNC_NONNULL((1, 2));
+
+/** @brief Converts from a TimeValue struct to your system's struct timeval.
+    @param dest An OSVR_TimeValue destination pointer.
+    @param src Pointer to a struct timeval you'd like to convert from.
+
+    The result is normalized.
+
+    If either parameter is NULL, the function will return without doing
+   anything.
+*/
+OSVR_UTIL_EXPORT void
+osvrStructTimevalToTimeValue(OSVR_OUT OSVR_TimeValue *dest,
+                             OSVR_IN_PTR const struct timeval *src)
+    OSVR_FUNC_NONNULL((1, 2));
+#endif
+
+/** @brief "Normalizes" a time value so that the absolute number of microseconds
+    is less than 1,000,000, and that the sign of both components is the same.
+
+    @param tv Address of a struct TimeValue to normalize in place.
+
+    If the given pointer is NULL, this function returns without doing anything.
+*/
+OSVR_UTIL_EXPORT void osvrTimeValueNormalize(OSVR_INOUT_PTR OSVR_TimeValue *tv)
+    OSVR_FUNC_NONNULL((1));
+
+/** @brief Sums two time values, replacing the first with the result.
+
+    @param tvA Destination and first source.
+    @param tvB second source
+
+    If a given pointer is NULL, this function returns without doing anything.
+
+    Both parameters are expected to be in normalized form.
+*/
+OSVR_UTIL_EXPORT void osvrTimeValueSum(OSVR_INOUT_PTR OSVR_TimeValue *tvA,
+                                       OSVR_IN_PTR const OSVR_TimeValue *tvB)
+    OSVR_FUNC_NONNULL((1, 2));
+
+/** @brief Computes the difference between two time values, replacing the first
+    with the result.
+
+    Effectively, `*tvA = *tvA - *tvB`
+
+    @param tvA Destination and first source.
+    @param tvB second source
+
+    If a given pointer is NULL, this function returns without doing anything.
+
+    Both parameters are expected to be in normalized form.
+*/
+OSVR_UTIL_EXPORT void
+osvrTimeValueDifference(OSVR_INOUT_PTR OSVR_TimeValue *tvA,
+                        OSVR_IN_PTR const OSVR_TimeValue *tvB)
+    OSVR_FUNC_NONNULL((1, 2));
+
+/** @brief  Compares two time values (assumed to be normalized), returning
+    the same values as strcmp
+
+    @return <0 if A is earlier than B, 0 if they are the same, and >0 if A
+    is later than B.
+*/
+OSVR_UTIL_EXPORT int osvrTimeValueCmp(OSVR_IN_PTR const OSVR_TimeValue *tvA,
+                                      OSVR_IN_PTR const OSVR_TimeValue *tvB)
+    OSVR_FUNC_NONNULL((1, 2));
+
+OSVR_EXTERN_C_END
+
+/** @brief Compute the difference between the two time values, returning the
+    duration as a double-precision floating-point number of seconds.
+
+    Effectively, `ret = *tvA - *tvB`
+
+    @param tvA first source.
+    @param tvB second source
+    @return Duration of timespan in seconds (floating-point)
+*/
+OSVR_INLINE double
+osvrTimeValueDurationSeconds(OSVR_IN_PTR const OSVR_TimeValue *tvA,
+                             OSVR_IN_PTR const OSVR_TimeValue *tvB) {
+    OSVR_TimeValue A = *tvA;
+    osvrTimeValueDifference(&A, tvB);
+    double dt = A.seconds + A.microseconds / 1000000.0;
+    return dt;
+}
+
+/** @brief True if A is later than B */
+OSVR_INLINE OSVR_CBool
+osvrTimeValueGreater(OSVR_IN_PTR const OSVR_TimeValue *tvA,
+                     OSVR_IN_PTR const OSVR_TimeValue *tvB) {
+    if (!tvA || !tvB) {
+        return OSVR_FALSE;
+    }
+    return ((tvA->seconds > tvB->seconds) ||
+            (tvA->seconds == tvB->seconds &&
+             tvA->microseconds > tvB->microseconds))
+               ? OSVR_TRUE
+               : OSVR_FALSE;
+}
+
+#ifdef __cplusplus
+
+#include <cmath>
+#include <cassert>
+
+/// Returns true if the time value is normalized. Typically used in assertions.
+inline bool osvrTimeValueIsNormalized(const OSVR_TimeValue &tv) {
+#ifdef __APPLE__
+    // apparently standard library used on mac only has floating-point abs?
+    return std::abs(double(tv.microseconds)) < 1000000 &&
+#else
+    return std::abs(tv.microseconds) < 1000000 &&
+#endif
+           ((tv.seconds > 0) == (tv.microseconds > 0));
+}
+
+/// True if A is later than B
+inline bool osvrTimeValueGreater(const OSVR_TimeValue &tvA,
+                                 const OSVR_TimeValue &tvB) {
+    assert(osvrTimeValueIsNormalized(tvA) &&
+           "First timevalue argument to comparison was not normalized!");
+    assert(osvrTimeValueIsNormalized(tvB) &&
+           "Second timevalue argument to comparison was not normalized!");
+    return (tvA.seconds > tvB.seconds) ||
+           (tvA.seconds == tvB.seconds && tvA.microseconds > tvB.microseconds);
+}
+
+/// Operator > overload for time values
+inline bool operator>(const OSVR_TimeValue &tvA, const OSVR_TimeValue &tvB) {
+    return osvrTimeValueGreater(tvA, tvB);
+}
+
+/// Operator < overload for time values
+inline bool operator<(const OSVR_TimeValue &tvA, const OSVR_TimeValue &tvB) {
+    // Change the order of arguments before forwarding.
+    return osvrTimeValueGreater(tvB, tvA);
+}
+
+/// Operator == overload for time values
+inline bool operator==(const OSVR_TimeValue &tvA, const OSVR_TimeValue &tvB) {
+    assert(
+        osvrTimeValueIsNormalized(tvA) &&
+        "First timevalue argument to equality comparison was not normalized!");
+    assert(
+        osvrTimeValueIsNormalized(tvB) &&
+        "Second timevalue argument to equality comparison was not normalized!");
+    return (tvA.seconds == tvB.seconds) &&
+           (tvA.microseconds == tvB.microseconds);
+}
+/// Operator == overload for time values
+inline bool operator!=(const OSVR_TimeValue &tvA, const OSVR_TimeValue &tvB) {
+    assert(osvrTimeValueIsNormalized(tvA) && "First timevalue argument to "
+                                             "inequality comparison was not "
+                                             "normalized!");
+    assert(osvrTimeValueIsNormalized(tvB) && "Second timevalue argument to "
+                                             "inequality comparison was not "
+                                             "normalized!");
+    return (tvA.seconds != tvB.seconds) ||
+           (tvA.microseconds != tvB.microseconds);
+}
+#endif
+
+/** @} */
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/Vec2C.h
@@ -0,0 +1,86 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_Vec2C_h_GUID_F9715DE4_2649_4182_0F4C_D62121235D5F
+#define INCLUDED_Vec2C_h_GUID_F9715DE4_2649_4182_0F4C_D62121235D5F
+
+/* Internal Includes */
+#include <osvr/Util/APIBaseC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup UtilMath
+    @{
+*/
+/** @brief A structure defining a 2D vector, which represents position
+*/
+typedef struct OSVR_Vec2 {
+    /** @brief Internal array data. */
+    double data[2];
+} OSVR_Vec2;
+
+#define OSVR_VEC_MEMBER(COMPONENT, INDEX)                                      \
+    /** @brief Accessor for Vec2 component COMPONENT */                        \
+    OSVR_INLINE double osvrVec2Get##COMPONENT(OSVR_Vec2 const *v) {            \
+        return v->data[INDEX];                                                 \
+    }                                                                          \
+    /** @brief Setter for Vec2 component COMPONENT */                          \
+    OSVR_INLINE void osvrVec2Set##COMPONENT(OSVR_Vec2 *v, double val) {        \
+        v->data[INDEX] = val;                                                  \
+    }
+
+OSVR_VEC_MEMBER(X, 0)
+OSVR_VEC_MEMBER(Y, 1)
+
+#undef OSVR_VEC_MEMBER
+
+/** @brief Set a Vec2 to the zero vector */
+OSVR_INLINE void osvrVec2Zero(OSVR_Vec2 *v) {
+    osvrVec2SetX(v, 0);
+    osvrVec2SetY(v, 0);
+}
+
+/** @} */
+
+OSVR_EXTERN_C_END
+
+#ifdef __cplusplus
+template <typename StreamType>
+inline StreamType &operator<<(StreamType &os, OSVR_Vec2 const &vec) {
+    os << "(" << vec.data[0] << ", " << vec.data[1] << ")";
+    return os;
+}
+#endif
+
+#endif // INCLUDED_Vec2C_h_GUID_F9715DE4_2649_4182_0F4C_D62121235D5F
new file mode 100644
--- /dev/null
+++ b/gfx/vr/osvr/Util/Vec3C.h
@@ -0,0 +1,89 @@
+/** @file
+    @brief Header
+
+    Must be c-safe!
+
+    @date 2014
+
+    @author
+    Sensics, Inc.
+    <http://sensics.com/osvr>
+*/
+
+/*
+// Copyright 2014 Sensics, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#ifndef INCLUDED_Vec3C_h_GUID_BF4E98ED_74CF_4785_DB61_109A00BA74DE
+#define INCLUDED_Vec3C_h_GUID_BF4E98ED_74CF_4785_DB61_109A00BA74DE
+
+/* Internal Includes */
+#include <osvr/Util/APIBaseC.h>
+
+/* Library/third-party includes */
+/* none */
+
+/* Standard includes */
+/* none */
+
+OSVR_EXTERN_C_BEGIN
+
+/** @addtogroup UtilMath
+    @{
+*/
+/** @brief A structure defining a 3D vector, often a position/translation.
+*/
+typedef struct OSVR_Vec3 {
+    /** @brief Internal array data. */
+    double data[3];
+} OSVR_Vec3;
+
+#define OSVR_VEC_MEMBER(COMPONENT, INDEX)                                      \
+    /** @brief Accessor for Vec3 component COMPONENT */                        \
+    OSVR_INLINE double osvrVec3Get##COMPONENT(OSVR_Vec3 const *v) {            \
+        return v->data[INDEX];                                                 \
+    }                                                                          \
+    /** @brief Setter for Vec3 component COMPONENT */                          \
+    OSVR_INLINE void osvrVec3Set##COMPONENT(OSVR_Vec3 *v, double val) {        \
+        v->data[INDEX] = val;                                                  \
+    }
+
+OSVR_VEC_MEMBER(X, 0)
+OSVR_VEC_MEMBER(Y, 1)
+OSVR_VEC_MEMBER(Z, 2)
+
+#undef OSVR_VEC_MEMBER
+
+/** @brief Set a Vec3 to the zero vector */
+OSVR_INLINE void osvrVec3Zero(OSVR_Vec3 *v) {
+    osvrVec3SetX(v, 0);
+    osvrVec3SetY(v, 0);
+    osvrVec3SetZ(v, 0);
+}
+
+/** @} */
+
+OSVR_EXTERN_C_END
+
+#ifdef __cplusplus
+template <typename StreamType>
+inline StreamType &operator<<(StreamType &os, OSVR_Vec3 const &vec) {
+    os << "(" << vec.data[0] << ", " << vec.data[1] << ", " << vec.data[2]
+       << ")";
+    return os;
+}
+#endif
+
+#endif
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4804,26 +4804,33 @@ pref("dom.vr.enabled", false);
 pref("dom.vr.enabled", true);
 #endif
 // Oculus > 0.5
 pref("dom.vr.oculus.enabled", true);
 // Oculus <= 0.5; will only trigger if > 0.5 is not used or found
 pref("dom.vr.oculus050.enabled", true);
 // Cardboard VR device is disabled by default
 pref("dom.vr.cardboard.enabled", false);
+// OSVR device
+pref("dom.vr.osvr.enabled", false);
 // 0 = never; 1 = only if real devices aren't there; 2 = always
 pref("dom.vr.add-test-devices", 0);
 // Pose prediction reduces latency effects by returning future predicted HMD
 // poses to callers of the WebVR API.  This currently only has an effect for
 // Oculus Rift on SDK 0.8 or greater.  It is disabled by default for now due to
 // frame uniformity issues with e10s.
 pref("dom.vr.poseprediction.enabled", false);
 // true = show the VR textures in our compositing output; false = don't.
 // true might have performance impact
 pref("gfx.vr.mirror-textures", false);
+// path to OSVR DLLs
+pref("gfx.vr.osvr.utilLibPath", "");
+pref("gfx.vr.osvr.commonLibPath", "");
+pref("gfx.vr.osvr.clientLibPath", "");
+pref("gfx.vr.osvr.clientKitLibPath", "");
 
 // MMS UA Profile settings
 pref("wap.UAProf.url", "");
 pref("wap.UAProf.tagname", "x-wap-profile");
 
 // MMS version 1.1 = 0x11 (or decimal 17)
 // MMS version 1.3 = 0x13 (or decimal 19)
 // @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.34