summaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/OVR_Profile.h
diff options
context:
space:
mode:
Diffstat (limited to 'LibOVR/Src/OVR_Profile.h')
-rw-r--r--LibOVR/Src/OVR_Profile.h385
1 files changed, 248 insertions, 137 deletions
diff --git a/LibOVR/Src/OVR_Profile.h b/LibOVR/Src/OVR_Profile.h
index df25fea..2c5e4c2 100644
--- a/LibOVR/Src/OVR_Profile.h
+++ b/LibOVR/Src/OVR_Profile.h
@@ -6,7 +6,7 @@ Content : Structs and functions for loading and storing device profile set
Created : February 14, 2013
Notes :
Profiles are used to store per-user settings that can be transferred and used
- across multiple applications. For example, player IPD can be configured once
+ across multiple applications. For example, player IPD can be configured once
and reused for a unified experience across games. Configuration and saving of profiles
can be accomplished in game via the Profile API or by the official Oculus Configuration
Utility.
@@ -25,11 +25,12 @@ otherwise accompanies this software in either electronic or hard copy form.
#include "Kernel/OVR_String.h"
#include "Kernel/OVR_RefCount.h"
#include "Kernel/OVR_Array.h"
+#include "Kernel/OVR_Math.h"
namespace OVR {
// Defines the profile object for each device type
-enum ProfileType
+enum ProfileDeviceType
{
Profile_Unknown = 0,
Profile_GenericHMD = 10,
@@ -37,119 +38,17 @@ enum ProfileType
Profile_RiftDKHD = 12,
};
-class Profile;
-
-// -----------------------------------------------------------------------------
-// ***** ProfileManager
-
-// Profiles are interfaced through a ProfileManager object. Applications should
-// create a ProfileManager each time they intend to read or write user profile data.
-// The scope of the ProfileManager object defines when disk I/O is performed. Disk
-// reads are performed on the first profile access and disk writes are performed when
-// the ProfileManager goes out of scope. All profile interactions between these times
-// are performed in local memory and are fast. A typical profile interaction might
-// look like this:
//
-// {
-// Ptr<ProfileManager> pm = *ProfileManager::Create();
-// Ptr<Profile> profile = pm->LoadProfile(Profile_RiftDK1,
-// pm->GetDefaultProfileName(Profile_RiftDK1));
-// if (profile)
-// { // Retrieve the current profile settings
-// }
-// } // Profile will be destroyed and any disk I/O completed when going out of scope
-
-class ProfileManager : public RefCountBase<ProfileManager>
-{
-protected:
- // Synchronize ProfileManager access since it may be accessed from multiple threads,
- // as it's shared through DeviceManager.
- Lock ProfileLock;
- Array<Ptr<Profile> > ProfileCache;
- ProfileType CacheDevice;
- String DefaultProfile;
- bool Changed;
- char NameBuff[32];
-
-public:
- static ProfileManager* Create();
-
- // Static interface functions
- int GetProfileCount(ProfileType device);
- const char* GetProfileName(ProfileType device, unsigned int index);
- bool HasProfile(ProfileType device, const char* name);
- Profile* LoadProfile(ProfileType device, unsigned int index);
- Profile* LoadProfile(ProfileType device, const char* name);
- Profile* GetDeviceDefaultProfile(ProfileType device);
- const char* GetDefaultProfileName(ProfileType device);
- bool SetDefaultProfileName(ProfileType device, const char* name);
- bool Save(const Profile* profile);
- bool Delete(const Profile* profile);
-
-protected:
- ProfileManager();
- ~ProfileManager();
- void LoadCache(ProfileType device);
- void SaveCache();
- void ClearCache();
- Profile* CreateProfileObject(const char* user,
- ProfileType device,
- const char** device_name);
-};
-
-//-------------------------------------------------------------------
-// ***** Profile
-
-// The base profile for all users. This object is not created directly.
-// Instead derived device objects provide add specific device members to
-// the base profile
-
-class Profile : public RefCountBase<Profile>
-{
-public:
- enum { MaxNameLen = 32 };
-
- enum GenderType
- {
- Gender_Unspecified = 0,
- Gender_Male = 1,
- Gender_Female = 2
- };
-
- ProfileType Type; // The type of device profile
- char Name[MaxNameLen]; // The name given to this profile
-
-protected:
- GenderType Gender; // The gender of the user
- float PlayerHeight; // The height of the user in meters
- float IPD; // Distance between eyes in meters
-
-public:
- virtual Profile* Clone() const = 0;
-
- // These are properties which are intrinsic to the user and affect scene setup
- GenderType GetGender() { return Gender; };
- float GetPlayerHeight() { return PlayerHeight; };
- float GetIPD() { return IPD; };
- float GetEyeHeight();
-
- void SetGender(GenderType gender) { Gender = gender; };
- void SetPlayerHeight(float height) { PlayerHeight = height; };
- void SetIPD(float ipd) { IPD = ipd; };
-
-protected:
- Profile(ProfileType type, const char* name);
-
- virtual bool ParseProperty(const char* prop, const char* sval);
-
- friend class ProfileManager;
-};
+// HMDProfile and it's child classes, RiftProfile, RiftDk1Profile and
+// RiftDKHDProfile represent the intersection of 'per-user' and 'per-device'
+// settings.
+//
//-----------------------------------------------------------------------------
// ***** HMDProfile
// The generic HMD profile is used for properties that are common to all headsets
-class HMDProfile : public Profile
+class HmdDevice
{
protected:
// FOV extents in pixels measured by a user
@@ -159,8 +58,7 @@ protected:
int RR; // right eye outer extent
public:
- virtual Profile* Clone() const;
-
+ virtual ~HmdDevice() {}
void SetLL(int val) { LL = val; };
void SetLR(int val) { LR = val; };
void SetRL(int val) { RL = val; };
@@ -170,13 +68,19 @@ public:
int GetLR() { return LR; };
int GetRL() { return RL; };
int GetRR() { return RR; };
+ virtual ProfileDeviceType GetDeviceType() const {
+ return Profile_GenericHMD;
+ }
protected:
- HMDProfile(ProfileType type, const char* name);
-
- virtual bool ParseProperty(const char* prop, const char* sval);
-
- friend class ProfileManager;
+ HmdDevice() {
+ LL = 0;
+ LR = 0;
+ RL = 0;
+ RR = 0;
+ }
+ friend class ProfileLoader;
+ friend class Profile;
};
// For headsets that use eye cups
@@ -187,52 +91,259 @@ enum EyeCupType
EyeCup_C = 2
};
-//-----------------------------------------------------------------------------
-// ***** RiftDK1Profile
-
-// This profile is specific to the Rift Dev Kit 1 and contains overrides specific
-// to that device and lens cup settings.
-class RiftDK1Profile : public HMDProfile
-{
+class RiftDevice : public HmdDevice {
protected:
EyeCupType EyeCups; // Which eye cup does the player use
public:
- virtual Profile* Clone() const;
-
EyeCupType GetEyeCup() { return EyeCups; };
void SetEyeCup(EyeCupType cup) { EyeCups = cup; };
protected:
- RiftDK1Profile(const char* name);
+ RiftDevice() {
+ EyeCups = EyeCup_A;
+ }
+ friend class ProfileLoader;
+ friend class Profile;
+};
- virtual bool ParseProperty(const char* prop, const char* sval);
+//-----------------------------------------------------------------------------
+// ***** RiftDK1Profile
- friend class ProfileManager;
+// This profile is specific to the Rift Dev Kit 1 and contains overrides specific
+// to that device and lens cup settings.
+class RiftDK1Device : public RiftDevice
+{
+public:
+ virtual ProfileDeviceType GetDeviceType() const {
+ return Profile_RiftDK1;
+ }
+
+protected:
+ RiftDK1Device() {
+
+ }
+ friend class ProfileLoader;
+ friend class Profile;
};
//-----------------------------------------------------------------------------
// ***** RiftDKHDProfile
-// This profile is specific to the Rift HD Dev Kit and contains overrides specific
+// This profile is specific to the Rift HD Dev Kit and contains overrides specific
// to that device and lens cup settings.
-class RiftDKHDProfile : public HMDProfile
+class RiftDKHDDevice : public RiftDevice
{
+public:
+ virtual ProfileDeviceType GetDeviceType() const {
+ return Profile_RiftDKHD;
+ }
+
protected:
- EyeCupType EyeCups; // Which eye cup does the player use
+ RiftDKHDDevice() {
+ }
+ friend class ProfileLoader;
+ friend class Profile;
+};
+template <class KeyType>
+class KeyedObject {
public:
- virtual Profile* Clone() const;
+ virtual ~KeyedObject() {
+ }
+ virtual const KeyType & GetKey() const = 0;
+};
+//-------------------------------------------------------------------
+// ***** Profile
- EyeCupType GetEyeCup() { return EyeCups; };
- void SetEyeCup(EyeCupType cup) { EyeCups = cup; };
+// The base profile for all users. This object is not created directly.
+//
+class Profile : public RefCountBase<Profile>, KeyedObject<String>
+{
+public:
+ enum GenderType
+ {
+ Gender_Unspecified = 0,
+ Gender_Male = 1,
+ Gender_Female = 2
+ };
+
+ String Name; // The name given to this profile
protected:
- RiftDKHDProfile(const char* name);
+ GenderType Gender; // The gender of the user
+ float PlayerHeight; // The height of the user in meters
+ float IPD; // Distance between eyes in meters
+ Quatf StrabismusCorrection; // Amount to rotate modelview matrix to correct for corss-eyed vision
+ // Should be applied as is to the left eye, and inverted to apply to the
+ // right eye
+ HmdDevice Generic;
+ RiftDK1Device RiftDK1;
+ RiftDKHDDevice RiftDKHD;
- virtual bool ParseProperty(const char* prop, const char* sval);
+public:
+ const String & GetKey() const { return Name; };
+ // These are properties which are intrinsic to the user and affect scene setup
+ GenderType GetGender() const { return Gender; };
+ float GetPlayerHeight() const { return PlayerHeight; };
+ float GetIPD() const { return IPD; };
+ float GetEyeHeight() const;
+ const Quatf & GetStrabismusCorrection() const { return StrabismusCorrection; };
+ HmdDevice & GetGenericDevice() { return Generic; }
+ RiftDK1Device & GetRiftDK1Device() { return RiftDK1; }
+ RiftDKHDDevice & GetRiftDKHDDevice() { return RiftDKHD; }
+ const HmdDevice & GetGenericDevice() const { return Generic; }
+ const RiftDK1Device& GetRiftDK1Device() const { return RiftDK1; }
+ const RiftDKHDDevice&GetRiftDKHDDevice() const { return RiftDKHD; }
+
+ void SetGender(GenderType gender) { Gender = gender; };
+ void SetPlayerHeight(float height) { PlayerHeight = height; };
+ void SetIPD(float ipd) { IPD = ipd; };
+ void SetStrabismusCorrection(const Quatf & quat) { StrabismusCorrection = quat; };
+ Profile * Clone() const {
+ return new Profile(*this);
+ }
+protected:
+ Profile(const char* name);
friend class ProfileManager;
+ friend class ProfileLoader;
+};
+
+
+/*
+ * A really hacky low-performing associative array, because the
+ * ProfileManager is attempting to mimic the functionality of one
+ *
+ * It should have the same performance characteristics as the
+ * previous ProfileManager embedded implementation. I'm not write a
+ * full treemap or hashmap implementaiton because, seriously, there are
+ * plenty out there in the standard libraries, and if OVR doesn't want to
+ * use them then I'm not going to get roped into building one just to
+ * support the policy of never using STL.
+ *
+ * Using at(KeyType) instead of operator[KeyType] since the latter would
+ * interfere with ability to access the index based base class operator[]
+ */
+template <class ValueType, class KeyType>
+class AssociativePtrArray : public Array<Ptr<ValueType> > {
+public:
+ enum {
+ npos = -1
+ };
+
+ int IndexOf(const KeyType & key) const {
+ for (int i = 0; i< this->GetSize(); ++i) {
+ const Ptr<ValueType> & data = this->Data.Data[i];
+ if (data && data->GetKey() == key) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ ValueType * at(const KeyType & key) {
+ int index = IndexOf(key);
+ if (npos == index) {
+ return Ptr<ValueType>();
+ }
+ Ptr<ValueType> & ptr = this->Data.Data[index];
+ return ptr;
+ }
+
+ const ValueType * at(const KeyType & key) const {
+ int index = IndexOf(key);
+ if (npos == index) {
+ return Ptr<ValueType>();
+ }
+ const Ptr<ValueType> & ptr = this->Data.Data[index];
+ return ptr;
+ }
+};
+
+// -----------------------------------------------------------------------------
+// ***** ProfileManager
+
+// Profiles are interfaced through a ProfileManager object. Applications should
+// create a ProfileManager each time they intend to read or write user profile data.
+// The scope of the ProfileManager object defines when disk I/O is performed. Disk
+// reads are performed on the first profile access and disk writes are performed when
+// the ProfileManager goes out of scope. All profile interactions between these times
+// are performed in local memory and are fast. A typical profile interaction might
+// look like this:
+//
+// {
+// Ptr<ProfileManager> pm = *ProfileManager::Create();
+// Ptr<Profile> profile = pm->LoadProfile(pm->GetDefaultProfileName());
+// if (profile)
+// { // Retrieve the current profile settings
+// }
+// } // Profile will be destroyed and any disk I/O completed when going out of scope
+
+class ProfileManager : public RefCountBase<ProfileManager>
+{
+protected:
+ // Synchronize ProfileManager access since it may be accessed from multiple threads,
+ // as it's shared through DeviceManager.
+ Lock ProfileLock;
+ typedef AssociativePtrArray<Profile, String> Map;
+ Map ProfileCache;
+ String DefaultProfile;
+ bool Changed;
+ bool Loaded;
+ // A container for the name data returned by GetDefaultProfileName()
+ // which can't be a String, because once acquired by the caller,
+ // it can't be allowed to be deallocated without risk. Ultimately
+ // this is caused by the inability to be able to safely return the
+ // String type from methods, which itself boils down to the problem
+ // with providing an explicit operator const char *() on a String
+ // class. Doing so makes it too easy for a caller to get a char *
+ // to a temporary or have the pointer become deallocated memory
+ // at some later point unexpectedly.
+ char NameBuff[32];
+
+public:
+ static ProfileManager* Create();
+
+ // Static interface functions
+ unsigned GetProfileCount();
+ bool HasProfile(const char* name);
+ Profile* LoadProfile(const char* name);
+ Profile* GetDefaultProfile();
+ const char* GetDefaultProfileName();
+ bool SetDefaultProfileName(const char* name);
+
+ // The previous implementation seemed to imply that if you loaded
+ // some profiles for a given 'device type' and then saved changes,
+ // and then loaded a different device type, your changes would be lost
+ // because the cache would be cleared without ever being persisted to
+ // disk. The redesign fixes this by eliminating the 'per-device-type'
+ // profile mechanism.
+ //
+ // Profiles represent a users settings and they
+ // may have different settings for each device, so the profile should
+ // encapsulate all of them.
+ //
+ // Ideally, you should be able to query the top level profile for
+ // properties related to the hardware based on whatever you're using,
+ // rather than having to query specifically for generic, DK1 or DKHD
+ // but the class hierarchy makes that problematic.
+ bool Save(const Profile * profile);
+ bool Delete(const Profile * profile);
+
+ // Index based fetching is completely removed. I have no idea what
+ // was intended to be useful for. Perhaps it was intended as a
+ // potential optimization since querying by name is O(N) instead of
+ // O(1), but it's unfathomable that the performance difference would
+ // ever be noticeable, unless the caller is doing something pathological
+ // like calling using profile manager every frame, and unlikely even
+ // then
+protected:
+ ProfileManager();
+ ~ProfileManager();
+ void LoadCache();
+ void SaveCache();
+ void ClearCache();
};
@@ -240,4 +351,4 @@ String GetBaseOVRPath(bool create_dir);
}
-#endif // OVR_Profile_h \ No newline at end of file
+#endif // OVR_Profile_h