rev |
line source |
nuclear@1
|
1 /************************************************************************************
|
nuclear@1
|
2
|
nuclear@1
|
3 Filename : OVR_Linux_HMDDevice.h
|
nuclear@1
|
4 Content : Linux HMDDevice implementation
|
nuclear@1
|
5 Created : June 17, 2013
|
nuclear@1
|
6 Authors : Brant Lewis
|
nuclear@1
|
7
|
nuclear@1
|
8 Copyright : Copyright 2013 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_Linux_HMDDevice.h"
|
nuclear@1
|
17
|
nuclear@1
|
18 #include "OVR_Linux_DeviceManager.h"
|
nuclear@1
|
19
|
nuclear@1
|
20 #include "OVR_Profile.h"
|
nuclear@1
|
21
|
nuclear@1
|
22 #include <X11/Xlib.h>
|
nuclear@1
|
23 #include <X11/extensions/Xinerama.h>
|
nuclear@1
|
24
|
nuclear@1
|
25 namespace OVR { namespace Linux {
|
nuclear@1
|
26
|
nuclear@1
|
27 //-------------------------------------------------------------------------------------
|
nuclear@1
|
28
|
nuclear@1
|
29 HMDDeviceCreateDesc::HMDDeviceCreateDesc(DeviceFactory* factory, const String& displayDeviceName, long dispId)
|
nuclear@1
|
30 : DeviceCreateDesc(factory, Device_HMD),
|
nuclear@1
|
31 DisplayDeviceName(displayDeviceName),
|
nuclear@1
|
32 DesktopX(0), DesktopY(0), Contents(0),
|
nuclear@1
|
33 HResolution(0), VResolution(0), HScreenSize(0), VScreenSize(0),
|
nuclear@1
|
34 DisplayId(dispId)
|
nuclear@1
|
35 {
|
nuclear@1
|
36 DeviceId = DisplayDeviceName;
|
nuclear@1
|
37 }
|
nuclear@1
|
38
|
nuclear@1
|
39 HMDDeviceCreateDesc::HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other)
|
nuclear@1
|
40 : DeviceCreateDesc(other.pFactory, Device_HMD),
|
nuclear@1
|
41 DeviceId(other.DeviceId), DisplayDeviceName(other.DisplayDeviceName),
|
nuclear@1
|
42 DesktopX(other.DesktopX), DesktopY(other.DesktopY), Contents(other.Contents),
|
nuclear@1
|
43 HResolution(other.HResolution), VResolution(other.VResolution),
|
nuclear@1
|
44 HScreenSize(other.HScreenSize), VScreenSize(other.VScreenSize),
|
nuclear@1
|
45 DisplayId(other.DisplayId)
|
nuclear@1
|
46 {
|
nuclear@1
|
47 }
|
nuclear@1
|
48
|
nuclear@1
|
49 HMDDeviceCreateDesc::MatchResult HMDDeviceCreateDesc::MatchDevice(const DeviceCreateDesc& other,
|
nuclear@1
|
50 DeviceCreateDesc** pcandidate) const
|
nuclear@1
|
51 {
|
nuclear@1
|
52 if ((other.Type != Device_HMD) || (other.pFactory != pFactory))
|
nuclear@1
|
53 return Match_None;
|
nuclear@1
|
54
|
nuclear@1
|
55 // There are several reasons we can come in here:
|
nuclear@1
|
56 // a) Matching this HMD Monitor created desc to OTHER HMD Monitor desc
|
nuclear@1
|
57 // - Require exact device DeviceId/DeviceName match
|
nuclear@1
|
58 // b) Matching SensorDisplayInfo created desc to OTHER HMD Monitor desc
|
nuclear@1
|
59 // - This DeviceId is empty; becomes candidate
|
nuclear@1
|
60 // c) Matching this HMD Monitor created desc to SensorDisplayInfo desc
|
nuclear@1
|
61 // - This other.DeviceId is empty; becomes candidate
|
nuclear@1
|
62
|
nuclear@1
|
63 const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
|
nuclear@1
|
64
|
nuclear@1
|
65 if ((DeviceId == s2.DeviceId) &&
|
nuclear@1
|
66 (DisplayId == s2.DisplayId))
|
nuclear@1
|
67 {
|
nuclear@1
|
68 // Non-null DeviceId may match while size is different if screen size was overwritten
|
nuclear@1
|
69 // by SensorDisplayInfo in prior iteration.
|
nuclear@1
|
70 if (!DeviceId.IsEmpty() ||
|
nuclear@1
|
71 ((HScreenSize == s2.HScreenSize) &&
|
nuclear@1
|
72 (VScreenSize == s2.VScreenSize)) )
|
nuclear@1
|
73 {
|
nuclear@1
|
74 *pcandidate = 0;
|
nuclear@1
|
75 return Match_Found;
|
nuclear@1
|
76 }
|
nuclear@1
|
77 }
|
nuclear@1
|
78
|
nuclear@1
|
79
|
nuclear@1
|
80 // DisplayInfo takes precedence, although we try to match it first.
|
nuclear@1
|
81 if ((HResolution == s2.HResolution) &&
|
nuclear@1
|
82 (VResolution == s2.VResolution) &&
|
nuclear@1
|
83 (HScreenSize == s2.HScreenSize) &&
|
nuclear@1
|
84 (VScreenSize == s2.VScreenSize))
|
nuclear@1
|
85 {
|
nuclear@1
|
86 if (DeviceId.IsEmpty() && !s2.DeviceId.IsEmpty())
|
nuclear@1
|
87 {
|
nuclear@1
|
88 *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
|
nuclear@1
|
89 return Match_Candidate;
|
nuclear@1
|
90 }
|
nuclear@1
|
91
|
nuclear@1
|
92 *pcandidate = 0;
|
nuclear@1
|
93 return Match_Found;
|
nuclear@1
|
94 }
|
nuclear@1
|
95
|
nuclear@1
|
96 // SensorDisplayInfo may override resolution settings, so store as candidate.
|
nuclear@1
|
97 if (s2.DeviceId.IsEmpty())
|
nuclear@1
|
98 {
|
nuclear@1
|
99 *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
|
nuclear@1
|
100 return Match_Candidate;
|
nuclear@1
|
101 }
|
nuclear@1
|
102 // OTHER HMD Monitor desc may initialize DeviceName/Id
|
nuclear@1
|
103 else if (DeviceId.IsEmpty())
|
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
|
nuclear@1
|
109 return Match_None;
|
nuclear@1
|
110 }
|
nuclear@1
|
111
|
nuclear@1
|
112
|
nuclear@1
|
113 bool HMDDeviceCreateDesc::UpdateMatchedCandidate(const DeviceCreateDesc& other,
|
nuclear@1
|
114 bool* newDeviceFlag)
|
nuclear@1
|
115 {
|
nuclear@1
|
116 // This candidate was the the "best fit" to apply sensor DisplayInfo to.
|
nuclear@1
|
117 OVR_ASSERT(other.Type == Device_HMD);
|
nuclear@1
|
118
|
nuclear@1
|
119 const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
|
nuclear@1
|
120
|
nuclear@1
|
121 // Force screen size on resolution from SensorDisplayInfo.
|
nuclear@1
|
122 // We do this because USB detection is more reliable as compared to HDMI EDID,
|
nuclear@1
|
123 // which may be corrupted by splitter reporting wrong monitor
|
nuclear@1
|
124 if (s2.DeviceId.IsEmpty())
|
nuclear@1
|
125 {
|
nuclear@1
|
126 HScreenSize = s2.HScreenSize;
|
nuclear@1
|
127 VScreenSize = s2.VScreenSize;
|
nuclear@1
|
128 Contents |= Contents_Screen;
|
nuclear@1
|
129
|
nuclear@1
|
130 if (s2.Contents & HMDDeviceCreateDesc::Contents_Distortion)
|
nuclear@1
|
131 {
|
nuclear@1
|
132 memcpy(DistortionK, s2.DistortionK, sizeof(float)*4);
|
nuclear@1
|
133 Contents |= Contents_Distortion;
|
nuclear@1
|
134 }
|
nuclear@1
|
135 DeviceId = s2.DeviceId;
|
nuclear@1
|
136 DisplayId = s2.DisplayId;
|
nuclear@1
|
137 DisplayDeviceName = s2.DisplayDeviceName;
|
nuclear@1
|
138 if (newDeviceFlag) *newDeviceFlag = true;
|
nuclear@1
|
139 }
|
nuclear@1
|
140 else if (DeviceId.IsEmpty())
|
nuclear@1
|
141 {
|
nuclear@1
|
142 DeviceId = s2.DeviceId;
|
nuclear@1
|
143 DisplayId = s2.DisplayId;
|
nuclear@1
|
144 DisplayDeviceName = s2.DisplayDeviceName;
|
nuclear@1
|
145
|
nuclear@1
|
146 // ScreenSize and Resolution are NOT assigned here, since they may have
|
nuclear@1
|
147 // come from a sensor DisplayInfo (which has precedence over HDMI).
|
nuclear@1
|
148
|
nuclear@1
|
149 if (newDeviceFlag) *newDeviceFlag = true;
|
nuclear@1
|
150 }
|
nuclear@1
|
151 else
|
nuclear@1
|
152 {
|
nuclear@1
|
153 if (newDeviceFlag) *newDeviceFlag = false;
|
nuclear@1
|
154 }
|
nuclear@1
|
155
|
nuclear@1
|
156 return true;
|
nuclear@1
|
157 }
|
nuclear@1
|
158
|
nuclear@1
|
159 bool HMDDeviceCreateDesc::MatchDevice(const String& path)
|
nuclear@1
|
160 {
|
nuclear@1
|
161 return DeviceId.CompareNoCase(path) == 0;
|
nuclear@1
|
162 }
|
nuclear@1
|
163
|
nuclear@1
|
164 //-------------------------------------------------------------------------------------
|
nuclear@1
|
165 // ***** HMDDeviceFactory
|
nuclear@1
|
166
|
nuclear@1
|
167 HMDDeviceFactory HMDDeviceFactory::Instance;
|
nuclear@1
|
168
|
nuclear@1
|
169 void HMDDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
|
nuclear@1
|
170 {
|
nuclear@1
|
171 // For now we'll assume the Rift DK1 is attached in extended monitor mode. Ultimately we need to
|
nuclear@1
|
172 // use XFree86 to enumerate X11 screens in case the Rift is attached as a separate screen. We also
|
nuclear@1
|
173 // need to be able to read the EDID manufacturer product code to be able to differentiate between
|
nuclear@1
|
174 // Rift models.
|
nuclear@1
|
175
|
nuclear@1
|
176 bool foundHMD = false;
|
nuclear@1
|
177
|
nuclear@1
|
178 Display* display = XOpenDisplay(NULL);
|
nuclear@1
|
179 if (display && XineramaIsActive(display))
|
nuclear@1
|
180 {
|
nuclear@1
|
181 int numberOfScreens;
|
nuclear@1
|
182 XineramaScreenInfo* screens = XineramaQueryScreens(display, &numberOfScreens);
|
nuclear@1
|
183
|
nuclear@1
|
184 for (int i = 0; i < numberOfScreens; i++)
|
nuclear@1
|
185 {
|
nuclear@1
|
186 XineramaScreenInfo screenInfo = screens[i];
|
nuclear@1
|
187
|
nuclear@1
|
188 if (screenInfo.width == 1280 && screenInfo.height == 800)
|
nuclear@1
|
189 {
|
nuclear@1
|
190 String deviceName = "OVR0001";
|
nuclear@1
|
191
|
nuclear@1
|
192 HMDDeviceCreateDesc hmdCreateDesc(this, deviceName, i);
|
nuclear@1
|
193 hmdCreateDesc.SetScreenParameters(screenInfo.x_org, screenInfo.y_org, 1280, 800, 0.14976f, 0.0936f);
|
nuclear@1
|
194
|
nuclear@1
|
195 OVR_DEBUG_LOG_TEXT(("DeviceManager - HMD Found %s - %d\n",
|
nuclear@1
|
196 deviceName.ToCStr(), i));
|
nuclear@1
|
197
|
nuclear@1
|
198 // Notify caller about detected device. This will call EnumerateAddDevice
|
nuclear@1
|
199 // if the this is the first time device was detected.
|
nuclear@1
|
200 visitor.Visit(hmdCreateDesc);
|
nuclear@1
|
201 foundHMD = true;
|
nuclear@1
|
202 break;
|
nuclear@1
|
203 }
|
nuclear@1
|
204 }
|
nuclear@1
|
205
|
nuclear@1
|
206 XFree(screens);
|
nuclear@1
|
207 }
|
nuclear@1
|
208
|
nuclear@1
|
209
|
nuclear@1
|
210 // Real HMD device is not found; however, we still may have a 'fake' HMD
|
nuclear@1
|
211 // device created via SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo.
|
nuclear@1
|
212 // Need to find it and set 'Enumerated' to true to avoid Removal notification.
|
nuclear@1
|
213 if (!foundHMD)
|
nuclear@1
|
214 {
|
nuclear@1
|
215 Ptr<DeviceCreateDesc> hmdDevDesc = getManager()->FindDevice("", Device_HMD);
|
nuclear@1
|
216 if (hmdDevDesc)
|
nuclear@1
|
217 hmdDevDesc->Enumerated = true;
|
nuclear@1
|
218 }
|
nuclear@1
|
219 }
|
nuclear@1
|
220
|
nuclear@1
|
221 DeviceBase* HMDDeviceCreateDesc::NewDeviceInstance()
|
nuclear@1
|
222 {
|
nuclear@1
|
223 return new HMDDevice(this);
|
nuclear@1
|
224 }
|
nuclear@1
|
225
|
nuclear@1
|
226 bool HMDDeviceCreateDesc::Is7Inch() const
|
nuclear@1
|
227 {
|
nuclear@1
|
228 return (strstr(DeviceId.ToCStr(), "OVR0001") != 0) || (Contents & Contents_7Inch);
|
nuclear@1
|
229 }
|
nuclear@1
|
230
|
nuclear@1
|
231 Profile* HMDDeviceCreateDesc::GetProfileAddRef() const
|
nuclear@1
|
232 {
|
nuclear@1
|
233 // Create device may override profile name, so get it from there is possible.
|
nuclear@1
|
234 ProfileManager* profileManager = GetManagerImpl()->GetProfileManager();
|
nuclear@1
|
235 ProfileType profileType = GetProfileType();
|
nuclear@1
|
236 const char * profileName = pDevice ?
|
nuclear@1
|
237 ((HMDDevice*)pDevice)->GetProfileName() :
|
nuclear@1
|
238 profileManager->GetDefaultProfileName(profileType);
|
nuclear@1
|
239
|
nuclear@1
|
240 return profileName ?
|
nuclear@1
|
241 profileManager->LoadProfile(profileType, profileName) :
|
nuclear@1
|
242 profileManager->GetDeviceDefaultProfile(profileType);
|
nuclear@1
|
243 }
|
nuclear@1
|
244
|
nuclear@1
|
245
|
nuclear@1
|
246 bool HMDDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
|
nuclear@1
|
247 {
|
nuclear@1
|
248 if ((info->InfoClassType != Device_HMD) &&
|
nuclear@1
|
249 (info->InfoClassType != Device_None))
|
nuclear@1
|
250 return false;
|
nuclear@1
|
251
|
nuclear@1
|
252 bool is7Inch = Is7Inch();
|
nuclear@1
|
253
|
nuclear@1
|
254 OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength,
|
nuclear@1
|
255 is7Inch ? "Oculus Rift DK1" :
|
nuclear@1
|
256 ((HResolution >= 1920) ? "Oculus Rift DK HD" : "Oculus Rift DK1-Prototype") );
|
nuclear@1
|
257 OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, "Oculus VR");
|
nuclear@1
|
258 info->Type = Device_HMD;
|
nuclear@1
|
259 info->Version = 0;
|
nuclear@1
|
260
|
nuclear@1
|
261 // Display detection.
|
nuclear@1
|
262 if (info->InfoClassType == Device_HMD)
|
nuclear@1
|
263 {
|
nuclear@1
|
264 HMDInfo* hmdInfo = static_cast<HMDInfo*>(info);
|
nuclear@1
|
265
|
nuclear@1
|
266 hmdInfo->DesktopX = DesktopX;
|
nuclear@1
|
267 hmdInfo->DesktopY = DesktopY;
|
nuclear@1
|
268 hmdInfo->HResolution = HResolution;
|
nuclear@1
|
269 hmdInfo->VResolution = VResolution;
|
nuclear@1
|
270 hmdInfo->HScreenSize = HScreenSize;
|
nuclear@1
|
271 hmdInfo->VScreenSize = VScreenSize;
|
nuclear@1
|
272 hmdInfo->VScreenCenter = VScreenSize * 0.5f;
|
nuclear@1
|
273 hmdInfo->InterpupillaryDistance = 0.064f; // Default IPD; should be configurable.
|
nuclear@1
|
274 hmdInfo->LensSeparationDistance = 0.0635f;
|
nuclear@1
|
275
|
nuclear@1
|
276 // Obtain IPD from profile.
|
nuclear@1
|
277 Ptr<Profile> profile = *GetProfileAddRef();
|
nuclear@1
|
278
|
nuclear@1
|
279 if (profile)
|
nuclear@1
|
280 {
|
nuclear@1
|
281 hmdInfo->InterpupillaryDistance = profile->GetIPD();
|
nuclear@1
|
282 // TBD: Switch on EyeCup type.
|
nuclear@1
|
283 }
|
nuclear@1
|
284
|
nuclear@1
|
285 if (Contents & Contents_Distortion)
|
nuclear@1
|
286 {
|
nuclear@1
|
287 memcpy(hmdInfo->DistortionK, DistortionK, sizeof(float)*4);
|
nuclear@1
|
288 }
|
nuclear@1
|
289 else
|
nuclear@1
|
290 {
|
nuclear@1
|
291 if (is7Inch)
|
nuclear@1
|
292 {
|
nuclear@1
|
293 // 7" screen.
|
nuclear@1
|
294 hmdInfo->DistortionK[0] = 1.0f;
|
nuclear@1
|
295 hmdInfo->DistortionK[1] = 0.22f;
|
nuclear@1
|
296 hmdInfo->DistortionK[2] = 0.24f;
|
nuclear@1
|
297 hmdInfo->EyeToScreenDistance = 0.041f;
|
nuclear@1
|
298 }
|
nuclear@1
|
299 else
|
nuclear@1
|
300 {
|
nuclear@1
|
301 hmdInfo->DistortionK[0] = 1.0f;
|
nuclear@1
|
302 hmdInfo->DistortionK[1] = 0.18f;
|
nuclear@1
|
303 hmdInfo->DistortionK[2] = 0.115f;
|
nuclear@1
|
304
|
nuclear@1
|
305 if (HResolution == 1920)
|
nuclear@1
|
306 hmdInfo->EyeToScreenDistance = 0.040f;
|
nuclear@1
|
307 else
|
nuclear@1
|
308 hmdInfo->EyeToScreenDistance = 0.0387f;
|
nuclear@1
|
309 }
|
nuclear@1
|
310
|
nuclear@1
|
311 hmdInfo->ChromaAbCorrection[0] = 0.996f;
|
nuclear@1
|
312 hmdInfo->ChromaAbCorrection[1] = -0.004f;
|
nuclear@1
|
313 hmdInfo->ChromaAbCorrection[2] = 1.014f;
|
nuclear@1
|
314 hmdInfo->ChromaAbCorrection[3] = 0.0f;
|
nuclear@1
|
315 }
|
nuclear@1
|
316
|
nuclear@1
|
317 OVR_strcpy(hmdInfo->DisplayDeviceName, sizeof(hmdInfo->DisplayDeviceName),
|
nuclear@1
|
318 DisplayDeviceName.ToCStr());
|
nuclear@1
|
319 hmdInfo->DisplayId = DisplayId;
|
nuclear@1
|
320 }
|
nuclear@1
|
321
|
nuclear@1
|
322 return true;
|
nuclear@1
|
323 }
|
nuclear@1
|
324
|
nuclear@1
|
325 //-------------------------------------------------------------------------------------
|
nuclear@1
|
326 // ***** HMDDevice
|
nuclear@1
|
327
|
nuclear@1
|
328 HMDDevice::HMDDevice(HMDDeviceCreateDesc* createDesc)
|
nuclear@1
|
329 : OVR::DeviceImpl<OVR::HMDDevice>(createDesc, 0)
|
nuclear@1
|
330 {
|
nuclear@1
|
331 }
|
nuclear@1
|
332 HMDDevice::~HMDDevice()
|
nuclear@1
|
333 {
|
nuclear@1
|
334 }
|
nuclear@1
|
335
|
nuclear@1
|
336 bool HMDDevice::Initialize(DeviceBase* parent)
|
nuclear@1
|
337 {
|
nuclear@1
|
338 pParent = parent;
|
nuclear@1
|
339
|
nuclear@1
|
340 // Initialize user profile to default for device.
|
nuclear@1
|
341 ProfileManager* profileManager = GetManager()->GetProfileManager();
|
nuclear@1
|
342 ProfileName = profileManager->GetDefaultProfileName(getDesc()->GetProfileType());
|
nuclear@1
|
343
|
nuclear@1
|
344 return true;
|
nuclear@1
|
345 }
|
nuclear@1
|
346 void HMDDevice::Shutdown()
|
nuclear@1
|
347 {
|
nuclear@1
|
348 ProfileName.Clear();
|
nuclear@1
|
349 pCachedProfile.Clear();
|
nuclear@1
|
350 pParent.Clear();
|
nuclear@1
|
351 }
|
nuclear@1
|
352
|
nuclear@1
|
353 Profile* HMDDevice::GetProfile() const
|
nuclear@1
|
354 {
|
nuclear@1
|
355 if (!pCachedProfile)
|
nuclear@1
|
356 pCachedProfile = *getDesc()->GetProfileAddRef();
|
nuclear@1
|
357 return pCachedProfile.GetPtr();
|
nuclear@1
|
358 }
|
nuclear@1
|
359
|
nuclear@1
|
360 const char* HMDDevice::GetProfileName() const
|
nuclear@1
|
361 {
|
nuclear@1
|
362 return ProfileName.ToCStr();
|
nuclear@1
|
363 }
|
nuclear@1
|
364
|
nuclear@1
|
365 bool HMDDevice::SetProfileName(const char* name)
|
nuclear@1
|
366 {
|
nuclear@1
|
367 pCachedProfile.Clear();
|
nuclear@1
|
368 if (!name)
|
nuclear@1
|
369 {
|
nuclear@1
|
370 ProfileName.Clear();
|
nuclear@1
|
371 return 0;
|
nuclear@1
|
372 }
|
nuclear@1
|
373 if (GetManager()->GetProfileManager()->HasProfile(getDesc()->GetProfileType(), name))
|
nuclear@1
|
374 {
|
nuclear@1
|
375 ProfileName = name;
|
nuclear@1
|
376 return true;
|
nuclear@1
|
377 }
|
nuclear@1
|
378 return false;
|
nuclear@1
|
379 }
|
nuclear@1
|
380
|
nuclear@1
|
381 OVR::SensorDevice* HMDDevice::GetSensor()
|
nuclear@1
|
382 {
|
nuclear@1
|
383 // Just return first sensor found since we have no way to match it yet.
|
nuclear@1
|
384 OVR::SensorDevice* sensor = GetManager()->EnumerateDevices<SensorDevice>().CreateDevice();
|
nuclear@1
|
385 if (sensor)
|
nuclear@1
|
386 sensor->SetCoordinateFrame(SensorDevice::Coord_HMD);
|
nuclear@1
|
387 return sensor;
|
nuclear@1
|
388 }
|
nuclear@1
|
389
|
nuclear@1
|
390 }} // namespace OVR::Linux
|
nuclear@1
|
391
|
nuclear@1
|
392
|