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 348388 2da4c57f45951fe964d32c6ca78a6c1dfe02f2a9
parent 348387 85a2d1e3cf9548108ec1124f001a1abe9ace1f03
child 348389 0d41311af46d5b3c2606361018e2d1100161cf44
push id14828
push userpehrsons@gmail.com
push dateThu, 07 Apr 2016 12:57:27 +0000
reviewerskip
bugs1198518
milestone48.0a1
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