oculus1

annotate libovr/Src/OVR_Profile.cpp @ 23:0c76f70fb7e9

merged
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 28 Sep 2013 04:13:33 +0300
parents
children
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