Bug 1341423 - Integrate OpenVR binding library r=daoshengmu

MozReview-Commit-ID: GaUnfbXgh9L

--HG--
rename : gfx/vr/openvr/openvr.h => gfx/vr/openvr/headers/openvr.h
extra : rebase_source : e7a0983371c1ed381ddf431e2d5a814c510d4967
This commit is contained in:
Kearwood Gilbert 2017-02-27 16:59:30 -08:00
parent 61ce5526c6
commit 8cedccb89e
30 changed files with 3328 additions and 228 deletions

View file

@ -25,6 +25,7 @@
^gfx/ots/.*
^gfx/qcms/.*
^gfx/skia/.*
^gfx/vr/openvr/.*
^gfx/webrender.*
^gfx/webrender_traits.*
^gfx/ycbcr/.*

View file

@ -453,7 +453,6 @@ private:
DECL_GFX_PREF(Once, "gfx.touch.resample.old-touch-threshold",TouchResampleOldTouchThreshold, int32_t, 17);
DECL_GFX_PREF(Once, "gfx.touch.resample.vsync-adjust", TouchVsyncSampleAdjust, int32_t, 5);
DECL_GFX_PREF(Once, "gfx.vr.openvr-runtime", VROpenVRRuntime, std::string, "");
DECL_GFX_PREF(Live, "gfx.vsync.collect-scroll-transforms", CollectScrollTransforms, bool, false);
DECL_GFX_PREF(Once, "gfx.vsync.compositor.unobserve-count", CompositorUnobserveCount, int32_t, 10);
DECL_GFX_PREF(Live, "gfx.webrender.profiler.enable", WebRenderProfilerEnabled, bool, false);

View file

@ -7,7 +7,6 @@
#include "VRManager.h"
#include "VRManagerParent.h"
#include "gfxVR.h"
#include "gfxVROpenVR.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/VRDisplay.h"
#include "mozilla/dom/GamepadEventTypes.h"
@ -18,6 +17,7 @@
#include "gfxVR.h"
#if defined(XP_WIN)
#include "gfxVROculus.h"
#include "gfxVROpenVR.h"
#endif
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
#include "gfxVROSVR.h"
@ -75,15 +75,14 @@ VRManager::VRManager()
if (mgr) {
mManagers.AppendElement(mgr);
}
#endif
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
// OpenVR is cross platform compatible
// OpenVR is cross platform compatible, but supported only on Windows for now
mgr = VRSystemManagerOpenVR::Create();
if (mgr) {
mManagers.AppendElement(mgr);
}
#endif
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
// OSVR is cross platform compatible
mgr = VRSystemManagerOSVR::Create();
if (mgr) {

View file

@ -20,10 +20,12 @@
#endif // XP_WIN
#include "gfxVROpenVR.h"
#include "VRManager.h"
#include "nsServiceManagerUtils.h"
#include "nsIScreenManager.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/dom/GamepadEventTypes.h"
#include "mozilla/dom/GamepadBinding.h"
@ -37,60 +39,11 @@ using namespace mozilla::gfx::impl;
using namespace mozilla::layers;
using namespace mozilla::dom;
namespace {
extern "C" {
typedef uint32_t (VR_CALLTYPE * pfn_VR_InitInternal)(::vr::HmdError *peError, ::vr::EVRApplicationType eApplicationType);
typedef void (VR_CALLTYPE * pfn_VR_ShutdownInternal)();
typedef bool (VR_CALLTYPE * pfn_VR_IsHmdPresent)();
typedef bool (VR_CALLTYPE * pfn_VR_IsRuntimeInstalled)();
typedef const char * (VR_CALLTYPE * pfn_VR_GetStringForHmdError)(::vr::HmdError error);
typedef void * (VR_CALLTYPE * pfn_VR_GetGenericInterface)(const char *pchInterfaceVersion, ::vr::HmdError *peError);
} // extern "C"
} // namespace
static pfn_VR_InitInternal vr_InitInternal = nullptr;
static pfn_VR_ShutdownInternal vr_ShutdownInternal = nullptr;
static pfn_VR_IsHmdPresent vr_IsHmdPresent = nullptr;
static pfn_VR_IsRuntimeInstalled vr_IsRuntimeInstalled = nullptr;
static pfn_VR_GetStringForHmdError vr_GetStringForHmdError = nullptr;
static pfn_VR_GetGenericInterface vr_GetGenericInterface = nullptr;
#define BTN_MASK_FROM_ID(_id) \
vr::ButtonMaskFromId(vr::EVRButtonId::_id)
static const uint32_t kNumOpenVRHaptcs = 1;
bool
LoadOpenVRRuntime()
{
static PRLibrary *openvrLib = nullptr;
std::string openvrPath = gfxPrefs::VROpenVRRuntime();
if (!openvrPath.c_str())
return false;
openvrLib = PR_LoadLibrary(openvrPath.c_str());
if (!openvrLib)
return false;
#define REQUIRE_FUNCTION(_x) do { \
*(void **)&vr_##_x = (void *) PR_FindSymbol(openvrLib, "VR_" #_x); \
if (!vr_##_x) { printf_stderr("VR_" #_x " symbol missing\n"); return false; } \
} while (0)
REQUIRE_FUNCTION(InitInternal);
REQUIRE_FUNCTION(ShutdownInternal);
REQUIRE_FUNCTION(IsHmdPresent);
REQUIRE_FUNCTION(IsRuntimeInstalled);
REQUIRE_FUNCTION(GetStringForHmdError);
REQUIRE_FUNCTION(GetGenericInterface);
#undef REQUIRE_FUNCTION
return true;
}
VRDisplayOpenVR::VRDisplayOpenVR(::vr::IVRSystem *aVRSystem,
::vr::IVRChaperone *aVRChaperone,
::vr::IVRCompositor *aVRCompositor)
@ -152,7 +105,7 @@ void
VRDisplayOpenVR::Destroy()
{
StopPresentation();
vr_ShutdownInternal();
::vr::VR_Shutdown();
}
void
@ -344,7 +297,7 @@ VRDisplayOpenVR::SubmitFrame(TextureSourceD3D11* aSource,
::vr::Texture_t tex;
tex.handle = (void *)aSource->GetD3D11Texture();
tex.eType = ::vr::EGraphicsAPIConvention::API_DirectX;
tex.eType = ::vr::ETextureType::TextureType_DirectX;
tex.eColorSpace = ::vr::EColorSpace::ColorSpace_Auto;
::vr::VRTextureBounds_t bounds;
@ -383,7 +336,7 @@ void
VRDisplayOpenVR::NotifyVSync()
{
// We update mIsConneced once per frame.
mDisplayInfo.mIsConnected = vr_IsHmdPresent();
mDisplayInfo.mIsConnected = ::vr::VR_IsHmdPresent();
// Make sure we respond to OpenVR events even when not presenting
PollEvents();
@ -554,11 +507,7 @@ VRSystemManagerOpenVR::Create()
return nullptr;
}
if (!LoadOpenVRRuntime()) {
return nullptr;
}
if (!vr_IsRuntimeInstalled()) {
if (!::vr::VR_IsRuntimeInstalled()) {
return nullptr;
}
@ -585,31 +534,31 @@ VRSystemManagerOpenVR::Shutdown()
void
VRSystemManagerOpenVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
{
if (!vr_IsHmdPresent()) {
if (!::vr::VR_IsHmdPresent()) {
if (mOpenVRHMD) {
mOpenVRHMD = nullptr;
}
} else if (mOpenVRHMD == nullptr) {
::vr::HmdError err;
vr_InitInternal(&err, ::vr::EVRApplicationType::VRApplication_Scene);
::vr::VR_Init(&err, ::vr::EVRApplicationType::VRApplication_Scene);
if (err) {
return;
}
::vr::IVRSystem *system = (::vr::IVRSystem *)vr_GetGenericInterface(::vr::IVRSystem_Version, &err);
::vr::IVRSystem *system = (::vr::IVRSystem *)::vr::VR_GetGenericInterface(::vr::IVRSystem_Version, &err);
if (err || !system) {
vr_ShutdownInternal();
::vr::VR_Shutdown();
return;
}
::vr::IVRChaperone *chaperone = (::vr::IVRChaperone *)vr_GetGenericInterface(::vr::IVRChaperone_Version, &err);
::vr::IVRChaperone *chaperone = (::vr::IVRChaperone *)::vr::VR_GetGenericInterface(::vr::IVRChaperone_Version, &err);
if (err || !chaperone) {
vr_ShutdownInternal();
::vr::VR_Shutdown();
return;
}
::vr::IVRCompositor *compositor = (::vr::IVRCompositor*)vr_GetGenericInterface(::vr::IVRCompositor_Version, &err);
::vr::IVRCompositor *compositor = (::vr::IVRCompositor*)::vr::VR_GetGenericInterface(::vr::IVRCompositor_Version, &err);
if (err || !compositor) {
vr_ShutdownInternal();
::vr::VR_Shutdown();
return;
}
@ -659,7 +608,7 @@ VRSystemManagerOpenVR::HandleInput()
mVRSystem->GetTrackedDeviceClass(trackedIndex)
== vr::TrackedDeviceClass_GenericTracker);
if (mVRSystem->GetControllerState(trackedIndex, &state)) {
if (mVRSystem->GetControllerState(trackedIndex, &state, sizeof(state))) {
for (uint32_t j = 0; j < vr::k_unControllerStateAxisCount; ++j) {
const uint32_t axisType = mVRSystem->GetInt32TrackedDeviceProperty(
trackedIndex,

View file

@ -14,16 +14,9 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/EnumeratedArray.h"
#include "openvr/openvr.h"
#include "openvr.h"
#include "gfxVR.h"
// OpenVR Interfaces
namespace vr {
class IVRChaperone;
class IVRCompositor;
class IVRSystem;
struct TrackedDevicePose_t;
}
#include "VRDisplayHost.h"
namespace mozilla {
namespace gfx {

View file

@ -23,7 +23,6 @@ LOCAL_INCLUDES += [
UNIFIED_SOURCES += [
'gfxVR.cpp',
'gfxVROpenVR.cpp',
'gfxVROSVR.cpp',
'gfxVRPuppet.cpp',
'ipc/VRLayerChild.cpp',
@ -37,8 +36,12 @@ UNIFIED_SOURCES += [
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
DIRS += [
'openvr',
]
SOURCES += [
'gfxVROculus.cpp',
'gfxVROpenVR.cpp',
]
IPDL_SOURCES = [

View file

@ -1,2 +0,0 @@
See https://github.com/ValveSoftware/openvr/

13
gfx/vr/openvr/README.md Normal file
View file

@ -0,0 +1,13 @@
OpenVR SDK
---
OpenVR is an API and runtime that allows access to VR hardware from multiple
vendors without requiring that applications have specific knowledge of the
hardware they are targeting. This repository is an SDK that contains the API
and samples. The runtime is under SteamVR in Tools on Steam.
### Documentation
Documentation for the API is available on the [Github Wiki](https://github.com/ValveSoftware/openvr/wiki/API-Documentation)
More information on OpenVR and SteamVR can be found on http://steamvr.com

View file

@ -0,0 +1,50 @@
This directory contains files from the OpenVR SDK, version 1.0.6.
This SDK contains the OpenVR API interface headers and functions to load the
OpenVR runtime libraries which actually implement the functionality. The
loading functions parse a .json file in a pre-defined location on the
end-user's machine to get details used to bind the correct runtime library.
The OpenVR implementation ensures forward and backwards compatibility as of
the current version.
Updated versions of the OpenVR SDK are available on Github:
https://github.com/ValveSoftware/openvr
We only use some files from the SDK:
- We strip out files such as C# headers, plain C API versions, and files
needed only when implementing OpenVR drivers.
- CMake related files, such as CMakeLists.txt are skipped as we use moz.build
files to configure the library.
- The "src/jsoncpp.cpp" file and the "src/json" directory can be skipped. OpenVR
uses the jsoncpp library, which we have already imported elsewhere.
Steps to update the library:
- Copy "README.md" from the root of the openvr repo to the "gfx/vr/openvr" directory.
- Copy "headers/openvr.h" to "gfx/vr/openvr/headers" directory. The other files
in this directory can be ignored.
- The rest of the files in the "src" directory and the "src/vrcommon" are copied
to the "gfx/vr/openvr/src" directory.
- Update "gfx/vr/openvr/moz.build" when files are added or removed.
- Update the "strtools_public.h" and "strtools_public.cpp" files, commenting out
the "Uint64ToString" function. This function name conflicts with another used
in Gecko. Fortunately, the OpenVR SDK does not use this function either.
- Replace the #define VR_INTERFACE in openvr.h to avoid extern'ing the functions.
Unlike the usual OpenVR API builds, we are not building a separate dll.
- Update this README.mozilla file with the new OpenVR SDK version and any
additional steps needed for newer versions.
- Ensure that any changes made within the OpenVR files have comments including
the string "Mozilla" and reference this file for easy identification.

View file

@ -15,6 +15,16 @@
#ifndef _INCLUDE_VRTYPES_H
#define _INCLUDE_VRTYPES_H
// Forward declarations to avoid requiring vulkan.h
struct VkDevice_T;
struct VkPhysicalDevice_T;
struct VkInstance_T;
struct VkQueue_T;
// Forward declarations to avoid requiring d3d12.h
struct ID3D12Resource;
struct ID3D12CommandQueue;
namespace vr
{
@ -105,10 +115,13 @@ enum EVREye
Eye_Right = 1
};
enum EGraphicsAPIConvention
enum ETextureType
{
API_DirectX = 0, // Normalized Z goes from 0 at the viewer to 1 at the far clip plane
API_OpenGL = 1, // Normalized Z goes from 1 at the viewer to -1 at the far clip plane
TextureType_DirectX = 0, // Handle is an ID3D11Texture
TextureType_OpenGL = 1, // Handle is an OpenGL texture name or an OpenGL render buffer name, depending on submit flags
TextureType_Vulkan = 2, // Handle is a pointer to a VRVulkanTextureData_t structure
TextureType_IOSurface = 3, // Handle is a macOS cross-process-sharable IOSurface
TextureType_DirectX12 = 4, // Handle is a pointer to a D3D12TextureData_t structure
};
enum EColorSpace
@ -120,11 +133,15 @@ enum EColorSpace
struct Texture_t
{
void* handle; // Native d3d texture pointer or GL texture id.
EGraphicsAPIConvention eType;
void* handle; // See ETextureType definition above
ETextureType eType;
EColorSpace eColorSpace;
};
// Handle to a shared texture (HANDLE on Windows obtained using OpenSharedResource).
typedef uint64_t SharedTextureHandle_t;
#define INVALID_SHARED_TEXTURE_HANDLE ((vr::SharedTextureHandle_t)0)
enum ETrackingResult
{
TrackingResult_Uninitialized = 1,
@ -136,7 +153,6 @@ enum ETrackingResult
TrackingResult_Running_OutOfRange = 201,
};
static const uint32_t k_unTrackingStringSize = 32;
static const uint32_t k_unMaxDriverDebugResponseSize = 32768;
/** Used to pass device IDs to API calls */
@ -154,8 +170,6 @@ enum ETrackedDeviceClass
TrackedDeviceClass_Controller = 2, // Tracked controllers
TrackedDeviceClass_GenericTracker = 3, // Generic trackers, similar to controllers
TrackedDeviceClass_TrackingReference = 4, // Camera and base stations that serve as tracking reference points
TrackedDeviceClass_Other = 1000,
};
@ -188,14 +202,40 @@ enum ETrackingUniverseOrigin
{
TrackingUniverseSeated = 0, // Poses are provided relative to the seated zero pose
TrackingUniverseStanding = 1, // Poses are provided relative to the safe bounds configured by the user
TrackingUniverseRawAndUncalibrated = 2, // Poses are provided in the coordinate system defined by the driver. You probably don't want this one.
TrackingUniverseRawAndUncalibrated = 2, // Poses are provided in the coordinate system defined by the driver. It has Y up and is unified for devices of the same driver. You usually don't want this one.
};
// Refers to a single container of properties
typedef uint64_t PropertyContainerHandle_t;
typedef uint32_t PropertyTypeTag_t;
static const PropertyContainerHandle_t k_ulInvalidPropertyContainer = 0;
static const PropertyTypeTag_t k_unInvalidPropertyTag = 0;
// Use these tags to set/get common types as struct properties
static const PropertyTypeTag_t k_unFloatPropertyTag = 1;
static const PropertyTypeTag_t k_unInt32PropertyTag = 2;
static const PropertyTypeTag_t k_unUint64PropertyTag = 3;
static const PropertyTypeTag_t k_unBoolPropertyTag = 4;
static const PropertyTypeTag_t k_unStringPropertyTag = 5;
static const PropertyTypeTag_t k_unHmdMatrix34PropertyTag = 20;
static const PropertyTypeTag_t k_unHmdMatrix44PropertyTag = 21;
static const PropertyTypeTag_t k_unHmdVector3PropertyTag = 22;
static const PropertyTypeTag_t k_unHmdVector4PropertyTag = 23;
static const PropertyTypeTag_t k_unHiddenAreaPropertyTag = 30;
static const PropertyTypeTag_t k_unOpenVRInternalReserved_Start = 1000;
static const PropertyTypeTag_t k_unOpenVRInternalReserved_End = 10000;
/** Each entry in this enum represents a property that can be retrieved about a
* tracked device. Many fields are only valid for one ETrackedDeviceClass. */
enum ETrackedDeviceProperty
{
Prop_Invalid = 0,
// general properties that apply to all device classes
Prop_TrackingSystemName_String = 1000,
Prop_ModelNumber_String = 1001,
@ -230,6 +270,9 @@ enum ETrackedDeviceProperty
Prop_HasCamera_Bool = 1030,
Prop_DriverVersion_String = 1031,
Prop_Firmware_ForceUpdateRequired_Bool = 1032,
Prop_ViveSystemButtonFixRequired_Bool = 1033,
Prop_ParentDriver_Uint64 = 1034,
// Properties that are unique to TrackedDeviceClass_HMD
Prop_ReportsTimeSinceVSync_Bool = 2000,
@ -269,6 +312,12 @@ enum ETrackedDeviceProperty
Prop_ScreenshotHorizontalFieldOfViewDegrees_Float = 2034,
Prop_ScreenshotVerticalFieldOfViewDegrees_Float = 2035,
Prop_DisplaySuppressed_Bool = 2036,
Prop_DisplayAllowNightMode_Bool = 2037,
Prop_DisplayMCImageWidth_Int32 = 2038,
Prop_DisplayMCImageHeight_Int32 = 2039,
Prop_DisplayMCImageNumChannels_Int32 = 2040,
Prop_DisplayMCImageData_Binary = 2041,
Prop_UsesDriverDirectMode_Bool = 2042,
// Properties that are unique to TrackedDeviceClass_Controller
Prop_AttachedDeviceId_String = 3000,
@ -289,6 +338,25 @@ enum ETrackedDeviceProperty
Prop_TrackingRangeMaximumMeters_Float = 4005,
Prop_ModeLabel_String = 4006,
// Properties that are used for user interface like icons names
Prop_IconPathName_String = 5000, // usually a directory named "icons"
Prop_NamedIconPathDeviceOff_String = 5001, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
Prop_NamedIconPathDeviceSearching_String = 5002, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
Prop_NamedIconPathDeviceSearchingAlert_String = 5003, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
Prop_NamedIconPathDeviceReady_String = 5004, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
Prop_NamedIconPathDeviceReadyAlert_String = 5005, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
Prop_NamedIconPathDeviceNotReady_String = 5006, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
Prop_NamedIconPathDeviceStandby_String = 5007, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
Prop_NamedIconPathDeviceAlertLow_String = 5008, // PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others
// Properties that are used by helpers, but are opaque to applications
Prop_DisplayHiddenArea_Binary_Start = 5100,
Prop_DisplayHiddenArea_Binary_End = 5150,
// Properties that are unique to drivers
Prop_UserConfigPath_String = 6000,
Prop_InstallPath_String = 6001,
// Vendors are free to expose private debug data in this reserved region
Prop_VendorSpecific_Reserved_Start = 10000,
Prop_VendorSpecific_Reserved_End = 10999,
@ -304,12 +372,14 @@ enum ETrackedPropertyError
TrackedProp_WrongDataType = 1,
TrackedProp_WrongDeviceClass = 2,
TrackedProp_BufferTooSmall = 3,
TrackedProp_UnknownProperty = 4,
TrackedProp_UnknownProperty = 4, // Driver has not set the property (and may not ever).
TrackedProp_InvalidDevice = 5,
TrackedProp_CouldNotContactServer = 6,
TrackedProp_ValueNotProvidedByDevice = 7,
TrackedProp_StringExceedsMaximumLength = 8,
TrackedProp_NotYetAvailable = 9, // The property value isn't known yet, but is expected soon. Call again later.
TrackedProp_PermissionDenied = 10,
TrackedProp_InvalidOperation = 11,
};
/** Allows the application to control what part of the provided texture will be used in the
@ -334,8 +404,32 @@ enum EVRSubmitFlags
// If the texture pointer passed in is actually a renderbuffer (e.g. for MSAA in OpenGL) then set this flag.
Submit_GlRenderBuffer = 0x02,
// Do not use
Submit_Reserved = 0x04,
};
/** Data required for passing Vulkan textures to IVRCompositor::Submit.
* Be sure to call OpenVR_Shutdown before destroying these resources. */
struct VRVulkanTextureData_t
{
uint64_t m_nImage; // VkImage
VkDevice_T *m_pDevice;
VkPhysicalDevice_T *m_pPhysicalDevice;
VkInstance_T *m_pInstance;
VkQueue_T *m_pQueue;
uint32_t m_nQueueFamilyIndex;
uint32_t m_nWidth, m_nHeight, m_nFormat, m_nSampleCount;
};
/** Data required for passing D3D12 textures to IVRCompositor::Submit.
* Be sure to call OpenVR_Shutdown before destroying these resources. */
struct D3D12TextureData_t
{
ID3D12Resource *m_pResource;
ID3D12CommandQueue *m_pCommandQueue;
uint32_t m_nNodeMask;
};
/** Status of the overall system or tracked objects */
enum EVRState
@ -366,6 +460,8 @@ enum EVREventType
VREvent_LeaveStandbyMode = 107,
VREvent_TrackedDeviceRoleChanged = 108,
VREvent_WatchdogWakeUpRequested = 109,
VREvent_LensDistortionChanged = 110,
VREvent_PropertyChanged = 111,
VREvent_ButtonPress = 200, // data is controller
VREvent_ButtonUnpress = 201, // data is controller
@ -411,6 +507,7 @@ enum EVREventType
VREvent_DashboardGuideButtonUp = 515,
VREvent_ScreenshotTriggered = 516, // Screenshot button combo was pressed, Dashboard should request a screenshot
VREvent_ImageFailed = 517, // Sent to overlays when a SetOverlayRaw or SetOverlayfromFail fails to load
VREvent_DashboardOverlayCreated = 518,
// Screenshot API
VREvent_RequestScreenshot = 520, // Sent by vrclient application to compositor to take a screenshot
@ -419,6 +516,8 @@ enum EVREventType
VREvent_SubmitScreenshotToDashboard = 523, // Sent by compositor to the dashboard that a completed screenshot was submitted
VREvent_ScreenshotProgressToDashboard = 524, // Sent by compositor to the dashboard that a completed screenshot was submitted
VREvent_PrimaryDashboardDeviceChanged = 525,
VREvent_Notification_Shown = 600,
VREvent_Notification_Hidden = 601,
VREvent_Notification_BeginInteraction = 602,
@ -443,6 +542,7 @@ enum EVREventType
VREvent_ReprojectionSettingHasChanged = 852,
VREvent_ModelSkinSettingsHaveChanged = 853,
VREvent_EnvironmentSettingsHaveChanged = 854,
VREvent_PowerSettingsHaveChanged = 855,
VREvent_StatusUpdate = 900,
@ -460,6 +560,7 @@ enum EVREventType
VREvent_ApplicationTransitionNewAppStarted = 1302,
VREvent_ApplicationListUpdated = 1303,
VREvent_ApplicationMimeTypeLoad = 1304,
VREvent_ApplicationTransitionNewAppLaunchComplete = 1305,
VREvent_Compositor_MirrorWindowShown = 1400,
VREvent_Compositor_MirrorWindowHidden = 1401,
@ -470,11 +571,14 @@ enum EVREventType
VREvent_TrackedCamera_StopVideoStream = 1501,
VREvent_TrackedCamera_PauseVideoStream = 1502,
VREvent_TrackedCamera_ResumeVideoStream = 1503,
VREvent_TrackedCamera_EditingSurface = 1550,
VREvent_PerformanceTest_EnableCapture = 1600,
VREvent_PerformanceTest_DisableCapture = 1601,
VREvent_PerformanceTest_FidelityLevel = 1602,
VREvent_MessageOverlay_Closed = 1650,
// Vendors are free to expose private events in this reserved region
VREvent_VendorSpecific_Reserved_Start = 10000,
VREvent_VendorSpecific_Reserved_End = 19999,
@ -504,6 +608,8 @@ enum EVRButtonId
k_EButton_DPad_Down = 6,
k_EButton_A = 7,
k_EButton_ProximitySensor = 31,
k_EButton_Axis0 = 32,
k_EButton_Axis1 = 33,
k_EButton_Axis2 = 34,
@ -652,7 +758,24 @@ struct VREvent_ApplicationLaunch_t
uint32_t unArgsHandle;
};
/** If you change this you must manually update openvr_interop.cs.py */
struct VREvent_EditingCameraSurface_t
{
uint64_t overlayHandle;
uint32_t nVisualMode;
};
struct VREvent_MessageOverlay_t
{
uint32_t unVRMessageOverlayResponse; // vr::VRMessageOverlayResponse enum
};
struct VREvent_Property_t
{
PropertyContainerHandle_t container;
ETrackedDeviceProperty prop;
};
/** NOTE!!! If you change this you MUST manually update openvr_interop.cs.py */
typedef union
{
VREvent_Reserved_t reserved;
@ -672,6 +795,9 @@ typedef union
VREvent_Screenshot_t screenshot;
VREvent_ScreenshotProgress_t screenshotProgress;
VREvent_ApplicationLaunch_t applicationLaunch;
VREvent_EditingCameraSurface_t cameraSurface;
VREvent_MessageOverlay_t messageOverlay;
VREvent_Property_t property;
} VREvent_Data_t;
/** An event posted by the server to all running applications */
@ -698,6 +824,16 @@ struct HiddenAreaMesh_t
};
enum EHiddenAreaMeshType
{
k_eHiddenAreaMesh_Standard = 0,
k_eHiddenAreaMesh_Inverse = 1,
k_eHiddenAreaMesh_LineLoop = 2,
k_eHiddenAreaMesh_Max = 3,
};
/** Identifies what kind of axis is on the controller at index n. Read this type
* with pVRSystem->Get( nControllerDeviceIndex, Prop_Axis0Type_Int32 + n );
*/
@ -799,8 +935,10 @@ enum EVROverlayError
VROverlayError_RequestFailed = 23,
VROverlayError_InvalidTexture = 24,
VROverlayError_UnableToLoadFile = 25,
VROVerlayError_KeyboardAlreadyInUse = 26,
VROverlayError_KeyboardAlreadyInUse = 26,
VROverlayError_NoNeighbor = 27,
VROverlayError_TooManyMaskPrimitives = 29,
VROverlayError_BadMaskPrimitive = 30,
};
/** enum values to pass in to VR_Init to identify whether the application will
@ -882,6 +1020,8 @@ enum EVRInitError
VRInitError_Init_InvalidApplicationType = 130,
VRInitError_Init_NotAvailableToWatchdogApps = 131,
VRInitError_Init_WatchdogDisabledInSettings = 132,
VRInitError_Init_VRDashboardNotFound = 133,
VRInitError_Init_VRDashboardStartupFailed = 134,
VRInitError_Driver_Failed = 200,
VRInitError_Driver_Unknown = 201,
@ -1000,6 +1140,12 @@ static const uint32_t k_unScreenshotHandleInvalid = 0;
#pragma pack( pop )
// Mozilla changed VR_INTERFACE. We don't want to extern the API functions.
// See README.mozilla
#define VR_INTERFACE
/*
// figure out how to import from the VR API dll
#if defined(_WIN32)
@ -1020,7 +1166,7 @@ static const uint32_t k_unScreenshotHandleInvalid = 0;
#else
#error "Unsupported Platform."
#endif
*/
#if defined( _WIN32 )
#define VR_CALLTYPE __cdecl
@ -1069,15 +1215,16 @@ public:
virtual void GetRecommendedRenderTargetSize( uint32_t *pnWidth, uint32_t *pnHeight ) = 0;
/** The projection matrix for the specified eye */
virtual HmdMatrix44_t GetProjectionMatrix( EVREye eEye, float fNearZ, float fFarZ, EGraphicsAPIConvention eProjType ) = 0;
virtual HmdMatrix44_t GetProjectionMatrix( EVREye eEye, float fNearZ, float fFarZ ) = 0;
/** The components necessary to build your own projection matrix in case your
* application is doing something fancy like infinite Z */
virtual void GetProjectionRaw( EVREye eEye, float *pfLeft, float *pfRight, float *pfTop, float *pfBottom ) = 0;
/** Returns the result of the distortion function for the specified eye and input UVs. UVs go from 0,0 in
* the upper left of that eye's viewport and 1,1 in the lower right of that eye's viewport. */
virtual DistortionCoordinates_t ComputeDistortion( EVREye eEye, float fU, float fV ) = 0;
/** Gets the result of the distortion function for the specified eye and input UVs. UVs go from 0,0 in
* the upper left of that eye's viewport and 1,1 in the lower right of that eye's viewport.
* Returns true for success. Otherwise, returns false, and distortion coordinates are not suitable. */
virtual bool ComputeDistortion( EVREye eEye, float fU, float fV, DistortionCoordinates_t *pDistortionCoordinates ) = 0;
/** Returns the transform from eye space to the head space. Eye space is the per-eye flavor of head
* space that provides stereo disparity. Instead of Model * View * Projection the sequence is Model * View * Eye^-1 * Projection.
@ -1098,8 +1245,8 @@ public:
virtual int32_t GetD3D9AdapterIndex() = 0;
/** [D3D10/11 Only]
* Returns the adapter index and output index that the user should pass into EnumAdapters and EnumOutputs
* to create the device and swap chain in DX10 and DX11. If an error occurs both indices will be set to -1.
* Returns the adapter index that the user should pass into EnumAdapters to create the device
* and swap chain in DX10 and DX11. If an error occurs the index will be set to -1.
*/
virtual void GetDXGIOutputInfo( int32_t *pnAdapterIndex ) = 0;
@ -1211,7 +1358,7 @@ public:
/** Returns a string property. If the device index is not valid or the property is not a string type this function will
* return 0. Otherwise it returns the length of the number of bytes necessary to hold this string including the trailing
* null. Strings will generally fit in buffers of k_unTrackingStringSize characters. */
* null. Strings will always fit in buffers of k_unMaxPropertyStringSize characters. */
virtual uint32_t GetStringTrackedDeviceProperty( vr::TrackedDeviceIndex_t unDeviceIndex, ETrackedDeviceProperty prop, VR_OUT_STRING() char *pchValue, uint32_t unBufferSize, ETrackedPropertyError *pError = 0L ) = 0;
/** returns a string that corresponds with the specified property error. The string will be the name
@ -1239,14 +1386,15 @@ public:
// Rendering helper methods
// ------------------------------------
/** Returns the stencil mesh information for the current HMD. If this HMD does not have a stencil mesh the vertex data and count will be
* NULL and 0 respectively. This mesh is meant to be rendered into the stencil buffer (or into the depth buffer setting nearz) before rendering
* each eye's view. The pixels covered by this mesh will never be seen by the user after the lens distortion is applied and based on visibility to the panels.
* This will improve perf by letting the GPU early-reject pixels the user will never see before running the pixel shader.
/** Returns the hidden area mesh for the current HMD. The pixels covered by this mesh will never be seen by the user after the lens distortion is
* applied based on visibility to the panels. If this HMD does not have a hidden area mesh, the vertex data and count will be NULL and 0 respectively.
* This mesh is meant to be rendered into the stencil buffer (or into the depth buffer setting nearz) before rendering each eye's view.
* This will improve performance by letting the GPU early-reject pixels the user will never see before running the pixel shader.
* NOTE: Render this mesh with backface culling disabled since the winding order of the vertices can be different per-HMD or per-eye.
* Setting the bInverse argument to true will produce the visible area mesh that is commonly used in place of full-screen quads. The visible area mesh covers all of the pixels the hidden area mesh does not cover.
* Setting the bLineLoop argument will return a line loop of vertices in HiddenAreaMesh_t->pVertexData with HiddenAreaMesh_t->unTriangleCount set to the number of vertices.
*/
virtual HiddenAreaMesh_t GetHiddenAreaMesh( EVREye eEye ) = 0;
virtual HiddenAreaMesh_t GetHiddenAreaMesh( EVREye eEye, EHiddenAreaMeshType type = k_eHiddenAreaMesh_Standard ) = 0;
// ------------------------------------
// Controller methods
@ -1254,12 +1402,12 @@ public:
/** Fills the supplied struct with the current state of the controller. Returns false if the controller index
* is invalid. */
virtual bool GetControllerState( vr::TrackedDeviceIndex_t unControllerDeviceIndex, vr::VRControllerState_t *pControllerState ) = 0;
virtual bool GetControllerState( vr::TrackedDeviceIndex_t unControllerDeviceIndex, vr::VRControllerState_t *pControllerState, uint32_t unControllerStateSize ) = 0;
/** fills the supplied struct with the current state of the controller and the provided pose with the pose of
* the controller when the controller state was updated most recently. Use this form if you need a precise controller
* pose as input to your application when the user presses or releases a button. */
virtual bool GetControllerStateWithPose( ETrackingUniverseOrigin eOrigin, vr::TrackedDeviceIndex_t unControllerDeviceIndex, vr::VRControllerState_t *pControllerState, TrackedDevicePose_t *pTrackedDevicePose ) = 0;
virtual bool GetControllerStateWithPose( ETrackingUniverseOrigin eOrigin, vr::TrackedDeviceIndex_t unControllerDeviceIndex, vr::VRControllerState_t *pControllerState, uint32_t unControllerStateSize, TrackedDevicePose_t *pTrackedDevicePose ) = 0;
/** Trigger a single haptic pulse on a controller. After this call the application may not trigger another haptic pulse on this controller
* and axis combination for 5ms. */
@ -1292,7 +1440,6 @@ public:
* The size of the response including its terminating null is returned. */
virtual uint32_t DriverDebugRequest( vr::TrackedDeviceIndex_t unDeviceIndex, const char *pchRequest, char *pchResponseBuffer, uint32_t unResponseBufferSize ) = 0;
// ------------------------------------
// Firmware methods
// ------------------------------------
@ -1304,7 +1451,6 @@ public:
* Prop_Firmware_ManualUpdateURL_String should point to an URL describing the manual update process */
virtual vr::EVRFirmwareError PerformFirmwareUpdate( vr::TrackedDeviceIndex_t unDeviceIndex ) = 0;
// ------------------------------------
// Application life cycle methods
// ------------------------------------
@ -1320,7 +1466,7 @@ public:
};
static const char * const IVRSystem_Version = "IVRSystem_012";
static const char * const IVRSystem_Version = "IVRSystem_015";
}
@ -1378,6 +1524,7 @@ namespace vr
VRApplicationProperty_IsDashboardOverlay_Bool = 60,
VRApplicationProperty_IsTemplate_Bool = 61,
VRApplicationProperty_IsInstanced_Bool = 62,
VRApplicationProperty_IsInternal_Bool = 63,
VRApplicationProperty_LastLaunchTime_Uint64 = 70,
};
@ -1399,6 +1546,10 @@ namespace vr
const char *pchValue;
};
/** Currently recognized mime types */
static const char * const k_pch_MimeType_HomeApp = "vr/home";
static const char * const k_pch_MimeType_GameTheater = "vr/game_theater";
class IVRApplications
{
public:
@ -1421,7 +1572,7 @@ namespace vr
/** Returns the key of the specified application. The index is at least 0 and is less than the return
* value of GetApplicationCount(). The buffer should be at least k_unMaxApplicationKeyLength in order to
* fit the key. */
virtual EVRApplicationError GetApplicationKeyByIndex( uint32_t unApplicationIndex, char *pchAppKeyBuffer, uint32_t unAppKeyBufferLen ) = 0;
virtual EVRApplicationError GetApplicationKeyByIndex( uint32_t unApplicationIndex, VR_OUT_STRING() char *pchAppKeyBuffer, uint32_t unAppKeyBufferLen ) = 0;
/** Returns the key of the application for the specified Process Id. The buffer should be at least
* k_unMaxApplicationKeyLength in order to fit the key. */
@ -1461,7 +1612,7 @@ namespace vr
// --------------- Application properties --------------- //
/** Returns a value for an application property. The required buffer size to fit this value will be returned. */
virtual uint32_t GetApplicationPropertyString( const char *pchAppKey, EVRApplicationProperty eProperty, char *pchPropertyValueBuffer, uint32_t unPropertyValueBufferLen, EVRApplicationError *peError = nullptr ) = 0;
virtual uint32_t GetApplicationPropertyString( const char *pchAppKey, EVRApplicationProperty eProperty, VR_OUT_STRING() char *pchPropertyValueBuffer, uint32_t unPropertyValueBufferLen, EVRApplicationError *peError = nullptr ) = 0;
/** Returns a bool value for an application property. Returns false in all error cases. */
virtual bool GetApplicationPropertyBool( const char *pchAppKey, EVRApplicationProperty eProperty, EVRApplicationError *peError = nullptr ) = 0;
@ -1521,6 +1672,11 @@ namespace vr
* If working directory is NULL or "" the directory portion of the binary path will be
* the working directory. */
virtual EVRApplicationError LaunchInternalProcess( const char *pchBinaryPath, const char *pchArguments, const char *pchWorkingDirectory ) = 0;
/** Returns the current scene process ID according to the application system. A scene process will get scene
* focus once it starts rendering, but it will appear here once it calls VR_Init with the Scene application
* type. */
virtual uint32_t GetCurrentSceneProcessId() = 0;
};
static const char * const IVRApplications_Version = "IVRApplications_006";
@ -1536,6 +1692,8 @@ namespace vr
VRSettingsError_IPCFailed = 1,
VRSettingsError_WriteFailed = 2,
VRSettingsError_ReadFailed = 3,
VRSettingsError_JsonParseFailed = 4,
VRSettingsError_UnsetSettingHasNoDefault = 5, // This will be returned if the setting does not appear in the appropriate default file and has not been set
};
// The maximum length of a settings key
@ -1549,25 +1707,27 @@ namespace vr
// Returns true if file sync occurred (force or settings dirty)
virtual bool Sync( bool bForce = false, EVRSettingsError *peError = nullptr ) = 0;
virtual bool GetBool( const char *pchSection, const char *pchSettingsKey, bool bDefaultValue, EVRSettingsError *peError = nullptr ) = 0;
virtual void SetBool( const char *pchSection, const char *pchSettingsKey, bool bValue, EVRSettingsError *peError = nullptr ) = 0;
virtual int32_t GetInt32( const char *pchSection, const char *pchSettingsKey, int32_t nDefaultValue, EVRSettingsError *peError = nullptr ) = 0;
virtual void SetInt32( const char *pchSection, const char *pchSettingsKey, int32_t nValue, EVRSettingsError *peError = nullptr ) = 0;
virtual float GetFloat( const char *pchSection, const char *pchSettingsKey, float flDefaultValue, EVRSettingsError *peError = nullptr ) = 0;
virtual void SetFloat( const char *pchSection, const char *pchSettingsKey, float flValue, EVRSettingsError *peError = nullptr ) = 0;
virtual void GetString( const char *pchSection, const char *pchSettingsKey, VR_OUT_STRING() char *pchValue, uint32_t unValueLen, const char *pchDefaultValue, EVRSettingsError *peError = nullptr ) = 0;
virtual void SetString( const char *pchSection, const char *pchSettingsKey, const char *pchValue, EVRSettingsError *peError = nullptr ) = 0;
// Users of the system need to provide a proper default in default.vrsettings in the resources/settings/ directory
// of either the runtime or the driver_xxx directory. Otherwise the default will be false, 0, 0.0 or ""
virtual bool GetBool( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0;
virtual int32_t GetInt32( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0;
virtual float GetFloat( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0;
virtual void GetString( const char *pchSection, const char *pchSettingsKey, VR_OUT_STRING() char *pchValue, uint32_t unValueLen, EVRSettingsError *peError = nullptr ) = 0;
virtual void RemoveSection( const char *pchSection, EVRSettingsError *peError = nullptr ) = 0;
virtual void RemoveKeyInSection( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0;
};
//-----------------------------------------------------------------------------
static const char * const IVRSettings_Version = "IVRSettings_001";
static const char * const IVRSettings_Version = "IVRSettings_002";
//-----------------------------------------------------------------------------
// steamvr keys
static const char * const k_pch_SteamVR_Section = "steamvr";
static const char * const k_pch_SteamVR_RequireHmd_String = "requireHmd";
static const char * const k_pch_SteamVR_ForcedDriverKey_String = "forcedDriver";
@ -1581,16 +1741,13 @@ namespace vr
static const char * const k_pch_SteamVR_LogLevel_Int32 = "loglevel";
static const char * const k_pch_SteamVR_IPD_Float = "ipd";
static const char * const k_pch_SteamVR_Background_String = "background";
static const char * const k_pch_SteamVR_BackgroundUseDomeProjection_Bool = "backgroundUseDomeProjection";
static const char * const k_pch_SteamVR_BackgroundCameraHeight_Float = "backgroundCameraHeight";
static const char * const k_pch_SteamVR_BackgroundDomeRadius_Float = "backgroundDomeRadius";
static const char * const k_pch_SteamVR_Environment_String = "environment";
static const char * const k_pch_SteamVR_GridColor_String = "gridColor";
static const char * const k_pch_SteamVR_PlayAreaColor_String = "playAreaColor";
static const char * const k_pch_SteamVR_ShowStage_Bool = "showStage";
static const char * const k_pch_SteamVR_ActivateMultipleDrivers_Bool = "activateMultipleDrivers";
static const char * const k_pch_SteamVR_PowerOffOnExit_Bool = "powerOffOnExit";
static const char * const k_pch_SteamVR_StandbyAppRunningTimeout_Float = "standbyAppRunningTimeout";
static const char * const k_pch_SteamVR_StandbyNoAppTimeout_Float = "standbyNoAppTimeout";
static const char * const k_pch_SteamVR_DirectMode_Bool = "directMode";
static const char * const k_pch_SteamVR_DirectModeEdidVid_Int32 = "directModeEdidVid";
static const char * const k_pch_SteamVR_DirectModeEdidPid_Int32 = "directModeEdidPid";
@ -1599,35 +1756,35 @@ namespace vr
static const char * const k_pch_SteamVR_BaseStationPowerManagement_Bool = "basestationPowerManagement";
static const char * const k_pch_SteamVR_NeverKillProcesses_Bool = "neverKillProcesses";
static const char * const k_pch_SteamVR_RenderTargetMultiplier_Float = "renderTargetMultiplier";
static const char * const k_pch_SteamVR_AllowReprojection_Bool = "allowReprojection";
static const char * const k_pch_SteamVR_AllowAsyncReprojection_Bool = "allowAsyncReprojection";
static const char * const k_pch_SteamVR_AllowReprojection_Bool = "allowInterleavedReprojection";
static const char * const k_pch_SteamVR_ForceReprojection_Bool = "forceReprojection";
static const char * const k_pch_SteamVR_ForceFadeOnBadTracking_Bool = "forceFadeOnBadTracking";
static const char * const k_pch_SteamVR_DefaultMirrorView_Int32 = "defaultMirrorView";
static const char * const k_pch_SteamVR_ShowMirrorView_Bool = "showMirrorView";
static const char * const k_pch_SteamVR_MirrorViewGeometry_String = "mirrorViewGeometry";
static const char * const k_pch_SteamVR_StartMonitorFromAppLaunch = "startMonitorFromAppLaunch";
static const char * const k_pch_SteamVR_AutoLaunchSteamVROnButtonPress = "autoLaunchSteamVROnButtonPress";
static const char * const k_pch_SteamVR_UseGenericGraphcisDevice_Bool = "useGenericGraphicsDevice";
static const char * const k_pch_SteamVR_StartCompositorFromAppLaunch_Bool = "startCompositorFromAppLaunch";
static const char * const k_pch_SteamVR_StartDashboardFromAppLaunch_Bool = "startDashboardFromAppLaunch";
static const char * const k_pch_SteamVR_StartOverlayAppsFromDashboard_Bool = "startOverlayAppsFromDashboard";
static const char * const k_pch_SteamVR_EnableHomeApp = "enableHomeApp";
static const char * const k_pch_SteamVR_SetInitialDefaultHomeApp = "setInitialDefaultHomeApp";
static const char * const k_pch_SteamVR_CycleBackgroundImageTimeSec_Int32 = "CycleBackgroundImageTimeSec";
static const char * const k_pch_SteamVR_RetailDemo_Bool = "retailDemo";
static const char * const k_pch_SteamVR_IpdOffset_Float = "ipdOffset";
//-----------------------------------------------------------------------------
// lighthouse keys
static const char * const k_pch_Lighthouse_Section = "driver_lighthouse";
static const char * const k_pch_Lighthouse_DisableIMU_Bool = "disableimu";
static const char * const k_pch_Lighthouse_UseDisambiguation_String = "usedisambiguation";
static const char * const k_pch_Lighthouse_DisambiguationDebug_Int32 = "disambiguationdebug";
static const char * const k_pch_Lighthouse_PrimaryBasestation_Int32 = "primarybasestation";
static const char * const k_pch_Lighthouse_LighthouseName_String = "lighthousename";
static const char * const k_pch_Lighthouse_MaxIncidenceAngleDegrees_Float = "maxincidenceangledegrees";
static const char * const k_pch_Lighthouse_UseLighthouseDirect_Bool = "uselighthousedirect";
static const char * const k_pch_Lighthouse_DBHistory_Bool = "dbhistory";
//-----------------------------------------------------------------------------
// null keys
static const char * const k_pch_Null_Section = "driver_null";
static const char * const k_pch_Null_EnableNullDriver_Bool = "enable";
static const char * const k_pch_Null_SerialNumber_String = "serialNumber";
static const char * const k_pch_Null_ModelNumber_String = "modelNumber";
static const char * const k_pch_Null_WindowX_Int32 = "windowX";
@ -1643,6 +1800,7 @@ namespace vr
// user interface keys
static const char * const k_pch_UserInterface_Section = "userinterface";
static const char * const k_pch_UserInterface_StatusAlwaysOnTop_Bool = "StatusAlwaysOnTop";
static const char * const k_pch_UserInterface_MinimizeToTray_Bool = "MinimizeToTray";
static const char * const k_pch_UserInterface_Screenshots_Bool = "screenshots";
static const char * const k_pch_UserInterface_ScreenshotType_Int = "screenshotType";
@ -1696,6 +1854,7 @@ namespace vr
static const char * const k_pch_Camera_BoundsColorGammaG_Int32 = "cameraBoundsColorGammaG";
static const char * const k_pch_Camera_BoundsColorGammaB_Int32 = "cameraBoundsColorGammaB";
static const char * const k_pch_Camera_BoundsColorGammaA_Int32 = "cameraBoundsColorGammaA";
static const char * const k_pch_Camera_BoundsStrength_Int32 = "cameraBoundsStrength";
//-----------------------------------------------------------------------------
// audio keys
@ -1707,10 +1866,29 @@ namespace vr
static const char * const k_pch_audio_OffRecordDevice_String = "offRecordDevice";
static const char * const k_pch_audio_VIVEHDMIGain = "viveHDMIGain";
//-----------------------------------------------------------------------------
// power management keys
static const char * const k_pch_Power_Section = "power";
static const char * const k_pch_Power_PowerOffOnExit_Bool = "powerOffOnExit";
static const char * const k_pch_Power_TurnOffScreensTimeout_Float = "turnOffScreensTimeout";
static const char * const k_pch_Power_TurnOffControllersTimeout_Float = "turnOffControllersTimeout";
static const char * const k_pch_Power_ReturnToWatchdogTimeout_Float = "returnToWatchdogTimeout";
static const char * const k_pch_Power_AutoLaunchSteamVROnButtonPress = "autoLaunchSteamVROnButtonPress";
//-----------------------------------------------------------------------------
// dashboard keys
static const char * const k_pch_Dashboard_Section = "dashboard";
static const char * const k_pch_Dashboard_EnableDashboard_Bool = "enableDashboard";
static const char * const k_pch_Dashboard_ArcadeMode_Bool = "arcadeMode";
//-----------------------------------------------------------------------------
// model skin keys
static const char * const k_pch_modelskin_Section = "modelskins";
//-----------------------------------------------------------------------------
// driver keys - These could be checked in any driver_<name> section
static const char * const k_pch_Driver_Enable_Bool = "enable";
} // namespace vr
// ivrchaperone.h
@ -1741,7 +1919,7 @@ enum ChaperoneCalibrationState
// Errors
ChaperoneCalibrationState_Error = 200, // The UniverseID is invalid
ChaperoneCalibrationState_Error_BaseStationUninitalized = 201, // Tracking center hasn't be calibrated for at least one of the base stations
ChaperoneCalibrationState_Error_BaseStationUninitialized = 201, // Tracking center hasn't be calibrated for at least one of the base stations
ChaperoneCalibrationState_Error_BaseStationConflict = 202, // Tracking center is calibrated, but base stations disagree on the tracking space
ChaperoneCalibrationState_Error_PlayAreaInvalid = 203, // Play Area hasn't been calibrated for the current tracking center
ChaperoneCalibrationState_Error_CollisionBoundsInvalid = 204, // Collision Bounds haven't been calibrated for the current tracking center
@ -1911,10 +2089,17 @@ enum EVRCompositorError
VRCompositorError_TextureUsesUnsupportedFormat = 105,
VRCompositorError_SharedTexturesNotSupported = 106,
VRCompositorError_IndexOutOfRange = 107,
VRCompositorError_AlreadySubmitted = 108,
};
const uint32_t VRCompositor_ReprojectionReason_Cpu = 0x01;
const uint32_t VRCompositor_ReprojectionReason_Gpu = 0x02;
const uint32_t VRCompositor_ReprojectionAsync = 0x04; // This flag indicates the async reprojection mode is active,
// but does not indicate if reprojection actually happened or not.
// Use the ReprojectionReason flags above to check if reprojection
// was actually applied (i.e. scene texture was reused).
// NumFramePresents > 1 also indicates the scene texture was reused,
// and also the number of times that it was presented in total.
/** Provides a single frame's timing information to the app */
struct Compositor_FrameTiming
@ -1922,6 +2107,7 @@ struct Compositor_FrameTiming
uint32_t m_nSize; // Set to sizeof( Compositor_FrameTiming )
uint32_t m_nFrameIndex;
uint32_t m_nNumFramePresents; // number of times this frame was presented
uint32_t m_nNumMisPresented; // number of times this frame was presented on a vsync other than it was originally predicted to
uint32_t m_nNumDroppedFrames; // number of additional times previous frame was scanned out
uint32_t m_nReprojectionFlags;
@ -1998,7 +2184,14 @@ public:
/** Gets current tracking space returned by WaitGetPoses */
virtual ETrackingUniverseOrigin GetTrackingSpace() = 0;
/** Returns pose(s) to use to render scene (and optionally poses predicted two frames out for gameplay). */
/** Scene applications should call this function to get poses to render with (and optionally poses predicted an additional frame out to use for gameplay).
* This function will block until "running start" milliseconds before the start of the frame, and should be called at the last moment before needing to
* start rendering.
*
* Return codes:
* - IsNotSceneApplication (make sure to call VR_Init with VRApplicaiton_Scene)
* - DoNotHaveFocus (some other app has taken focus - this will throttle the call to 10hz to reduce the impact on that app)
*/
virtual EVRCompositorError WaitGetPoses( VR_ARRAY_COUNT(unRenderPoseArrayCount) TrackedDevicePose_t* pRenderPoseArray, uint32_t unRenderPoseArrayCount,
VR_ARRAY_COUNT(unGamePoseArrayCount) TrackedDevicePose_t* pGamePoseArray, uint32_t unGamePoseArrayCount ) = 0;
@ -2016,6 +2209,15 @@ public:
*
* OpenGL dirty state:
* glBindTexture
*
* Return codes:
* - IsNotSceneApplication (make sure to call VR_Init with VRApplicaiton_Scene)
* - DoNotHaveFocus (some other app has taken focus)
* - TextureIsOnWrongDevice (application did not use proper AdapterIndex - see IVRSystem.GetDXGIOutputInfo)
* - SharedTexturesNotSupported (application needs to call CreateDXGIFactory1 or later before creating DX device)
* - TextureUsesUnsupportedFormat (scene textures must be compatible with DXGI sharing rules - e.g. uncompressed, no mips, etc.)
* - InvalidTexture (usually means bad arguments passed in)
* - AlreadySubmitted (app has submitted two left textures or two right textures in a single frame - i.e. before calling WaitGetPoses again)
*/
virtual EVRCompositorError Submit( EVREye eEye, const Texture_t *pTexture, const VRTextureBounds_t* pBounds = 0, EVRSubmitFlags nSubmitFlags = Submit_Default ) = 0;
@ -2034,6 +2236,10 @@ public:
* Be sure to set timing.size = sizeof(Compositor_FrameTiming) on struct passed in before calling this function. */
virtual bool GetFrameTiming( Compositor_FrameTiming *pTiming, uint32_t unFramesAgo = 0 ) = 0;
/** Interface for copying a range of timing data. Frames are returned in ascending order (oldest to newest) with the last being the most recent frame.
* Only the first entry's m_nSize needs to be set, as the rest will be inferred from that. Returns total number of entries filled out. */
virtual uint32_t GetFrameTimings( Compositor_FrameTiming *pTiming, uint32_t nFrames ) = 0;
/** Returns the time in seconds left in the current (as identified by FrameTiming's frameIndex) frame.
* Due to "running start", this value may roll over to the next frame before ever reaching 0.0. */
virtual float GetFrameTimeRemaining() = 0;
@ -2046,9 +2252,15 @@ public:
* would be FadeToColor( 0.0, 0.0, 0.0, 0.0, 0.0 ). Values are in un-premultiplied alpha space. */
virtual void FadeToColor( float fSeconds, float fRed, float fGreen, float fBlue, float fAlpha, bool bBackground = false ) = 0;
/** Get current fade color value. */
virtual HmdColor_t GetCurrentFadeColor( bool bBackground = false ) = 0;
/** Fading the Grid in or out in fSeconds */
virtual void FadeGrid( float fSeconds, bool bFadeIn ) = 0;
/** Get current alpha value of grid. */
virtual float GetCurrentGridAlpha() = 0;
/** Override the skybox used in the compositor (e.g. for during level loads when the app can't feed scene images fast enough)
* Order is Front, Back, Left, Right, Top, Bottom. If only a single texture is passed, it is assumed in lat-long format.
* If two are passed, it is assumed a lat-long stereo pair. */
@ -2105,17 +2317,30 @@ public:
/** Temporarily suspends rendering (useful for finer control over scene transitions). */
virtual void SuspendRendering( bool bSuspend ) = 0;
/** Opens a shared D3D11 texture with the undistorted composited image for each eye. */
/** Opens a shared D3D11 texture with the undistorted composited image for each eye. Use ReleaseMirrorTextureD3D11 when finished
* instead of calling Release on the resource itself. */
virtual vr::EVRCompositorError GetMirrorTextureD3D11( vr::EVREye eEye, void *pD3D11DeviceOrResource, void **ppD3D11ShaderResourceView ) = 0;
virtual void ReleaseMirrorTextureD3D11( void *pD3D11ShaderResourceView ) = 0;
/** Access to mirror textures from OpenGL. */
virtual vr::EVRCompositorError GetMirrorTextureGL( vr::EVREye eEye, vr::glUInt_t *pglTextureId, vr::glSharedTextureHandle_t *pglSharedTextureHandle ) = 0;
virtual bool ReleaseSharedGLTexture( vr::glUInt_t glTextureId, vr::glSharedTextureHandle_t glSharedTextureHandle ) = 0;
virtual void LockGLSharedTextureForAccess( vr::glSharedTextureHandle_t glSharedTextureHandle ) = 0;
virtual void UnlockGLSharedTextureForAccess( vr::glSharedTextureHandle_t glSharedTextureHandle ) = 0;
/** [Vulkan Only]
* return 0. Otherwise it returns the length of the number of bytes necessary to hold this string including the trailing
* null. The string will be a space separated list of-required instance extensions to enable in VkCreateInstance */
virtual uint32_t GetVulkanInstanceExtensionsRequired( VR_OUT_STRING() char *pchValue, uint32_t unBufferSize ) = 0;
/** [Vulkan only]
* return 0. Otherwise it returns the length of the number of bytes necessary to hold this string including the trailing
* null. The string will be a space separated list of required device extensions to enable in VkCreateDevice */
virtual uint32_t GetVulkanDeviceExtensionsRequired( VkPhysicalDevice_T *pPhysicalDevice, VR_OUT_STRING() char *pchValue, uint32_t unBufferSize ) = 0;
};
static const char * const IVRCompositor_Version = "IVRCompositor_016";
static const char * const IVRCompositor_Version = "IVRCompositor_020";
} // namespace vr
@ -2232,6 +2457,9 @@ namespace vr
/** The maximum number of overlays that can exist in the system at one time. */
static const uint32_t k_unMaxOverlayCount = 64;
/** The maximum number of overlay intersection mask primitives per overlay */
static const uint32_t k_unMaxOverlayIntersectionMaskPrimitivesCount = 32;
/** Types of input supported by VR Overlays */
enum VROverlayInputMethod
{
@ -2288,6 +2516,20 @@ namespace vr
// If this is set on an overlay owned by the scene application that overlay
// will be sorted with the "Other" overlays on top of all other scene overlays
VROverlayFlags_SortWithNonSceneOverlays = 14,
// If set, the overlay will be shown in the dashboard, otherwise it will be hidden.
VROverlayFlags_VisibleInDashboard = 15,
};
enum VRMessageOverlayResponse
{
VRMessageOverlayResponse_ButtonPress_0 = 0,
VRMessageOverlayResponse_ButtonPress_1 = 1,
VRMessageOverlayResponse_ButtonPress_2 = 2,
VRMessageOverlayResponse_ButtonPress_3 = 3,
VRMessageOverlayResponse_CouldntFindSystemOverlay = 4,
VRMessageOverlayResponse_CouldntFindOrCreateClientOverlay= 5,
VRMessageOverlayResponse_ApplicationQuit = 6
};
struct VROverlayIntersectionParams_t
@ -2331,6 +2573,40 @@ namespace vr
OverlayDirection_Count = 4,
};
enum EVROverlayIntersectionMaskPrimitiveType
{
OverlayIntersectionPrimitiveType_Rectangle,
OverlayIntersectionPrimitiveType_Circle,
};
struct IntersectionMaskRectangle_t
{
float m_flTopLeftX;
float m_flTopLeftY;
float m_flWidth;
float m_flHeight;
};
struct IntersectionMaskCircle_t
{
float m_flCenterX;
float m_flCenterY;
float m_flRadius;
};
/** NOTE!!! If you change this you MUST manually update openvr_interop.cs.py and openvr_api_flat.h.py */
typedef union
{
IntersectionMaskRectangle_t m_Rectangle;
IntersectionMaskCircle_t m_Circle;
} VROverlayIntersectionMaskPrimitive_Data_t;
struct VROverlayIntersectionMaskPrimitive_t
{
EVROverlayIntersectionMaskPrimitiveType m_nPrimitiveType;
VROverlayIntersectionMaskPrimitive_Data_t m_Primitive;
};
class IVROverlay
{
public:
@ -2571,7 +2847,7 @@ namespace vr
* pNativeTextureHandle is an OUTPUT, it will be a pointer to a ID3D11ShaderResourceView *.
* pNativeTextureRef is an INPUT and should be a ID3D11Resource *. The device used by pNativeTextureRef will be used to bind pNativeTextureHandle.
*/
virtual EVROverlayError GetOverlayTexture( VROverlayHandle_t ulOverlayHandle, void **pNativeTextureHandle, void *pNativeTextureRef, uint32_t *pWidth, uint32_t *pHeight, uint32_t *pNativeFormat, EGraphicsAPIConvention *pAPI, EColorSpace *pColorSpace ) = 0;
virtual EVROverlayError GetOverlayTexture( VROverlayHandle_t ulOverlayHandle, void **pNativeTextureHandle, void *pNativeTextureRef, uint32_t *pWidth, uint32_t *pHeight, uint32_t *pNativeFormat, ETextureType *pAPIType, EColorSpace *pColorSpace, VRTextureBounds_t *pTextureBounds ) = 0;
/** Release the pNativeTextureHandle provided from the GetOverlayTexture call, this allows the system to free the underlying GPU resources for this object,
* so only do it once you stop rendering this texture.
@ -2627,9 +2903,25 @@ namespace vr
/** Set the position of the keyboard in overlay space by telling it to avoid a rectangle in the overlay. Rectangle coords have (0,0) in the bottom left **/
virtual void SetKeyboardPositionForOverlay( VROverlayHandle_t ulOverlayHandle, HmdRect2_t avoidRect ) = 0;
// ---------------------------------------------
// Overlay input methods
// ---------------------------------------------
/** Sets a list of primitives to be used for controller ray intersection
* typically the size of the underlying UI in pixels (not in world space). */
virtual EVROverlayError SetOverlayIntersectionMask( VROverlayHandle_t ulOverlayHandle, VROverlayIntersectionMaskPrimitive_t *pMaskPrimitives, uint32_t unNumMaskPrimitives, uint32_t unPrimitiveSize = sizeof( VROverlayIntersectionMaskPrimitive_t ) ) = 0;
virtual EVROverlayError GetOverlayFlags( VROverlayHandle_t ulOverlayHandle, uint32_t *pFlags ) = 0;
// ---------------------------------------------
// Message box methods
// ---------------------------------------------
/** Show the message overlay. This will block and return you a result. **/
virtual VRMessageOverlayResponse ShowMessageOverlay( const char* pchText, const char* pchCaption, const char* pchButton0Text, const char* pchButton1Text = nullptr, const char* pchButton2Text = nullptr, const char* pchButton3Text = nullptr ) = 0;
};
static const char * const IVROverlay_Version = "IVROverlay_013";
static const char * const IVROverlay_Version = "IVROverlay_014";
} // namespace vr
@ -2874,7 +3166,7 @@ public:
/** Gets size of the image frame. */
virtual vr::EVRTrackedCameraError GetCameraFrameSize( vr::TrackedDeviceIndex_t nDeviceIndex, vr::EVRTrackedCameraFrameType eFrameType, uint32_t *pnWidth, uint32_t *pnHeight, uint32_t *pnFrameBufferSize ) = 0;
virtual vr::EVRTrackedCameraError GetCameraIntrinisics( vr::TrackedDeviceIndex_t nDeviceIndex, vr::EVRTrackedCameraFrameType eFrameType, vr::HmdVector2_t *pFocalLength, vr::HmdVector2_t *pCenter ) = 0;
virtual vr::EVRTrackedCameraError GetCameraIntrinsics( vr::TrackedDeviceIndex_t nDeviceIndex, vr::EVRTrackedCameraFrameType eFrameType, vr::HmdVector2_t *pFocalLength, vr::HmdVector2_t *pCenter ) = 0;
virtual vr::EVRTrackedCameraError GetCameraProjection( vr::TrackedDeviceIndex_t nDeviceIndex, vr::EVRTrackedCameraFrameType eFrameType, float flZNear, float flZFar, vr::HmdMatrix44_t *pProjection ) = 0;
@ -2895,7 +3187,12 @@ public:
/** Gets size of the image frame. */
virtual vr::EVRTrackedCameraError GetVideoStreamTextureSize( vr::TrackedDeviceIndex_t nDeviceIndex, vr::EVRTrackedCameraFrameType eFrameType, vr::VRTextureBounds_t *pTextureBounds, uint32_t *pnWidth, uint32_t *pnHeight ) = 0;
/** Access a shared D3D11 texture for the specified tracked camera stream */
/** Access a shared D3D11 texture for the specified tracked camera stream.
* The camera frame type VRTrackedCameraFrameType_Undistorted is not supported directly as a shared texture. It is an interior subregion of the shared texture VRTrackedCameraFrameType_MaximumUndistorted.
* Instead, use GetVideoStreamTextureSize() with VRTrackedCameraFrameType_Undistorted to determine the proper interior subregion bounds along with GetVideoStreamTextureD3D11() with
* VRTrackedCameraFrameType_MaximumUndistorted to provide the texture. The VRTrackedCameraFrameType_MaximumUndistorted will yield an image where the invalid regions are decoded
* by the alpha channel having a zero component. The valid regions all have a non-zero alpha component. The subregion as described by VRTrackedCameraFrameType_Undistorted
* guarantees a rectangle where all pixels are valid. */
virtual vr::EVRTrackedCameraError GetVideoStreamTextureD3D11( vr::TrackedCameraHandle_t hTrackedCamera, vr::EVRTrackedCameraFrameType eFrameType, void *pD3D11DeviceOrResource, void **ppD3D11ShaderResourceView, vr::CameraVideoStreamFrameHeader_t *pFrameHeader, uint32_t nFrameHeaderSize ) = 0;
/** Access a shared GL texture for the specified tracked camera stream */
@ -3045,7 +3342,6 @@ static const char * const IVRResources_Version = "IVRResources_001";
#endif // _OPENVR_API
namespace vr
{
/** Finds the active installation of the VR API and initializes it. The provided path must be absolute
@ -3096,7 +3392,6 @@ namespace vr
// They will go away in the future.
typedef EVRInitError HmdError;
typedef EVREye Hmd_Eye;
typedef EGraphicsAPIConvention GraphicsAPIConvention;
typedef EColorSpace ColorSpace;
typedef ETrackingResult HmdTrackingResult;
typedef ETrackedDeviceClass TrackedDeviceClass;

47
gfx/vr/openvr/moz.build Normal file
View file

@ -0,0 +1,47 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
FINAL_LIBRARY = 'xul'
DEFINES['VR_API_PUBLIC'] = True
if CONFIG['OS_ARCH'] == 'WINNT':
if CONFIG['HAVE_64BIT_BUILD']:
DEFINES['WIN64'] = True
else:
DEFINES['WIN32'] = True
# When we support platforms other than Windows, we
# will also need to define these:
#
# LINUX64
# LINUX
# OSX
# POSIX
LOCAL_INCLUDES += [
'/toolkit/crashreporter/jsoncpp/include',
]
USE_LIBS += [
'jsoncpp',
]
EXPORTS += [
'headers/openvr.h',
]
SOURCES += [
'src/dirtools_public.cpp',
'src/envvartools_public.cpp',
'src/hmderrors_public.cpp',
'src/openvr_api_public.cpp',
'src/pathtools_public.cpp',
'src/sharedlibtools_public.cpp',
'src/strtools_public.cpp',
'src/vrpathregistry_public.cpp',
]

35
gfx/vr/openvr/src/README Normal file
View file

@ -0,0 +1,35 @@
This is the source code for the OpenVR API client binding library which connects
OpenVR applications to the SteamVR runtime, taking into account the version
of the OpenVR interface they were compiled against.
The client binding library - openvr_api.dll on Windows, openvr_api.so on
Linux, and openvr_api.dylib on macOS - knows how to find and read the
SteamVR runtime installation information which allows it to find and
dynamically connect to the installed runtime. In combination with the
interface version identifiers from /include/openvr.h which are baked
into applications at the time they are built, the OpenVR API client
binding library captures and conveys to the SteamVR runtime the version
of the OpenVR API interface behavior that the application expects.
Applications carry with them a private/local copy of the client binding
library when they ship, and they should install it locally to their
application. Applications should not install the client binding library
globally or attempt to link to a globally installed client binding library.
Doing so negates at least part of the ability for the client binding library
to accurately reflect the version of the OpenVR API that the application
was built against, and so hinders compatibility support in the face of
API changes.
Most applications should simply link to and redistribute with their application
the pre-built client binding library found in the /bin directory of this
repository. Some small number of applications which have specific requirements
around redistributing only binaries they build themselves should build
the client library from this source and either statically link it into
their application or redistribute the binary they build.
This is a cmake project, to build it use the version of cmake appropriate
for your platform. For example, to build on a POSIX system simply perform
cd src; mkdir _build; cd _build; cmake ..; make
and you will end up with the static library /src/_build/libopenvr_api.a

View file

@ -0,0 +1,101 @@
//========= Copyright Valve Corporation ============//
#include "dirtools_public.h"
#include "strtools_public.h"
#include "pathtools_public.h"
#include <errno.h>
#include <string.h>
#ifdef _WIN32
#include "windows.h"
#else
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif
#if defined( OSX )
#include <sys/syslimits.h>
#endif
//-----------------------------------------------------------------------------
// Purpose: utility function to create dirs & subdirs
//-----------------------------------------------------------------------------
bool BCreateDirectoryRecursive( const char *pchPath )
{
// Does it already exist?
if ( Path_IsDirectory( pchPath ) )
return true;
// copy the path into something we can munge
int len = (int)strlen( pchPath );
char *path = (char *)malloc( len + 1 );
strcpy( path, pchPath );
// Walk backwards to first non-existing dir that we find
char *s = path + len - 1;
const char slash = Path_GetSlash();
while ( s > path )
{
if ( *s == slash )
{
*s = '\0';
bool bExists = Path_IsDirectory( path );
*s = slash;
if ( bExists )
{
++s;
break;
}
}
--s;
}
// and then move forwards from there
while ( *s )
{
if ( *s == slash )
{
*s = '\0';
BCreateDirectory( path );
*s = slash;
}
s++;
}
bool bRetVal = BCreateDirectory( path );
free( path );
return bRetVal;
}
//-----------------------------------------------------------------------------
// Purpose: Creates the directory, returning true if it is created, or if it already existed
//-----------------------------------------------------------------------------
bool BCreateDirectory( const char *pchPath )
{
#ifdef WIN32
std::wstring wPath = UTF8to16( pchPath );
if ( ::CreateDirectoryW( wPath.c_str(), NULL ) )
return true;
if ( ::GetLastError() == ERROR_ALREADY_EXISTS )
return true;
return false;
#else
int i = mkdir( pchPath, S_IRWXU | S_IRWXG | S_IRWXO );
if ( i == 0 )
return true;
if ( errno == EEXIST )
return true;
return false;
#endif
}

View file

@ -0,0 +1,17 @@
//========= Copyright Valve Corporation ============//
#pragma once
#include <stdint.h>
#include <string>
#if !defined(_WIN32)
#include <sys/types.h>
#include <sys/stat.h>
#endif
extern bool BCreateDirectoryRecursive( const char *pchPath );
extern bool BCreateDirectory( const char *pchPath );

View file

@ -0,0 +1,46 @@
//========= Copyright Valve Corporation ============//
#include "envvartools_public.h"
#include <stdlib.h>
#if defined(_WIN32)
#include <Windows.h>
#undef GetEnvironmentVariable
#undef SetEnvironmentVariable
#endif
std::string GetEnvironmentVariable( const char *pchVarName )
{
#if defined(_WIN32)
char rchValue[32767]; // max size for an env var on Windows
DWORD cChars = GetEnvironmentVariableA( pchVarName, rchValue, sizeof( rchValue ) );
if( cChars == 0 )
return "";
else
return rchValue;
#elif defined(POSIX)
char *pchValue = getenv( pchVarName );
if( pchValue )
return pchValue;
else
return "";
#else
#error "Unsupported Platform"
#endif
}
bool SetEnvironmentVariable( const char *pchVarName, const char *pchVarValue )
{
#if defined(_WIN32)
return 0 != SetEnvironmentVariableA( pchVarName, pchVarValue );
#elif defined(POSIX)
if( pchVarValue == NULL )
return 0 == unsetenv( pchVarName );
else
return 0 == setenv( pchVarName, pchVarValue, 1 );
#else
#error "Unsupported Platform"
#endif
}

View file

@ -0,0 +1,7 @@
//========= Copyright Valve Corporation ============//
#pragma once
#include <string>
std::string GetEnvironmentVariable( const char *pchVarName );
bool SetEnvironmentVariable( const char *pchVarName, const char *pchVarValue );

View file

@ -0,0 +1,205 @@
//========= Copyright Valve Corporation ============//
#include "openvr.h"
#include "hmderrors_public.h"
#include <stdio.h>
#include <algorithm>
using namespace vr;
#define RETURN_ENUM_AS_STRING(enumValue) case enumValue: return #enumValue;
const char *GetEnglishStringForHmdError( vr::EVRInitError eError )
{
switch( eError )
{
case VRInitError_None: return "No Error (0)";
case VRInitError_Init_InstallationNotFound: return "Installation Not Found (100)";
case VRInitError_Init_InstallationCorrupt: return "Installation Corrupt (101)";
case VRInitError_Init_VRClientDLLNotFound: return "vrclient Shared Lib Not Found (102)";
case VRInitError_Init_FileNotFound: return "File Not Found (103)";
case VRInitError_Init_FactoryNotFound: return "Factory Function Not Found (104)";
case VRInitError_Init_InterfaceNotFound: return "Interface Not Found (105)";
case VRInitError_Init_InvalidInterface: return "Invalid Interface (106)";
case VRInitError_Init_UserConfigDirectoryInvalid: return "User Config Directory Invalid (107)";
case VRInitError_Init_HmdNotFound: return "Hmd Not Found (108)";
case VRInitError_Init_NotInitialized: return "Not Initialized (109)";
case VRInitError_Init_PathRegistryNotFound: return "Installation path could not be located (110)";
case VRInitError_Init_NoConfigPath: return "Config path could not be located (111)";
case VRInitError_Init_NoLogPath: return "Log path could not be located (112)";
case VRInitError_Init_PathRegistryNotWritable: return "Unable to write path registry (113)";
case VRInitError_Init_AppInfoInitFailed: return "App info manager init failed (114)";
case VRInitError_Init_Retry: return "Internal Retry (115)";
case VRInitError_Init_InitCanceledByUser: return "User Canceled Init (116)";
case VRInitError_Init_AnotherAppLaunching: return "Another app was already launching (117)";
case VRInitError_Init_SettingsInitFailed: return "Settings manager init failed (118)";
case VRInitError_Init_ShuttingDown: return "VR system shutting down (119)";
case VRInitError_Init_TooManyObjects: return "Too many tracked objects (120)";
case VRInitError_Init_NoServerForBackgroundApp: return "Not starting vrserver for background app (121)";
case VRInitError_Init_NotSupportedWithCompositor: return "The requested interface is incompatible with the compositor and the compositor is running (122)";
case VRInitError_Init_NotAvailableToUtilityApps: return "This interface is not available to utility applications (123)";
case VRInitError_Init_Internal: return "vrserver internal error (124)";
case VRInitError_Init_HmdDriverIdIsNone: return "Hmd DriverId is invalid (125)";
case VRInitError_Init_HmdNotFoundPresenceFailed: return "Hmd Not Found Presence Failed (126)";
case VRInitError_Driver_Failed: return "Driver Failed (200)";
case VRInitError_Driver_Unknown: return "Driver Not Known (201)";
case VRInitError_Driver_HmdUnknown: return "HMD Not Known (202)";
case VRInitError_Driver_NotLoaded: return "Driver Not Loaded (203)";
case VRInitError_Driver_RuntimeOutOfDate: return "Driver runtime is out of date (204)";
case VRInitError_Driver_HmdInUse: return "HMD already in use by another application (205)";
case VRInitError_Driver_NotCalibrated: return "Device is not calibrated (206)";
case VRInitError_Driver_CalibrationInvalid: return "Device Calibration is invalid (207)";
case VRInitError_Driver_HmdDisplayNotFound: return "HMD detected over USB, but Monitor not found (208)";
case VRInitError_Driver_TrackedDeviceInterfaceUnknown: return "Driver Tracked Device Interface unknown (209)";
// case VRInitError_Driver_HmdDisplayNotFoundAfterFix: return "HMD detected over USB, but Monitor not found after attempt to fix (210)"; // taken out upon Ben's request: He thinks that there is no need to separate that error from 208
case VRInitError_Driver_HmdDriverIdOutOfBounds: return "Hmd DriverId is our of bounds (211)";
case VRInitError_Driver_HmdDisplayMirrored: return "HMD detected over USB, but Monitor may be mirrored instead of extended (212)";
case VRInitError_IPC_ServerInitFailed: return "VR Server Init Failed (300)";
case VRInitError_IPC_ConnectFailed: return "Connect to VR Server Failed (301)";
case VRInitError_IPC_SharedStateInitFailed: return "Shared IPC State Init Failed (302)";
case VRInitError_IPC_CompositorInitFailed: return "Shared IPC Compositor Init Failed (303)";
case VRInitError_IPC_MutexInitFailed: return "Shared IPC Mutex Init Failed (304)";
case VRInitError_IPC_Failed: return "Shared IPC Failed (305)";
case VRInitError_IPC_CompositorConnectFailed: return "Shared IPC Compositor Connect Failed (306)";
case VRInitError_IPC_CompositorInvalidConnectResponse: return "Shared IPC Compositor Invalid Connect Response (307)";
case VRInitError_IPC_ConnectFailedAfterMultipleAttempts: return "Shared IPC Connect Failed After Multiple Attempts (308)";
case VRInitError_Compositor_Failed: return "Compositor failed to initialize (400)";
case VRInitError_Compositor_D3D11HardwareRequired: return "Compositor failed to find DX11 hardware (401)";
case VRInitError_Compositor_FirmwareRequiresUpdate: return "Compositor requires mandatory firmware update (402)";
case VRInitError_Compositor_OverlayInitFailed: return "Compositor initialization succeeded, but overlay init failed (403)";
// Oculus
case VRInitError_VendorSpecific_UnableToConnectToOculusRuntime: return "Unable to connect to Oculus Runtime (1000)";
// Lighthouse
case VRInitError_VendorSpecific_HmdFound_CantOpenDevice: return "HMD found, but can not open device (1101)";
case VRInitError_VendorSpecific_HmdFound_UnableToRequestConfigStart: return "HMD found, but unable to request config (1102)";
case VRInitError_VendorSpecific_HmdFound_NoStoredConfig: return "HMD found, but no stored config (1103)";
case VRInitError_VendorSpecific_HmdFound_ConfigFailedSanityCheck: return "HMD found, but failed configuration check (1113)";
case VRInitError_VendorSpecific_HmdFound_ConfigTooBig: return "HMD found, but config too big (1104)";
case VRInitError_VendorSpecific_HmdFound_ConfigTooSmall: return "HMD found, but config too small (1105)";
case VRInitError_VendorSpecific_HmdFound_UnableToInitZLib: return "HMD found, but unable to init ZLib (1106)";
case VRInitError_VendorSpecific_HmdFound_CantReadFirmwareVersion: return "HMD found, but problems with the data (1107)";
case VRInitError_VendorSpecific_HmdFound_UnableToSendUserDataStart: return "HMD found, but problems with the data (1108)";
case VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataStart: return "HMD found, but problems with the data (1109)";
case VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataNext: return "HMD found, but problems with the data (1110)";
case VRInitError_VendorSpecific_HmdFound_UserDataAddressRange: return "HMD found, but problems with the data (1111)";
case VRInitError_VendorSpecific_HmdFound_UserDataError: return "HMD found, but problems with the data (1112)";
case VRInitError_Steam_SteamInstallationNotFound: return "Unable to find Steam installation (2000)";
default:
{
static char buf[128];
sprintf( buf, "Unknown error (%d)", eError );
return buf;
}
}
}
const char *GetIDForVRInitError( vr::EVRInitError eError )
{
switch( eError )
{
RETURN_ENUM_AS_STRING( VRInitError_None );
RETURN_ENUM_AS_STRING( VRInitError_Unknown );
RETURN_ENUM_AS_STRING( VRInitError_Init_InstallationNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_InstallationCorrupt );
RETURN_ENUM_AS_STRING( VRInitError_Init_VRClientDLLNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_FileNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_FactoryNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_InterfaceNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_InvalidInterface );
RETURN_ENUM_AS_STRING( VRInitError_Init_UserConfigDirectoryInvalid );
RETURN_ENUM_AS_STRING( VRInitError_Init_HmdNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_NotInitialized );
RETURN_ENUM_AS_STRING( VRInitError_Init_PathRegistryNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_NoConfigPath );
RETURN_ENUM_AS_STRING( VRInitError_Init_NoLogPath );
RETURN_ENUM_AS_STRING( VRInitError_Init_PathRegistryNotWritable );
RETURN_ENUM_AS_STRING( VRInitError_Init_AppInfoInitFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_Retry );
RETURN_ENUM_AS_STRING( VRInitError_Init_InitCanceledByUser );
RETURN_ENUM_AS_STRING( VRInitError_Init_AnotherAppLaunching );
RETURN_ENUM_AS_STRING( VRInitError_Init_SettingsInitFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_ShuttingDown );
RETURN_ENUM_AS_STRING( VRInitError_Init_TooManyObjects );
RETURN_ENUM_AS_STRING( VRInitError_Init_NoServerForBackgroundApp );
RETURN_ENUM_AS_STRING( VRInitError_Init_NotSupportedWithCompositor );
RETURN_ENUM_AS_STRING( VRInitError_Init_NotAvailableToUtilityApps );
RETURN_ENUM_AS_STRING( VRInitError_Init_Internal );
RETURN_ENUM_AS_STRING( VRInitError_Init_VRMonitorNotFound );
RETURN_ENUM_AS_STRING( VRInitError_Init_VRMonitorStartupFailed );
RETURN_ENUM_AS_STRING( VRInitError_Init_LowPowerWatchdogNotSupported );
RETURN_ENUM_AS_STRING( VRInitError_Init_InvalidApplicationType );
RETURN_ENUM_AS_STRING( VRInitError_Init_NotAvailableToWatchdogApps );
RETURN_ENUM_AS_STRING( VRInitError_Init_WatchdogDisabledInSettings );
RETURN_ENUM_AS_STRING( VRInitError_Init_HmdDriverIdIsNone );
RETURN_ENUM_AS_STRING( VRInitError_Init_HmdNotFoundPresenceFailed );
RETURN_ENUM_AS_STRING( VRInitError_Driver_Failed );
RETURN_ENUM_AS_STRING( VRInitError_Driver_Unknown );
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdUnknown);
RETURN_ENUM_AS_STRING( VRInitError_Driver_NotLoaded);
RETURN_ENUM_AS_STRING( VRInitError_Driver_RuntimeOutOfDate);
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdInUse);
RETURN_ENUM_AS_STRING( VRInitError_Driver_NotCalibrated);
RETURN_ENUM_AS_STRING( VRInitError_Driver_CalibrationInvalid);
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDisplayNotFound);
RETURN_ENUM_AS_STRING( VRInitError_Driver_TrackedDeviceInterfaceUnknown );
// RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDisplayNotFoundAfterFix );
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDriverIdOutOfBounds );
RETURN_ENUM_AS_STRING( VRInitError_Driver_HmdDisplayMirrored );
RETURN_ENUM_AS_STRING( VRInitError_IPC_ServerInitFailed);
RETURN_ENUM_AS_STRING( VRInitError_IPC_ConnectFailed);
RETURN_ENUM_AS_STRING( VRInitError_IPC_SharedStateInitFailed);
RETURN_ENUM_AS_STRING( VRInitError_IPC_CompositorInitFailed);
RETURN_ENUM_AS_STRING( VRInitError_IPC_MutexInitFailed);
RETURN_ENUM_AS_STRING( VRInitError_IPC_Failed);
RETURN_ENUM_AS_STRING( VRInitError_IPC_CompositorConnectFailed);
RETURN_ENUM_AS_STRING( VRInitError_IPC_CompositorInvalidConnectResponse);
RETURN_ENUM_AS_STRING( VRInitError_IPC_ConnectFailedAfterMultipleAttempts);
RETURN_ENUM_AS_STRING( VRInitError_Compositor_Failed );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_D3D11HardwareRequired );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_FirmwareRequiresUpdate );
RETURN_ENUM_AS_STRING( VRInitError_Compositor_OverlayInitFailed );
// Oculus
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_UnableToConnectToOculusRuntime);
// Lighthouse
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_CantOpenDevice);
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToRequestConfigStart);
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_NoStoredConfig);
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_ConfigFailedSanityCheck );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_ConfigTooBig );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_ConfigTooSmall );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToInitZLib );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_CantReadFirmwareVersion );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToSendUserDataStart );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataStart );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UnableToGetUserDataNext );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UserDataAddressRange );
RETURN_ENUM_AS_STRING( VRInitError_VendorSpecific_HmdFound_UserDataError );
RETURN_ENUM_AS_STRING( VRInitError_Steam_SteamInstallationNotFound );
default:
{
static char buf[128];
sprintf( buf, "Unknown error (%d)", eError );
return buf;
}
}
}

View file

@ -0,0 +1,6 @@
//========= Copyright Valve Corporation ============//
#pragma once
const char *GetEnglishStringForHmdError( vr::EVRInitError eError );
const char *GetIDForVRInitError( vr::EVRInitError eError );

View file

@ -0,0 +1,35 @@
//========= Copyright Valve Corporation ============//
#pragma once
namespace vr
{
class IVRClientCore
{
public:
/** Initializes the system */
virtual EVRInitError Init( vr::EVRApplicationType eApplicationType ) = 0;
/** cleans up everything in vrclient.dll and prepares the DLL to be unloaded */
virtual void Cleanup() = 0;
/** checks to see if the specified interface/version is supported in this vrclient.dll */
virtual EVRInitError IsInterfaceVersionValid( const char *pchInterfaceVersion ) = 0;
/** Retrieves any interface from vrclient.dll */
virtual void *GetGenericInterface( const char *pchNameAndVersion, EVRInitError *peError ) = 0;
/** Returns true if any driver has an HMD attached. Can be called outside of Init/Cleanup */
virtual bool BIsHmdPresent() = 0;
/** Returns an english error string from inside vrclient.dll which might be newer than the API DLL */
virtual const char *GetEnglishStringForHmdError( vr::EVRInitError eError ) = 0;
/** Returns an error symbol from inside vrclient.dll which might be newer than the API DLL */
virtual const char *GetIDForVRInitError( vr::EVRInitError eError ) = 0;
};
static const char * const IVRClientCore_Version = "IVRClientCore_002";
}

View file

@ -0,0 +1,284 @@
//========= Copyright Valve Corporation ============//
#define VR_API_EXPORT 1
#include "openvr.h"
#include "ivrclientcore.h"
#include "pathtools_public.h"
#include "sharedlibtools_public.h"
#include "envvartools_public.h"
#include "hmderrors_public.h"
#include "vrpathregistry_public.h"
using vr::EVRInitError;
using vr::IVRSystem;
using vr::IVRClientCore;
using vr::VRInitError_None;
namespace vr
{
static void *g_pVRModule = NULL;
static IVRClientCore *g_pHmdSystem = NULL;
typedef void* (*VRClientCoreFactoryFn)(const char *pInterfaceName, int *pReturnCode);
static uint32_t g_nVRToken = 0;
uint32_t VR_GetInitToken()
{
return g_nVRToken;
}
EVRInitError VR_LoadHmdSystemInternal();
void CleanupInternalInterfaces();
uint32_t VR_InitInternal( EVRInitError *peError, vr::EVRApplicationType eApplicationType )
{
EVRInitError err = VR_LoadHmdSystemInternal();
if (err != vr::VRInitError_None)
{
SharedLib_Unload(g_pVRModule);
g_pHmdSystem = NULL;
g_pVRModule = NULL;
if (peError)
*peError = err;
return 0;
}
err = g_pHmdSystem->Init(eApplicationType);
if (err != VRInitError_None)
{
SharedLib_Unload(g_pVRModule);
g_pHmdSystem = NULL;
g_pVRModule = NULL;
if (peError)
*peError = err;
return 0;
}
if (peError)
*peError = VRInitError_None;
return ++g_nVRToken;
}
void VR_ShutdownInternal()
{
if (g_pHmdSystem)
{
g_pHmdSystem->Cleanup();
g_pHmdSystem = NULL;
}
if (g_pVRModule)
{
SharedLib_Unload(g_pVRModule);
g_pVRModule = NULL;
}
#if !defined( VR_API_PUBLIC )
CleanupInternalInterfaces();
#endif
++g_nVRToken;
}
EVRInitError VR_LoadHmdSystemInternal()
{
std::string sRuntimePath, sConfigPath, sLogPath;
bool bReadPathRegistry = CVRPathRegistry_Public::GetPaths( &sRuntimePath, &sConfigPath, &sLogPath, NULL, NULL );
if( !bReadPathRegistry )
{
return vr::VRInitError_Init_PathRegistryNotFound;
}
// figure out where we're going to look for vrclient.dll
// see if the specified path actually exists.
if( !Path_IsDirectory( sRuntimePath ) )
{
return vr::VRInitError_Init_InstallationNotFound;
}
// Because we don't have a way to select debug vs. release yet we'll just
// use debug if it's there
#if defined( LINUX64 )
std::string sTestPath = Path_Join( sRuntimePath, "bin", PLATSUBDIR );
#else
std::string sTestPath = Path_Join( sRuntimePath, "bin" );
#endif
if( !Path_IsDirectory( sTestPath ) )
{
return vr::VRInitError_Init_InstallationCorrupt;
}
#if defined( WIN64 )
std::string sDLLPath = Path_Join( sTestPath, "vrclient_x64" DYNAMIC_LIB_EXT );
#else
std::string sDLLPath = Path_Join( sTestPath, "vrclient" DYNAMIC_LIB_EXT );
#endif
// only look in the override
void *pMod = SharedLib_Load( sDLLPath.c_str() );
// nothing more to do if we can't load the DLL
if( !pMod )
{
return vr::VRInitError_Init_VRClientDLLNotFound;
}
VRClientCoreFactoryFn fnFactory = ( VRClientCoreFactoryFn )( SharedLib_GetFunction( pMod, "VRClientCoreFactory" ) );
if( !fnFactory )
{
SharedLib_Unload( pMod );
return vr::VRInitError_Init_FactoryNotFound;
}
int nReturnCode = 0;
g_pHmdSystem = static_cast< IVRClientCore * > ( fnFactory( vr::IVRClientCore_Version, &nReturnCode ) );
if( !g_pHmdSystem )
{
SharedLib_Unload( pMod );
return vr::VRInitError_Init_InterfaceNotFound;
}
g_pVRModule = pMod;
return VRInitError_None;
}
void *VR_GetGenericInterface(const char *pchInterfaceVersion, EVRInitError *peError)
{
if (!g_pHmdSystem)
{
if (peError)
*peError = vr::VRInitError_Init_NotInitialized;
return NULL;
}
return g_pHmdSystem->GetGenericInterface(pchInterfaceVersion, peError);
}
bool VR_IsInterfaceVersionValid(const char *pchInterfaceVersion)
{
if (!g_pHmdSystem)
{
return false;
}
return g_pHmdSystem->IsInterfaceVersionValid(pchInterfaceVersion) == VRInitError_None;
}
bool VR_IsHmdPresent()
{
if( g_pHmdSystem )
{
// if we're already initialized, just call through
return g_pHmdSystem->BIsHmdPresent();
}
else
{
// otherwise we need to do a bit more work
EVRInitError err = VR_LoadHmdSystemInternal();
if( err != VRInitError_None )
return false;
bool bHasHmd = g_pHmdSystem->BIsHmdPresent();
g_pHmdSystem = NULL;
SharedLib_Unload( g_pVRModule );
g_pVRModule = NULL;
return bHasHmd;
}
}
/** Returns true if the OpenVR runtime is installed. */
bool VR_IsRuntimeInstalled()
{
if( g_pHmdSystem )
{
// if we're already initialized, OpenVR is obviously installed
return true;
}
else
{
// otherwise we need to do a bit more work
std::string sRuntimePath, sConfigPath, sLogPath;
bool bReadPathRegistry = CVRPathRegistry_Public::GetPaths( &sRuntimePath, &sConfigPath, &sLogPath, NULL, NULL );
if( !bReadPathRegistry )
{
return false;
}
// figure out where we're going to look for vrclient.dll
// see if the specified path actually exists.
if( !Path_IsDirectory( sRuntimePath ) )
{
return false;
}
// the installation may be corrupt in some way, but it certainly looks installed
return true;
}
}
/** Returns where OpenVR runtime is installed. */
const char *VR_RuntimePath()
{
// otherwise we need to do a bit more work
static std::string sRuntimePath;
std::string sConfigPath, sLogPath;
bool bReadPathRegistry = CVRPathRegistry_Public::GetPaths( &sRuntimePath, &sConfigPath, &sLogPath, NULL, NULL );
if ( !bReadPathRegistry )
{
return nullptr;
}
// figure out where we're going to look for vrclient.dll
// see if the specified path actually exists.
if ( !Path_IsDirectory( sRuntimePath ) )
{
return nullptr;
}
return sRuntimePath.c_str();
}
/** Returns the symbol version of an HMD error. */
const char *VR_GetVRInitErrorAsSymbol( EVRInitError error )
{
if( g_pHmdSystem )
return g_pHmdSystem->GetIDForVRInitError( error );
else
return GetIDForVRInitError( error );
}
/** Returns the english string version of an HMD error. */
const char *VR_GetVRInitErrorAsEnglishDescription( EVRInitError error )
{
if ( g_pHmdSystem )
return g_pHmdSystem->GetEnglishStringForHmdError( error );
else
return GetEnglishStringForHmdError( error );
}
VR_INTERFACE const char *VR_CALLTYPE VR_GetStringForHmdError( vr::EVRInitError error );
/** Returns the english string version of an HMD error. */
const char *VR_GetStringForHmdError( EVRInitError error )
{
return VR_GetVRInitErrorAsEnglishDescription( error );
}
}

View file

@ -0,0 +1,818 @@
//========= Copyright Valve Corporation ============//
#include "strtools_public.h"
#include "pathtools_public.h"
#if defined( _WIN32)
#include <Windows.h>
#include <direct.h>
#include <Shobjidl.h>
#include <KnownFolders.h>
#include <Shlobj.h>
#undef GetEnvironmentVariable
#else
#include <dlfcn.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#endif
#if defined OSX
#include <Foundation/Foundation.h>
#include <AppKit/AppKit.h>
#include <mach-o/dyld.h>
#define _S_IFDIR S_IFDIR // really from tier0/platform.h which we dont have yet
#endif
#include <sys/stat.h>
#include <algorithm>
/** Returns the path (including filename) to the current executable */
std::string Path_GetExecutablePath()
{
#if defined( _WIN32 )
wchar_t *pwchPath = new wchar_t[MAX_UNICODE_PATH];
char *pchPath = new char[MAX_UNICODE_PATH_IN_UTF8];
::GetModuleFileNameW( NULL, pwchPath, MAX_UNICODE_PATH );
WideCharToMultiByte( CP_UTF8, 0, pwchPath, -1, pchPath, MAX_UNICODE_PATH_IN_UTF8, NULL, NULL );
delete[] pwchPath;
std::string sPath = pchPath;
delete[] pchPath;
return sPath;
#elif defined( OSX )
char rchPath[1024];
uint32_t nBuff = sizeof( rchPath );
bool bSuccess = _NSGetExecutablePath(rchPath, &nBuff) == 0;
rchPath[nBuff-1] = '\0';
if( bSuccess )
return rchPath;
else
return "";
#elif defined LINUX
char rchPath[1024];
size_t nBuff = sizeof( rchPath );
ssize_t nRead = readlink("/proc/self/exe", rchPath, nBuff-1 );
if ( nRead != -1 )
{
rchPath[ nRead ] = 0;
return rchPath;
}
else
{
return "";
}
#else
AssertMsg( false, "Implement Plat_GetExecutablePath" );
return "";
#endif
}
/** Returns the path of the current working directory */
std::string Path_GetWorkingDirectory()
{
std::string sPath;
#if defined( _WIN32 )
wchar_t buf[MAX_UNICODE_PATH];
sPath = UTF16to8( _wgetcwd( buf, MAX_UNICODE_PATH ) );
#else
char buf[ 1024 ];
sPath = getcwd( buf, sizeof( buf ) );
#endif
return sPath;
}
/** Sets the path of the current working directory. Returns true if this was successful. */
bool Path_SetWorkingDirectory( const std::string & sPath )
{
bool bSuccess;
#if defined( _WIN32 )
std::wstring wsPath = UTF8to16( sPath.c_str() );
bSuccess = 0 == _wchdir( wsPath.c_str() );
#else
bSuccess = 0 == chdir( sPath.c_str() );
#endif
return bSuccess;
}
/** Returns the specified path without its filename */
std::string Path_StripFilename( const std::string & sPath, char slash )
{
if( slash == 0 )
slash = Path_GetSlash();
std::string::size_type n = sPath.find_last_of( slash );
if( n == std::string::npos )
return sPath;
else
return std::string( sPath.begin(), sPath.begin() + n );
}
/** returns just the filename from the provided full or relative path. */
std::string Path_StripDirectory( const std::string & sPath, char slash )
{
if( slash == 0 )
slash = Path_GetSlash();
std::string::size_type n = sPath.find_last_of( slash );
if( n == std::string::npos )
return sPath;
else
return std::string( sPath.begin() + n + 1, sPath.end() );
}
/** returns just the filename with no extension of the provided filename.
* If there is a path the path is left intact. */
std::string Path_StripExtension( const std::string & sPath )
{
for( std::string::const_reverse_iterator i = sPath.rbegin(); i != sPath.rend(); i++ )
{
if( *i == '.' )
{
return std::string( sPath.begin(), i.base() - 1 );
}
// if we find a slash there is no extension
if( *i == '\\' || *i == '/' )
break;
}
// we didn't find an extension
return sPath;
}
/** returns just extension of the provided filename (if any). */
std::string Path_GetExtension( const std::string & sPath )
{
for ( std::string::const_reverse_iterator i = sPath.rbegin(); i != sPath.rend(); i++ )
{
if ( *i == '.' )
{
return std::string( i.base(), sPath.end() );
}
// if we find a slash there is no extension
if ( *i == '\\' || *i == '/' )
break;
}
// we didn't find an extension
return "";
}
bool Path_IsAbsolute( const std::string & sPath )
{
if( sPath.empty() )
return false;
#if defined( WIN32 )
if ( sPath.size() < 3 ) // must be c:\x or \\x at least
return false;
if ( sPath[1] == ':' ) // drive letter plus slash, but must test both slash cases
{
if ( sPath[2] == '\\' || sPath[2] == '/' )
return true;
}
else if ( sPath[0] == '\\' && sPath[1] == '\\' ) // UNC path
return true;
#else
if( sPath[0] == '\\' || sPath[0] == '/' ) // any leading slash
return true;
#endif
return false;
}
/** Makes an absolute path from a relative path and a base path */
std::string Path_MakeAbsolute( const std::string & sRelativePath, const std::string & sBasePath, char slash )
{
if( slash == 0 )
slash = Path_GetSlash();
if( Path_IsAbsolute( sRelativePath ) )
return sRelativePath;
else
{
if( !Path_IsAbsolute( sBasePath ) )
return "";
std::string sCompacted = Path_Compact( Path_Join( sBasePath, sRelativePath, slash ), slash );
if( Path_IsAbsolute( sCompacted ) )
return sCompacted;
else
return "";
}
}
/** Fixes the directory separators for the current platform */
std::string Path_FixSlashes( const std::string & sPath, char slash )
{
if( slash == 0 )
slash = Path_GetSlash();
std::string sFixed = sPath;
for( std::string::iterator i = sFixed.begin(); i != sFixed.end(); i++ )
{
if( *i == '/' || *i == '\\' )
*i = slash;
}
return sFixed;
}
char Path_GetSlash()
{
#if defined(_WIN32)
return '\\';
#else
return '/';
#endif
}
/** Jams two paths together with the right kind of slash */
std::string Path_Join( const std::string & first, const std::string & second, char slash )
{
if( slash == 0 )
slash = Path_GetSlash();
// only insert a slash if we don't already have one
std::string::size_type nLen = first.length();
if( !nLen )
return second;
#if defined(_WIN32)
if( first.back() == '\\' || first.back() == '/' )
nLen--;
#else
char last_char = first[first.length()-1];
if (last_char == '\\' || last_char == '/')
nLen--;
#endif
return first.substr( 0, nLen ) + std::string( 1, slash ) + second;
}
std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, char slash )
{
return Path_Join( Path_Join( first, second, slash ), third, slash );
}
std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, const std::string &fourth, char slash )
{
return Path_Join( Path_Join( Path_Join( first, second, slash ), third, slash ), fourth, slash );
}
std::string Path_Join(
const std::string & first,
const std::string & second,
const std::string & third,
const std::string & fourth,
const std::string & fifth,
char slash )
{
return Path_Join( Path_Join( Path_Join( Path_Join( first, second, slash ), third, slash ), fourth, slash ), fifth, slash );
}
std::string Path_RemoveTrailingSlash( const std::string & sRawPath, char slash )
{
if ( slash == 0 )
slash = Path_GetSlash();
std::string sPath = sRawPath;
std::string::size_type nCurrent = sRawPath.length();
if ( nCurrent == 0 )
return sPath;
int nLastFound = -1;
nCurrent--;
while( nCurrent != 0 )
{
if ( sRawPath[ nCurrent ] == slash )
{
nLastFound = (int)nCurrent;
nCurrent--;
}
else
{
break;
}
}
if ( nLastFound >= 0 )
{
sPath.erase( nLastFound, std::string::npos );
}
return sPath;
}
/** Removes redundant <dir>/.. elements in the path. Returns an empty path if the
* specified path has a broken number of directories for its number of ..s */
std::string Path_Compact( const std::string & sRawPath, char slash )
{
if( slash == 0 )
slash = Path_GetSlash();
std::string sPath = Path_FixSlashes( sRawPath, slash );
std::string sSlashString( 1, slash );
// strip out all /./
for( std::string::size_type i = 0; (i + 3) < sPath.length(); )
{
if( sPath[ i ] == slash && sPath[ i+1 ] == '.' && sPath[ i+2 ] == slash )
{
sPath.replace( i, 3, sSlashString );
}
else
{
++i;
}
}
// get rid of trailing /. but leave the path separator
if( sPath.length() > 2 )
{
std::string::size_type len = sPath.length();
if( sPath[ len-1 ] == '.' && sPath[ len-2 ] == slash )
{
// sPath.pop_back();
sPath[len-1] = 0; // for now, at least
}
}
// get rid of leading ./
if( sPath.length() > 2 )
{
if( sPath[ 0 ] == '.' && sPath[ 1 ] == slash )
{
sPath.replace( 0, 2, "" );
}
}
// each time we encounter .. back up until we've found the previous directory name
// then get rid of both
std::string::size_type i = 0;
while( i < sPath.length() )
{
if( i > 0 && sPath.length() - i >= 2
&& sPath[i] == '.'
&& sPath[i+1] == '.'
&& ( i + 2 == sPath.length() || sPath[ i+2 ] == slash )
&& sPath[ i-1 ] == slash )
{
// check if we've hit the start of the string and have a bogus path
if( i == 1 )
return "";
// find the separator before i-1
std::string::size_type iDirStart = i-2;
while( iDirStart > 0 && sPath[ iDirStart - 1 ] != slash )
--iDirStart;
// remove everything from iDirStart to i+2
sPath.replace( iDirStart, (i - iDirStart) + 3, "" );
// start over
i = 0;
}
else
{
++i;
}
}
return sPath;
}
/** Returns the path to the current DLL or exe */
std::string Path_GetThisModulePath()
{
// gets the path of vrclient.dll itself
#ifdef WIN32
HMODULE hmodule = NULL;
::GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast<LPCTSTR>(Path_GetThisModulePath), &hmodule );
wchar_t *pwchPath = new wchar_t[MAX_UNICODE_PATH];
char *pchPath = new char[ MAX_UNICODE_PATH_IN_UTF8 ];
::GetModuleFileNameW( hmodule, pwchPath, MAX_UNICODE_PATH );
WideCharToMultiByte( CP_UTF8, 0, pwchPath, -1, pchPath, MAX_UNICODE_PATH_IN_UTF8, NULL, NULL );
delete[] pwchPath;
std::string sPath = pchPath;
delete [] pchPath;
return sPath;
#elif defined( OSX ) || defined( LINUX )
// get the addr of a function in vrclient.so and then ask the dlopen system about it
Dl_info info;
dladdr( (void *)Path_GetThisModulePath, &info );
return info.dli_fname;
#endif
}
/** returns true if the specified path exists and is a directory */
bool Path_IsDirectory( const std::string & sPath )
{
std::string sFixedPath = Path_FixSlashes( sPath );
if( sFixedPath.empty() )
return false;
char cLast = sFixedPath[ sFixedPath.length() - 1 ];
if( cLast == '/' || cLast == '\\' )
sFixedPath.erase( sFixedPath.end() - 1, sFixedPath.end() );
// see if the specified path actually exists.
#if defined(POSIX)
struct stat buf;
if ( stat( sFixedPath.c_str(), &buf ) == -1 )
{
return false;
}
#if defined( LINUX ) || defined( OSX )
return S_ISDIR( buf.st_mode );
#else
return (buf.st_mode & _S_IFDIR) != 0;
#endif
#else
struct _stat buf;
std::wstring wsFixedPath = UTF8to16( sFixedPath.c_str() );
if ( _wstat( wsFixedPath.c_str(), &buf ) == -1 )
{
return false;
}
return (buf.st_mode & _S_IFDIR) != 0;
#endif
}
/** returns true if the specified path represents an app bundle */
bool Path_IsAppBundle( const std::string & sPath )
{
#if defined(OSX)
NSBundle *bundle = [ NSBundle bundleWithPath: [ NSString stringWithUTF8String:sPath.c_str() ] ];
bool bisAppBundle = ( nullptr != bundle );
[ bundle release ];
return bisAppBundle;
#else
return false;
#endif
}
//-----------------------------------------------------------------------------
// Purpose: returns true if the the path exists
//-----------------------------------------------------------------------------
bool Path_Exists( const std::string & sPath )
{
std::string sFixedPath = Path_FixSlashes( sPath );
if( sFixedPath.empty() )
return false;
#if defined( WIN32 )
struct _stat buf;
std::wstring wsFixedPath = UTF8to16( sFixedPath.c_str() );
if ( _wstat( wsFixedPath.c_str(), &buf ) == -1 )
{
return false;
}
#else
struct stat buf;
if ( stat ( sFixedPath.c_str(), &buf ) == -1)
{
return false;
}
#endif
return true;
}
//-----------------------------------------------------------------------------
// Purpose: helper to find a directory upstream from a given path
//-----------------------------------------------------------------------------
std::string Path_FindParentDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName )
{
std::string strFoundPath = "";
std::string strCurrentPath = Path_FixSlashes( strStartDirectory );
if ( strCurrentPath.length() == 0 )
return "";
bool bExists = Path_Exists( strCurrentPath );
std::string strCurrentDirectoryName = Path_StripDirectory( strCurrentPath );
if ( bExists && stricmp( strCurrentDirectoryName.c_str(), strDirectoryName.c_str() ) == 0 )
return strCurrentPath;
while( bExists && strCurrentPath.length() != 0 )
{
strCurrentPath = Path_StripFilename( strCurrentPath );
strCurrentDirectoryName = Path_StripDirectory( strCurrentPath );
bExists = Path_Exists( strCurrentPath );
if ( bExists && stricmp( strCurrentDirectoryName.c_str(), strDirectoryName.c_str() ) == 0 )
return strCurrentPath;
}
return "";
}
//-----------------------------------------------------------------------------
// Purpose: helper to find a subdirectory upstream from a given path
//-----------------------------------------------------------------------------
std::string Path_FindParentSubDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName )
{
std::string strFoundPath = "";
std::string strCurrentPath = Path_FixSlashes( strStartDirectory );
if ( strCurrentPath.length() == 0 )
return "";
bool bExists = Path_Exists( strCurrentPath );
while( bExists && strCurrentPath.length() != 0 )
{
strCurrentPath = Path_StripFilename( strCurrentPath );
bExists = Path_Exists( strCurrentPath );
if( Path_Exists( Path_Join( strCurrentPath, strDirectoryName ) ) )
{
strFoundPath = Path_Join( strCurrentPath, strDirectoryName );
break;
}
}
return strFoundPath;
}
//-----------------------------------------------------------------------------
// Purpose: reading and writing files in the vortex directory
//-----------------------------------------------------------------------------
unsigned char * Path_ReadBinaryFile( const std::string &strFilename, int *pSize )
{
FILE *f;
#if defined( POSIX )
f = fopen( strFilename.c_str(), "rb" );
#else
std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
// the open operation needs to be sharable, therefore use of _wfsopen instead of _wfopen_s
f = _wfsopen( wstrFilename.c_str(), L"rb", _SH_DENYNO );
#endif
unsigned char* buf = NULL;
if ( f != NULL )
{
fseek(f, 0, SEEK_END);
int size = ftell(f);
fseek(f, 0, SEEK_SET);
buf = new unsigned char[size];
if (buf && fread(buf, size, 1, f) == 1)
{
if (pSize)
*pSize = size;
}
else
{
delete[] buf;
buf = 0;
}
fclose(f);
}
return buf;
}
uint32_t Path_ReadBinaryFile( const std::string &strFilename, unsigned char *pBuffer, uint32_t unSize )
{
FILE *f;
#if defined( POSIX )
f = fopen( strFilename.c_str(), "rb" );
#else
std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"rb" );
if ( err != 0 )
{
f = NULL;
}
#endif
uint32_t unSizeToReturn = 0;
if ( f != NULL )
{
fseek( f, 0, SEEK_END );
uint32_t size = (uint32_t)ftell( f );
fseek( f, 0, SEEK_SET );
if ( size > unSize || !pBuffer )
{
unSizeToReturn = (uint32_t)size;
}
else
{
if ( fread( pBuffer, size, 1, f ) == 1 )
{
unSizeToReturn = (uint32_t)size;
}
}
fclose( f );
}
return unSizeToReturn;
}
bool Path_WriteBinaryFile(const std::string &strFilename, unsigned char *pData, unsigned nSize)
{
FILE *f;
#if defined( POSIX )
f = fopen(strFilename.c_str(), "wb");
#else
std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"wb" );
if (err != 0)
{
f = NULL;
}
#endif
size_t written = 0;
if (f != NULL) {
written = fwrite(pData, sizeof(unsigned char), nSize, f);
fclose(f);
}
return written = nSize ? true : false;
}
std::string Path_ReadTextFile( const std::string &strFilename )
{
// doing it this way seems backwards, but I don't
// see an easy way to do this with C/C++ style IO
// that isn't worse...
int size;
unsigned char* buf = Path_ReadBinaryFile( strFilename, &size );
if (!buf)
return "";
// convert CRLF -> LF
size_t outsize = 1;
for (int i=1; i < size; i++)
{
if (buf[i] == '\n' && buf[i-1] == '\r') // CRLF
buf[outsize-1] = '\n'; // ->LF
else
buf[outsize++] = buf[i]; // just copy
}
std::string ret((char *)buf, outsize);
delete[] buf;
return ret;
}
bool Path_WriteStringToTextFile( const std::string &strFilename, const char *pchData )
{
FILE *f;
#if defined( POSIX )
f = fopen( strFilename.c_str(), "w" );
#else
std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"w" );
if ( err != 0 )
{
f = NULL;
}
#endif
bool ok = false;
if ( f != NULL )
{
ok = fputs( pchData, f) >= 0;
fclose(f);
}
return ok;
}
bool Path_WriteStringToTextFileAtomic( const std::string &strFilename, const char *pchData )
{
std::string strTmpFilename = strFilename + ".tmp";
if ( !Path_WriteStringToTextFile( strTmpFilename, pchData ) )
return false;
// Platform specific atomic file replacement
#if defined( _WIN32 )
std::wstring wsFilename = UTF8to16( strFilename.c_str() );
std::wstring wsTmpFilename = UTF8to16( strTmpFilename.c_str() );
if ( !::ReplaceFileW( wsFilename.c_str(), wsTmpFilename.c_str(), nullptr, 0, 0, 0 ) )
{
// if we couldn't ReplaceFile, try a non-atomic write as a fallback
if ( !Path_WriteStringToTextFile( strFilename, pchData ) )
return false;
}
#elif defined( POSIX )
if ( rename( strTmpFilename.c_str(), strFilename.c_str() ) == -1 )
return false;
#else
#error Do not know how to write atomic file
#endif
return true;
}
#if defined(WIN32)
#define FILE_URL_PREFIX "file:///"
#else
#define FILE_URL_PREFIX "file://"
#endif
// ----------------------------------------------------------------------------------------------------------------------------
// Purpose: Turns a path to a file on disk into a URL (or just returns the value if it's already a URL)
// ----------------------------------------------------------------------------------------------------------------------------
std::string Path_FilePathToUrl( const std::string & sRelativePath, const std::string & sBasePath )
{
if ( !strnicmp( sRelativePath.c_str(), "http://", 7 )
|| !strnicmp( sRelativePath.c_str(), "https://", 8 )
|| !strnicmp( sRelativePath.c_str(), "file://", 7 ) )
{
return sRelativePath;
}
else
{
std::string sAbsolute = Path_MakeAbsolute( sRelativePath, sBasePath );
if ( sAbsolute.empty() )
return sAbsolute;
return std::string( FILE_URL_PREFIX ) + sAbsolute;
}
}
// -----------------------------------------------------------------------------------------------------
// Purpose: Strips off file:// off a URL and returns the path. For other kinds of URLs an empty string is returned
// -----------------------------------------------------------------------------------------------------
std::string Path_UrlToFilePath( const std::string & sFileUrl )
{
if ( !strnicmp( sFileUrl.c_str(), FILE_URL_PREFIX, strlen( FILE_URL_PREFIX ) ) )
{
return sFileUrl.c_str() + strlen( FILE_URL_PREFIX );
}
else
{
return "";
}
}
// -----------------------------------------------------------------------------------------------------
// Purpose: Returns the root of the directory the system wants us to store user documents in
// -----------------------------------------------------------------------------------------------------
std::string GetUserDocumentsPath()
{
#if defined( WIN32 )
WCHAR rwchPath[MAX_PATH];
if ( !SUCCEEDED( SHGetFolderPathW( NULL, CSIDL_MYDOCUMENTS | CSIDL_FLAG_CREATE, NULL, 0, rwchPath ) ) )
{
return "";
}
// Convert the path to UTF-8 and store in the output
std::string sUserPath = UTF16to8( rwchPath );
return sUserPath;
#elif defined( OSX )
@autoreleasepool {
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES );
if ( [paths count] == 0 )
{
return "";
}
return [[paths objectAtIndex:0] UTF8String];
}
#elif defined( LINUX )
// @todo: not solved/changed as part of OSX - still not real - just removed old class based steam cut and paste
const char *pchHome = getenv( "HOME" );
if ( pchHome == NULL )
{
return "";
}
return pchHome;
#endif
}

View file

@ -0,0 +1,129 @@
//========= Copyright Valve Corporation ============//
#pragma once
#include <string>
#include <stdint.h>
/** Returns the path (including filename) to the current executable */
std::string Path_GetExecutablePath();
/** Returns the path of the current working directory */
std::string Path_GetWorkingDirectory();
/** Sets the path of the current working directory. Returns true if this was successful. */
bool Path_SetWorkingDirectory( const std::string & sPath );
/** returns the path (including filename) of the current shared lib or DLL */
std::string Path_GetThisModulePath();
/** Returns the specified path without its filename.
* If slash is unspecified the native path separator of the current platform
* will be used. */
std::string Path_StripFilename( const std::string & sPath, char slash = 0 );
/** returns just the filename from the provided full or relative path. */
std::string Path_StripDirectory( const std::string & sPath, char slash = 0 );
/** returns just the filename with no extension of the provided filename.
* If there is a path the path is left intact. */
std::string Path_StripExtension( const std::string & sPath );
/** returns just extension of the provided filename (if any). */
std::string Path_GetExtension( const std::string & sPath );
/** Returns true if the path is absolute */
bool Path_IsAbsolute( const std::string & sPath );
/** Makes an absolute path from a relative path and a base path */
std::string Path_MakeAbsolute( const std::string & sRelativePath, const std::string & sBasePath, char slash = 0 );
/** Fixes the directory separators for the current platform.
* If slash is unspecified the native path separator of the current platform
* will be used. */
std::string Path_FixSlashes( const std::string & sPath, char slash = 0 );
/** Returns the path separator for the current platform */
char Path_GetSlash();
/** Jams two paths together with the right kind of slash */
std::string Path_Join( const std::string & first, const std::string & second, char slash = 0 );
std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, char slash = 0 );
std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, const std::string &fourth, char slash = 0 );
std::string Path_Join(
const std::string & first,
const std::string & second,
const std::string & third,
const std::string & fourth,
const std::string & fifth,
char slash = 0 );
/** Removes redundant <dir>/.. elements in the path. Returns an empty path if the
* specified path has a broken number of directories for its number of ..s.
* If slash is unspecified the native path separator of the current platform
* will be used. */
std::string Path_Compact( const std::string & sRawPath, char slash = 0 );
//** Removed trailing slashes */
std::string Path_RemoveTrailingSlash( const std::string & sRawPath, char slash = 0 );
/** returns true if the specified path exists and is a directory */
bool Path_IsDirectory( const std::string & sPath );
/** returns true if the specified path represents an app bundle */
bool Path_IsAppBundle( const std::string & sPath );
/** returns true if the the path exists */
bool Path_Exists( const std::string & sPath );
/** Helper functions to find parent directories or subdirectories of parent directories */
std::string Path_FindParentDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName );
std::string Path_FindParentSubDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName );
/** Path operations to read or write text/binary files */
unsigned char * Path_ReadBinaryFile( const std::string &strFilename, int *pSize );
uint32_t Path_ReadBinaryFile( const std::string &strFilename, unsigned char *pBuffer, uint32_t unSize );
bool Path_WriteBinaryFile( const std::string &strFilename, unsigned char *pData, unsigned nSize );
std::string Path_ReadTextFile( const std::string &strFilename );
bool Path_WriteStringToTextFile( const std::string &strFilename, const char *pchData );
bool Path_WriteStringToTextFileAtomic( const std::string &strFilename, const char *pchData );
/** Returns a file:// url for paths, or an http or https url if that's what was provided */
std::string Path_FilePathToUrl( const std::string & sRelativePath, const std::string & sBasePath );
/** Strips off file:// off a URL and returns the path. For other kinds of URLs an empty string is returned */
std::string Path_UrlToFilePath( const std::string & sFileUrl );
/** Returns the root of the directory the system wants us to store user documents in */
std::string GetUserDocumentsPath();
#ifndef MAX_UNICODE_PATH
#define MAX_UNICODE_PATH 32767
#endif
#ifndef MAX_UNICODE_PATH_IN_UTF8
#define MAX_UNICODE_PATH_IN_UTF8 (MAX_UNICODE_PATH * 4)
#endif
//-----------------------------------------------------------------------------
#if defined(WIN32)
#define DYNAMIC_LIB_EXT ".dll"
#ifdef _WIN64
#define PLATSUBDIR "win64"
#else
#define PLATSUBDIR "win32"
#endif
#elif defined(OSX)
#define DYNAMIC_LIB_EXT ".dylib"
#define PLATSUBDIR "osx32"
#elif defined(LINUX)
#define DYNAMIC_LIB_EXT ".so"
#if defined( LINUX32 )
#define PLATSUBDIR "linux32"
#else
#define PLATSUBDIR "linux64"
#endif
#else
#warning "Unknown platform for PLATSUBDIR"
#define PLATSUBDIR "unknown_platform"
#endif

View file

@ -0,0 +1,41 @@
//========= Copyright Valve Corporation ============//
#include "sharedlibtools_public.h"
#include <string.h>
#if defined(_WIN32)
#include <Windows.h>
#endif
#if defined(POSIX)
#include <dlfcn.h>
#endif
SharedLibHandle SharedLib_Load( const char *pchPath )
{
#if defined( _WIN32)
return (SharedLibHandle)LoadLibraryEx( pchPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
#elif defined(POSIX)
return (SharedLibHandle)dlopen(pchPath, RTLD_LOCAL|RTLD_NOW);
#endif
}
void *SharedLib_GetFunction( SharedLibHandle lib, const char *pchFunctionName)
{
#if defined( _WIN32)
return GetProcAddress( (HMODULE)lib, pchFunctionName );
#elif defined(POSIX)
return dlsym( lib, pchFunctionName );
#endif
}
void SharedLib_Unload( SharedLibHandle lib )
{
#if defined( _WIN32)
FreeLibrary( (HMODULE)lib );
#elif defined(POSIX)
dlclose( lib );
#endif
}

View file

@ -0,0 +1,10 @@
//========= Copyright Valve Corporation ============//
#pragma once
typedef void *SharedLibHandle;
SharedLibHandle SharedLib_Load( const char *pchPath );
void *SharedLib_GetFunction( SharedLibHandle lib, const char *pchFunctionName);
void SharedLib_Unload( SharedLibHandle lib );

View file

@ -0,0 +1,439 @@
//========= Copyright Valve Corporation ============//
#include "strtools_public.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool StringHasPrefix( const std::string & sString, const std::string & sPrefix )
{
return 0 == strnicmp( sString.c_str(), sPrefix.c_str(), sPrefix.length() );
}
bool StringHasPrefixCaseSensitive( const std::string & sString, const std::string & sPrefix )
{
return 0 == strncmp( sString.c_str(), sPrefix.c_str(), sPrefix.length() );
}
bool StringHasSuffix( const std::string &sString, const std::string &sSuffix )
{
size_t cStrLen = sString.length();
size_t cSuffixLen = sSuffix.length();
if ( cSuffixLen > cStrLen )
return false;
std::string sStringSuffix = sString.substr( cStrLen - cSuffixLen, cSuffixLen );
return 0 == stricmp( sStringSuffix.c_str(), sSuffix.c_str() );
}
bool StringHasSuffixCaseSensitive( const std::string &sString, const std::string &sSuffix )
{
size_t cStrLen = sString.length();
size_t cSuffixLen = sSuffix.length();
if ( cSuffixLen > cStrLen )
return false;
std::string sStringSuffix = sString.substr( cStrLen - cSuffixLen, cSuffixLen );
return 0 == strncmp( sStringSuffix.c_str(), sSuffix.c_str(),cSuffixLen );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
std::string UTF16to8(const wchar_t * in)
{
std::string out;
unsigned int codepoint = 0;
for ( ; in && *in != 0; ++in )
{
if (*in >= 0xd800 && *in <= 0xdbff)
codepoint = ((*in - 0xd800) << 10) + 0x10000;
else
{
if (*in >= 0xdc00 && *in <= 0xdfff)
codepoint |= *in - 0xdc00;
else
codepoint = *in;
if (codepoint <= 0x7f)
out.append(1, static_cast<char>(codepoint));
else if (codepoint <= 0x7ff)
{
out.append(1, static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
else if (codepoint <= 0xffff)
{
out.append(1, static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
else
{
out.append(1, static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
codepoint = 0;
}
}
return out;
}
std::wstring UTF8to16(const char * in)
{
std::wstring out;
unsigned int codepoint = 0;
int following = 0;
for ( ; in && *in != 0; ++in )
{
unsigned char ch = *in;
if (ch <= 0x7f)
{
codepoint = ch;
following = 0;
}
else if (ch <= 0xbf)
{
if (following > 0)
{
codepoint = (codepoint << 6) | (ch & 0x3f);
--following;
}
}
else if (ch <= 0xdf)
{
codepoint = ch & 0x1f;
following = 1;
}
else if (ch <= 0xef)
{
codepoint = ch & 0x0f;
following = 2;
}
else
{
codepoint = ch & 0x07;
following = 3;
}
if (following == 0)
{
if (codepoint > 0xffff)
{
out.append(1, static_cast<wchar_t>(0xd800 + (codepoint >> 10)));
out.append(1, static_cast<wchar_t>(0xdc00 + (codepoint & 0x03ff)));
}
else
out.append(1, static_cast<wchar_t>(codepoint));
codepoint = 0;
}
}
return out;
}
void strcpy_safe( char *pchBuffer, size_t unBufferSizeBytes, const char *pchSource )
{
pchBuffer[ unBufferSizeBytes - 1 ] = '\0';
strncpy( pchBuffer, pchSource, unBufferSizeBytes - 1 );
}
// --------------------------------------------------------------------
// Purpose: converts a string to upper case
// --------------------------------------------------------------------
std::string StringToUpper( const std::string & sString )
{
std::string sOut;
sOut.reserve( sString.size() + 1 );
for( std::string::const_iterator i = sString.begin(); i != sString.end(); i++ )
{
sOut.push_back( (char)toupper( *i ) );
}
return sOut;
}
// --------------------------------------------------------------------
// Purpose: converts a string to lower case
// --------------------------------------------------------------------
std::string StringToLower( const std::string & sString )
{
std::string sOut;
sOut.reserve( sString.size() + 1 );
for( std::string::const_iterator i = sString.begin(); i != sString.end(); i++ )
{
sOut.push_back( (char)tolower( *i ) );
}
return sOut;
}
uint32_t ReturnStdString( const std::string & sValue, char *pchBuffer, uint32_t unBufferLen )
{
uint32_t unLen = (uint32_t)sValue.length() + 1;
if( !pchBuffer || !unBufferLen )
return unLen;
if( unBufferLen < unLen )
{
pchBuffer[0] = '\0';
}
else
{
memcpy( pchBuffer, sValue.c_str(), unLen );
}
return unLen;
}
void BufferToStdString( std::string & sDest, const char *pchBuffer, uint32_t unBufferLen )
{
sDest.resize( unBufferLen + 1 );
memcpy( const_cast< char* >( sDest.c_str() ), pchBuffer, unBufferLen );
const_cast< char* >( sDest.c_str() )[ unBufferLen ] = '\0';
}
// Commented out by Mozilla, please see README.mozilla
/** Returns a std::string from a uint64_t */
/*
std::string Uint64ToString( uint64_t ulValue )
{
char buf[ 22 ];
#if defined( _WIN32 )
sprintf_s( buf, "%llu", ulValue );
#else
snprintf( buf, sizeof( buf ), "%llu", (long long unsigned int ) ulValue );
#endif
return buf;
}
*/
/** returns a uint64_t from a string */
uint64_t StringToUint64( const std::string & sValue )
{
return strtoull( sValue.c_str(), NULL, 0 );
}
//-----------------------------------------------------------------------------
// Purpose: Helper for converting a numeric value to a hex digit, value should be 0-15.
//-----------------------------------------------------------------------------
char cIntToHexDigit( int nValue )
{
//Assert( nValue >= 0 && nValue <= 15 );
return "0123456789ABCDEF"[ nValue & 15 ];
}
//-----------------------------------------------------------------------------
// Purpose: Helper for converting a hex char value to numeric, return -1 if the char
// is not a valid hex digit.
//-----------------------------------------------------------------------------
int iHexCharToInt( char cValue )
{
int32_t iValue = cValue;
if ( (uint32_t)( iValue - '0' ) < 10 )
return iValue - '0';
iValue |= 0x20;
if ( (uint32_t)( iValue - 'a' ) < 6 )
return iValue - 'a' + 10;
return -1;
}
//-----------------------------------------------------------------------------
// Purpose: Internal implementation of encode, works in the strict RFC manner, or
// with spaces turned to + like HTML form encoding.
//-----------------------------------------------------------------------------
void V_URLEncodeInternal( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen, bool bUsePlusForSpace )
{
//AssertMsg( nDestLen > 3*nSourceLen, "Target buffer for V_URLEncode should be 3x source length, plus one for terminating null\n" );
int iDestPos = 0;
for ( int i=0; i < nSourceLen; ++i )
{
// worst case we need 3 additional chars
if( (iDestPos+3) > nDestLen )
{
pchDest[0] = '\0';
// AssertMsg( false, "Target buffer too short\n" );
return;
}
// We allow only a-z, A-Z, 0-9, period, underscore, and hyphen to pass through unescaped.
// These are the characters allowed by both the original RFC 1738 and the latest RFC 3986.
// Current specs also allow '~', but that is forbidden under original RFC 1738.
if ( !( pchSource[i] >= 'a' && pchSource[i] <= 'z' ) && !( pchSource[i] >= 'A' && pchSource[i] <= 'Z' ) && !(pchSource[i] >= '0' && pchSource[i] <= '9' )
&& pchSource[i] != '-' && pchSource[i] != '_' && pchSource[i] != '.'
)
{
if ( bUsePlusForSpace && pchSource[i] == ' ' )
{
pchDest[iDestPos++] = '+';
}
else
{
pchDest[iDestPos++] = '%';
uint8_t iValue = pchSource[i];
if ( iValue == 0 )
{
pchDest[iDestPos++] = '0';
pchDest[iDestPos++] = '0';
}
else
{
char cHexDigit1 = cIntToHexDigit( iValue % 16 );
iValue /= 16;
char cHexDigit2 = cIntToHexDigit( iValue );
pchDest[iDestPos++] = cHexDigit2;
pchDest[iDestPos++] = cHexDigit1;
}
}
}
else
{
pchDest[iDestPos++] = pchSource[i];
}
}
if( (iDestPos+1) > nDestLen )
{
pchDest[0] = '\0';
//AssertMsg( false, "Target buffer too short to terminate\n" );
return;
}
// Null terminate
pchDest[iDestPos++] = 0;
}
//-----------------------------------------------------------------------------
// Purpose: Internal implementation of decode, works in the strict RFC manner, or
// with spaces turned to + like HTML form encoding.
//
// Returns the amount of space used in the output buffer.
//-----------------------------------------------------------------------------
size_t V_URLDecodeInternal( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen, bool bUsePlusForSpace )
{
if ( nDecodeDestLen < nEncodedSourceLen )
{
//AssertMsg( false, "V_URLDecode needs a dest buffer at least as large as the source" );
return 0;
}
int iDestPos = 0;
for( int i=0; i < nEncodedSourceLen; ++i )
{
if ( bUsePlusForSpace && pchEncodedSource[i] == '+' )
{
pchDecodeDest[ iDestPos++ ] = ' ';
}
else if ( pchEncodedSource[i] == '%' )
{
// Percent signifies an encoded value, look ahead for the hex code, convert to numeric, and use that
// First make sure we have 2 more chars
if ( i < nEncodedSourceLen - 2 )
{
char cHexDigit1 = pchEncodedSource[i+1];
char cHexDigit2 = pchEncodedSource[i+2];
// Turn the chars into a hex value, if they are not valid, then we'll
// just place the % and the following two chars direct into the string,
// even though this really shouldn't happen, who knows what bad clients
// may do with encoding.
bool bValid = false;
int iValue = iHexCharToInt( cHexDigit1 );
if ( iValue != -1 )
{
iValue *= 16;
int iValue2 = iHexCharToInt( cHexDigit2 );
if ( iValue2 != -1 )
{
iValue += iValue2;
pchDecodeDest[ iDestPos++ ] = (char)iValue;
bValid = true;
}
}
if ( !bValid )
{
pchDecodeDest[ iDestPos++ ] = '%';
pchDecodeDest[ iDestPos++ ] = cHexDigit1;
pchDecodeDest[ iDestPos++ ] = cHexDigit2;
}
}
// Skip ahead
i += 2;
}
else
{
pchDecodeDest[ iDestPos++ ] = pchEncodedSource[i];
}
}
// We may not have extra room to NULL terminate, since this can be used on raw data, but if we do
// go ahead and do it as this can avoid bugs.
if ( iDestPos < nDecodeDestLen )
{
pchDecodeDest[iDestPos] = 0;
}
return (size_t)iDestPos;
}
//-----------------------------------------------------------------------------
// Purpose: Encodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
// This version of the call isn't a strict RFC implementation, but uses + for space as is
// the standard in HTML form encoding, despite it not being part of the RFC.
//
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
//-----------------------------------------------------------------------------
void V_URLEncode( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen )
{
return V_URLEncodeInternal( pchDest, nDestLen, pchSource, nSourceLen, true );
}
//-----------------------------------------------------------------------------
// Purpose: Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
// This version of the call isn't a strict RFC implementation, but uses + for space as is
// the standard in HTML form encoding, despite it not being part of the RFC.
//
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
// Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed.
//-----------------------------------------------------------------------------
size_t V_URLDecode( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen )
{
return V_URLDecodeInternal( pchDecodeDest, nDecodeDestLen, pchEncodedSource, nEncodedSourceLen, true );
}
//-----------------------------------------------------------------------------
void V_StripExtension( std::string &in )
{
// Find the last dot. If it's followed by a dot or a slash, then it's part of a
// directory specifier like ../../somedir/./blah.
std::string::size_type test = in.rfind( '.' );
if ( test != std::string::npos )
{
// This handles things like ".\blah" or "c:\my@email.com\abc\def\geh"
// Which would otherwise wind up with "" and "c:\my@email", respectively.
if ( in.rfind( '\\' ) < test && in.rfind( '/' ) < test )
{
in.resize( test );
}
}
}

View file

@ -0,0 +1,127 @@
//========= Copyright Valve Corporation ============//
#pragma once
#include <string>
#include <stdint.h>
#include <sys/types.h>
/** returns true if the string has the prefix */
bool StringHasPrefix( const std::string & sString, const std::string & sPrefix );
bool StringHasPrefixCaseSensitive( const std::string & sString, const std::string & sPrefix );
/** returns if the string has the suffix */
bool StringHasSuffix( const std::string &sString, const std::string &sSuffix );
bool StringHasSuffixCaseSensitive( const std::string &sString, const std::string &sSuffix );
/** converts a UTF-16 string to a UTF-8 string */
std::string UTF16to8(const wchar_t * in);
/** converts a UTF-8 string to a UTF-16 string */
std::wstring UTF8to16(const char * in);
#define Utf16FromUtf8 UTF8to16
/** safely copy a string into a buffer */
void strcpy_safe( char *pchBuffer, size_t unBufferSizeBytes, const char *pchSource );
template< size_t bufferSize >
void strcpy_safe( char (& buffer) [ bufferSize ], const char *pchSource )
{
strcpy_safe( buffer, bufferSize, pchSource );
}
/** converts a string to upper case */
std::string StringToUpper( const std::string & sString );
/** converts a string to lower case */
std::string StringToLower( const std::string & sString );
// we stricmp (from WIN) but it isn't POSIX - OSX/LINUX have strcasecmp so just inline bridge to it
#if defined( OSX ) || defined( LINUX )
#include <strings.h>
inline int stricmp(const char *pStr1, const char *pStr2) { return strcasecmp(pStr1,pStr2); }
#define _stricmp stricmp
inline int strnicmp( const char *pStr1, const char *pStr2, size_t unBufferLen ) { return strncasecmp( pStr1,pStr2, unBufferLen ); }
#define _strnicmp strnicmp
#define _vsnprintf_s vsnprintf
#define _TRUNCATE ((size_t)-1)
#endif
#if defined( OSX )
// behaviors ensure NULL-termination at least as well as _TRUNCATE does, but
// wcsncpy_s/strncpy_s can non-NULL-terminate, wcslcpy/strlcpy can not.
inline errno_t wcsncpy_s(wchar_t *strDest, size_t numberOfElements, const wchar_t *strSource, size_t count)
{
return wcslcpy(strDest, strSource, numberOfElements);
}
inline errno_t strncpy_s(char *strDest, size_t numberOfElements, const char *strSource, size_t count)
{
return strlcpy(strDest, strSource, numberOfElements);
}
#endif
#if defined( LINUX )
// this implementation does not return whether or not the destination was
// truncated, but that is straightforward to fix if anybody actually needs the
// return code.
#include "string.h"
inline void wcsncpy_s(wchar_t *strDest, size_t numberOfElements, const wchar_t *strSource, size_t count)
{
wcsncpy(strDest, strSource, numberOfElements);
strDest[numberOfElements-1] = '\0';
}
inline void strncpy_s(char *strDest, size_t numberOfElements, const char *strSource, size_t count)
{
strncpy(strDest, strSource, numberOfElements);
strDest[numberOfElements-1] = '\0';
}
#endif
#if defined( _WIN32 ) && _MSC_VER < 1800
inline uint64_t strtoull(const char *str, char **endptr, int base) { return _strtoui64( str, endptr, base ); }
#endif
/* Handles copying a std::string into a buffer as would be provided in an API */
uint32_t ReturnStdString( const std::string & sValue, char *pchBuffer, uint32_t unBufferLen );
/* Handles copying a buffer into an std::string and auto adds null terminator */
void BufferToStdString( std::string & sDest, const char *pchBuffer, uint32_t unBufferLen );
/** Returns a std::string from a uint64_t */
// std::string Uint64ToString( uint64_t ulValue );
// Commented out by Mozilla, please see README.mozilla
/** returns a uint64_t from a string */
uint64_t StringToUint64( const std::string & sValue );
//-----------------------------------------------------------------------------
// Purpose: Encodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
// This version of the call isn't a strict RFC implementation, but uses + for space as is
// the standard in HTML form encoding, despite it not being part of the RFC.
//
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
//-----------------------------------------------------------------------------
void V_URLEncode( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen );
//-----------------------------------------------------------------------------
// Purpose: Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2.
// This version of the call isn't a strict RFC implementation, but uses + for space as is
// the standard in HTML form encoding, despite it not being part of the RFC.
//
// Dest buffer should be at least as large as source buffer to guarantee room for decode.
// Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed.
//-----------------------------------------------------------------------------
size_t V_URLDecode( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen );
//-----------------------------------------------------------------------------
// Purpose: strip extension from a path
//-----------------------------------------------------------------------------
void V_StripExtension( std::string &in );

View file

@ -0,0 +1,409 @@
//========= Copyright Valve Corporation ============//
#include "vrpathregistry_public.h"
#include "json/json.h"
#include "pathtools_public.h"
#include "envvartools_public.h"
#include "strtools_public.h"
#include "dirtools_public.h"
#if defined( WIN32 )
#include <windows.h>
#include <Shlobj.h>
#undef GetEnvironmentVariable
#elif defined OSX
#include <Foundation/Foundation.h>
#include <AppKit/AppKit.h>
#elif defined(LINUX)
#include <dlfcn.h>
#include <stdio.h>
#endif
#include <algorithm>
#ifndef VRLog
#if defined( WIN32 )
#define VRLog(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
#else
#define VRLog(args...) fprintf(stderr, args)
#endif
#endif
/** Returns the root of the directory the system wants us to store user config data in */
static std::string GetAppSettingsPath()
{
#if defined( WIN32 )
WCHAR rwchPath[MAX_PATH];
if( !SUCCEEDED( SHGetFolderPathW( NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, rwchPath ) ) )
{
return "";
}
// Convert the path to UTF-8 and store in the output
std::string sUserPath = UTF16to8( rwchPath );
return sUserPath;
#elif defined( OSX )
std::string sSettingsDir;
@autoreleasepool {
// Search for the path
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSApplicationSupportDirectory, NSUserDomainMask, YES );
if ( [paths count] == 0 )
{
return "";
}
NSString *resolvedPath = [paths objectAtIndex:0];
resolvedPath = [resolvedPath stringByAppendingPathComponent: @"OpenVR"];
if ( ![[NSFileManager new] createDirectoryAtPath: resolvedPath withIntermediateDirectories:YES attributes:nil error:nil] )
{
return "";
}
sSettingsDir.assign( [resolvedPath UTF8String] );
}
return sSettingsDir;
#elif defined( LINUX )
// As defined by XDG Base Directory Specification
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
const char *pchHome = getenv("XDG_CONFIG_HOME");
if ( ( pchHome != NULL) && ( pchHome[0] != '\0' ) )
{
return pchHome;
}
//
// XDG_CONFIG_HOME is not defined, use ~/.config instead
//
pchHome = getenv( "HOME" );
if ( pchHome == NULL )
{
return "";
}
std::string sUserPath( pchHome );
sUserPath = Path_Join( sUserPath, ".config" );
return sUserPath;
#else
#warning "Unsupported platform"
#endif
}
// ---------------------------------------------------------------------------
// Purpose: Constructor
// ---------------------------------------------------------------------------
CVRPathRegistry_Public::CVRPathRegistry_Public()
{
}
// ---------------------------------------------------------------------------
// Purpose: Computes the registry filename
// ---------------------------------------------------------------------------
std::string CVRPathRegistry_Public::GetOpenVRConfigPath()
{
std::string sConfigPath = GetAppSettingsPath();
if( sConfigPath.empty() )
return "";
#if defined( _WIN32 ) || defined( LINUX )
sConfigPath = Path_Join( sConfigPath, "openvr" );
#elif defined ( OSX )
sConfigPath = Path_Join( sConfigPath, ".openvr" );
#else
#warning "Unsupported platform"
#endif
sConfigPath = Path_FixSlashes( sConfigPath );
return sConfigPath;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
std::string CVRPathRegistry_Public::GetVRPathRegistryFilename()
{
std::string sPath = GetOpenVRConfigPath();
if ( sPath.empty() )
return "";
#if defined( _WIN32 )
sPath = Path_Join( sPath, "openvrpaths.vrpath" );
#elif defined ( POSIX )
sPath = Path_Join( sPath, "openvrpaths.vrpath" );
#else
#error "Unsupported platform"
#endif
sPath = Path_FixSlashes( sPath );
return sPath;
}
// ---------------------------------------------------------------------------
// Purpose: Converts JSON to a history array
// ---------------------------------------------------------------------------
static void ParseStringListFromJson( std::vector< std::string > *pvecHistory, const Json::Value & root, const char *pchArrayName )
{
if( !root.isMember( pchArrayName ) )
return;
const Json::Value & arrayNode = root[ pchArrayName ];
if( !arrayNode )
{
VRLog( "VR Path Registry node %s is not an array\n", pchArrayName );
return;
}
pvecHistory->clear();
pvecHistory->reserve( arrayNode.size() );
for( uint32_t unIndex = 0; unIndex < arrayNode.size(); unIndex++ )
{
std::string sPath( arrayNode[ unIndex ].asString() );
pvecHistory->push_back( sPath );
}
}
// ---------------------------------------------------------------------------
// Purpose: Converts a history array to JSON
// ---------------------------------------------------------------------------
static void StringListToJson( const std::vector< std::string > & vecHistory, Json::Value & root, const char *pchArrayName )
{
Json::Value & arrayNode = root[ pchArrayName ];
for( auto i = vecHistory.begin(); i != vecHistory.end(); i++ )
{
arrayNode.append( *i );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CVRPathRegistry_Public::ToJsonString( std::string &sJsonString )
{
std::string sRegPath = GetVRPathRegistryFilename();
if( sRegPath.empty() )
return false;
std::string sRegistryContents = Path_ReadTextFile( sRegPath );
if( sRegistryContents.empty() )
return false;
sJsonString = sRegistryContents;
return true;
}
// ---------------------------------------------------------------------------
// Purpose: Loads the config file from its well known location
// ---------------------------------------------------------------------------
bool CVRPathRegistry_Public::BLoadFromFile()
{
std::string sRegPath = GetVRPathRegistryFilename();
if( sRegPath.empty() )
{
VRLog( "Unable to determine VR Path Registry filename\n" );
return false;
}
std::string sRegistryContents = Path_ReadTextFile( sRegPath );
if( sRegistryContents.empty() )
{
VRLog( "Unable to read VR Path Registry from %s\n", sRegPath.c_str() );
return false;
}
Json::Value root;
Json::Reader reader;
if( !reader.parse( sRegistryContents, root ) )
{
VRLog( "Unable to parse %s: %s\n", sRegPath.c_str(), reader.getFormattedErrorMessages().c_str() );
return false;
}
ParseStringListFromJson( &m_vecRuntimePath, root, "runtime" );
ParseStringListFromJson( &m_vecConfigPath, root, "config" );
ParseStringListFromJson( &m_vecLogPath, root, "log" );
if (root.isMember( "external_drivers" ) && root[ "external_drivers" ].isArray() )
{
ParseStringListFromJson( &m_vecExternalDrivers, root, "external_drivers" );
}
return true;
}
// ---------------------------------------------------------------------------
// Purpose: Saves the config file to its well known location
// ---------------------------------------------------------------------------
bool CVRPathRegistry_Public::BSaveToFile() const
{
#if defined( DASHBOARD_BUILD_MODE )
return false;
#else
std::string sRegPath = GetVRPathRegistryFilename();
if( sRegPath.empty() )
return false;
Json::Value root;
root[ "version" ] = 1;
root[ "jsonid" ] = "vrpathreg";
StringListToJson( m_vecRuntimePath, root, "runtime" );
StringListToJson( m_vecConfigPath, root, "config" );
StringListToJson( m_vecLogPath, root, "log" );
StringListToJson( m_vecExternalDrivers, root, "external_drivers" );
Json::StyledWriter writer;
std::string sRegistryContents = writer.write( root );
// make sure the directory we're writing into actually exists
std::string sRegDirectory = Path_StripFilename( sRegPath );
if( !BCreateDirectoryRecursive( sRegDirectory.c_str() ) )
{
VRLog( "Unable to create path registry directory %s\n", sRegDirectory.c_str() );
return false;
}
if( !Path_WriteStringToTextFile( sRegPath, sRegistryContents.c_str() ) )
{
VRLog( "Unable to write VR path registry to %s\n", sRegPath.c_str() );
return false;
}
return true;
#endif
}
// ---------------------------------------------------------------------------
// Purpose: Returns the current runtime path or NULL if no path is configured.
// ---------------------------------------------------------------------------
std::string CVRPathRegistry_Public::GetRuntimePath() const
{
if( m_vecRuntimePath.empty() )
return "";
else
return m_vecRuntimePath.front().c_str();
}
// ---------------------------------------------------------------------------
// Purpose: Returns the current config path or NULL if no path is configured.
// ---------------------------------------------------------------------------
std::string CVRPathRegistry_Public::GetConfigPath() const
{
if( m_vecConfigPath.empty() )
return "";
else
return m_vecConfigPath.front().c_str();
}
// ---------------------------------------------------------------------------
// Purpose: Returns the current log path or NULL if no path is configured.
// ---------------------------------------------------------------------------
std::string CVRPathRegistry_Public::GetLogPath() const
{
if( m_vecLogPath.empty() )
return "";
else
return m_vecLogPath.front().c_str();
}
// ---------------------------------------------------------------------------
// Purpose: Returns paths using the path registry and the provided override
// values. Pass NULL for any paths you don't care about.
// ---------------------------------------------------------------------------
bool CVRPathRegistry_Public::GetPaths( std::string *psRuntimePath, std::string *psConfigPath, std::string *psLogPath, const char *pchConfigPathOverride, const char *pchLogPathOverride, std::vector<std::string> *pvecExternalDrivers )
{
CVRPathRegistry_Public pathReg;
bool bLoadedRegistry = pathReg.BLoadFromFile();
int nCountEnvironmentVariables = 0;
if( psRuntimePath )
{
if ( GetEnvironmentVariable( k_pchRuntimeOverrideVar ).length() != 0 )
{
*psRuntimePath = GetEnvironmentVariable( k_pchRuntimeOverrideVar );
nCountEnvironmentVariables++;
}
else if( !pathReg.GetRuntimePath().empty() )
{
*psRuntimePath = pathReg.GetRuntimePath();
}
else
{
*psRuntimePath = "";
}
}
if( psConfigPath )
{
if ( GetEnvironmentVariable( k_pchConfigOverrideVar ).length() != 0 )
{
*psConfigPath = GetEnvironmentVariable( k_pchConfigOverrideVar );
nCountEnvironmentVariables++;
}
else if( pchConfigPathOverride )
{
*psConfigPath = pchConfigPathOverride;
}
else if( !pathReg.GetConfigPath().empty() )
{
*psConfigPath = pathReg.GetConfigPath();
}
else
{
*psConfigPath = "";
}
}
if( psLogPath )
{
if ( GetEnvironmentVariable( k_pchLogOverrideVar ).length() != 0 )
{
*psLogPath = GetEnvironmentVariable( k_pchLogOverrideVar );
nCountEnvironmentVariables++;
}
else if( pchLogPathOverride )
{
*psLogPath = pchLogPathOverride;
}
else if( !pathReg.GetLogPath().empty() )
{
*psLogPath = pathReg.GetLogPath();
}
else
{
*psLogPath = "";
}
}
if ( pvecExternalDrivers )
{
*pvecExternalDrivers = pathReg.m_vecExternalDrivers;
}
if ( nCountEnvironmentVariables == 3 )
{
// all three environment variables where set, so we don't need the physical file
return true;
}
return bLoadedRegistry;
}

View file

@ -0,0 +1,45 @@
//========= Copyright Valve Corporation ============//
#pragma once
#include <string>
#include <vector>
#include <stdint.h>
static const char *k_pchRuntimeOverrideVar = "VR_OVERRIDE";
static const char *k_pchConfigOverrideVar = "VR_CONFIG_PATH";
static const char *k_pchLogOverrideVar = "VR_LOG_PATH";
class CVRPathRegistry_Public
{
public:
static std::string GetVRPathRegistryFilename();
static std::string GetOpenVRConfigPath();
public:
CVRPathRegistry_Public();
/** Returns paths using the path registry and the provided override values. Pass NULL for any paths you don't care about.
* Returns false if the path registry could not be read. Valid paths might still be returned based on environment variables. */
static bool GetPaths( std::string *psRuntimePath, std::string *psConfigPath, std::string *psLogPath, const char *pchConfigPathOverride, const char *pchLogPathOverride, std::vector<std::string> *pvecExternalDrivers = NULL );
bool BLoadFromFile();
bool BSaveToFile() const;
bool ToJsonString( std::string &sJsonString );
// methods to get the current values
std::string GetRuntimePath() const;
std::string GetConfigPath() const;
std::string GetLogPath() const;
protected:
typedef std::vector< std::string > StringVector_t;
// index 0 is the current setting
StringVector_t m_vecRuntimePath;
StringVector_t m_vecLogPath;
StringVector_t m_vecConfigPath;
// full list of external drivers
StringVector_t m_vecExternalDrivers;
};

View file

@ -5076,8 +5076,6 @@ pref("dom.vr.poseprediction.enabled", true);
// this requirement to be disabled for special cases such as during automated
// tests or in a headless kiosk system.
pref("dom.vr.require-gesture", true);
// path to openvr DLL
pref("gfx.vr.openvr-runtime", "");
// path to OSVR DLLs
pref("gfx.vr.osvr.utilLibPath", "");
pref("gfx.vr.osvr.commonLibPath", "");

View file

@ -12,6 +12,7 @@ gfx/harfbuzz/
gfx/ots/
gfx/qcms/
gfx/skia/
gfx/vr/openvr/
gfx/webrender
gfx/webrender_traits
gfx/ycbcr/