rev |
line source |
nuclear@1
|
1 /************************************************************************************
|
nuclear@1
|
2
|
nuclear@1
|
3 PublicHeader: None
|
nuclear@1
|
4 Filename : OVR_Profile.cpp
|
nuclear@1
|
5 Content : Structs and functions for loading and storing device profile settings
|
nuclear@1
|
6 Created : February 14, 2013
|
nuclear@1
|
7 Notes :
|
nuclear@1
|
8
|
nuclear@1
|
9 Profiles are used to store per-user settings that can be transferred and used
|
nuclear@1
|
10 across multiple applications. For example, player IPD can be configured once
|
nuclear@1
|
11 and reused for a unified experience across games. Configuration and saving of profiles
|
nuclear@1
|
12 can be accomplished in game via the Profile API or by the official Oculus Configuration
|
nuclear@1
|
13 Utility.
|
nuclear@1
|
14
|
nuclear@1
|
15 Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
|
nuclear@1
|
16
|
nuclear@1
|
17 Use of this software is subject to the terms of the Oculus license
|
nuclear@1
|
18 agreement provided at the time of installation or download, or which
|
nuclear@1
|
19 otherwise accompanies this software in either electronic or hard copy form.
|
nuclear@1
|
20
|
nuclear@1
|
21 ************************************************************************************/
|
nuclear@1
|
22
|
nuclear@1
|
23 #include "OVR_Profile.h"
|
nuclear@1
|
24 #include "OVR_JSON.h"
|
nuclear@1
|
25 #include "Kernel/OVR_Types.h"
|
nuclear@1
|
26 #include "Kernel/OVR_SysFile.h"
|
nuclear@1
|
27 #include "Kernel/OVR_Allocator.h"
|
nuclear@1
|
28 #include "Kernel/OVR_Array.h"
|
nuclear@1
|
29
|
nuclear@1
|
30 #ifdef OVR_OS_WIN32
|
nuclear@1
|
31 #include <Shlobj.h>
|
nuclear@1
|
32 #else
|
nuclear@1
|
33 #include <dirent.h>
|
nuclear@1
|
34 #include <sys/stat.h>
|
nuclear@1
|
35
|
nuclear@1
|
36 #ifdef OVR_OS_LINUX
|
nuclear@1
|
37 #include <unistd.h>
|
nuclear@1
|
38 #include <pwd.h>
|
nuclear@1
|
39 #endif
|
nuclear@1
|
40
|
nuclear@1
|
41 #endif
|
nuclear@1
|
42
|
nuclear@1
|
43 #define PROFILE_VERSION 1.0
|
nuclear@1
|
44
|
nuclear@1
|
45 namespace OVR {
|
nuclear@1
|
46
|
nuclear@1
|
47 //-----------------------------------------------------------------------------
|
nuclear@1
|
48 // Returns the pathname of the JSON file containing the stored profiles
|
nuclear@1
|
49 String GetBaseOVRPath(bool create_dir)
|
nuclear@1
|
50 {
|
nuclear@1
|
51 String path;
|
nuclear@1
|
52
|
nuclear@1
|
53 #if defined(OVR_OS_WIN32)
|
nuclear@1
|
54
|
nuclear@1
|
55 TCHAR data_path[MAX_PATH];
|
nuclear@1
|
56 SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, NULL, 0, data_path);
|
nuclear@1
|
57 path = String(data_path);
|
nuclear@1
|
58
|
nuclear@1
|
59 path += "/Oculus";
|
nuclear@1
|
60
|
nuclear@1
|
61 if (create_dir)
|
nuclear@1
|
62 { // Create the Oculus directory if it doesn't exist
|
nuclear@1
|
63 WCHAR wpath[128];
|
nuclear@1
|
64 OVR::UTF8Util::DecodeString(wpath, path.ToCStr());
|
nuclear@1
|
65
|
nuclear@1
|
66 DWORD attrib = GetFileAttributes(wpath);
|
nuclear@1
|
67 bool exists = attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY);
|
nuclear@1
|
68 if (!exists)
|
nuclear@1
|
69 {
|
nuclear@1
|
70 CreateDirectory(wpath, NULL);
|
nuclear@1
|
71 }
|
nuclear@1
|
72 }
|
nuclear@1
|
73
|
nuclear@1
|
74 #elif defined(OVR_OS_MAC)
|
nuclear@1
|
75
|
nuclear@1
|
76 const char* home = getenv("HOME");
|
nuclear@1
|
77 path = home;
|
nuclear@1
|
78 path += "/Library/Preferences/Oculus";
|
nuclear@1
|
79
|
nuclear@1
|
80 if (create_dir)
|
nuclear@1
|
81 { // Create the Oculus directory if it doesn't exist
|
nuclear@1
|
82 DIR* dir = opendir(path);
|
nuclear@1
|
83 if (dir == NULL)
|
nuclear@1
|
84 {
|
nuclear@1
|
85 mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
|
nuclear@1
|
86 }
|
nuclear@1
|
87 else
|
nuclear@1
|
88 {
|
nuclear@1
|
89 closedir(dir);
|
nuclear@1
|
90 }
|
nuclear@1
|
91 }
|
nuclear@1
|
92
|
nuclear@1
|
93 #else
|
nuclear@1
|
94
|
nuclear@1
|
95 passwd* pwd = getpwuid(getuid());
|
nuclear@1
|
96 const char* home = pwd->pw_dir;
|
nuclear@1
|
97 path = home;
|
nuclear@1
|
98 path += "/.config/Oculus";
|
nuclear@1
|
99
|
nuclear@1
|
100 if (create_dir)
|
nuclear@1
|
101 { // Create the Oculus directory if it doesn't exist
|
nuclear@1
|
102 DIR* dir = opendir(path);
|
nuclear@1
|
103 if (dir == NULL)
|
nuclear@1
|
104 {
|
nuclear@1
|
105 mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
|
nuclear@1
|
106 }
|
nuclear@1
|
107 else
|
nuclear@1
|
108 {
|
nuclear@1
|
109 closedir(dir);
|
nuclear@1
|
110 }
|
nuclear@1
|
111 }
|
nuclear@1
|
112
|
nuclear@1
|
113 #endif
|
nuclear@1
|
114
|
nuclear@1
|
115 return path;
|
nuclear@1
|
116 }
|
nuclear@1
|
117
|
nuclear@1
|
118 String GetProfilePath(bool create_dir)
|
nuclear@1
|
119 {
|
nuclear@1
|
120 String path = GetBaseOVRPath(create_dir);
|
nuclear@1
|
121 path += "/Profiles.json";
|
nuclear@1
|
122 return path;
|
nuclear@1
|
123 }
|
nuclear@1
|
124
|
nuclear@1
|
125 //-----------------------------------------------------------------------------
|
nuclear@1
|
126 // ***** ProfileManager
|
nuclear@1
|
127
|
nuclear@1
|
128 ProfileManager::ProfileManager()
|
nuclear@1
|
129 {
|
nuclear@1
|
130 Changed = false;
|
nuclear@1
|
131 CacheDevice = Profile_Unknown;
|
nuclear@1
|
132 }
|
nuclear@1
|
133
|
nuclear@1
|
134 ProfileManager::~ProfileManager()
|
nuclear@1
|
135 {
|
nuclear@1
|
136 // If the profiles have been altered then write out the profile file
|
nuclear@1
|
137 if (Changed)
|
nuclear@1
|
138 SaveCache();
|
nuclear@1
|
139
|
nuclear@1
|
140 ClearCache();
|
nuclear@1
|
141 }
|
nuclear@1
|
142
|
nuclear@1
|
143 ProfileManager* ProfileManager::Create()
|
nuclear@1
|
144 {
|
nuclear@1
|
145 return new ProfileManager();
|
nuclear@1
|
146 }
|
nuclear@1
|
147
|
nuclear@1
|
148 Profile* ProfileManager::CreateProfileObject(const char* user,
|
nuclear@1
|
149 ProfileType device,
|
nuclear@1
|
150 const char** device_name)
|
nuclear@1
|
151 {
|
nuclear@1
|
152 Lock::Locker lockScope(&ProfileLock);
|
nuclear@1
|
153
|
nuclear@1
|
154 Profile* profile = NULL;
|
nuclear@1
|
155 switch (device)
|
nuclear@1
|
156 {
|
nuclear@1
|
157 case Profile_RiftDK1:
|
nuclear@1
|
158 *device_name = "RiftDK1";
|
nuclear@1
|
159 profile = new RiftDK1Profile(user);
|
nuclear@1
|
160 break;
|
nuclear@1
|
161 case Profile_RiftDKHD:
|
nuclear@1
|
162 case Profile_Unknown:
|
nuclear@1
|
163 break;
|
nuclear@1
|
164 }
|
nuclear@1
|
165
|
nuclear@1
|
166 return profile;
|
nuclear@1
|
167 }
|
nuclear@1
|
168
|
nuclear@1
|
169
|
nuclear@1
|
170 // Clear the local profile cache
|
nuclear@1
|
171 void ProfileManager::ClearCache()
|
nuclear@1
|
172 {
|
nuclear@1
|
173 Lock::Locker lockScope(&ProfileLock);
|
nuclear@1
|
174
|
nuclear@1
|
175 ProfileCache.Clear();
|
nuclear@1
|
176 CacheDevice = Profile_Unknown;
|
nuclear@1
|
177 }
|
nuclear@1
|
178
|
nuclear@1
|
179
|
nuclear@1
|
180 // Poplulates the local profile cache. This occurs on the first access of the profile
|
nuclear@1
|
181 // data. All profile operations are performed against the local cache until the
|
nuclear@1
|
182 // ProfileManager is released or goes out of scope at which time the cache is serialized
|
nuclear@1
|
183 // to disk.
|
nuclear@1
|
184 void ProfileManager::LoadCache(ProfileType device)
|
nuclear@1
|
185 {
|
nuclear@1
|
186 Lock::Locker lockScope(&ProfileLock);
|
nuclear@1
|
187
|
nuclear@1
|
188 ClearCache();
|
nuclear@1
|
189
|
nuclear@1
|
190 String path = GetProfilePath(false);
|
nuclear@1
|
191
|
nuclear@1
|
192 Ptr<JSON> root = *JSON::Load(path);
|
nuclear@1
|
193 if (!root || root->GetItemCount() < 3)
|
nuclear@1
|
194 return;
|
nuclear@1
|
195
|
nuclear@1
|
196 // First read the file type and version to make sure this is a valid file
|
nuclear@1
|
197 JSON* item0 = root->GetFirstItem();
|
nuclear@1
|
198 JSON* item1 = root->GetNextItem(item0);
|
nuclear@1
|
199 JSON* item2 = root->GetNextItem(item1);
|
nuclear@1
|
200
|
nuclear@1
|
201 if (OVR_strcmp(item0->Name, "Oculus Profile Version") == 0)
|
nuclear@1
|
202 { // In the future I may need to check versioning to determine parse method
|
nuclear@1
|
203 }
|
nuclear@1
|
204 else
|
nuclear@1
|
205 {
|
nuclear@1
|
206 return;
|
nuclear@1
|
207 }
|
nuclear@1
|
208
|
nuclear@1
|
209 DefaultProfile = item1->Value;
|
nuclear@1
|
210
|
nuclear@1
|
211 // Read the number of profiles
|
nuclear@1
|
212 int profileCount = (int)item2->dValue;
|
nuclear@1
|
213 JSON* profileItem = item2;
|
nuclear@1
|
214
|
nuclear@1
|
215 for (int p=0; p<profileCount; p++)
|
nuclear@1
|
216 {
|
nuclear@1
|
217 profileItem = profileItem->GetNextItem(profileItem);
|
nuclear@1
|
218 if (!profileItem)
|
nuclear@1
|
219 break;
|
nuclear@1
|
220
|
nuclear@1
|
221 // Read the required Name field
|
nuclear@1
|
222 const char* profileName;
|
nuclear@1
|
223 JSON* item = profileItem->GetFirstItem();
|
nuclear@1
|
224
|
nuclear@1
|
225 if (item && (OVR_strcmp(item->Name, "Name") == 0))
|
nuclear@1
|
226 {
|
nuclear@1
|
227 profileName = item->Value;
|
nuclear@1
|
228 }
|
nuclear@1
|
229 else
|
nuclear@1
|
230 {
|
nuclear@1
|
231 return; // invalid field
|
nuclear@1
|
232 }
|
nuclear@1
|
233
|
nuclear@1
|
234 const char* deviceName = 0;
|
nuclear@1
|
235 bool deviceFound = false;
|
nuclear@1
|
236 Ptr<Profile> profile = *CreateProfileObject(profileName, device, &deviceName);
|
nuclear@1
|
237
|
nuclear@1
|
238 // Read the base profile fields.
|
nuclear@1
|
239 if (profile)
|
nuclear@1
|
240 {
|
nuclear@1
|
241 while (item = profileItem->GetNextItem(item), item)
|
nuclear@1
|
242 {
|
nuclear@1
|
243 if (item->Type != JSON_Object)
|
nuclear@1
|
244 {
|
nuclear@1
|
245 profile->ParseProperty(item->Name, item->Value);
|
nuclear@1
|
246 }
|
nuclear@1
|
247 else
|
nuclear@1
|
248 { // Search for the matching device to get device specific fields
|
nuclear@1
|
249 if (!deviceFound && OVR_strcmp(item->Name, deviceName) == 0)
|
nuclear@1
|
250 {
|
nuclear@1
|
251 deviceFound = true;
|
nuclear@1
|
252
|
nuclear@1
|
253 for (JSON* deviceItem = item->GetFirstItem(); deviceItem;
|
nuclear@1
|
254 deviceItem = item->GetNextItem(deviceItem))
|
nuclear@1
|
255 {
|
nuclear@1
|
256 profile->ParseProperty(deviceItem->Name, deviceItem->Value);
|
nuclear@1
|
257 }
|
nuclear@1
|
258 }
|
nuclear@1
|
259 }
|
nuclear@1
|
260 }
|
nuclear@1
|
261 }
|
nuclear@1
|
262
|
nuclear@1
|
263 // Add the new profile
|
nuclear@1
|
264 if (deviceFound)
|
nuclear@1
|
265 ProfileCache.PushBack(profile);
|
nuclear@1
|
266 }
|
nuclear@1
|
267
|
nuclear@1
|
268 CacheDevice = device;
|
nuclear@1
|
269 }
|
nuclear@1
|
270
|
nuclear@1
|
271
|
nuclear@1
|
272 // Serializes the profiles to disk.
|
nuclear@1
|
273 void ProfileManager::SaveCache()
|
nuclear@1
|
274 {
|
nuclear@1
|
275 String path = GetProfilePath(true);
|
nuclear@1
|
276
|
nuclear@1
|
277 Lock::Locker lockScope(&ProfileLock);
|
nuclear@1
|
278
|
nuclear@1
|
279 // TODO: Since there is only a single device type now, a full tree overwrite
|
nuclear@1
|
280 // is sufficient but in the future a selective device branch replacement will
|
nuclear@1
|
281 // be necessary
|
nuclear@1
|
282
|
nuclear@1
|
283 Ptr<JSON> root = *JSON::CreateObject();
|
nuclear@1
|
284 root->AddNumberItem("Oculus Profile Version", PROFILE_VERSION);
|
nuclear@1
|
285 root->AddStringItem("CurrentProfile", DefaultProfile);
|
nuclear@1
|
286 root->AddNumberItem("ProfileCount", (double) ProfileCache.GetSize());
|
nuclear@1
|
287
|
nuclear@1
|
288 // Generate a JSON subtree for each profile
|
nuclear@1
|
289 for (unsigned int i=0; i<ProfileCache.GetSize(); i++)
|
nuclear@1
|
290 {
|
nuclear@1
|
291 Profile* profile = ProfileCache[i];
|
nuclear@1
|
292
|
nuclear@1
|
293 JSON* json_profile = JSON::CreateObject();
|
nuclear@1
|
294 json_profile->Name = "Profile";
|
nuclear@1
|
295 json_profile->AddStringItem("Name", profile->Name);
|
nuclear@1
|
296 const char* gender;
|
nuclear@1
|
297 switch (profile->GetGender())
|
nuclear@1
|
298 {
|
nuclear@1
|
299 case Profile::Gender_Male: gender = "Male"; break;
|
nuclear@1
|
300 case Profile::Gender_Female: gender = "Female"; break;
|
nuclear@1
|
301 default: gender = "Unspecified";
|
nuclear@1
|
302 }
|
nuclear@1
|
303 json_profile->AddStringItem("Gender", gender);
|
nuclear@1
|
304 json_profile->AddNumberItem("PlayerHeight", profile->PlayerHeight);
|
nuclear@1
|
305 json_profile->AddNumberItem("IPD", profile->IPD);
|
nuclear@1
|
306
|
nuclear@1
|
307 if (profile->Type == Profile_RiftDK1)
|
nuclear@1
|
308 {
|
nuclear@1
|
309 RiftDK1Profile* riftdk1 = (RiftDK1Profile*)profile;
|
nuclear@1
|
310 JSON* json_riftdk1 = JSON::CreateObject();
|
nuclear@1
|
311 json_profile->AddItem("RiftDK1", json_riftdk1);
|
nuclear@1
|
312
|
nuclear@1
|
313 const char* eyecup = "A";
|
nuclear@1
|
314 switch (riftdk1->EyeCups)
|
nuclear@1
|
315 {
|
nuclear@1
|
316 case RiftDK1Profile::EyeCup_A: eyecup = "A"; break;
|
nuclear@1
|
317 case RiftDK1Profile::EyeCup_B: eyecup = "B"; break;
|
nuclear@1
|
318 case RiftDK1Profile::EyeCup_C: eyecup = "C"; break;
|
nuclear@1
|
319 }
|
nuclear@1
|
320 json_riftdk1->AddStringItem("EyeCup", eyecup);
|
nuclear@1
|
321 json_riftdk1->AddNumberItem("LL", riftdk1->LL);
|
nuclear@1
|
322 json_riftdk1->AddNumberItem("LR", riftdk1->LR);
|
nuclear@1
|
323 json_riftdk1->AddNumberItem("RL", riftdk1->RL);
|
nuclear@1
|
324 json_riftdk1->AddNumberItem("RR", riftdk1->RR);
|
nuclear@1
|
325 }
|
nuclear@1
|
326
|
nuclear@1
|
327 root->AddItem("Profile", json_profile);
|
nuclear@1
|
328 }
|
nuclear@1
|
329
|
nuclear@1
|
330 root->Save(path);
|
nuclear@1
|
331 }
|
nuclear@1
|
332
|
nuclear@1
|
333 // Returns the number of stored profiles for this device type
|
nuclear@1
|
334 int ProfileManager::GetProfileCount(ProfileType device)
|
nuclear@1
|
335 {
|
nuclear@1
|
336 Lock::Locker lockScope(&ProfileLock);
|
nuclear@1
|
337
|
nuclear@1
|
338 if (CacheDevice == Profile_Unknown)
|
nuclear@1
|
339 LoadCache(device);
|
nuclear@1
|
340
|
nuclear@1
|
341 return (int)ProfileCache.GetSize();
|
nuclear@1
|
342 }
|
nuclear@1
|
343
|
nuclear@1
|
344 // Returns the profile name of a specific profile in the list. The returned
|
nuclear@1
|
345 // memory is locally allocated and should not be stored or deleted. Returns NULL
|
nuclear@1
|
346 // if the index is invalid
|
nuclear@1
|
347 const char* ProfileManager::GetProfileName(ProfileType device, unsigned int index)
|
nuclear@1
|
348 {
|
nuclear@1
|
349 Lock::Locker lockScope(&ProfileLock);
|
nuclear@1
|
350
|
nuclear@1
|
351 if (CacheDevice == Profile_Unknown)
|
nuclear@1
|
352 LoadCache(device);
|
nuclear@1
|
353
|
nuclear@1
|
354 if (index < ProfileCache.GetSize())
|
nuclear@1
|
355 {
|
nuclear@1
|
356 Profile* profile = ProfileCache[index];
|
nuclear@1
|
357 OVR_strcpy(NameBuff, Profile::MaxNameLen, profile->Name);
|
nuclear@1
|
358 return NameBuff;
|
nuclear@1
|
359 }
|
nuclear@1
|
360 else
|
nuclear@1
|
361 {
|
nuclear@1
|
362 return NULL;
|
nuclear@1
|
363 }
|
nuclear@1
|
364 }
|
nuclear@1
|
365
|
nuclear@1
|
366 bool ProfileManager::HasProfile(ProfileType device, const char* name)
|
nuclear@1
|
367 {
|
nuclear@1
|
368 Lock::Locker lockScope(&ProfileLock);
|
nuclear@1
|
369
|
nuclear@1
|
370 if (CacheDevice == Profile_Unknown)
|
nuclear@1
|
371 LoadCache(device);
|
nuclear@1
|
372
|
nuclear@1
|
373 for (unsigned i = 0; i< ProfileCache.GetSize(); i++)
|
nuclear@1
|
374 {
|
nuclear@1
|
375 if (ProfileCache[i] && OVR_strcmp(ProfileCache[i]->Name, name) == 0)
|
nuclear@1
|
376 return true;
|
nuclear@1
|
377 }
|
nuclear@1
|
378 return false;
|
nuclear@1
|
379 }
|
nuclear@1
|
380
|
nuclear@1
|
381
|
nuclear@1
|
382 // Returns a specific profile object in the list. The returned memory should be
|
nuclear@1
|
383 // encapsulated in a Ptr<> object or released after use. Returns NULL if the index
|
nuclear@1
|
384 // is invalid
|
nuclear@1
|
385 Profile* ProfileManager::LoadProfile(ProfileType device, unsigned int index)
|
nuclear@1
|
386 {
|
nuclear@1
|
387 Lock::Locker lockScope(&ProfileLock);
|
nuclear@1
|
388
|
nuclear@1
|
389 if (CacheDevice == Profile_Unknown)
|
nuclear@1
|
390 LoadCache(device);
|
nuclear@1
|
391
|
nuclear@1
|
392 if (index < ProfileCache.GetSize())
|
nuclear@1
|
393 {
|
nuclear@1
|
394 Profile* profile = ProfileCache[index];
|
nuclear@1
|
395 return profile->Clone();
|
nuclear@1
|
396 }
|
nuclear@1
|
397 else
|
nuclear@1
|
398 {
|
nuclear@1
|
399 return NULL;
|
nuclear@1
|
400 }
|
nuclear@1
|
401 }
|
nuclear@1
|
402
|
nuclear@1
|
403 // Returns a profile object for a particular device and user name. The returned
|
nuclear@1
|
404 // memory should be encapsulated in a Ptr<> object or released after use. Returns
|
nuclear@1
|
405 // NULL if the profile is not found
|
nuclear@1
|
406 Profile* ProfileManager::LoadProfile(ProfileType device, const char* user)
|
nuclear@1
|
407 {
|
nuclear@1
|
408 if (user == NULL)
|
nuclear@1
|
409 return NULL;
|
nuclear@1
|
410
|
nuclear@1
|
411 Lock::Locker lockScope(&ProfileLock);
|
nuclear@1
|
412
|
nuclear@1
|
413 if (CacheDevice == Profile_Unknown)
|
nuclear@1
|
414 LoadCache(device);
|
nuclear@1
|
415
|
nuclear@1
|
416 for (unsigned int i=0; i<ProfileCache.GetSize(); i++)
|
nuclear@1
|
417 {
|
nuclear@1
|
418 if (OVR_strcmp(user, ProfileCache[i]->Name) == 0)
|
nuclear@1
|
419 { // Found the requested user profile
|
nuclear@1
|
420 Profile* profile = ProfileCache[i];
|
nuclear@1
|
421 return profile->Clone();
|
nuclear@1
|
422 }
|
nuclear@1
|
423 }
|
nuclear@1
|
424
|
nuclear@1
|
425 return NULL;
|
nuclear@1
|
426 }
|
nuclear@1
|
427
|
nuclear@1
|
428 // Returns a profile with all system default values
|
nuclear@1
|
429 Profile* ProfileManager::GetDeviceDefaultProfile(ProfileType device)
|
nuclear@1
|
430 {
|
nuclear@1
|
431 const char* device_name = NULL;
|
nuclear@1
|
432 return CreateProfileObject("default", device, &device_name);
|
nuclear@1
|
433 }
|
nuclear@1
|
434
|
nuclear@1
|
435 // Returns the name of the profile that is marked as the current default user.
|
nuclear@1
|
436 const char* ProfileManager::GetDefaultProfileName(ProfileType device)
|
nuclear@1
|
437 {
|
nuclear@1
|
438 Lock::Locker lockScope(&ProfileLock);
|
nuclear@1
|
439
|
nuclear@1
|
440 if (CacheDevice == Profile_Unknown)
|
nuclear@1
|
441 LoadCache(device);
|
nuclear@1
|
442
|
nuclear@1
|
443 if (ProfileCache.GetSize() > 0)
|
nuclear@1
|
444 {
|
nuclear@1
|
445 OVR_strcpy(NameBuff, Profile::MaxNameLen, DefaultProfile);
|
nuclear@1
|
446 return NameBuff;
|
nuclear@1
|
447 }
|
nuclear@1
|
448 else
|
nuclear@1
|
449 {
|
nuclear@1
|
450 return NULL;
|
nuclear@1
|
451 }
|
nuclear@1
|
452 }
|
nuclear@1
|
453
|
nuclear@1
|
454 // Marks a particular user as the current default user.
|
nuclear@1
|
455 bool ProfileManager::SetDefaultProfileName(ProfileType device, const char* name)
|
nuclear@1
|
456 {
|
nuclear@1
|
457 Lock::Locker lockScope(&ProfileLock);
|
nuclear@1
|
458
|
nuclear@1
|
459 if (CacheDevice == Profile_Unknown)
|
nuclear@1
|
460 LoadCache(device);
|
nuclear@1
|
461 // TODO: I should verify that the user is valid
|
nuclear@1
|
462 if (ProfileCache.GetSize() > 0)
|
nuclear@1
|
463 {
|
nuclear@1
|
464 DefaultProfile = name;
|
nuclear@1
|
465 Changed = true;
|
nuclear@1
|
466 return true;
|
nuclear@1
|
467 }
|
nuclear@1
|
468 else
|
nuclear@1
|
469 {
|
nuclear@1
|
470 return false;
|
nuclear@1
|
471 }
|
nuclear@1
|
472 }
|
nuclear@1
|
473
|
nuclear@1
|
474
|
nuclear@1
|
475 // Saves a new or existing profile. Returns true on success or false on an
|
nuclear@1
|
476 // invalid or failed save.
|
nuclear@1
|
477 bool ProfileManager::Save(const Profile* profile)
|
nuclear@1
|
478 {
|
nuclear@1
|
479 Lock::Locker lockScope(&ProfileLock);
|
nuclear@1
|
480
|
nuclear@1
|
481 if (OVR_strcmp(profile->Name, "default") == 0)
|
nuclear@1
|
482 return false; // don't save a default profile
|
nuclear@1
|
483
|
nuclear@1
|
484 // TODO: I should also verify that this profile type matches the current cache
|
nuclear@1
|
485 if (CacheDevice == Profile_Unknown)
|
nuclear@1
|
486 LoadCache(profile->Type);
|
nuclear@1
|
487
|
nuclear@1
|
488 // Look for the pre-existence of this profile
|
nuclear@1
|
489 bool added = false;
|
nuclear@1
|
490 for (unsigned int i=0; i<ProfileCache.GetSize(); i++)
|
nuclear@1
|
491 {
|
nuclear@1
|
492 int compare = OVR_strcmp(profile->Name, ProfileCache[i]->Name);
|
nuclear@1
|
493
|
nuclear@1
|
494 if (compare == 0)
|
nuclear@1
|
495 {
|
nuclear@1
|
496 // TODO: I should do a proper field comparison to avoid unnecessary
|
nuclear@1
|
497 // overwrites and file saves
|
nuclear@1
|
498
|
nuclear@1
|
499 // Replace the previous instance with the new profile
|
nuclear@1
|
500 ProfileCache[i] = *profile->Clone();
|
nuclear@1
|
501 added = true;
|
nuclear@1
|
502 Changed = true;
|
nuclear@1
|
503 break;
|
nuclear@1
|
504 }
|
nuclear@1
|
505 }
|
nuclear@1
|
506
|
nuclear@1
|
507 if (!added)
|
nuclear@1
|
508 {
|
nuclear@1
|
509 ProfileCache.PushBack(*profile->Clone());
|
nuclear@1
|
510 if (ProfileCache.GetSize() == 1)
|
nuclear@1
|
511 CacheDevice = profile->Type;
|
nuclear@1
|
512
|
nuclear@1
|
513 Changed = true;
|
nuclear@1
|
514 }
|
nuclear@1
|
515
|
nuclear@1
|
516 return true;
|
nuclear@1
|
517 }
|
nuclear@1
|
518
|
nuclear@1
|
519 // Removes an existing profile. Returns true if the profile was found and deleted
|
nuclear@1
|
520 // and returns false otherwise.
|
nuclear@1
|
521 bool ProfileManager::Delete(const Profile* profile)
|
nuclear@1
|
522 {
|
nuclear@1
|
523 Lock::Locker lockScope(&ProfileLock);
|
nuclear@1
|
524
|
nuclear@1
|
525 if (OVR_strcmp(profile->Name, "default") == 0)
|
nuclear@1
|
526 return false; // don't delete a default profile
|
nuclear@1
|
527
|
nuclear@1
|
528 if (CacheDevice == Profile_Unknown)
|
nuclear@1
|
529 LoadCache(profile->Type);
|
nuclear@1
|
530
|
nuclear@1
|
531 // Look for the existence of this profile
|
nuclear@1
|
532 for (unsigned int i=0; i<ProfileCache.GetSize(); i++)
|
nuclear@1
|
533 {
|
nuclear@1
|
534 if (OVR_strcmp(profile->Name, ProfileCache[i]->Name) == 0)
|
nuclear@1
|
535 {
|
nuclear@1
|
536 if (OVR_strcmp(profile->Name, DefaultProfile) == 0)
|
nuclear@1
|
537 DefaultProfile.Clear();
|
nuclear@1
|
538
|
nuclear@1
|
539 ProfileCache.RemoveAt(i);
|
nuclear@1
|
540 Changed = true;
|
nuclear@1
|
541 return true;
|
nuclear@1
|
542 }
|
nuclear@1
|
543 }
|
nuclear@1
|
544
|
nuclear@1
|
545 return false;
|
nuclear@1
|
546 }
|
nuclear@1
|
547
|
nuclear@1
|
548
|
nuclear@1
|
549
|
nuclear@1
|
550 //-----------------------------------------------------------------------------
|
nuclear@1
|
551 // ***** Profile
|
nuclear@1
|
552
|
nuclear@1
|
553 Profile::Profile(ProfileType device, const char* name)
|
nuclear@1
|
554 {
|
nuclear@1
|
555 Type = device;
|
nuclear@1
|
556 Gender = Gender_Unspecified;
|
nuclear@1
|
557 PlayerHeight = 1.778f; // 5'10" inch man
|
nuclear@1
|
558 IPD = 0.064f;
|
nuclear@1
|
559 OVR_strcpy(Name, MaxNameLen, name);
|
nuclear@1
|
560 }
|
nuclear@1
|
561
|
nuclear@1
|
562
|
nuclear@1
|
563 bool Profile::ParseProperty(const char* prop, const char* sval)
|
nuclear@1
|
564 {
|
nuclear@1
|
565 if (OVR_strcmp(prop, "Name") == 0)
|
nuclear@1
|
566 {
|
nuclear@1
|
567 OVR_strcpy(Name, MaxNameLen, sval);
|
nuclear@1
|
568 return true;
|
nuclear@1
|
569 }
|
nuclear@1
|
570 else if (OVR_strcmp(prop, "Gender") == 0)
|
nuclear@1
|
571 {
|
nuclear@1
|
572 if (OVR_strcmp(sval, "Male") == 0)
|
nuclear@1
|
573 Gender = Gender_Male;
|
nuclear@1
|
574 else if (OVR_strcmp(sval, "Female") == 0)
|
nuclear@1
|
575 Gender = Gender_Female;
|
nuclear@1
|
576 else
|
nuclear@1
|
577 Gender = Gender_Unspecified;
|
nuclear@1
|
578
|
nuclear@1
|
579 return true;
|
nuclear@1
|
580 }
|
nuclear@1
|
581 else if (OVR_strcmp(prop, "PlayerHeight") == 0)
|
nuclear@1
|
582 {
|
nuclear@1
|
583 PlayerHeight = (float)atof(sval);
|
nuclear@1
|
584 return true;
|
nuclear@1
|
585 }
|
nuclear@1
|
586 else if (OVR_strcmp(prop, "IPD") == 0)
|
nuclear@1
|
587 {
|
nuclear@1
|
588 IPD = (float)atof(sval);
|
nuclear@1
|
589 return true;
|
nuclear@1
|
590 }
|
nuclear@1
|
591
|
nuclear@1
|
592 return false;
|
nuclear@1
|
593 }
|
nuclear@1
|
594
|
nuclear@1
|
595
|
nuclear@1
|
596 // Computes the eye height from the metric head height
|
nuclear@1
|
597 float Profile::GetEyeHeight()
|
nuclear@1
|
598 {
|
nuclear@1
|
599 const float EYE_TO_HEADTOP_RATIO = 0.44538f;
|
nuclear@1
|
600 const float MALE_AVG_HEAD_HEIGHT = 0.232f;
|
nuclear@1
|
601 const float FEMALE_AVG_HEAD_HEIGHT = 0.218f;
|
nuclear@1
|
602
|
nuclear@1
|
603 // compute distance from top of skull to the eye
|
nuclear@1
|
604 float head_height;
|
nuclear@1
|
605 if (Gender == Gender_Female)
|
nuclear@1
|
606 head_height = FEMALE_AVG_HEAD_HEIGHT;
|
nuclear@1
|
607 else
|
nuclear@1
|
608 head_height = MALE_AVG_HEAD_HEIGHT;
|
nuclear@1
|
609
|
nuclear@1
|
610 float skull = EYE_TO_HEADTOP_RATIO * head_height;
|
nuclear@1
|
611
|
nuclear@1
|
612 float eye_height = PlayerHeight - skull;
|
nuclear@1
|
613 return eye_height;
|
nuclear@1
|
614 }
|
nuclear@1
|
615
|
nuclear@1
|
616
|
nuclear@1
|
617 //-----------------------------------------------------------------------------
|
nuclear@1
|
618 // ***** RiftDK1Profile
|
nuclear@1
|
619
|
nuclear@1
|
620 RiftDK1Profile::RiftDK1Profile(const char* name) : Profile(Profile_RiftDK1, name)
|
nuclear@1
|
621 {
|
nuclear@1
|
622 EyeCups = EyeCup_A;
|
nuclear@1
|
623 LL = 0;
|
nuclear@1
|
624 LR = 0;
|
nuclear@1
|
625 RL = 0;
|
nuclear@1
|
626 RR = 0;
|
nuclear@1
|
627 }
|
nuclear@1
|
628
|
nuclear@1
|
629 bool RiftDK1Profile::ParseProperty(const char* prop, const char* sval)
|
nuclear@1
|
630 {
|
nuclear@1
|
631 if (OVR_strcmp(prop, "EyeCup") == 0)
|
nuclear@1
|
632 {
|
nuclear@1
|
633 switch (sval[0])
|
nuclear@1
|
634 {
|
nuclear@1
|
635 case 'C': EyeCups = EyeCup_C; break;
|
nuclear@1
|
636 case 'B': EyeCups = EyeCup_B; break;
|
nuclear@1
|
637 default: EyeCups = EyeCup_A; break;
|
nuclear@1
|
638 }
|
nuclear@1
|
639 return true;
|
nuclear@1
|
640 }
|
nuclear@1
|
641 else if (OVR_strcmp(prop, "LL") == 0)
|
nuclear@1
|
642 {
|
nuclear@1
|
643 LL = atoi(sval);
|
nuclear@1
|
644 return true;
|
nuclear@1
|
645 }
|
nuclear@1
|
646 else if (OVR_strcmp(prop, "LR") == 0)
|
nuclear@1
|
647 {
|
nuclear@1
|
648 LR = atoi(sval);
|
nuclear@1
|
649 return true;
|
nuclear@1
|
650 }
|
nuclear@1
|
651 else if (OVR_strcmp(prop, "RL") == 0)
|
nuclear@1
|
652 {
|
nuclear@1
|
653 RL = atoi(sval);
|
nuclear@1
|
654 return true;
|
nuclear@1
|
655 }
|
nuclear@1
|
656 else if (OVR_strcmp(prop, "RR") == 0)
|
nuclear@1
|
657 {
|
nuclear@1
|
658 RR = atoi(sval);
|
nuclear@1
|
659 return true;
|
nuclear@1
|
660 }
|
nuclear@1
|
661
|
nuclear@1
|
662 return Profile::ParseProperty(prop, sval);
|
nuclear@1
|
663 }
|
nuclear@1
|
664
|
nuclear@1
|
665 Profile* RiftDK1Profile::Clone() const
|
nuclear@1
|
666 {
|
nuclear@1
|
667 RiftDK1Profile* profile = new RiftDK1Profile(*this);
|
nuclear@1
|
668 return profile;
|
nuclear@1
|
669 }
|
nuclear@1
|
670
|
nuclear@1
|
671 } // OVR
|