OVR_Win32_HMDDevice.cpp
Go to the documentation of this file.
00001 /************************************************************************************
00002 
00003 Filename    :   OVR_Win32_HMDDevice.cpp
00004 Content     :   Win32 Interface to HMD - detects HMD display
00005 Created     :   September 21, 2012
00006 Authors     :   Michael Antonov
00007 
00008 Copyright   :   Copyright 2012 Oculus VR, Inc. All Rights reserved.
00009 
00010 Use of this software is subject to the terms of the Oculus license
00011 agreement provided at the time of installation or download, or which
00012 otherwise accompanies this software in either electronic or hard copy form.
00013 
00014 *************************************************************************************/
00015 
00016 #include "OVR_Win32_HMDDevice.h"
00017 
00018 #include "OVR_Win32_DeviceManager.h"
00019 
00020 #include <tchar.h>
00021 
00022 namespace OVR { namespace Win32 {
00023 
00024 //-------------------------------------------------------------------------------------
00025 
00026 HMDDeviceCreateDesc::HMDDeviceCreateDesc(DeviceFactory* factory, 
00027                                          const String& deviceId, const String& displayDeviceName)
00028         : DeviceCreateDesc(factory, Device_HMD),
00029           DeviceId(deviceId), DisplayDeviceName(displayDeviceName),
00030           DesktopX(0), DesktopY(0), Contents(0),
00031           HResolution(0), VResolution(0), HScreenSize(0), VScreenSize(0)
00032 {
00033 }
00034 HMDDeviceCreateDesc::HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other)
00035         : DeviceCreateDesc(other.pFactory, Device_HMD),
00036           DeviceId(other.DeviceId), DisplayDeviceName(other.DisplayDeviceName),
00037           DesktopX(other.DesktopX), DesktopY(other.DesktopY), Contents(other.Contents),
00038           HResolution(other.HResolution), VResolution(other.VResolution),
00039           HScreenSize(other.HScreenSize), VScreenSize(other.VScreenSize)
00040 {
00041 }
00042 
00043 HMDDeviceCreateDesc::MatchResult HMDDeviceCreateDesc::MatchDevice(const DeviceCreateDesc& other,
00044                                                                   DeviceCreateDesc** pcandidate) const
00045 {
00046     if ((other.Type != Device_HMD) || (other.pFactory != pFactory))
00047         return Match_None;
00048 
00049     // There are several reasons we can come in here:
00050     //   a) Matching this HMD Monitor created desc to OTHER HMD Monitor desc
00051     //          - Require exact device DeviceId/DeviceName match
00052     //   b) Matching SensorDisplayInfo created desc to OTHER HMD Monitor desc
00053     //          - This DeviceId is empty; becomes candidate
00054     //   c) Matching this HMD Monitor created desc to SensorDisplayInfo desc
00055     //          - This other.DeviceId is empty; becomes candidate
00056 
00057     const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
00058 
00059     if ((DeviceId == s2.DeviceId) &&
00060         (DisplayDeviceName == s2.DisplayDeviceName))
00061     {
00062         // Non-null DeviceId may match while size is different if screen size was overwritten
00063         // by SensorDisplayInfo in prior iteration.
00064         if (!DeviceId.IsEmpty() ||
00065              ((HScreenSize == s2.HScreenSize) &&
00066               (VScreenSize == s2.VScreenSize)) )
00067         {            
00068             *pcandidate = 0;
00069             return Match_Found;
00070         }
00071     }
00072 
00073 
00074     // DisplayInfo takes precedence, although we try to match it first.
00075     if ((HResolution == s2.HResolution) &&
00076         (VResolution == s2.VResolution) &&
00077         (HScreenSize == s2.HScreenSize) &&
00078         (VScreenSize == s2.VScreenSize))
00079     {
00080         if (DeviceId.IsEmpty() && !s2.DeviceId.IsEmpty())
00081         {
00082             *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
00083             return Match_Candidate;
00084         }
00085 
00086         *pcandidate = 0;
00087         return Match_Found;
00088     }
00089     
00090     // SensorDisplayInfo may override resolution settings, so store as candidate.
00091     if (s2.DeviceId.IsEmpty())
00092     {        
00093         *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
00094         return Match_Candidate;
00095     }
00096     // OTHER HMD Monitor desc may initialize DeviceName/Id
00097     else if (DeviceId.IsEmpty())
00098     {
00099         *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
00100         return Match_Candidate;
00101     }
00102     
00103     return Match_None;
00104 }
00105 
00106 
00107 bool HMDDeviceCreateDesc::UpdateMatchedCandidate(const DeviceCreateDesc& other, 
00108                                                  bool* newDeviceFlag)
00109 {
00110     // This candidate was the the "best fit" to apply sensor DisplayInfo to.
00111     OVR_ASSERT(other.Type == Device_HMD);
00112     
00113     const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
00114 
00115     // Force screen size on resolution from SensorDisplayInfo.
00116     // We do this because USB detection is more reliable as compared to HDMI EDID,
00117     // which may be corrupted by splitter reporting wrong monitor 
00118     if (s2.DeviceId.IsEmpty())
00119     {
00120         HScreenSize = s2.HScreenSize;
00121         VScreenSize = s2.VScreenSize;
00122         Contents |= Contents_Screen;
00123 
00124         if (s2.Contents & HMDDeviceCreateDesc::Contents_Distortion)
00125         {
00126             memcpy(DistortionK, s2.DistortionK, sizeof(float)*4);
00127             Contents |= Contents_Distortion;
00128         }
00129         DeviceId          = s2.DeviceId;
00130         DisplayDeviceName = s2.DisplayDeviceName;
00131         DesktopX          = s2.DesktopX;
00132         DesktopY          = s2.DesktopY;
00133         if (newDeviceFlag) *newDeviceFlag = true;
00134     }
00135     else if (DeviceId.IsEmpty())
00136     {
00137         DeviceId          = s2.DeviceId;
00138         DisplayDeviceName = s2.DisplayDeviceName;
00139         DesktopX          = s2.DesktopX;
00140         DesktopY          = s2.DesktopY;
00141 
00142                 // ScreenSize and Resolution are NOT assigned here, since they may have
00143                 // come from a sensor DisplayInfo (which has precedence over HDMI).
00144 
00145         if (newDeviceFlag) *newDeviceFlag = true;
00146     }
00147     else
00148     {
00149         if (newDeviceFlag) *newDeviceFlag = false;
00150     }
00151 
00152     return true;
00153 }
00154 
00155 bool HMDDeviceCreateDesc::MatchDevice(const String& path)
00156 {
00157     return DeviceId.CompareNoCase(path) == 0;
00158 }
00159     
00160 //-------------------------------------------------------------------------------------
00161 
00162 
00163 const wchar_t* FormatDisplayStateFlags(wchar_t* buff, int length, DWORD flags)
00164 {
00165     buff[0] = 0;
00166     if (flags & DISPLAY_DEVICE_ACTIVE)
00167         wcscat_s(buff, length, L"Active ");
00168     if (flags & DISPLAY_DEVICE_MIRRORING_DRIVER)
00169         wcscat_s(buff, length, L"Mirroring_Driver ");
00170     if (flags & DISPLAY_DEVICE_MODESPRUNED)
00171         wcscat_s(buff, length, L"ModesPruned ");
00172     if (flags & DISPLAY_DEVICE_PRIMARY_DEVICE)
00173         wcscat_s(buff, length, L"Primary ");
00174     if (flags & DISPLAY_DEVICE_REMOVABLE)
00175         wcscat_s(buff, length, L"Removable ");
00176     if (flags & DISPLAY_DEVICE_VGA_COMPATIBLE)
00177         wcscat_s(buff, length, L"VGA_Compatible ");
00178     return buff;
00179 }
00180 
00181 
00182 //-------------------------------------------------------------------------------------
00183 // Callback for monitor enumeration to store all the monitor handles
00184 
00185 // Used to capture all the active monitor handles
00186 struct MonitorSet
00187 {
00188     enum { MaxMonitors = 8 };
00189     HMONITOR Monitors[MaxMonitors];
00190     int      MonitorCount;
00191 };
00192 
00193 BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData)
00194 {
00195     MonitorSet* monitorSet = (MonitorSet*)dwData;
00196     if (monitorSet->MonitorCount > MonitorSet::MaxMonitors)
00197         return FALSE;
00198 
00199     monitorSet->Monitors[monitorSet->MonitorCount] = hMonitor;
00200     monitorSet->MonitorCount++;
00201     return TRUE;
00202 };
00203 
00204 //-------------------------------------------------------------------------------------
00205 // ***** HMDDeviceFactory
00206 
00207 HMDDeviceFactory HMDDeviceFactory::Instance;
00208 
00209 void HMDDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
00210 {
00211     MonitorSet monitors;
00212     monitors.MonitorCount = 0;
00213     // Get all the monitor handles 
00214     EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&monitors);
00215 
00216     bool foundHMD = false;
00217     
00218    // DeviceManager* manager = getManager();
00219     DISPLAY_DEVICE dd, ddm;
00220     UINT           i, j;    
00221 
00222     for (i = 0; 
00223         (ZeroMemory(&dd, sizeof(dd)), dd.cb = sizeof(dd),
00224         EnumDisplayDevices(0, i, &dd, 0)) != 0;  i++)
00225     {
00226         
00227         /*
00228         wchar_t buff[500], flagsBuff[200];
00229         
00230         swprintf_s(buff, 500, L"\nDEV: \"%s\" \"%s\" 0x%08x=%s\n     \"%s\" \"%s\"\n",
00231             dd.DeviceName, dd.DeviceString,
00232             dd.StateFlags, FormatDisplayStateFlags(flagsBuff, 200, dd.StateFlags),
00233             dd.DeviceID, dd.DeviceKey);
00234         ::OutputDebugString(buff);
00235         */
00236 
00237         for (j = 0; 
00238             (ZeroMemory(&ddm, sizeof(ddm)), ddm.cb = sizeof(ddm),
00239             EnumDisplayDevices(dd.DeviceName, j, &ddm, 0)) != 0;  j++)
00240         {
00241             /*
00242             wchar_t mbuff[500];
00243             swprintf_s(mbuff, 500, L"MON: \"%s\" \"%s\" 0x%08x=%s\n     \"%s\" \"%s\"\n",
00244                 ddm.DeviceName, ddm.DeviceString,
00245                 ddm.StateFlags, FormatDisplayStateFlags(flagsBuff, 200, ddm.StateFlags),
00246                 ddm.DeviceID, ddm.DeviceKey);
00247             ::OutputDebugString(mbuff);
00248             */
00249 
00250             // Our monitor hardware has string "RTD2205" in it
00251             // Nate's device "CVT0003"
00252             if (wcsstr(ddm.DeviceID, L"RTD2205") || 
00253                 wcsstr(ddm.DeviceID, L"CVT0003") || 
00254                 wcsstr(ddm.DeviceID, L"MST0030") ||
00255                 wcsstr(ddm.DeviceID, L"OVR00") ) // Part of Oculus EDID.
00256             {
00257                 String deviceId(ddm.DeviceID);
00258                 String displayDeviceName(ddm.DeviceName);
00259 
00260                 // The default monitor coordinates
00261                 int mx      = 0;
00262                 int my      = 0;
00263                 int mwidth  = 1280;
00264                 int mheight = 800;
00265 
00266                 // Find the matching MONITORINFOEX for this device so we can get the 
00267                 // screen coordinates
00268                 MONITORINFOEX info;
00269                 for (int m=0; m < monitors.MonitorCount; m++)
00270                 {
00271                     info.cbSize = sizeof(MONITORINFOEX);
00272                     GetMonitorInfo(monitors.Monitors[m], &info);
00273                     if (_tcsstr(ddm.DeviceName, info.szDevice) == ddm.DeviceName)
00274                     {   // If the device name starts with the monitor name
00275                         // then we found the matching DISPLAY_DEVICE and MONITORINFO
00276                         // so we can gather the monitor coordinates
00277                         mx = info.rcMonitor.left;
00278                         my = info.rcMonitor.top;
00279                         //mwidth = info.rcMonitor.right - info.rcMonitor.left;
00280                         //mheight = info.rcMonitor.bottom - info.rcMonitor.top;
00281                         break;
00282                     }
00283                 }
00284 
00285                 HMDDeviceCreateDesc hmdCreateDesc(this, deviceId, displayDeviceName);
00286                                 
00287                                 if (wcsstr(ddm.DeviceID, L"OVR0002"))
00288                                 {
00289                                         hmdCreateDesc.SetScreenParameters(mx, my, 1920, 1080, 0.12096f, 0.06804f);
00290                                 }
00291                                 else
00292                                 {
00293                                         if (hmdCreateDesc.Is7Inch())
00294                                         {
00295                                                 // Physical dimension of SLA screen.
00296                                                 hmdCreateDesc.SetScreenParameters(mx, my, mwidth, mheight, 0.14976f, 0.0936f);
00297                                         }
00298                                         else
00299                                         {
00300                                                 hmdCreateDesc.SetScreenParameters(mx, my, mwidth, mheight, 0.12096f, 0.0756f);
00301                                         }
00302                                 }
00303 
00304 
00305                 OVR_DEBUG_LOG_TEXT(("DeviceManager - HMD Found %s - %s\n",
00306                                     deviceId.ToCStr(), displayDeviceName.ToCStr()));
00307 
00308                 // Notify caller about detected device. This will call EnumerateAddDevice
00309                 // if the this is the first time device was detected.
00310                 visitor.Visit(hmdCreateDesc);
00311                 foundHMD = true;
00312                 break;
00313             }
00314         }
00315     }
00316 
00317     // Real HMD device is not found; however, we still may have a 'fake' HMD
00318     // device created via SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo.
00319     // Need to find it and set 'Enumerated' to true to avoid Removal notification.
00320     if (!foundHMD)
00321     {
00322         Ptr<DeviceCreateDesc> hmdDevDesc = getManager()->FindDevice("", Device_HMD);
00323         if (hmdDevDesc)
00324             hmdDevDesc->Enumerated = true;
00325     }
00326 }
00327 
00328 DeviceBase* HMDDeviceCreateDesc::NewDeviceInstance()
00329 {
00330     return new HMDDevice(this);
00331 }
00332 
00333 bool HMDDeviceCreateDesc::Is7Inch() const
00334 {
00335     return (strstr(DeviceId.ToCStr(), "OVR0001") != 0) || (Contents & Contents_7Inch);
00336 }
00337 
00338 Profile* HMDDeviceCreateDesc::GetProfileAddRef() const
00339 {
00340     // Create device may override profile name, so get it from there is possible.
00341     ProfileManager* profileManager = GetManagerImpl()->GetProfileManager();
00342     ProfileType     profileType    = GetProfileType();
00343     const char *    profileName    = pDevice ?
00344                         ((HMDDevice*)pDevice)->GetProfileName() :
00345                         profileManager->GetDefaultProfileName(profileType);
00346     
00347     return profileName ? 
00348         profileManager->LoadProfile(profileType, profileName) :
00349         profileManager->GetDeviceDefaultProfile(profileType);
00350 }
00351 
00352 
00353 bool HMDDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
00354 {
00355     if ((info->InfoClassType != Device_HMD) &&
00356         (info->InfoClassType != Device_None))
00357         return false;
00358 
00359     bool is7Inch = Is7Inch();
00360 
00361     OVR_strcpy(info->ProductName,  DeviceInfo::MaxNameLength,
00362                is7Inch ? "Oculus Rift DK1" :
00363                            ((HResolution >= 1920) ? "Oculus Rift DK HD" : "Oculus Rift DK1-Prototype") );
00364     OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, "Oculus VR");
00365     info->Type    = Device_HMD;
00366     info->Version = 0;
00367 
00368     // Display detection.
00369     if (info->InfoClassType == Device_HMD)
00370     {
00371         HMDInfo* hmdInfo = static_cast<HMDInfo*>(info);
00372 
00373         hmdInfo->DesktopX               = DesktopX;
00374         hmdInfo->DesktopY               = DesktopY;
00375         hmdInfo->HResolution            = HResolution;
00376         hmdInfo->VResolution            = VResolution;
00377         hmdInfo->HScreenSize            = HScreenSize;
00378         hmdInfo->VScreenSize            = VScreenSize;
00379         hmdInfo->VScreenCenter          = VScreenSize * 0.5f;
00380         hmdInfo->InterpupillaryDistance = 0.064f;  // Default IPD; should be configurable.
00381         hmdInfo->LensSeparationDistance = 0.0635f;
00382 
00383         // Obtain IPD from profile.
00384         Ptr<Profile> profile = *GetProfileAddRef();
00385 
00386         if (profile)
00387         {
00388             hmdInfo->InterpupillaryDistance = profile->GetIPD();
00389             // TBD: Switch on EyeCup type.
00390         }
00391 
00392         if (Contents & Contents_Distortion)
00393         {
00394             memcpy(hmdInfo->DistortionK, DistortionK, sizeof(float)*4);
00395         }
00396         else
00397         {                                               
00398                         if (is7Inch)
00399             {
00400                 // 7" screen.
00401                 hmdInfo->DistortionK[0]      = 1.0f;
00402                 hmdInfo->DistortionK[1]      = 0.22f;
00403                 hmdInfo->DistortionK[2]      = 0.24f;
00404                 hmdInfo->EyeToScreenDistance = 0.041f;
00405             }
00406             else
00407             {
00408                 hmdInfo->DistortionK[0]      = 1.0f;
00409                 hmdInfo->DistortionK[1]      = 0.18f;
00410                 hmdInfo->DistortionK[2]      = 0.115f;
00411 
00412                                 if (HResolution == 1920)
00413                                         hmdInfo->EyeToScreenDistance = 0.040f;
00414                                 else
00415                                         hmdInfo->EyeToScreenDistance = 0.0387f;
00416             }
00417 
00418                         hmdInfo->ChromaAbCorrection[0] = 0.996f;
00419                         hmdInfo->ChromaAbCorrection[1] = -0.004f;
00420                         hmdInfo->ChromaAbCorrection[2] = 1.014f;
00421                         hmdInfo->ChromaAbCorrection[3] = 0.0f;
00422         }
00423 
00424         OVR_strcpy(hmdInfo->DisplayDeviceName, sizeof(hmdInfo->DisplayDeviceName),
00425                    DisplayDeviceName.ToCStr());
00426     }
00427 
00428     return true;
00429 }
00430 
00431 //-------------------------------------------------------------------------------------
00432 // ***** HMDDevice
00433 
00434 HMDDevice::HMDDevice(HMDDeviceCreateDesc* createDesc)
00435     : OVR::DeviceImpl<OVR::HMDDevice>(createDesc, 0)
00436 {
00437 }
00438 HMDDevice::~HMDDevice()
00439 {
00440 }
00441 
00442 bool HMDDevice::Initialize(DeviceBase* parent)
00443 {
00444     pParent = parent;
00445 
00446     // Initialize user profile to default for device.
00447     ProfileManager* profileManager = GetManager()->GetProfileManager();    
00448     ProfileName = profileManager->GetDefaultProfileName(getDesc()->GetProfileType());
00449 
00450     return true;
00451 }
00452 void HMDDevice::Shutdown()
00453 {
00454     ProfileName.Clear();
00455     pCachedProfile.Clear();
00456     pParent.Clear();
00457 }
00458 
00459 Profile* HMDDevice::GetProfile() const
00460 {    
00461     if (!pCachedProfile)
00462         pCachedProfile = *getDesc()->GetProfileAddRef();
00463     return pCachedProfile.GetPtr();
00464 }
00465 
00466 const char* HMDDevice::GetProfileName() const
00467 {
00468     return ProfileName.ToCStr();
00469 }
00470 
00471 bool HMDDevice::SetProfileName(const char* name)
00472 {
00473     pCachedProfile.Clear();
00474     if (!name)
00475     {
00476         ProfileName.Clear();
00477         return 0;
00478     }
00479     if (GetManager()->GetProfileManager()->HasProfile(getDesc()->GetProfileType(), name))
00480     {
00481         ProfileName = name;
00482         return true;
00483     }
00484     return false;
00485 }
00486 
00487 OVR::SensorDevice* HMDDevice::GetSensor()
00488 {
00489     // Just return first sensor found since we have no way to match it yet.
00490     OVR::SensorDevice* sensor = GetManager()->EnumerateDevices<SensorDevice>().CreateDevice();
00491     if (sensor)
00492         sensor->SetCoordinateFrame(SensorDevice::Coord_HMD);
00493     return sensor;
00494 }
00495 
00496 }} // namespace OVR::Win32
00497 
00498 


oculus_sdk
Author(s):
autogenerated on Mon Oct 6 2014 03:01:19