oculus1

annotate libovr/Src/osx/OVR_OSX_HMDDevice.cpp @ 1:e2f9e4603129

added LibOVR and started a simple vr wrapper.
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 14 Sep 2013 16:14:59 +0300
parents
children
rev   line source
nuclear@1 1 /************************************************************************************
nuclear@1 2
nuclear@1 3 Filename : OVR_OSX_HMDDevice.cpp
nuclear@1 4 Content : OSX Interface to HMD - detects HMD display
nuclear@1 5 Created : September 21, 2012
nuclear@1 6 Authors : Michael Antonov
nuclear@1 7
nuclear@1 8 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
nuclear@1 9
nuclear@1 10 Use of this software is subject to the terms of the Oculus license
nuclear@1 11 agreement provided at the time of installation or download, or which
nuclear@1 12 otherwise accompanies this software in either electronic or hard copy form.
nuclear@1 13
nuclear@1 14 *************************************************************************************/
nuclear@1 15
nuclear@1 16 #include "OVR_OSX_HMDDevice.h"
nuclear@1 17 #include <CoreGraphics/CGDirectDisplay.h>
nuclear@1 18 #include <CoreGraphics/CGDisplayConfiguration.h>
nuclear@1 19 #include <CoreFoundation/CoreFoundation.h>
nuclear@1 20 #include <CoreFoundation/CFString.h>
nuclear@1 21 #include <IOKit/graphics/IOGraphicsLib.h>
nuclear@1 22
nuclear@1 23 namespace OVR { namespace OSX {
nuclear@1 24
nuclear@1 25 //-------------------------------------------------------------------------------------
nuclear@1 26
nuclear@1 27 HMDDeviceCreateDesc::HMDDeviceCreateDesc(DeviceFactory* factory,
nuclear@1 28 UInt32 vend, UInt32 prod, const String& displayDeviceName, long dispId)
nuclear@1 29 : DeviceCreateDesc(factory, Device_HMD),
nuclear@1 30 DisplayDeviceName(displayDeviceName),
nuclear@1 31 DesktopX(0), DesktopY(0), Contents(0),
nuclear@1 32 HResolution(0), VResolution(0), HScreenSize(0), VScreenSize(0),
nuclear@1 33 DisplayId(dispId)
nuclear@1 34 {
nuclear@1 35 /* //??????????
nuclear@1 36 char idstring[9];
nuclear@1 37 idstring[0] = 'A'-1+((vend>>10) & 31);
nuclear@1 38 idstring[1] = 'A'-1+((vend>>5) & 31);
nuclear@1 39 idstring[2] = 'A'-1+((vend>>0) & 31);
nuclear@1 40 snprintf(idstring+3, 5, "%04d", prod);
nuclear@1 41 DeviceId = idstring;*/
nuclear@1 42 DeviceId = DisplayDeviceName;
nuclear@1 43 }
nuclear@1 44
nuclear@1 45 HMDDeviceCreateDesc::HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other)
nuclear@1 46 : DeviceCreateDesc(other.pFactory, Device_HMD),
nuclear@1 47 DeviceId(other.DeviceId), DisplayDeviceName(other.DisplayDeviceName),
nuclear@1 48 DesktopX(other.DesktopX), DesktopY(other.DesktopY), Contents(other.Contents),
nuclear@1 49 HResolution(other.HResolution), VResolution(other.VResolution),
nuclear@1 50 HScreenSize(other.HScreenSize), VScreenSize(other.VScreenSize),
nuclear@1 51 DisplayId(other.DisplayId)
nuclear@1 52 {
nuclear@1 53 }
nuclear@1 54
nuclear@1 55 HMDDeviceCreateDesc::MatchResult HMDDeviceCreateDesc::MatchDevice(const DeviceCreateDesc& other,
nuclear@1 56 DeviceCreateDesc** pcandidate) const
nuclear@1 57 {
nuclear@1 58 if ((other.Type != Device_HMD) || (other.pFactory != pFactory))
nuclear@1 59 return Match_None;
nuclear@1 60
nuclear@1 61 // There are several reasons we can come in here:
nuclear@1 62 // a) Matching this HMD Monitor created desc to OTHER HMD Monitor desc
nuclear@1 63 // - Require exact device DeviceId/DeviceName match
nuclear@1 64 // b) Matching SensorDisplayInfo created desc to OTHER HMD Monitor desc
nuclear@1 65 // - This DeviceId is empty; becomes candidate
nuclear@1 66 // c) Matching this HMD Monitor created desc to SensorDisplayInfo desc
nuclear@1 67 // - This other.DeviceId is empty; becomes candidate
nuclear@1 68
nuclear@1 69 const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
nuclear@1 70
nuclear@1 71 if ((DeviceId == s2.DeviceId) &&
nuclear@1 72 (DisplayId == s2.DisplayId))
nuclear@1 73 {
nuclear@1 74 // Non-null DeviceId may match while size is different if screen size was overwritten
nuclear@1 75 // by SensorDisplayInfo in prior iteration.
nuclear@1 76 if (!DeviceId.IsEmpty() ||
nuclear@1 77 ((HScreenSize == s2.HScreenSize) &&
nuclear@1 78 (VScreenSize == s2.VScreenSize)) )
nuclear@1 79 {
nuclear@1 80 *pcandidate = 0;
nuclear@1 81 return Match_Found;
nuclear@1 82 }
nuclear@1 83 }
nuclear@1 84
nuclear@1 85
nuclear@1 86 // DisplayInfo takes precedence, although we try to match it first.
nuclear@1 87 if ((HResolution == s2.HResolution) &&
nuclear@1 88 (VResolution == s2.VResolution) &&
nuclear@1 89 (HScreenSize == s2.HScreenSize) &&
nuclear@1 90 (VScreenSize == s2.VScreenSize))
nuclear@1 91 {
nuclear@1 92 if (DeviceId.IsEmpty() && !s2.DeviceId.IsEmpty())
nuclear@1 93 {
nuclear@1 94 *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
nuclear@1 95 return Match_Candidate;
nuclear@1 96 }
nuclear@1 97
nuclear@1 98 *pcandidate = 0;
nuclear@1 99 return Match_Found;
nuclear@1 100 }
nuclear@1 101
nuclear@1 102 // SensorDisplayInfo may override resolution settings, so store as candidiate.
nuclear@1 103 if (s2.DeviceId.IsEmpty() && s2.DisplayId == 0)
nuclear@1 104 {
nuclear@1 105 *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
nuclear@1 106 return Match_Candidate;
nuclear@1 107 }
nuclear@1 108 // OTHER HMD Monitor desc may initialize DeviceName/Id
nuclear@1 109 else if (DeviceId.IsEmpty() && DisplayId == 0)
nuclear@1 110 {
nuclear@1 111 *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
nuclear@1 112 return Match_Candidate;
nuclear@1 113 }
nuclear@1 114
nuclear@1 115 return Match_None;
nuclear@1 116 }
nuclear@1 117
nuclear@1 118
nuclear@1 119 bool HMDDeviceCreateDesc::UpdateMatchedCandidate(const DeviceCreateDesc& other, bool* newDeviceFlag)
nuclear@1 120 {
nuclear@1 121 // This candidate was the the "best fit" to apply sensor DisplayInfo to.
nuclear@1 122 OVR_ASSERT(other.Type == Device_HMD);
nuclear@1 123
nuclear@1 124 const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
nuclear@1 125
nuclear@1 126 // Force screen size on resolution from SensorDisplayInfo.
nuclear@1 127 // We do this because USB detection is more reliable as compared to HDMI EDID,
nuclear@1 128 // which may be corrupted by splitter reporting wrong monitor
nuclear@1 129 if (s2.DeviceId.IsEmpty() && s2.DisplayId == 0)
nuclear@1 130 {
nuclear@1 131 // disconnected HMD: replace old descriptor by the 'fake' one.
nuclear@1 132 HScreenSize = s2.HScreenSize;
nuclear@1 133 VScreenSize = s2.VScreenSize;
nuclear@1 134 Contents |= Contents_Screen;
nuclear@1 135
nuclear@1 136 if (s2.Contents & HMDDeviceCreateDesc::Contents_Distortion)
nuclear@1 137 {
nuclear@1 138 memcpy(DistortionK, s2.DistortionK, sizeof(float)*4);
nuclear@1 139 Contents |= Contents_Distortion;
nuclear@1 140 }
nuclear@1 141 DeviceId = s2.DeviceId;
nuclear@1 142 DisplayId = s2.DisplayId;
nuclear@1 143 DisplayDeviceName = s2.DisplayDeviceName;
nuclear@1 144 if (newDeviceFlag) *newDeviceFlag = true;
nuclear@1 145 }
nuclear@1 146 else if (DeviceId.IsEmpty())
nuclear@1 147 {
nuclear@1 148 // This branch is executed when 'fake' HMD descriptor is being replaced by
nuclear@1 149 // the real one.
nuclear@1 150 DeviceId = s2.DeviceId;
nuclear@1 151 DisplayId = s2.DisplayId;
nuclear@1 152 DisplayDeviceName = s2.DisplayDeviceName;
nuclear@1 153 if (newDeviceFlag) *newDeviceFlag = true;
nuclear@1 154 }
nuclear@1 155 else
nuclear@1 156 {
nuclear@1 157 if (newDeviceFlag) *newDeviceFlag = false;
nuclear@1 158 }
nuclear@1 159
nuclear@1 160 return true;
nuclear@1 161 }
nuclear@1 162
nuclear@1 163
nuclear@1 164 //-------------------------------------------------------------------------------------
nuclear@1 165
nuclear@1 166
nuclear@1 167 //-------------------------------------------------------------------------------------
nuclear@1 168 // ***** HMDDeviceFactory
nuclear@1 169
nuclear@1 170 HMDDeviceFactory HMDDeviceFactory::Instance;
nuclear@1 171
nuclear@1 172 void HMDDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
nuclear@1 173 {
nuclear@1 174 CGDirectDisplayID Displays[32];
nuclear@1 175 uint32_t NDisplays = 0;
nuclear@1 176 CGGetOnlineDisplayList(32, Displays, &NDisplays);
nuclear@1 177
nuclear@1 178 for (int i = 0; i < NDisplays; i++)
nuclear@1 179 {
nuclear@1 180 io_service_t port = CGDisplayIOServicePort(Displays[i]);
nuclear@1 181 CFDictionaryRef DispInfo = IODisplayCreateInfoDictionary(port, kIODisplayMatchingInfo);
nuclear@1 182
nuclear@1 183 uint32_t vendor = CGDisplayVendorNumber(Displays[i]);
nuclear@1 184 uint32_t product = CGDisplayModelNumber(Displays[i]);
nuclear@1 185 unsigned mwidth = (unsigned)CGDisplayPixelsWide(Displays[i]);
nuclear@1 186 unsigned mheight = (unsigned)CGDisplayPixelsHigh(Displays[i]);
nuclear@1 187 CGRect desktop = CGDisplayBounds(Displays[i]);
nuclear@1 188
nuclear@1 189 if (vendor == 16082 && product == 1)
nuclear@1 190 {
nuclear@1 191 char idstring[9];
nuclear@1 192 idstring[0] = 'A'-1+((vendor>>10) & 31);
nuclear@1 193 idstring[1] = 'A'-1+((vendor>>5) & 31);
nuclear@1 194 idstring[2] = 'A'-1+((vendor>>0) & 31);
nuclear@1 195 snprintf(idstring+3, 5, "%04d", product);
nuclear@1 196
nuclear@1 197 HMDDeviceCreateDesc hmdCreateDesc(this, vendor, product, idstring, Displays[i]);
nuclear@1 198
nuclear@1 199 if (product == 2)
nuclear@1 200 {
nuclear@1 201 hmdCreateDesc.SetScreenParameters(desktop.origin.x, desktop.origin.y,
nuclear@1 202 mwidth, mheight, 0.12096f, 0.06804f);
nuclear@1 203 }
nuclear@1 204 else
nuclear@1 205 {
nuclear@1 206 if (hmdCreateDesc.Is7Inch())
nuclear@1 207 {
nuclear@1 208 // Physical dimension of SLA screen.
nuclear@1 209 hmdCreateDesc.SetScreenParameters(desktop.origin.x, desktop.origin.y,
nuclear@1 210 mwidth, mheight, 0.14976f, 0.0936f);
nuclear@1 211 }
nuclear@1 212 else
nuclear@1 213 {
nuclear@1 214 hmdCreateDesc.SetScreenParameters(desktop.origin.x, desktop.origin.y,
nuclear@1 215 mwidth, mheight, 0.12096f, 0.0756f);
nuclear@1 216 }
nuclear@1 217 }
nuclear@1 218
nuclear@1 219 OVR_DEBUG_LOG_TEXT(("DeviceManager - HMD Found %x:%x\n", vendor, product));
nuclear@1 220
nuclear@1 221 // Notify caller about detected device. This will call EnumerateAddDevice
nuclear@1 222 // if the this is the first time device was detected.
nuclear@1 223 visitor.Visit(hmdCreateDesc);
nuclear@1 224 }
nuclear@1 225 CFRelease(DispInfo);
nuclear@1 226 }
nuclear@1 227 }
nuclear@1 228
nuclear@1 229 DeviceBase* HMDDeviceCreateDesc::NewDeviceInstance()
nuclear@1 230 {
nuclear@1 231 return new HMDDevice(this);
nuclear@1 232 }
nuclear@1 233
nuclear@1 234 bool HMDDeviceCreateDesc::Is7Inch() const
nuclear@1 235 {
nuclear@1 236 return (strstr(DeviceId.ToCStr(), "OVR0001") != 0) || (Contents & Contents_7Inch);
nuclear@1 237 }
nuclear@1 238
nuclear@1 239 Profile* HMDDeviceCreateDesc::GetProfileAddRef() const
nuclear@1 240 {
nuclear@1 241 // Create device may override profile name, so get it from there is possible.
nuclear@1 242 ProfileManager* profileManager = GetManagerImpl()->GetProfileManager();
nuclear@1 243 ProfileType profileType = GetProfileType();
nuclear@1 244 const char * profileName = pDevice ?
nuclear@1 245 ((HMDDevice*)pDevice)->GetProfileName() :
nuclear@1 246 profileManager->GetDefaultProfileName(profileType);
nuclear@1 247
nuclear@1 248 return profileName ?
nuclear@1 249 profileManager->LoadProfile(profileType, profileName) :
nuclear@1 250 profileManager->GetDeviceDefaultProfile(profileType);
nuclear@1 251 }
nuclear@1 252
nuclear@1 253 bool HMDDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
nuclear@1 254 {
nuclear@1 255 if ((info->InfoClassType != Device_HMD) &&
nuclear@1 256 (info->InfoClassType != Device_None))
nuclear@1 257 return false;
nuclear@1 258
nuclear@1 259 bool is7Inch = Is7Inch();
nuclear@1 260
nuclear@1 261 OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength,
nuclear@1 262 is7Inch ? "Oculus Rift DK1" :
nuclear@1 263 ((HResolution >= 1920) ? "Oculus Rift DK HD" : "Oculus Rift DK1-Prototype") );
nuclear@1 264 OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, "Oculus VR");
nuclear@1 265 info->Type = Device_HMD;
nuclear@1 266 info->Version = 0;
nuclear@1 267
nuclear@1 268 // Display detection.
nuclear@1 269 if (info->InfoClassType == Device_HMD)
nuclear@1 270 {
nuclear@1 271 HMDInfo* hmdInfo = static_cast<HMDInfo*>(info);
nuclear@1 272
nuclear@1 273 hmdInfo->DesktopX = DesktopX;
nuclear@1 274 hmdInfo->DesktopY = DesktopY;
nuclear@1 275 hmdInfo->HResolution = HResolution;
nuclear@1 276 hmdInfo->VResolution = VResolution;
nuclear@1 277 hmdInfo->HScreenSize = HScreenSize;
nuclear@1 278 hmdInfo->VScreenSize = VScreenSize;
nuclear@1 279 hmdInfo->VScreenCenter = VScreenSize * 0.5f;
nuclear@1 280 hmdInfo->InterpupillaryDistance = 0.064f; // Default IPD; should be configurable.
nuclear@1 281 hmdInfo->LensSeparationDistance = 0.0635f;
nuclear@1 282
nuclear@1 283 // Obtain IPD from profile.
nuclear@1 284 Ptr<Profile> profile = *GetProfileAddRef();
nuclear@1 285
nuclear@1 286 if (profile)
nuclear@1 287 {
nuclear@1 288 hmdInfo->InterpupillaryDistance = profile->GetIPD();
nuclear@1 289 // TBD: Switch on EyeCup type.
nuclear@1 290 }
nuclear@1 291
nuclear@1 292 if (Contents & Contents_Distortion)
nuclear@1 293 {
nuclear@1 294 memcpy(hmdInfo->DistortionK, DistortionK, sizeof(float)*4);
nuclear@1 295 }
nuclear@1 296 else
nuclear@1 297 {
nuclear@1 298 if (is7Inch)
nuclear@1 299 {
nuclear@1 300 // 7" screen.
nuclear@1 301 hmdInfo->DistortionK[0] = 1.0f;
nuclear@1 302 hmdInfo->DistortionK[1] = 0.22f;
nuclear@1 303 hmdInfo->DistortionK[2] = 0.24f;
nuclear@1 304 hmdInfo->EyeToScreenDistance = 0.041f;
nuclear@1 305 }
nuclear@1 306 else
nuclear@1 307 {
nuclear@1 308 hmdInfo->DistortionK[0] = 1.0f;
nuclear@1 309 hmdInfo->DistortionK[1] = 0.18f;
nuclear@1 310 hmdInfo->DistortionK[2] = 0.115f;
nuclear@1 311
nuclear@1 312 if (HResolution == 1920)
nuclear@1 313 hmdInfo->EyeToScreenDistance = 0.040f;
nuclear@1 314 else
nuclear@1 315 hmdInfo->EyeToScreenDistance = 0.0387f;
nuclear@1 316 }
nuclear@1 317
nuclear@1 318 hmdInfo->ChromaAbCorrection[0] = 0.996f;
nuclear@1 319 hmdInfo->ChromaAbCorrection[1] = -0.004f;
nuclear@1 320 hmdInfo->ChromaAbCorrection[2] = 1.014f;
nuclear@1 321 hmdInfo->ChromaAbCorrection[3] = 0.0f;
nuclear@1 322 }
nuclear@1 323
nuclear@1 324 OVR_strcpy(hmdInfo->DisplayDeviceName, sizeof(hmdInfo->DisplayDeviceName),
nuclear@1 325 DisplayDeviceName.ToCStr());
nuclear@1 326 hmdInfo->DisplayId = DisplayId;
nuclear@1 327 }
nuclear@1 328
nuclear@1 329 return true;
nuclear@1 330 }
nuclear@1 331
nuclear@1 332 //-------------------------------------------------------------------------------------
nuclear@1 333 // ***** HMDDevice
nuclear@1 334
nuclear@1 335 HMDDevice::HMDDevice(HMDDeviceCreateDesc* createDesc)
nuclear@1 336 : OVR::DeviceImpl<OVR::HMDDevice>(createDesc, 0)
nuclear@1 337 {
nuclear@1 338 }
nuclear@1 339 HMDDevice::~HMDDevice()
nuclear@1 340 {
nuclear@1 341 }
nuclear@1 342
nuclear@1 343 bool HMDDevice::Initialize(DeviceBase* parent)
nuclear@1 344 {
nuclear@1 345 pParent = parent;
nuclear@1 346
nuclear@1 347 // Initialize user profile to default for device.
nuclear@1 348 ProfileManager* profileManager = GetManager()->GetProfileManager();
nuclear@1 349 ProfileName = profileManager->GetDefaultProfileName(getDesc()->GetProfileType());
nuclear@1 350
nuclear@1 351 return true;
nuclear@1 352 }
nuclear@1 353 void HMDDevice::Shutdown()
nuclear@1 354 {
nuclear@1 355 ProfileName.Clear();
nuclear@1 356 pCachedProfile.Clear();
nuclear@1 357 pParent.Clear();
nuclear@1 358 }
nuclear@1 359
nuclear@1 360 Profile* HMDDevice::GetProfile() const
nuclear@1 361 {
nuclear@1 362 if (!pCachedProfile)
nuclear@1 363 pCachedProfile = *getDesc()->GetProfileAddRef();
nuclear@1 364 return pCachedProfile.GetPtr();
nuclear@1 365 }
nuclear@1 366
nuclear@1 367 const char* HMDDevice::GetProfileName() const
nuclear@1 368 {
nuclear@1 369 return ProfileName.ToCStr();
nuclear@1 370 }
nuclear@1 371
nuclear@1 372 bool HMDDevice::SetProfileName(const char* name)
nuclear@1 373 {
nuclear@1 374 pCachedProfile.Clear();
nuclear@1 375 if (!name)
nuclear@1 376 {
nuclear@1 377 ProfileName.Clear();
nuclear@1 378 return 0;
nuclear@1 379 }
nuclear@1 380 if (GetManager()->GetProfileManager()->HasProfile(getDesc()->GetProfileType(), name))
nuclear@1 381 {
nuclear@1 382 ProfileName = name;
nuclear@1 383 return true;
nuclear@1 384 }
nuclear@1 385 return false;
nuclear@1 386 }
nuclear@1 387
nuclear@1 388 OVR::SensorDevice* HMDDevice::GetSensor()
nuclear@1 389 {
nuclear@1 390 // Just return first sensor found since we have no way to match it yet.
nuclear@1 391 OVR::SensorDevice* sensor = GetManager()->EnumerateDevices<SensorDevice>().CreateDevice();
nuclear@1 392 if (sensor)
nuclear@1 393 sensor->SetCoordinateFrame(SensorDevice::Coord_HMD);
nuclear@1 394 return sensor;
nuclear@1 395 }
nuclear@1 396
nuclear@1 397
nuclear@1 398 }} // namespace OVR::OSX
nuclear@1 399
nuclear@1 400