00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "OVR_Profile.h"
00024 #include "OVR_JSON.h"
00025 #include "Kernel/OVR_Types.h"
00026 #include "Kernel/OVR_SysFile.h"
00027 #include "Kernel/OVR_Allocator.h"
00028 #include "Kernel/OVR_Array.h"
00029
00030 #ifdef OVR_OS_WIN32
00031 #include <Shlobj.h>
00032 #else
00033 #include <dirent.h>
00034 #include <sys/stat.h>
00035
00036 #ifdef OVR_OS_LINUX
00037 #include <unistd.h>
00038 #include <pwd.h>
00039 #endif
00040
00041 #endif
00042
00043 #define PROFILE_VERSION 1.0
00044
00045 namespace OVR {
00046
00047
00048
00049 String GetProfilePath(bool create_dir)
00050 {
00051 String path;
00052
00053 #if defined(OVR_OS_WIN32)
00054
00055 PWSTR data_path = NULL;
00056 SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &data_path);
00057 path = String(data_path);
00058 CoTaskMemFree(data_path);
00059
00060 path += "/Oculus";
00061
00062 if (create_dir)
00063 {
00064 WCHAR wpath[128];
00065 OVR::UTF8Util::DecodeString(wpath, path.ToCStr());
00066
00067 DWORD attrib = GetFileAttributes(wpath);
00068 bool exists = attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY);
00069 if (!exists)
00070 {
00071 CreateDirectory(wpath, NULL);
00072 }
00073 }
00074
00075 #elif defined(OVR_OS_MAC)
00076
00077 const char* home = getenv("HOME");
00078 path = home;
00079 path += "/Library/Preferences/Oculus";
00080
00081 if (create_dir)
00082 {
00083 DIR* dir = opendir(path);
00084 if (dir == NULL)
00085 {
00086 mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
00087 }
00088 else
00089 {
00090 closedir(dir);
00091 }
00092 }
00093
00094 #else
00095
00096 passwd* pwd = getpwuid(getuid());
00097 const char* home = pwd->pw_dir;
00098 path = home;
00099 path += "/.config/Oculus";
00100
00101 if (create_dir)
00102 {
00103 DIR* dir = opendir(path);
00104 if (dir == NULL)
00105 {
00106 mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
00107 }
00108 else
00109 {
00110 closedir(dir);
00111 }
00112 }
00113
00114 #endif
00115
00116 path += "/Profiles.json";
00117 return path;
00118 }
00119
00120
00121
00122
00123
00124 ProfileManager::ProfileManager()
00125 {
00126 Changed = false;
00127 CacheDevice = Profile_Unknown;
00128 }
00129
00130 ProfileManager::~ProfileManager()
00131 {
00132
00133 if (Changed)
00134 SaveCache();
00135
00136 ClearCache();
00137 }
00138
00139 ProfileManager* ProfileManager::Create()
00140 {
00141 return new ProfileManager();
00142 }
00143
00144 Profile* ProfileManager::CreateProfileObject(const char* user,
00145 ProfileType device,
00146 const char** device_name)
00147 {
00148 Lock::Locker lockScope(&ProfileLock);
00149
00150 Profile* profile = NULL;
00151 switch (device)
00152 {
00153 case Profile_RiftDK1:
00154 *device_name = "RiftDK1";
00155 profile = new RiftDK1Profile(user);
00156 break;
00157 case Profile_RiftDKHD:
00158 case Profile_Unknown:
00159 break;
00160 }
00161
00162 return profile;
00163 }
00164
00165
00166
00167 void ProfileManager::ClearCache()
00168 {
00169 Lock::Locker lockScope(&ProfileLock);
00170
00171 ProfileCache.Clear();
00172 CacheDevice = Profile_Unknown;
00173 }
00174
00175
00176
00177
00178
00179
00180 void ProfileManager::LoadCache(ProfileType device)
00181 {
00182 Lock::Locker lockScope(&ProfileLock);
00183
00184 ClearCache();
00185
00186 String path = GetProfilePath(false);
00187
00188 Ptr<JSON> root = *JSON::Load(path);
00189 if (!root || root->GetItemCount() < 3)
00190 return;
00191
00192
00193 JSON* item0 = root->GetFirstItem();
00194 JSON* item1 = root->GetNextItem(item0);
00195 JSON* item2 = root->GetNextItem(item1);
00196
00197 if (OVR_strcmp(item0->Name, "Oculus Profile Version") == 0)
00198 {
00199 }
00200 else
00201 {
00202 return;
00203 }
00204
00205 DefaultProfile = item1->Value;
00206
00207
00208 int profileCount = (int)item2->dValue;
00209 JSON* profileItem = item2;
00210
00211 for (int p=0; p<profileCount; p++)
00212 {
00213 profileItem = profileItem->GetNextItem(profileItem);
00214 if (!profileItem)
00215 break;
00216
00217
00218 const char* profileName;
00219 JSON* item = profileItem->GetFirstItem();
00220
00221 if (item && (OVR_strcmp(item->Name, "Name") == 0))
00222 {
00223 profileName = item->Value;
00224 }
00225 else
00226 {
00227 return;
00228 }
00229
00230 const char* deviceName = 0;
00231 bool deviceFound = false;
00232 Ptr<Profile> profile = *CreateProfileObject(profileName, device, &deviceName);
00233
00234
00235 while (item = profileItem->GetNextItem(item), item)
00236 {
00237 if (item->Type != JSON_Object)
00238 {
00239 profile->ParseProperty(item->Name, item->Value);
00240 }
00241 else
00242 {
00243 if (!deviceFound && OVR_strcmp(item->Name, deviceName) == 0)
00244 {
00245 deviceFound = true;
00246
00247 for (JSON* deviceItem = item->GetFirstItem(); deviceItem;
00248 deviceItem = item->GetNextItem(deviceItem))
00249 {
00250 profile->ParseProperty(deviceItem->Name, deviceItem->Value);
00251 }
00252 }
00253 }
00254 }
00255
00256
00257 if (deviceFound)
00258 ProfileCache.PushBack(profile);
00259 }
00260
00261 CacheDevice = device;
00262 }
00263
00264
00265
00266 void ProfileManager::SaveCache()
00267 {
00268 String path = GetProfilePath(true);
00269
00270 Lock::Locker lockScope(&ProfileLock);
00271
00272
00273
00274
00275
00276 Ptr<JSON> root = *JSON::CreateObject();
00277 root->AddNumberItem("Oculus Profile Version", PROFILE_VERSION);
00278 root->AddStringItem("CurrentProfile", DefaultProfile);
00279 root->AddNumberItem("ProfileCount", (double) ProfileCache.GetSize());
00280
00281
00282 for (unsigned int i=0; i<ProfileCache.GetSize(); i++)
00283 {
00284 Profile* profile = ProfileCache[i];
00285
00286 JSON* json_profile = JSON::CreateObject();
00287 json_profile->Name = "Profile";
00288 json_profile->AddStringItem("Name", profile->Name);
00289 const char* gender;
00290 switch (profile->GetGender())
00291 {
00292 case Profile::Gender_Male: gender = "Male"; break;
00293 case Profile::Gender_Female: gender = "Female"; break;
00294 default: gender = "Unspecified";
00295 }
00296 json_profile->AddStringItem("Gender", gender);
00297 json_profile->AddNumberItem("PlayerHeight", profile->PlayerHeight);
00298 json_profile->AddNumberItem("IPD", profile->IPD);
00299
00300 if (profile->Type == Profile_RiftDK1)
00301 {
00302 RiftDK1Profile* riftdk1 = (RiftDK1Profile*)profile;
00303 JSON* json_riftdk1 = JSON::CreateObject();
00304 json_profile->AddItem("RiftDK1", json_riftdk1);
00305
00306 const char* eyecup = "A";
00307 switch (riftdk1->EyeCups)
00308 {
00309 case RiftDK1Profile::EyeCup_A: eyecup = "A"; break;
00310 case RiftDK1Profile::EyeCup_B: eyecup = "B"; break;
00311 case RiftDK1Profile::EyeCup_C: eyecup = "C"; break;
00312 }
00313 json_riftdk1->AddStringItem("EyeCup", eyecup);
00314 json_riftdk1->AddNumberItem("LL", riftdk1->LL);
00315 json_riftdk1->AddNumberItem("LR", riftdk1->LR);
00316 json_riftdk1->AddNumberItem("RL", riftdk1->RL);
00317 json_riftdk1->AddNumberItem("RR", riftdk1->RR);
00318 }
00319
00320 root->AddItem("Profile", json_profile);
00321 }
00322
00323 root->Save(path);
00324 }
00325
00326
00327 int ProfileManager::GetProfileCount(ProfileType device)
00328 {
00329 Lock::Locker lockScope(&ProfileLock);
00330
00331 if (CacheDevice == Profile_Unknown)
00332 LoadCache(device);
00333
00334 return (int)ProfileCache.GetSize();
00335 }
00336
00337
00338
00339
00340 const char* ProfileManager::GetProfileName(ProfileType device, unsigned int index)
00341 {
00342 Lock::Locker lockScope(&ProfileLock);
00343
00344 if (CacheDevice == Profile_Unknown)
00345 LoadCache(device);
00346
00347 if (index < ProfileCache.GetSize())
00348 {
00349 Profile* profile = ProfileCache[index];
00350 OVR_strcpy(NameBuff, Profile::MaxNameLen, profile->Name);
00351 return NameBuff;
00352 }
00353 else
00354 {
00355 return NULL;
00356 }
00357 }
00358
00359 bool ProfileManager::HasProfile(ProfileType device, const char* name)
00360 {
00361 Lock::Locker lockScope(&ProfileLock);
00362
00363 if (CacheDevice == Profile_Unknown)
00364 LoadCache(device);
00365
00366 for (unsigned i = 0; i< ProfileCache.GetSize(); i++)
00367 {
00368 if (ProfileCache[i] && OVR_strcmp(ProfileCache[i]->Name, name) == 0)
00369 return true;
00370 }
00371 return false;
00372 }
00373
00374
00375
00376
00377
00378 Profile* ProfileManager::LoadProfile(ProfileType device, unsigned int index)
00379 {
00380 Lock::Locker lockScope(&ProfileLock);
00381
00382 if (CacheDevice == Profile_Unknown)
00383 LoadCache(device);
00384
00385 if (index < ProfileCache.GetSize())
00386 {
00387 Profile* profile = ProfileCache[index];
00388 return profile->Clone();
00389 }
00390 else
00391 {
00392 return NULL;
00393 }
00394 }
00395
00396
00397
00398
00399 Profile* ProfileManager::LoadProfile(ProfileType device, const char* user)
00400 {
00401 if (user == NULL)
00402 return NULL;
00403
00404 Lock::Locker lockScope(&ProfileLock);
00405
00406 if (CacheDevice == Profile_Unknown)
00407 LoadCache(device);
00408
00409 for (unsigned int i=0; i<ProfileCache.GetSize(); i++)
00410 {
00411 if (OVR_strcmp(user, ProfileCache[i]->Name) == 0)
00412 {
00413 Profile* profile = ProfileCache[i];
00414 return profile->Clone();
00415 }
00416 }
00417
00418 return NULL;
00419 }
00420
00421
00422 Profile* ProfileManager::GetDeviceDefaultProfile(ProfileType device)
00423 {
00424 const char* device_name = NULL;
00425 return CreateProfileObject("default", device, &device_name);
00426 }
00427
00428
00429 const char* ProfileManager::GetDefaultProfileName(ProfileType device)
00430 {
00431 Lock::Locker lockScope(&ProfileLock);
00432
00433 if (CacheDevice == Profile_Unknown)
00434 LoadCache(device);
00435
00436 if (ProfileCache.GetSize() > 0)
00437 {
00438 OVR_strcpy(NameBuff, Profile::MaxNameLen, DefaultProfile);
00439 return NameBuff;
00440 }
00441 else
00442 {
00443 return NULL;
00444 }
00445 }
00446
00447
00448 bool ProfileManager::SetDefaultProfileName(ProfileType device, const char* name)
00449 {
00450 Lock::Locker lockScope(&ProfileLock);
00451
00452 if (CacheDevice == Profile_Unknown)
00453 LoadCache(device);
00454
00455 if (ProfileCache.GetSize() > 0)
00456 {
00457 DefaultProfile = name;
00458 Changed = true;
00459 return true;
00460 }
00461 else
00462 {
00463 return false;
00464 }
00465 }
00466
00467
00468
00469
00470 bool ProfileManager::Save(const Profile* profile)
00471 {
00472 Lock::Locker lockScope(&ProfileLock);
00473
00474 if (OVR_strcmp(profile->Name, "default") == 0)
00475 return false;
00476
00477
00478 if (CacheDevice == Profile_Unknown)
00479 LoadCache(profile->Type);
00480
00481
00482 bool added = false;
00483 for (unsigned int i=0; i<ProfileCache.GetSize(); i++)
00484 {
00485 int compare = OVR_strcmp(profile->Name, ProfileCache[i]->Name);
00486
00487 if (compare == 0)
00488 {
00489
00490
00491
00492
00493 ProfileCache[i] = *profile->Clone();
00494 added = true;
00495 Changed = true;
00496 break;
00497 }
00498 }
00499
00500 if (!added)
00501 {
00502 ProfileCache.PushBack(*profile->Clone());
00503 if (ProfileCache.GetSize() == 1)
00504 CacheDevice = profile->Type;
00505
00506 Changed = true;
00507 }
00508
00509 return true;
00510 }
00511
00512
00513
00514 bool ProfileManager::Delete(const Profile* profile)
00515 {
00516 Lock::Locker lockScope(&ProfileLock);
00517
00518 if (OVR_strcmp(profile->Name, "default") == 0)
00519 return false;
00520
00521 if (CacheDevice == Profile_Unknown)
00522 LoadCache(profile->Type);
00523
00524
00525 for (unsigned int i=0; i<ProfileCache.GetSize(); i++)
00526 {
00527 if (OVR_strcmp(profile->Name, ProfileCache[i]->Name) == 0)
00528 {
00529 if (OVR_strcmp(profile->Name, DefaultProfile) == 0)
00530 DefaultProfile.Clear();
00531
00532 ProfileCache.RemoveAt(i);
00533 Changed = true;
00534 return true;
00535 }
00536 }
00537
00538 return false;
00539 }
00540
00541
00542
00543
00544
00545
00546 Profile::Profile(ProfileType device, const char* name)
00547 {
00548 Type = device;
00549 Gender = Gender_Unspecified;
00550 PlayerHeight = 1.778f;
00551 IPD = 0.064f;
00552 OVR_strcpy(Name, MaxNameLen, name);
00553 }
00554
00555
00556 bool Profile::ParseProperty(const char* prop, const char* sval)
00557 {
00558 if (OVR_strcmp(prop, "Name") == 0)
00559 {
00560 OVR_strcpy(Name, MaxNameLen, sval);
00561 return true;
00562 }
00563 else if (OVR_strcmp(prop, "Gender") == 0)
00564 {
00565 if (OVR_strcmp(sval, "Male") == 0)
00566 Gender = Gender_Male;
00567 else if (OVR_strcmp(sval, "Female") == 0)
00568 Gender = Gender_Female;
00569 else
00570 Gender = Gender_Unspecified;
00571
00572 return true;
00573 }
00574 else if (OVR_strcmp(prop, "PlayerHeight") == 0)
00575 {
00576 PlayerHeight = (float)atof(sval);
00577 return true;
00578 }
00579 else if (OVR_strcmp(prop, "IPD") == 0)
00580 {
00581 IPD = (float)atof(sval);
00582 return true;
00583 }
00584
00585 return false;
00586 }
00587
00588
00589
00590 float Profile::GetEyeHeight()
00591 {
00592 const float EYE_TO_HEADTOP_RATIO = 0.44538f;
00593 const float MALE_AVG_HEAD_HEIGHT = 0.232f;
00594 const float FEMALE_AVG_HEAD_HEIGHT = 0.218f;
00595
00596
00597 float head_height;
00598 if (Gender == Gender_Female)
00599 head_height = FEMALE_AVG_HEAD_HEIGHT;
00600 else
00601 head_height = MALE_AVG_HEAD_HEIGHT;
00602
00603 float skull = EYE_TO_HEADTOP_RATIO * head_height;
00604
00605 float eye_height = PlayerHeight - skull;
00606 return eye_height;
00607 }
00608
00609
00610
00611
00612
00613 RiftDK1Profile::RiftDK1Profile(const char* name) : Profile(Profile_RiftDK1, name)
00614 {
00615 EyeCups = EyeCup_A;
00616 LL = 0;
00617 LR = 0;
00618 RL = 0;
00619 RR = 0;
00620 }
00621
00622 bool RiftDK1Profile::ParseProperty(const char* prop, const char* sval)
00623 {
00624 if (OVR_strcmp(prop, "EyeCup") == 0)
00625 {
00626 switch (sval[0])
00627 {
00628 case 'C': EyeCups = EyeCup_C; break;
00629 case 'B': EyeCups = EyeCup_B; break;
00630 default: EyeCups = EyeCup_A; break;
00631 }
00632 return true;
00633 }
00634 else if (OVR_strcmp(prop, "LL") == 0)
00635 {
00636 LL = atoi(sval);
00637 return true;
00638 }
00639 else if (OVR_strcmp(prop, "LR") == 0)
00640 {
00641 LR = atoi(sval);
00642 return true;
00643 }
00644 else if (OVR_strcmp(prop, "RL") == 0)
00645 {
00646 RL = atoi(sval);
00647 return true;
00648 }
00649 else if (OVR_strcmp(prop, "RR") == 0)
00650 {
00651 RR = atoi(sval);
00652 return true;
00653 }
00654
00655 return Profile::ParseProperty(prop, sval);
00656 }
00657
00658 Profile* RiftDK1Profile::Clone() const
00659 {
00660 RiftDK1Profile* profile = new RiftDK1Profile(*this);
00661 return profile;
00662 }
00663
00664 }