rev |
line source |
nuclear@0
|
1 /************************************************************************************
|
nuclear@0
|
2
|
nuclear@0
|
3 Filename : OVR_CAPI.cpp
|
nuclear@0
|
4 Content : Experimental simple C interface to the HMD - version 1.
|
nuclear@0
|
5 Created : November 30, 2013
|
nuclear@0
|
6 Authors : Michael Antonov
|
nuclear@0
|
7
|
nuclear@0
|
8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
|
nuclear@0
|
11 you may not use the Oculus VR Rift SDK except in compliance with the License,
|
nuclear@0
|
12 which is provided at the time of installation or download, or which
|
nuclear@0
|
13 otherwise accompanies this software in either electronic or hard copy form.
|
nuclear@0
|
14
|
nuclear@0
|
15 You may obtain a copy of the License at
|
nuclear@0
|
16
|
nuclear@0
|
17 http://www.oculusvr.com/licenses/LICENSE-3.2
|
nuclear@0
|
18
|
nuclear@0
|
19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
|
nuclear@0
|
20 distributed under the License is distributed on an "AS IS" BASIS,
|
nuclear@0
|
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
nuclear@0
|
22 See the License for the specific language governing permissions and
|
nuclear@0
|
23 limitations under the License.
|
nuclear@0
|
24
|
nuclear@0
|
25 ************************************************************************************/
|
nuclear@0
|
26
|
nuclear@0
|
27 #include "OVR_CAPI.h"
|
nuclear@0
|
28 #include "Kernel/OVR_Timer.h"
|
nuclear@0
|
29 #include "Kernel/OVR_Math.h"
|
nuclear@0
|
30 #include "Kernel/OVR_System.h"
|
nuclear@0
|
31 #include "OVR_Stereo.h"
|
nuclear@0
|
32 #include "OVR_Profile.h"
|
nuclear@0
|
33 #include "../Include/OVR_Version.h"
|
nuclear@0
|
34
|
nuclear@0
|
35 #include "CAPI/CAPI_HMDState.h"
|
nuclear@0
|
36 #include "CAPI/CAPI_FrameTimeManager.h"
|
nuclear@0
|
37
|
nuclear@0
|
38 #include "Service/Service_NetClient.h"
|
nuclear@0
|
39 #ifdef OVR_SINGLE_PROCESS
|
nuclear@0
|
40 #include "Service/Service_NetServer.h"
|
nuclear@0
|
41 #endif
|
nuclear@0
|
42
|
nuclear@0
|
43 #ifdef OVR_OS_WIN32
|
nuclear@0
|
44 #include "Displays/OVR_Win32_ShimFunctions.h"
|
nuclear@0
|
45 #endif
|
nuclear@0
|
46
|
nuclear@0
|
47
|
nuclear@0
|
48 using namespace OVR;
|
nuclear@0
|
49 using namespace OVR::Util::Render;
|
nuclear@0
|
50 using namespace OVR::Tracking;
|
nuclear@0
|
51
|
nuclear@0
|
52 //-------------------------------------------------------------------------------------
|
nuclear@0
|
53 // Math
|
nuclear@0
|
54 namespace OVR {
|
nuclear@0
|
55
|
nuclear@0
|
56
|
nuclear@0
|
57 // ***** FovPort
|
nuclear@0
|
58
|
nuclear@0
|
59 // C-interop support: FovPort <-> ovrFovPort
|
nuclear@0
|
60 FovPort::FovPort(const ovrFovPort &src)
|
nuclear@0
|
61 : UpTan(src.UpTan), DownTan(src.DownTan), LeftTan(src.LeftTan), RightTan(src.RightTan)
|
nuclear@0
|
62 { }
|
nuclear@0
|
63
|
nuclear@0
|
64 FovPort::operator ovrFovPort () const
|
nuclear@0
|
65 {
|
nuclear@0
|
66 ovrFovPort result;
|
nuclear@0
|
67 result.LeftTan = LeftTan;
|
nuclear@0
|
68 result.RightTan = RightTan;
|
nuclear@0
|
69 result.UpTan = UpTan;
|
nuclear@0
|
70 result.DownTan = DownTan;
|
nuclear@0
|
71 return result;
|
nuclear@0
|
72 }
|
nuclear@0
|
73
|
nuclear@0
|
74 // Converts Fov Tan angle units to [-1,1] render target NDC space
|
nuclear@0
|
75 Vector2f FovPort::TanAngleToRendertargetNDC(Vector2f const &tanEyeAngle)
|
nuclear@0
|
76 {
|
nuclear@0
|
77 ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(*this);
|
nuclear@0
|
78 return tanEyeAngle * eyeToSourceNDC.Scale + eyeToSourceNDC.Offset;
|
nuclear@0
|
79 }
|
nuclear@0
|
80
|
nuclear@0
|
81 // ***** SensorDataType
|
nuclear@0
|
82
|
nuclear@0
|
83 SensorDataType::SensorDataType(const ovrSensorData& s)
|
nuclear@0
|
84 {
|
nuclear@0
|
85 Acceleration = s.Accelerometer;
|
nuclear@0
|
86 RotationRate = s.Gyro;
|
nuclear@0
|
87 MagneticField = s.Magnetometer;
|
nuclear@0
|
88 Temperature = s.Temperature;
|
nuclear@0
|
89 AbsoluteTimeSeconds = s.TimeInSeconds;
|
nuclear@0
|
90 }
|
nuclear@0
|
91
|
nuclear@0
|
92 SensorDataType::operator ovrSensorData () const
|
nuclear@0
|
93 {
|
nuclear@0
|
94 ovrSensorData result;
|
nuclear@0
|
95 result.Accelerometer = Acceleration;
|
nuclear@0
|
96 result.Gyro = RotationRate;
|
nuclear@0
|
97 result.Magnetometer = MagneticField;
|
nuclear@0
|
98 result.Temperature = Temperature;
|
nuclear@0
|
99 result.TimeInSeconds = (float) AbsoluteTimeSeconds;
|
nuclear@0
|
100 return result;
|
nuclear@0
|
101 }
|
nuclear@0
|
102
|
nuclear@0
|
103
|
nuclear@0
|
104 // ***** SensorState
|
nuclear@0
|
105
|
nuclear@0
|
106 TrackingState::TrackingState(const ovrTrackingState& s)
|
nuclear@0
|
107 {
|
nuclear@0
|
108 HeadPose = s.HeadPose;
|
nuclear@0
|
109 CameraPose = s.CameraPose;
|
nuclear@0
|
110 LeveledCameraPose = s.LeveledCameraPose;
|
nuclear@0
|
111 RawSensorData = s.RawSensorData;
|
nuclear@0
|
112 StatusFlags = s.StatusFlags;
|
nuclear@0
|
113 LastVisionProcessingTime = s.LastVisionProcessingTime;
|
nuclear@0
|
114 LastVisionFrameLatency = s.LastVisionFrameLatency;
|
nuclear@0
|
115 LastCameraFrameCounter = s.LastCameraFrameCounter;
|
nuclear@0
|
116 }
|
nuclear@0
|
117
|
nuclear@0
|
118 TrackingState::operator ovrTrackingState() const
|
nuclear@0
|
119 {
|
nuclear@0
|
120 ovrTrackingState result;
|
nuclear@0
|
121 result.HeadPose = HeadPose;
|
nuclear@0
|
122 result.CameraPose = CameraPose;
|
nuclear@0
|
123 result.LeveledCameraPose = LeveledCameraPose;
|
nuclear@0
|
124 result.RawSensorData = RawSensorData;
|
nuclear@0
|
125 result.StatusFlags = StatusFlags;
|
nuclear@0
|
126 result.LastVisionProcessingTime = LastVisionProcessingTime;
|
nuclear@0
|
127 result.LastVisionFrameLatency = LastVisionFrameLatency;
|
nuclear@0
|
128 result.LastCameraFrameCounter = LastCameraFrameCounter;
|
nuclear@0
|
129 return result;
|
nuclear@0
|
130 }
|
nuclear@0
|
131
|
nuclear@0
|
132
|
nuclear@0
|
133 } // namespace OVR
|
nuclear@0
|
134
|
nuclear@0
|
135 //-------------------------------------------------------------------------------------
|
nuclear@0
|
136
|
nuclear@0
|
137 using namespace OVR::CAPI;
|
nuclear@0
|
138
|
nuclear@0
|
139 #ifdef __cplusplus
|
nuclear@0
|
140 extern "C" {
|
nuclear@0
|
141 #endif
|
nuclear@0
|
142
|
nuclear@0
|
143
|
nuclear@0
|
144 // Used to generate projection from ovrEyeDesc::Fov
|
nuclear@0
|
145 OVR_EXPORT ovrMatrix4f ovrMatrix4f_Projection(ovrFovPort fov, float znear, float zfar, ovrBool rightHanded)
|
nuclear@0
|
146 {
|
nuclear@0
|
147 return CreateProjection(rightHanded ? true : false, fov, znear, zfar);
|
nuclear@0
|
148 }
|
nuclear@0
|
149
|
nuclear@0
|
150
|
nuclear@0
|
151 OVR_EXPORT ovrMatrix4f ovrMatrix4f_OrthoSubProjection(ovrMatrix4f projection, ovrVector2f orthoScale,
|
nuclear@0
|
152 float orthoDistance, float hmdToEyeViewOffsetX)
|
nuclear@0
|
153 {
|
nuclear@0
|
154
|
nuclear@0
|
155 float orthoHorizontalOffset = hmdToEyeViewOffsetX / orthoDistance;
|
nuclear@0
|
156
|
nuclear@0
|
157 // Current projection maps real-world vector (x,y,1) to the RT.
|
nuclear@0
|
158 // We want to find the projection that maps the range [-FovPixels/2,FovPixels/2] to
|
nuclear@0
|
159 // the physical [-orthoHalfFov,orthoHalfFov]
|
nuclear@0
|
160 // Note moving the offset from M[0][2]+M[1][2] to M[0][3]+M[1][3] - this means
|
nuclear@0
|
161 // we don't have to feed in Z=1 all the time.
|
nuclear@0
|
162 // The horizontal offset math is a little hinky because the destination is
|
nuclear@0
|
163 // actually [-orthoHalfFov+orthoHorizontalOffset,orthoHalfFov+orthoHorizontalOffset]
|
nuclear@0
|
164 // So we need to first map [-FovPixels/2,FovPixels/2] to
|
nuclear@0
|
165 // [-orthoHalfFov+orthoHorizontalOffset,orthoHalfFov+orthoHorizontalOffset]:
|
nuclear@0
|
166 // x1 = x0 * orthoHalfFov/(FovPixels/2) + orthoHorizontalOffset;
|
nuclear@0
|
167 // = x0 * 2*orthoHalfFov/FovPixels + orthoHorizontalOffset;
|
nuclear@0
|
168 // But then we need the same mapping as the existing projection matrix, i.e.
|
nuclear@0
|
169 // x2 = x1 * Projection.M[0][0] + Projection.M[0][2];
|
nuclear@0
|
170 // = x0 * (2*orthoHalfFov/FovPixels + orthoHorizontalOffset) * Projection.M[0][0] + Projection.M[0][2];
|
nuclear@0
|
171 // = x0 * Projection.M[0][0]*2*orthoHalfFov/FovPixels +
|
nuclear@0
|
172 // orthoHorizontalOffset*Projection.M[0][0] + Projection.M[0][2];
|
nuclear@0
|
173 // So in the new projection matrix we need to scale by Projection.M[0][0]*2*orthoHalfFov/FovPixels and
|
nuclear@0
|
174 // offset by orthoHorizontalOffset*Projection.M[0][0] + Projection.M[0][2].
|
nuclear@0
|
175
|
nuclear@0
|
176 Matrix4f ortho;
|
nuclear@0
|
177 ortho.M[0][0] = projection.M[0][0] * orthoScale.x;
|
nuclear@0
|
178 ortho.M[0][1] = 0.0f;
|
nuclear@0
|
179 ortho.M[0][2] = 0.0f;
|
nuclear@0
|
180 ortho.M[0][3] = -projection.M[0][2] + ( orthoHorizontalOffset * projection.M[0][0] );
|
nuclear@0
|
181
|
nuclear@0
|
182 ortho.M[1][0] = 0.0f;
|
nuclear@0
|
183 ortho.M[1][1] = -projection.M[1][1] * orthoScale.y; // Note sign flip (text rendering uses Y=down).
|
nuclear@0
|
184 ortho.M[1][2] = 0.0f;
|
nuclear@0
|
185 ortho.M[1][3] = -projection.M[1][2];
|
nuclear@0
|
186
|
nuclear@0
|
187 /*
|
nuclear@0
|
188 if ( fabsf ( zNear - zFar ) < 0.001f )
|
nuclear@0
|
189 {
|
nuclear@0
|
190 ortho.M[2][0] = 0.0f;
|
nuclear@0
|
191 ortho.M[2][1] = 0.0f;
|
nuclear@0
|
192 ortho.M[2][2] = 0.0f;
|
nuclear@0
|
193 ortho.M[2][3] = zFar;
|
nuclear@0
|
194 }
|
nuclear@0
|
195 else
|
nuclear@0
|
196 {
|
nuclear@0
|
197 ortho.M[2][0] = 0.0f;
|
nuclear@0
|
198 ortho.M[2][1] = 0.0f;
|
nuclear@0
|
199 ortho.M[2][2] = zFar / (zNear - zFar);
|
nuclear@0
|
200 ortho.M[2][3] = (zFar * zNear) / (zNear - zFar);
|
nuclear@0
|
201 }
|
nuclear@0
|
202 */
|
nuclear@0
|
203
|
nuclear@0
|
204 // MA: Undo effect of sign
|
nuclear@0
|
205 ortho.M[2][0] = 0.0f;
|
nuclear@0
|
206 ortho.M[2][1] = 0.0f;
|
nuclear@0
|
207 //ortho.M[2][2] = projection.M[2][2] * projection.M[3][2] * -1.0f; // reverse right-handedness
|
nuclear@0
|
208 ortho.M[2][2] = 0.0f;
|
nuclear@0
|
209 ortho.M[2][3] = 0.0f;
|
nuclear@0
|
210 //projection.M[2][3];
|
nuclear@0
|
211
|
nuclear@0
|
212 // No perspective correction for ortho.
|
nuclear@0
|
213 ortho.M[3][0] = 0.0f;
|
nuclear@0
|
214 ortho.M[3][1] = 0.0f;
|
nuclear@0
|
215 ortho.M[3][2] = 0.0f;
|
nuclear@0
|
216 ortho.M[3][3] = 1.0f;
|
nuclear@0
|
217
|
nuclear@0
|
218 return ortho;
|
nuclear@0
|
219 }
|
nuclear@0
|
220
|
nuclear@0
|
221
|
nuclear@0
|
222 OVR_EXPORT double ovr_GetTimeInSeconds()
|
nuclear@0
|
223 {
|
nuclear@0
|
224 return Timer::GetSeconds();
|
nuclear@0
|
225 }
|
nuclear@0
|
226
|
nuclear@0
|
227 // Waits until the specified absolute time.
|
nuclear@0
|
228 OVR_EXPORT double ovr_WaitTillTime(double absTime)
|
nuclear@0
|
229 {
|
nuclear@0
|
230 double initialTime = ovr_GetTimeInSeconds();
|
nuclear@0
|
231 double newTime = initialTime;
|
nuclear@0
|
232
|
nuclear@0
|
233 while(newTime < absTime)
|
nuclear@0
|
234 {
|
nuclear@0
|
235 for (int j = 0; j < 5; j++)
|
nuclear@0
|
236 OVR_PROCESSOR_PAUSE();
|
nuclear@0
|
237
|
nuclear@0
|
238 newTime = ovr_GetTimeInSeconds();
|
nuclear@0
|
239 }
|
nuclear@0
|
240
|
nuclear@0
|
241 // How long we waited
|
nuclear@0
|
242 return newTime - initialTime;
|
nuclear@0
|
243 }
|
nuclear@0
|
244
|
nuclear@0
|
245
|
nuclear@0
|
246 //-------------------------------------------------------------------------------------
|
nuclear@0
|
247
|
nuclear@0
|
248 // 1. Init/shutdown.
|
nuclear@0
|
249
|
nuclear@0
|
250 static ovrBool CAPI_SystemInitCalled = 0;
|
nuclear@0
|
251 static ovrBool CAPI_ovrInitializeCalled = 0;
|
nuclear@0
|
252
|
nuclear@0
|
253 static OVR::Service::NetClient* CAPI_pNetClient = 0;
|
nuclear@0
|
254
|
nuclear@0
|
255 OVR_EXPORT ovrBool ovr_InitializeRenderingShim()
|
nuclear@0
|
256 {
|
nuclear@0
|
257 OVR::System::DirectDisplayInitialize();
|
nuclear@0
|
258 return OVR::System::DirectDisplayEnabled();
|
nuclear@0
|
259 }
|
nuclear@0
|
260
|
nuclear@0
|
261 OVR_EXPORT ovrBool ovr_Initialize()
|
nuclear@0
|
262 {
|
nuclear@0
|
263 if (CAPI_ovrInitializeCalled)
|
nuclear@0
|
264 return 1;
|
nuclear@0
|
265
|
nuclear@0
|
266 // We must set up the system for the plugin to work
|
nuclear@0
|
267 if (!OVR::System::IsInitialized())
|
nuclear@0
|
268 {
|
nuclear@0
|
269 OVR::System::Init(OVR::Log::ConfigureDefaultLog(OVR::LogMask_All));
|
nuclear@0
|
270 CAPI_SystemInitCalled = 1;
|
nuclear@0
|
271 }
|
nuclear@0
|
272
|
nuclear@0
|
273 if (!OVR::System::DirectDisplayEnabled() && !OVR::Display::InCompatibilityMode(false))
|
nuclear@0
|
274 {
|
nuclear@0
|
275 OVR_ASSERT(false);
|
nuclear@0
|
276 return 0;
|
nuclear@0
|
277 }
|
nuclear@0
|
278
|
nuclear@0
|
279 CAPI_pNetClient = NetClient::GetInstance();
|
nuclear@0
|
280
|
nuclear@0
|
281 #ifdef OVR_SINGLE_PROCESS
|
nuclear@0
|
282
|
nuclear@0
|
283 // If the server could not start running,
|
nuclear@0
|
284 if (Service::NetServer::GetInstance()->IsInitialized())
|
nuclear@0
|
285 {
|
nuclear@0
|
286 CAPI_pNetClient->Connect(true);
|
nuclear@0
|
287 }
|
nuclear@0
|
288 else
|
nuclear@0
|
289 {
|
nuclear@0
|
290 // This normally will happen if the OVRService is running in the background,
|
nuclear@0
|
291 // or another SingleProcess-mode app is running in the background.
|
nuclear@0
|
292 // In this case, it's using the hardware and we should not also attempt to use
|
nuclear@0
|
293 // the hardware.
|
nuclear@0
|
294 LogError("{ERR-079} [LibOVR] Server is already running");
|
nuclear@0
|
295 }
|
nuclear@0
|
296 #else
|
nuclear@0
|
297 CAPI_pNetClient->Connect(true);
|
nuclear@0
|
298 #endif
|
nuclear@0
|
299
|
nuclear@0
|
300 CAPI_ovrInitializeCalled = 1;
|
nuclear@0
|
301
|
nuclear@0
|
302 return 1;
|
nuclear@0
|
303 }
|
nuclear@0
|
304
|
nuclear@0
|
305 OVR_EXPORT void ovr_Shutdown()
|
nuclear@0
|
306 {
|
nuclear@0
|
307 // We should clean up the system to be complete
|
nuclear@0
|
308 if (OVR::System::IsInitialized() && CAPI_SystemInitCalled)
|
nuclear@0
|
309 {
|
nuclear@0
|
310 OVR::System::Destroy();
|
nuclear@0
|
311 }
|
nuclear@0
|
312
|
nuclear@0
|
313 CAPI_SystemInitCalled = 0;
|
nuclear@0
|
314 CAPI_ovrInitializeCalled = 0;
|
nuclear@0
|
315 }
|
nuclear@0
|
316
|
nuclear@0
|
317
|
nuclear@0
|
318 // There is a thread safety issue with ovrHmd_Detect in that multiple calls from different
|
nuclear@0
|
319 // threads can corrupt the global array state. This would lead to two problems:
|
nuclear@0
|
320 // a) Create(index) enumerator may miss or overshoot items. Probably not a big deal
|
nuclear@0
|
321 // as game logic can easily be written to only do Detect(s)/Creates in one place.
|
nuclear@0
|
322 // The alternative would be to return list handle.
|
nuclear@0
|
323 // b) TBD: Un-mutexed Detect access from two threads could lead to crash. We should
|
nuclear@0
|
324 // probably check this.
|
nuclear@0
|
325 //
|
nuclear@0
|
326
|
nuclear@0
|
327 OVR_EXPORT int ovrHmd_Detect()
|
nuclear@0
|
328 {
|
nuclear@0
|
329 if (!CAPI_ovrInitializeCalled)
|
nuclear@0
|
330 return 0;
|
nuclear@0
|
331
|
nuclear@0
|
332 return CAPI_pNetClient->Hmd_Detect();
|
nuclear@0
|
333 }
|
nuclear@0
|
334
|
nuclear@0
|
335
|
nuclear@0
|
336 // ovrHmd_Create us explicitly separated from ConfigureTracking and ConfigureRendering to allow creation of
|
nuclear@0
|
337 // a relatively light-weight handle that would reference the device going forward and would
|
nuclear@0
|
338 // survive future ovrHmd_Detect calls. That is once ovrHMD is returned, index is no longer
|
nuclear@0
|
339 // necessary and can be changed by a ovrHmd_Detect call.
|
nuclear@0
|
340 OVR_EXPORT ovrHmd ovrHmd_Create(int index)
|
nuclear@0
|
341 {
|
nuclear@0
|
342 if (!CAPI_ovrInitializeCalled)
|
nuclear@0
|
343 return 0;
|
nuclear@0
|
344
|
nuclear@0
|
345 double t0 = Timer::GetSeconds();
|
nuclear@0
|
346 HMDNetworkInfo netInfo;
|
nuclear@0
|
347
|
nuclear@0
|
348 // There may be some delay before the HMD is fully detected.
|
nuclear@0
|
349 // Since we are also trying to create the HMD immediately it may lose this race and
|
nuclear@0
|
350 // get "NO HMD DETECTED." Wait a bit longer to avoid this.
|
nuclear@0
|
351 while (!CAPI_pNetClient->Hmd_Create(index, &netInfo) ||
|
nuclear@0
|
352 netInfo.NetId == InvalidVirtualHmdId)
|
nuclear@0
|
353 {
|
nuclear@0
|
354 // If two seconds elapse and still no HMD detected,
|
nuclear@0
|
355 if (Timer::GetSeconds() - t0 > 2.)
|
nuclear@0
|
356 {
|
nuclear@0
|
357 if (!NetClient::GetInstance()->IsConnected(false, false))
|
nuclear@0
|
358 {
|
nuclear@0
|
359 NetClient::GetInstance()->SetLastError("Not connected to service");
|
nuclear@0
|
360 }
|
nuclear@0
|
361 else
|
nuclear@0
|
362 {
|
nuclear@0
|
363 NetClient::GetInstance()->SetLastError("No HMD Detected");
|
nuclear@0
|
364 }
|
nuclear@0
|
365
|
nuclear@0
|
366 return 0;
|
nuclear@0
|
367 }
|
nuclear@0
|
368 }
|
nuclear@0
|
369
|
nuclear@0
|
370 // Create HMD State object
|
nuclear@0
|
371 HMDState* hmds = HMDState::CreateHMDState(CAPI_pNetClient, netInfo);
|
nuclear@0
|
372 if (!hmds)
|
nuclear@0
|
373 {
|
nuclear@0
|
374 CAPI_pNetClient->Hmd_Release(netInfo.NetId);
|
nuclear@0
|
375
|
nuclear@0
|
376 NetClient::GetInstance()->SetLastError("Unable to create HMD state");
|
nuclear@0
|
377 return 0;
|
nuclear@0
|
378 }
|
nuclear@0
|
379
|
nuclear@0
|
380 // Reset frame timing so that FrameTimeManager values are properly initialized in AppRendered mode.
|
nuclear@0
|
381 ovrHmd_ResetFrameTiming(hmds->pHmdDesc, 0);
|
nuclear@0
|
382
|
nuclear@0
|
383 return hmds->pHmdDesc;
|
nuclear@0
|
384 }
|
nuclear@0
|
385
|
nuclear@0
|
386
|
nuclear@0
|
387 OVR_EXPORT ovrBool ovrHmd_AttachToWindow( ovrHmd hmd, void* window,
|
nuclear@0
|
388 const ovrRecti* destMirrorRect,
|
nuclear@0
|
389 const ovrRecti* sourceRenderTargetRect )
|
nuclear@0
|
390 {
|
nuclear@0
|
391 OVR_UNUSED( destMirrorRect );
|
nuclear@0
|
392 OVR_UNUSED( sourceRenderTargetRect );
|
nuclear@0
|
393
|
nuclear@0
|
394 if (!CAPI_ovrInitializeCalled)
|
nuclear@0
|
395 return false;
|
nuclear@0
|
396
|
nuclear@0
|
397 if (!hmd || !hmd->Handle)
|
nuclear@0
|
398 return false;
|
nuclear@0
|
399 #ifndef OVR_OS_MAC
|
nuclear@0
|
400 HMDState* hmds = (HMDState*)hmd->Handle;
|
nuclear@0
|
401 CAPI_pNetClient->Hmd_AttachToWindow(hmds->GetNetId(), window);
|
nuclear@0
|
402 hmds->pWindow = window;
|
nuclear@0
|
403 #endif
|
nuclear@0
|
404 #ifdef OVR_OS_WIN32
|
nuclear@0
|
405 Win32::DisplayShim::GetInstance().hWindow = (HWND)window;
|
nuclear@0
|
406 #endif
|
nuclear@0
|
407 #ifdef OVR_OS_MAC
|
nuclear@0
|
408 OVR_UNUSED(window);
|
nuclear@0
|
409 #endif
|
nuclear@0
|
410
|
nuclear@0
|
411 return true;
|
nuclear@0
|
412 }
|
nuclear@0
|
413
|
nuclear@0
|
414 OVR_EXPORT ovrHmd ovrHmd_CreateDebug(ovrHmdType type)
|
nuclear@0
|
415 {
|
nuclear@0
|
416 if (!CAPI_ovrInitializeCalled)
|
nuclear@0
|
417 return 0;
|
nuclear@0
|
418
|
nuclear@0
|
419 HMDState* hmds = HMDState::CreateHMDState(type);
|
nuclear@0
|
420
|
nuclear@0
|
421 return hmds->pHmdDesc;
|
nuclear@0
|
422 }
|
nuclear@0
|
423
|
nuclear@0
|
424 OVR_EXPORT void ovrHmd_Destroy(ovrHmd hmddesc)
|
nuclear@0
|
425 {
|
nuclear@0
|
426 if (!hmddesc || !hmddesc->Handle)
|
nuclear@0
|
427 return;
|
nuclear@0
|
428
|
nuclear@0
|
429 // TBD: Any extra shutdown?
|
nuclear@0
|
430 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
431
|
nuclear@0
|
432 { // Thread checker in its own scope, to avoid access after 'delete'.
|
nuclear@0
|
433 // Essentially just checks that no other RenderAPI function is executing.
|
nuclear@0
|
434 ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_Destroy");
|
nuclear@0
|
435 }
|
nuclear@0
|
436
|
nuclear@0
|
437 #ifdef OVR_OS_WIN32
|
nuclear@0
|
438 if (hmds->pWindow)
|
nuclear@0
|
439 {
|
nuclear@0
|
440 // ? ok to call
|
nuclear@0
|
441 //CAPI_pNetClient->Hmd_AttachToWindow(hmds->GetNetId(), 0);
|
nuclear@0
|
442 hmds->pWindow = 0;
|
nuclear@0
|
443 Win32::DisplayShim::GetInstance().hWindow = (HWND)0;
|
nuclear@0
|
444 }
|
nuclear@0
|
445 #endif
|
nuclear@0
|
446
|
nuclear@0
|
447 delete (HMDState*)hmddesc->Handle;
|
nuclear@0
|
448 }
|
nuclear@0
|
449
|
nuclear@0
|
450
|
nuclear@0
|
451 OVR_EXPORT const char* ovrHmd_GetLastError(ovrHmd hmddesc)
|
nuclear@0
|
452 {
|
nuclear@0
|
453 if (!CAPI_ovrInitializeCalled)
|
nuclear@0
|
454 {
|
nuclear@0
|
455 return "System initialize not called";
|
nuclear@0
|
456 }
|
nuclear@0
|
457
|
nuclear@0
|
458 VirtualHmdId netId = InvalidVirtualHmdId;
|
nuclear@0
|
459
|
nuclear@0
|
460 if (hmddesc && hmddesc->Handle)
|
nuclear@0
|
461 {
|
nuclear@0
|
462 HMDState* p = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
463 netId = p->GetNetId();
|
nuclear@0
|
464 }
|
nuclear@0
|
465
|
nuclear@0
|
466 return CAPI_pNetClient->Hmd_GetLastError(netId);
|
nuclear@0
|
467 }
|
nuclear@0
|
468
|
nuclear@0
|
469 #define OVR_VERSION_LIBOVR_PFX "libOVR:"
|
nuclear@0
|
470
|
nuclear@0
|
471 // Returns version string representing libOVR version. Static, so
|
nuclear@0
|
472 // string remains valid for app lifespan
|
nuclear@0
|
473 OVR_EXPORT const char* ovr_GetVersionString()
|
nuclear@0
|
474 {
|
nuclear@0
|
475 static const char* version = OVR_VERSION_LIBOVR_PFX OVR_VERSION_STRING;
|
nuclear@0
|
476 return version + sizeof(OVR_VERSION_LIBOVR_PFX) - 1;
|
nuclear@0
|
477 }
|
nuclear@0
|
478
|
nuclear@0
|
479
|
nuclear@0
|
480
|
nuclear@0
|
481 //-------------------------------------------------------------------------------------
|
nuclear@0
|
482
|
nuclear@0
|
483 // Returns capability bits that are enabled at this time; described by ovrHmdCapBits.
|
nuclear@0
|
484 // Note that this value is different font ovrHmdDesc::Caps, which describes what
|
nuclear@0
|
485 // capabilities are available.
|
nuclear@0
|
486 OVR_EXPORT unsigned int ovrHmd_GetEnabledCaps(ovrHmd hmddesc)
|
nuclear@0
|
487 {
|
nuclear@0
|
488 HMDState* p = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
489 return p ? p->EnabledHmdCaps : 0;
|
nuclear@0
|
490 }
|
nuclear@0
|
491
|
nuclear@0
|
492 // Modifies capability bits described by ovrHmdCapBits that can be modified,
|
nuclear@0
|
493 // such as ovrHmdCap_LowPersistance.
|
nuclear@0
|
494 OVR_EXPORT void ovrHmd_SetEnabledCaps(ovrHmd hmddesc, unsigned int capsBits)
|
nuclear@0
|
495 {
|
nuclear@0
|
496 HMDState* p = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
497 if (p)
|
nuclear@0
|
498 {
|
nuclear@0
|
499 p->SetEnabledHmdCaps(capsBits);
|
nuclear@0
|
500 }
|
nuclear@0
|
501 }
|
nuclear@0
|
502
|
nuclear@0
|
503
|
nuclear@0
|
504 //-------------------------------------------------------------------------------------
|
nuclear@0
|
505 // *** Sensor
|
nuclear@0
|
506
|
nuclear@0
|
507 // Sensor APIs are separated from Create & Configure for several reasons:
|
nuclear@0
|
508 // - They need custom parameters that control allocation of heavy resources
|
nuclear@0
|
509 // such as Vision tracking, which you don't want to create unless necessary.
|
nuclear@0
|
510 // - A game may want to switch some sensor settings based on user input,
|
nuclear@0
|
511 // or at lease enable/disable features such as Vision for debugging.
|
nuclear@0
|
512 // - The same or syntactically similar sensor interface is likely to be used if we
|
nuclear@0
|
513 // introduce controllers.
|
nuclear@0
|
514 //
|
nuclear@0
|
515 // - Sensor interface functions are all Thread-safe, unlike the frame/render API
|
nuclear@0
|
516 // functions that have different rules (all frame access functions
|
nuclear@0
|
517 // must be on render thread)
|
nuclear@0
|
518
|
nuclear@0
|
519 OVR_EXPORT ovrBool ovrHmd_ConfigureTracking(ovrHmd hmddesc, unsigned int supportedCaps,
|
nuclear@0
|
520 unsigned int requiredCaps)
|
nuclear@0
|
521 {
|
nuclear@0
|
522 if (hmddesc)
|
nuclear@0
|
523 {
|
nuclear@0
|
524 HMDState* p = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
525 return p->ConfigureTracking(supportedCaps, requiredCaps);
|
nuclear@0
|
526 }
|
nuclear@0
|
527
|
nuclear@0
|
528 return 0;
|
nuclear@0
|
529 }
|
nuclear@0
|
530
|
nuclear@0
|
531 OVR_EXPORT void ovrHmd_RecenterPose(ovrHmd hmddesc)
|
nuclear@0
|
532 {
|
nuclear@0
|
533 if (hmddesc)
|
nuclear@0
|
534 {
|
nuclear@0
|
535 HMDState* p = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
536 p->TheSensorStateReader.RecenterPose();
|
nuclear@0
|
537 }
|
nuclear@0
|
538 }
|
nuclear@0
|
539
|
nuclear@0
|
540 OVR_EXPORT ovrTrackingState ovrHmd_GetTrackingState(ovrHmd hmddesc, double absTime)
|
nuclear@0
|
541 {
|
nuclear@0
|
542 ovrTrackingState result;
|
nuclear@0
|
543
|
nuclear@0
|
544 if (hmddesc)
|
nuclear@0
|
545 {
|
nuclear@0
|
546 HMDState* p = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
547 result = p->PredictedTrackingState(absTime);
|
nuclear@0
|
548
|
nuclear@0
|
549 // Instrument data from eye pose
|
nuclear@0
|
550 p->LagStats.InstrumentEyePose(result);
|
nuclear@0
|
551 }
|
nuclear@0
|
552 else
|
nuclear@0
|
553 memset(&result, 0, sizeof(result));
|
nuclear@0
|
554
|
nuclear@0
|
555 #ifdef OVR_OS_WIN32
|
nuclear@0
|
556 // Set up display code for Windows
|
nuclear@0
|
557 Win32::DisplayShim::GetInstance().Active = (result.StatusFlags & ovrStatus_HmdConnected) != 0;
|
nuclear@0
|
558 #endif
|
nuclear@0
|
559
|
nuclear@0
|
560 return result;
|
nuclear@0
|
561 }
|
nuclear@0
|
562
|
nuclear@0
|
563
|
nuclear@0
|
564 //-------------------------------------------------------------------------------------
|
nuclear@0
|
565 // *** General Setup
|
nuclear@0
|
566
|
nuclear@0
|
567 // Per HMD -> calculateIdealPixelSize
|
nuclear@0
|
568 OVR_EXPORT ovrSizei ovrHmd_GetFovTextureSize(ovrHmd hmddesc, ovrEyeType eye, ovrFovPort fov,
|
nuclear@0
|
569 float pixelsPerDisplayPixel)
|
nuclear@0
|
570 {
|
nuclear@0
|
571 ovrHmdStruct * hmd = hmddesc->Handle;
|
nuclear@0
|
572 if (!hmd) return Sizei(0);
|
nuclear@0
|
573
|
nuclear@0
|
574 HMDState* hmds = (HMDState*)hmd;
|
nuclear@0
|
575 return hmds->RenderState.GetFOVTextureSize(eye, fov, pixelsPerDisplayPixel);
|
nuclear@0
|
576 }
|
nuclear@0
|
577
|
nuclear@0
|
578
|
nuclear@0
|
579 //-------------------------------------------------------------------------------------
|
nuclear@0
|
580
|
nuclear@0
|
581
|
nuclear@0
|
582 OVR_EXPORT
|
nuclear@0
|
583 ovrBool ovrHmd_ConfigureRendering( ovrHmd hmddesc,
|
nuclear@0
|
584 const ovrRenderAPIConfig* apiConfig,
|
nuclear@0
|
585 unsigned int distortionCaps,
|
nuclear@0
|
586 const ovrFovPort eyeFovIn[2],
|
nuclear@0
|
587 ovrEyeRenderDesc eyeRenderDescOut[2] )
|
nuclear@0
|
588 {
|
nuclear@0
|
589 ovrHmdStruct * hmd = hmddesc->Handle;
|
nuclear@0
|
590 if (!hmd) return 0;
|
nuclear@0
|
591 return ((HMDState*)hmd)->ConfigureRendering(eyeRenderDescOut, eyeFovIn,
|
nuclear@0
|
592 apiConfig, distortionCaps);
|
nuclear@0
|
593 }
|
nuclear@0
|
594
|
nuclear@0
|
595
|
nuclear@0
|
596
|
nuclear@0
|
597 // TBD: MA - Deprecated, need alternative
|
nuclear@0
|
598 void ovrHmd_SetVsync(ovrHmd hmddesc, ovrBool vsync)
|
nuclear@0
|
599 {
|
nuclear@0
|
600 ovrHmdStruct * hmd = hmddesc->Handle;
|
nuclear@0
|
601 if (!hmd) return;
|
nuclear@0
|
602
|
nuclear@0
|
603 return ((HMDState*)hmd)->TimeManager.SetVsync(vsync? true : false);
|
nuclear@0
|
604 }
|
nuclear@0
|
605
|
nuclear@0
|
606
|
nuclear@0
|
607 OVR_EXPORT ovrFrameTiming ovrHmd_BeginFrame(ovrHmd hmddesc, unsigned int frameIndex)
|
nuclear@0
|
608 {
|
nuclear@0
|
609 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
610 if (!hmds)
|
nuclear@0
|
611 {
|
nuclear@0
|
612 ovrFrameTiming f;
|
nuclear@0
|
613 memset(&f, 0, sizeof(f));
|
nuclear@0
|
614 return f;
|
nuclear@0
|
615 }
|
nuclear@0
|
616
|
nuclear@0
|
617 // Check: Proper configure and threading state for the call.
|
nuclear@0
|
618 hmds->checkRenderingConfigured("ovrHmd_BeginFrame");
|
nuclear@0
|
619 OVR_DEBUG_LOG_COND(hmds->BeginFrameCalled, ("ovrHmd_BeginFrame called multiple times."));
|
nuclear@0
|
620 ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_BeginFrame");
|
nuclear@0
|
621
|
nuclear@0
|
622 hmds->BeginFrameCalled = true;
|
nuclear@0
|
623 hmds->BeginFrameThreadId = OVR::GetCurrentThreadId();
|
nuclear@0
|
624
|
nuclear@0
|
625 return ovrHmd_BeginFrameTiming(hmddesc, frameIndex);
|
nuclear@0
|
626 }
|
nuclear@0
|
627
|
nuclear@0
|
628
|
nuclear@0
|
629 // Renders textures to frame buffer
|
nuclear@0
|
630 OVR_EXPORT void ovrHmd_EndFrame(ovrHmd hmddesc,
|
nuclear@0
|
631 const ovrPosef renderPose[2],
|
nuclear@0
|
632 const ovrTexture eyeTexture[2])
|
nuclear@0
|
633 {
|
nuclear@0
|
634 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
635 if (!hmds) return;
|
nuclear@0
|
636
|
nuclear@0
|
637 // Instrument when the EndFrame() call started
|
nuclear@0
|
638 hmds->LagStats.InstrumentEndFrameStart(ovr_GetTimeInSeconds());
|
nuclear@0
|
639
|
nuclear@0
|
640 hmds->SubmitEyeTextures(renderPose, eyeTexture);
|
nuclear@0
|
641
|
nuclear@0
|
642 // Debug state checks: Must be in BeginFrame, on the same thread.
|
nuclear@0
|
643 hmds->checkBeginFrameScope("ovrHmd_EndFrame");
|
nuclear@0
|
644 ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_EndFrame");
|
nuclear@0
|
645
|
nuclear@0
|
646 hmds->pRenderer->SetLatencyTestColor(hmds->LatencyTestActive ? hmds->LatencyTestDrawColor : NULL);
|
nuclear@0
|
647
|
nuclear@0
|
648 ovrHmd_GetLatencyTest2DrawColor(hmddesc, NULL); // We don't actually need to draw color, so send NULL
|
nuclear@0
|
649
|
nuclear@0
|
650 if (hmds->pRenderer)
|
nuclear@0
|
651 {
|
nuclear@0
|
652 hmds->pRenderer->SaveGraphicsState();
|
nuclear@0
|
653
|
nuclear@0
|
654 // See if we need to show the HSWDisplay.
|
nuclear@0
|
655 if (hmds->pHSWDisplay) // Until we know that these are valid, assume any of them can't be.
|
nuclear@0
|
656 {
|
nuclear@0
|
657 ovrHSWDisplayState hswDisplayState;
|
nuclear@0
|
658 hmds->pHSWDisplay->TickState(&hswDisplayState, true); // This may internally call HASWarning::Display.
|
nuclear@0
|
659
|
nuclear@0
|
660 if (hswDisplayState.Displayed)
|
nuclear@0
|
661 {
|
nuclear@0
|
662 hmds->pHSWDisplay->Render(ovrEye_Left, &eyeTexture[ovrEye_Left]);
|
nuclear@0
|
663 hmds->pHSWDisplay->Render(ovrEye_Right, &eyeTexture[ovrEye_Right]);
|
nuclear@0
|
664 }
|
nuclear@0
|
665 }
|
nuclear@0
|
666
|
nuclear@0
|
667 hmds->pRenderer->EndFrame(true);
|
nuclear@0
|
668 hmds->pRenderer->RestoreGraphicsState();
|
nuclear@0
|
669 }
|
nuclear@0
|
670
|
nuclear@0
|
671 // Call after present
|
nuclear@0
|
672 ovrHmd_EndFrameTiming(hmddesc);
|
nuclear@0
|
673
|
nuclear@0
|
674 // Instrument latency tester
|
nuclear@0
|
675 hmds->LagStats.InstrumentLatencyTimings(hmds->TimeManager);
|
nuclear@0
|
676
|
nuclear@0
|
677 // Instrument when the EndFrame() call ended
|
nuclear@0
|
678 hmds->LagStats.InstrumentEndFrameEnd(ovr_GetTimeInSeconds());
|
nuclear@0
|
679
|
nuclear@0
|
680 // Out of BeginFrame
|
nuclear@0
|
681 hmds->BeginFrameThreadId = 0;
|
nuclear@0
|
682 hmds->BeginFrameCalled = false;
|
nuclear@0
|
683 }
|
nuclear@0
|
684
|
nuclear@0
|
685
|
nuclear@0
|
686 // Not exposed as part of public API
|
nuclear@0
|
687 OVR_EXPORT void ovrHmd_RegisterPostDistortionCallback(ovrHmd hmddesc, PostDistortionCallback callback)
|
nuclear@0
|
688 {
|
nuclear@0
|
689 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
690 if (!hmds) return;
|
nuclear@0
|
691
|
nuclear@0
|
692 if (hmds->pRenderer)
|
nuclear@0
|
693 {
|
nuclear@0
|
694 hmds->pRenderer->RegisterPostDistortionCallback(callback);
|
nuclear@0
|
695 }
|
nuclear@0
|
696 }
|
nuclear@0
|
697
|
nuclear@0
|
698
|
nuclear@0
|
699
|
nuclear@0
|
700 //-------------------------------------------------------------------------------------
|
nuclear@0
|
701 // ***** Frame Timing logic
|
nuclear@0
|
702
|
nuclear@0
|
703
|
nuclear@0
|
704 OVR_EXPORT ovrFrameTiming ovrHmd_GetFrameTiming(ovrHmd hmddesc, unsigned int frameIndex)
|
nuclear@0
|
705 {
|
nuclear@0
|
706 ovrHmdStruct * hmd = hmddesc->Handle;
|
nuclear@0
|
707 ovrFrameTiming f;
|
nuclear@0
|
708 memset(&f, 0, sizeof(f));
|
nuclear@0
|
709
|
nuclear@0
|
710 HMDState* hmds = (HMDState*)hmd;
|
nuclear@0
|
711 if (hmds)
|
nuclear@0
|
712 {
|
nuclear@0
|
713 FrameTimeManager::Timing frameTiming = hmds->TimeManager.GetFrameTiming(frameIndex);
|
nuclear@0
|
714
|
nuclear@0
|
715 f.ThisFrameSeconds = frameTiming.ThisFrameTime;
|
nuclear@0
|
716 f.NextFrameSeconds = frameTiming.NextFrameTime;
|
nuclear@0
|
717 f.TimewarpPointSeconds = frameTiming.TimewarpPointTime;
|
nuclear@0
|
718 f.ScanoutMidpointSeconds = frameTiming.MidpointTime;
|
nuclear@0
|
719 f.EyeScanoutSeconds[0] = frameTiming.EyeRenderTimes[0];
|
nuclear@0
|
720 f.EyeScanoutSeconds[1] = frameTiming.EyeRenderTimes[1];
|
nuclear@0
|
721
|
nuclear@0
|
722 // Compute DeltaSeconds.
|
nuclear@0
|
723 f.DeltaSeconds = (hmds->LastGetFrameTimeSeconds == 0.0f) ? 0.0f :
|
nuclear@0
|
724 (float) (f.ThisFrameSeconds - hmds->LastFrameTimeSeconds);
|
nuclear@0
|
725 hmds->LastGetFrameTimeSeconds = f.ThisFrameSeconds;
|
nuclear@0
|
726 if (f.DeltaSeconds > 1.0f)
|
nuclear@0
|
727 f.DeltaSeconds = 1.0f;
|
nuclear@0
|
728 }
|
nuclear@0
|
729
|
nuclear@0
|
730 return f;
|
nuclear@0
|
731 }
|
nuclear@0
|
732
|
nuclear@0
|
733 OVR_EXPORT ovrFrameTiming ovrHmd_BeginFrameTiming(ovrHmd hmddesc, unsigned int frameIndex)
|
nuclear@0
|
734 {
|
nuclear@0
|
735 ovrHmdStruct * hmd = hmddesc->Handle;
|
nuclear@0
|
736 ovrFrameTiming f;
|
nuclear@0
|
737 memset(&f, 0, sizeof(f));
|
nuclear@0
|
738
|
nuclear@0
|
739 HMDState* hmds = (HMDState*)hmd;
|
nuclear@0
|
740 if (!hmds) return f;
|
nuclear@0
|
741
|
nuclear@0
|
742 // Check: Proper state for the call.
|
nuclear@0
|
743 OVR_DEBUG_LOG_COND(hmds->BeginFrameTimingCalled,
|
nuclear@0
|
744 ("ovrHmd_BeginFrameTiming called multiple times."));
|
nuclear@0
|
745 hmds->BeginFrameTimingCalled = true;
|
nuclear@0
|
746
|
nuclear@0
|
747 double thisFrameTime = hmds->TimeManager.BeginFrame(frameIndex);
|
nuclear@0
|
748
|
nuclear@0
|
749 const FrameTimeManager::Timing &frameTiming = hmds->TimeManager.GetFrameTiming();
|
nuclear@0
|
750
|
nuclear@0
|
751 f.ThisFrameSeconds = thisFrameTime;
|
nuclear@0
|
752 f.NextFrameSeconds = frameTiming.NextFrameTime;
|
nuclear@0
|
753 f.TimewarpPointSeconds = frameTiming.TimewarpPointTime;
|
nuclear@0
|
754 f.ScanoutMidpointSeconds= frameTiming.MidpointTime;
|
nuclear@0
|
755 f.EyeScanoutSeconds[0] = frameTiming.EyeRenderTimes[0];
|
nuclear@0
|
756 f.EyeScanoutSeconds[1] = frameTiming.EyeRenderTimes[1];
|
nuclear@0
|
757
|
nuclear@0
|
758 // Compute DeltaSeconds.
|
nuclear@0
|
759 f.DeltaSeconds = (hmds->LastFrameTimeSeconds == 0.0f) ? 0.0f :
|
nuclear@0
|
760 (float) (thisFrameTime - hmds->LastFrameTimeSeconds);
|
nuclear@0
|
761 hmds->LastFrameTimeSeconds = thisFrameTime;
|
nuclear@0
|
762 if (f.DeltaSeconds > 1.0f)
|
nuclear@0
|
763 f.DeltaSeconds = 1.0f;
|
nuclear@0
|
764
|
nuclear@0
|
765 return f;
|
nuclear@0
|
766 }
|
nuclear@0
|
767
|
nuclear@0
|
768
|
nuclear@0
|
769 OVR_EXPORT void ovrHmd_EndFrameTiming(ovrHmd hmddesc)
|
nuclear@0
|
770 {
|
nuclear@0
|
771 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
772 if (!hmds) return;
|
nuclear@0
|
773
|
nuclear@0
|
774 // Debug state checks: Must be in BeginFrameTiming, on the same thread.
|
nuclear@0
|
775 hmds->checkBeginFrameTimingScope("ovrHmd_EndTiming");
|
nuclear@0
|
776 // MA TBD: Correct check or not?
|
nuclear@0
|
777 // ThreadChecker::Scope checkScope(&hmds->RenderAPIThreadChecker, "ovrHmd_EndFrame");
|
nuclear@0
|
778
|
nuclear@0
|
779 hmds->TimeManager.EndFrame();
|
nuclear@0
|
780 hmds->BeginFrameTimingCalled = false;
|
nuclear@0
|
781
|
nuclear@0
|
782 bool dk2LatencyTest = (hmds->EnabledHmdCaps & ovrHmdCap_DynamicPrediction) != 0;
|
nuclear@0
|
783 if (dk2LatencyTest)
|
nuclear@0
|
784 {
|
nuclear@0
|
785 Util::FrameTimeRecordSet recordset;
|
nuclear@0
|
786 hmds->TheLatencyTestStateReader.GetRecordSet(recordset);
|
nuclear@0
|
787 hmds->TimeManager.UpdateFrameLatencyTrackingAfterEndFrame( hmds->LatencyTest2DrawColor,
|
nuclear@0
|
788 recordset);
|
nuclear@0
|
789 }
|
nuclear@0
|
790 }
|
nuclear@0
|
791
|
nuclear@0
|
792
|
nuclear@0
|
793 OVR_EXPORT void ovrHmd_ResetFrameTiming(ovrHmd hmddesc, unsigned int frameIndex)
|
nuclear@0
|
794 {
|
nuclear@0
|
795 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
796 if (!hmds) return;
|
nuclear@0
|
797
|
nuclear@0
|
798 hmds->TimeManager.ResetFrameTiming(frameIndex,
|
nuclear@0
|
799 false,
|
nuclear@0
|
800 hmds->RenderingConfigured);
|
nuclear@0
|
801 hmds->LastFrameTimeSeconds = 0.0;
|
nuclear@0
|
802 hmds->LastGetFrameTimeSeconds = 0.0;
|
nuclear@0
|
803 }
|
nuclear@0
|
804
|
nuclear@0
|
805 OVR_EXPORT void ovrHmd_GetEyePoses(ovrHmd hmd, unsigned int frameIndex, ovrVector3f hmdToEyeViewOffset[2],
|
nuclear@0
|
806 ovrPosef outEyePoses[2], ovrTrackingState* outHmdTrackingState)
|
nuclear@0
|
807 {
|
nuclear@0
|
808 HMDState* hmds = (HMDState*)hmd->Handle;
|
nuclear@0
|
809 if (!hmds) return;
|
nuclear@0
|
810
|
nuclear@0
|
811 hmds->LatencyTestActive = hmds->ProcessLatencyTest(hmds->LatencyTestDrawColor);
|
nuclear@0
|
812
|
nuclear@0
|
813 ovrTrackingState hmdTrackingState = hmds->TimeManager.GetEyePredictionTracking(hmd, ovrEye_Count, frameIndex);
|
nuclear@0
|
814 ovrPosef hmdPose = hmdTrackingState.HeadPose.ThePose;
|
nuclear@0
|
815
|
nuclear@0
|
816 // caller passed in a valid pointer, so copy to output
|
nuclear@0
|
817 if(outHmdTrackingState)
|
nuclear@0
|
818 *outHmdTrackingState = hmdTrackingState;
|
nuclear@0
|
819
|
nuclear@0
|
820 // Currently HmdToEyeViewOffset is only a 3D vector
|
nuclear@0
|
821 // (Negate HmdToEyeViewOffset because offset is a view matrix offset and not a camera offset)
|
nuclear@0
|
822 outEyePoses[0] = Posef(hmdPose.Orientation, ((Posef)hmdPose).Apply(-((Vector3f)hmdToEyeViewOffset[0])));
|
nuclear@0
|
823 outEyePoses[1] = Posef(hmdPose.Orientation, ((Posef)hmdPose).Apply(-((Vector3f)hmdToEyeViewOffset[1])));
|
nuclear@0
|
824
|
nuclear@0
|
825 // Instrument data from eye pose
|
nuclear@0
|
826 hmds->LagStats.InstrumentEyePose(hmdTrackingState);
|
nuclear@0
|
827 }
|
nuclear@0
|
828
|
nuclear@0
|
829 ovrPosef ovrHmd_GetHmdPosePerEye(ovrHmd hmd, ovrEyeType eye)
|
nuclear@0
|
830 {
|
nuclear@0
|
831 HMDState* hmds = (HMDState*)hmd->Handle;
|
nuclear@0
|
832 if (!hmds) return ovrPosef();
|
nuclear@0
|
833
|
nuclear@0
|
834 // This isn't a great place, but since we removed ovrHmd_BeginEyeRender...
|
nuclear@0
|
835 // Only process latency tester for drawing the left eye (assumes left eye is drawn first)
|
nuclear@0
|
836 if (hmds->pRenderer && eye == 0)
|
nuclear@0
|
837 {
|
nuclear@0
|
838 hmds->LatencyTestActive = hmds->ProcessLatencyTest(hmds->LatencyTestDrawColor);
|
nuclear@0
|
839 }
|
nuclear@0
|
840
|
nuclear@0
|
841 hmds->checkBeginFrameTimingScope("ovrHmd_GetEyePose");
|
nuclear@0
|
842 return hmds->TimeManager.GetEyePredictionPose(hmd, eye);
|
nuclear@0
|
843 }
|
nuclear@0
|
844
|
nuclear@0
|
845 OVR_EXPORT void ovrHmd_AddDistortionTimeMeasurement(ovrHmd hmddesc, double distortionTimeSeconds)
|
nuclear@0
|
846 {
|
nuclear@0
|
847 if (!hmddesc)
|
nuclear@0
|
848 return;
|
nuclear@0
|
849 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
850
|
nuclear@0
|
851 hmds->checkBeginFrameTimingScope("ovrHmd_GetTimewarpEyeMatrices");
|
nuclear@0
|
852 hmds->TimeManager.AddDistortionTimeMeasurement(distortionTimeSeconds);
|
nuclear@0
|
853 }
|
nuclear@0
|
854
|
nuclear@0
|
855
|
nuclear@0
|
856
|
nuclear@0
|
857 OVR_EXPORT void ovrHmd_GetEyeTimewarpMatricesDebug(ovrHmd hmddesc, ovrEyeType eye,
|
nuclear@0
|
858 ovrPosef renderPose, ovrMatrix4f twmOut[2],double debugTimingOffsetInSeconds)
|
nuclear@0
|
859 {
|
nuclear@0
|
860 if (!hmddesc)
|
nuclear@0
|
861 return;
|
nuclear@0
|
862 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
863
|
nuclear@0
|
864 // Debug checks: BeginFrame was called, on the same thread.
|
nuclear@0
|
865 hmds->checkBeginFrameTimingScope("ovrHmd_GetTimewarpEyeMatrices");
|
nuclear@0
|
866
|
nuclear@0
|
867 hmds->TimeManager.GetTimewarpMatrices(hmddesc, eye, renderPose, twmOut, debugTimingOffsetInSeconds);
|
nuclear@0
|
868
|
nuclear@0
|
869 /*
|
nuclear@0
|
870 // MA: Took this out because new latency test approach just sames
|
nuclear@0
|
871 // the sample times in FrameTimeManager.
|
nuclear@0
|
872 // TODO: if no timewarp, then test latency in begin eye render
|
nuclear@0
|
873 if (eye == 0)
|
nuclear@0
|
874 {
|
nuclear@0
|
875 hmds->ProcessLatencyTest2(hmds->LatencyTest2DrawColor, -1.0f);
|
nuclear@0
|
876 }
|
nuclear@0
|
877 */
|
nuclear@0
|
878 }
|
nuclear@0
|
879
|
nuclear@0
|
880
|
nuclear@0
|
881 OVR_EXPORT void ovrHmd_GetEyeTimewarpMatrices(ovrHmd hmddesc, ovrEyeType eye,
|
nuclear@0
|
882 ovrPosef renderPose, ovrMatrix4f twmOut[2])
|
nuclear@0
|
883 {
|
nuclear@0
|
884 return(ovrHmd_GetEyeTimewarpMatricesDebug(hmddesc, eye, renderPose, twmOut, 0.0));
|
nuclear@0
|
885 }
|
nuclear@0
|
886
|
nuclear@0
|
887
|
nuclear@0
|
888
|
nuclear@0
|
889 OVR_EXPORT ovrEyeRenderDesc ovrHmd_GetRenderDesc(ovrHmd hmddesc,
|
nuclear@0
|
890 ovrEyeType eyeType, ovrFovPort fov)
|
nuclear@0
|
891 {
|
nuclear@0
|
892 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
893 ovrEyeRenderDesc erd;
|
nuclear@0
|
894
|
nuclear@0
|
895 if (!hmds)
|
nuclear@0
|
896 {
|
nuclear@0
|
897 memset(&erd, 0, sizeof(erd));
|
nuclear@0
|
898 return erd;
|
nuclear@0
|
899 }
|
nuclear@0
|
900
|
nuclear@0
|
901 return hmds->RenderState.CalcRenderDesc(eyeType, fov);
|
nuclear@0
|
902 }
|
nuclear@0
|
903
|
nuclear@0
|
904
|
nuclear@0
|
905
|
nuclear@0
|
906 #define OVR_OFFSET_OF(s, field) ((size_t)&((s*)0)->field)
|
nuclear@0
|
907
|
nuclear@0
|
908
|
nuclear@0
|
909
|
nuclear@0
|
910
|
nuclear@0
|
911 OVR_EXPORT ovrBool ovrHmd_CreateDistortionMeshDebug( ovrHmd hmddesc,
|
nuclear@0
|
912 ovrEyeType eyeType, ovrFovPort fov,
|
nuclear@0
|
913 unsigned int distortionCaps,
|
nuclear@0
|
914 ovrDistortionMesh *meshData,
|
nuclear@0
|
915 float debugEyeReliefOverrideInMetres)
|
nuclear@0
|
916 {
|
nuclear@0
|
917 // The 'internal' function below can be found in CAPI_HMDState.
|
nuclear@0
|
918 // Not ideal, but navigating the convolutions of what compiles
|
nuclear@0
|
919 // where, meant they are in the few places which actually lets these compile.
|
nuclear@0
|
920 // Please relocate (if you wish) to a more meaningful place if you can navigate the compiler gymnastics :)
|
nuclear@0
|
921 return(ovrHmd_CreateDistortionMeshInternal( hmddesc->Handle,
|
nuclear@0
|
922 eyeType, fov,
|
nuclear@0
|
923 distortionCaps,
|
nuclear@0
|
924 meshData,
|
nuclear@0
|
925 debugEyeReliefOverrideInMetres));
|
nuclear@0
|
926
|
nuclear@0
|
927 }
|
nuclear@0
|
928 OVR_EXPORT ovrBool ovrHmd_CreateDistortionMesh( ovrHmd hmddesc,
|
nuclear@0
|
929 ovrEyeType eyeType, ovrFovPort fov,
|
nuclear@0
|
930 unsigned int distortionCaps,
|
nuclear@0
|
931 ovrDistortionMesh *meshData)
|
nuclear@0
|
932 {
|
nuclear@0
|
933 return(ovrHmd_CreateDistortionMeshDebug( hmddesc, eyeType, fov, distortionCaps,meshData, 0));
|
nuclear@0
|
934 }
|
nuclear@0
|
935
|
nuclear@0
|
936
|
nuclear@0
|
937
|
nuclear@0
|
938 // Frees distortion mesh allocated by ovrHmd_GenerateDistortionMesh. meshData elements
|
nuclear@0
|
939 // are set to null and 0s after the call.
|
nuclear@0
|
940 OVR_EXPORT void ovrHmd_DestroyDistortionMesh(ovrDistortionMesh* meshData)
|
nuclear@0
|
941 {
|
nuclear@0
|
942 if (meshData->pVertexData)
|
nuclear@0
|
943 DistortionMeshDestroy((DistortionMeshVertexData*)meshData->pVertexData,
|
nuclear@0
|
944 meshData->pIndexData);
|
nuclear@0
|
945 meshData->pVertexData = 0;
|
nuclear@0
|
946 meshData->pIndexData = 0;
|
nuclear@0
|
947 meshData->VertexCount = 0;
|
nuclear@0
|
948 meshData->IndexCount = 0;
|
nuclear@0
|
949 }
|
nuclear@0
|
950
|
nuclear@0
|
951
|
nuclear@0
|
952
|
nuclear@0
|
953 // Computes updated 'uvScaleOffsetOut' to be used with a distortion if render target size or
|
nuclear@0
|
954 // viewport changes after the fact. This can be used to adjust render size every frame, if desired.
|
nuclear@0
|
955 OVR_EXPORT void ovrHmd_GetRenderScaleAndOffset( ovrFovPort fov,
|
nuclear@0
|
956 ovrSizei textureSize, ovrRecti renderViewport,
|
nuclear@0
|
957 ovrVector2f uvScaleOffsetOut[2] )
|
nuclear@0
|
958 {
|
nuclear@0
|
959 // Find the mapping from TanAngle space to target NDC space.
|
nuclear@0
|
960 ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(fov);
|
nuclear@0
|
961 // Find the mapping from TanAngle space to textureUV space.
|
nuclear@0
|
962 ScaleAndOffset2D eyeToSourceUV = CreateUVScaleAndOffsetfromNDCScaleandOffset(
|
nuclear@0
|
963 eyeToSourceNDC,
|
nuclear@0
|
964 renderViewport, textureSize );
|
nuclear@0
|
965
|
nuclear@0
|
966 uvScaleOffsetOut[0] = eyeToSourceUV.Scale;
|
nuclear@0
|
967 uvScaleOffsetOut[1] = eyeToSourceUV.Offset;
|
nuclear@0
|
968 }
|
nuclear@0
|
969
|
nuclear@0
|
970
|
nuclear@0
|
971 //-------------------------------------------------------------------------------------
|
nuclear@0
|
972 // ***** Latency Test interface
|
nuclear@0
|
973
|
nuclear@0
|
974 OVR_EXPORT ovrBool ovrHmd_GetLatencyTestDrawColor(ovrHmd hmddesc, unsigned char rgbColorOut[3])
|
nuclear@0
|
975 {
|
nuclear@0
|
976 HMDState* p = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
977 rgbColorOut[0] = p->LatencyTestDrawColor[0];
|
nuclear@0
|
978 rgbColorOut[1] = p->LatencyTestDrawColor[1];
|
nuclear@0
|
979 rgbColorOut[2] = p->LatencyTestDrawColor[2];
|
nuclear@0
|
980 return p->LatencyTestActive;
|
nuclear@0
|
981 }
|
nuclear@0
|
982
|
nuclear@0
|
983 OVR_EXPORT ovrBool ovrHmd_ProcessLatencyTest(ovrHmd hmddesc, unsigned char rgbColorOut[3])
|
nuclear@0
|
984 {
|
nuclear@0
|
985 OVR_UNUSED(hmddesc);
|
nuclear@0
|
986 return NetClient::GetInstance()->LatencyUtil_ProcessInputs(Timer::GetSeconds(), rgbColorOut);
|
nuclear@0
|
987 }
|
nuclear@0
|
988
|
nuclear@0
|
989 OVR_EXPORT const char* ovrHmd_GetLatencyTestResult(ovrHmd hmddesc)
|
nuclear@0
|
990 {
|
nuclear@0
|
991 OVR_UNUSED(hmddesc);
|
nuclear@0
|
992 return NetClient::GetInstance()->LatencyUtil_GetResultsString();
|
nuclear@0
|
993 }
|
nuclear@0
|
994
|
nuclear@0
|
995 OVR_EXPORT ovrBool ovrHmd_GetLatencyTest2DrawColor(ovrHmd hmddesc, unsigned char rgbColorOut[3])
|
nuclear@0
|
996 {
|
nuclear@0
|
997 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
998 if (!hmds) return false;
|
nuclear@0
|
999
|
nuclear@0
|
1000 // TBD: Move directly into renderer
|
nuclear@0
|
1001 bool dk2LatencyTest = (hmds->EnabledHmdCaps & ovrHmdCap_DynamicPrediction) != 0;
|
nuclear@0
|
1002 if (dk2LatencyTest)
|
nuclear@0
|
1003 {
|
nuclear@0
|
1004 hmds->TimeManager.GetFrameLatencyTestDrawColor(hmds->LatencyTest2DrawColor);
|
nuclear@0
|
1005 if(rgbColorOut != NULL)
|
nuclear@0
|
1006 {
|
nuclear@0
|
1007 rgbColorOut[0] = hmds->LatencyTest2DrawColor[0];
|
nuclear@0
|
1008 rgbColorOut[1] = hmds->LatencyTest2DrawColor[1];
|
nuclear@0
|
1009 rgbColorOut[2] = hmds->LatencyTest2DrawColor[2];
|
nuclear@0
|
1010 }
|
nuclear@0
|
1011
|
nuclear@0
|
1012 if(hmds->pRenderer != NULL)
|
nuclear@0
|
1013 hmds->pRenderer->SetLatencyTest2Color(hmds->LatencyTest2DrawColor);
|
nuclear@0
|
1014 }
|
nuclear@0
|
1015 else
|
nuclear@0
|
1016 {
|
nuclear@0
|
1017 if(hmds->pRenderer != NULL)
|
nuclear@0
|
1018 hmds->pRenderer->SetLatencyTest2Color(NULL);
|
nuclear@0
|
1019 }
|
nuclear@0
|
1020
|
nuclear@0
|
1021 return dk2LatencyTest;
|
nuclear@0
|
1022 }
|
nuclear@0
|
1023
|
nuclear@0
|
1024
|
nuclear@0
|
1025 OVR_EXPORT double ovrHmd_GetMeasuredLatencyTest2(ovrHmd hmddesc)
|
nuclear@0
|
1026 {
|
nuclear@0
|
1027 HMDState* p = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
1028
|
nuclear@0
|
1029 // MA Test
|
nuclear@0
|
1030 float latencyRender, latencyTimewarp, latencyPostPresent;
|
nuclear@0
|
1031
|
nuclear@0
|
1032 p->TimeManager.GetLatencyTimings(latencyRender, latencyTimewarp, latencyPostPresent);
|
nuclear@0
|
1033 return latencyPostPresent;
|
nuclear@0
|
1034 }
|
nuclear@0
|
1035
|
nuclear@0
|
1036
|
nuclear@0
|
1037 //-------------------------------------------------------------------------------------
|
nuclear@0
|
1038 // ***** Health and Safety Warning Display interface
|
nuclear@0
|
1039 //
|
nuclear@0
|
1040
|
nuclear@0
|
1041 OVR_EXPORT void ovrHmd_GetHSWDisplayState(ovrHmd hmd, ovrHSWDisplayState *hswDisplayState)
|
nuclear@0
|
1042 {
|
nuclear@0
|
1043 OVR::CAPI::HMDState* pHMDState = (OVR::CAPI::HMDState*)hmd->Handle;
|
nuclear@0
|
1044
|
nuclear@0
|
1045 if (pHMDState)
|
nuclear@0
|
1046 {
|
nuclear@0
|
1047 OVR::CAPI::HSWDisplay* pHSWDisplay = pHMDState->pHSWDisplay;
|
nuclear@0
|
1048
|
nuclear@0
|
1049 if(pHSWDisplay)
|
nuclear@0
|
1050 pHSWDisplay->TickState(hswDisplayState); // This may internally call HSWDisplay::Display.
|
nuclear@0
|
1051 }
|
nuclear@0
|
1052 }
|
nuclear@0
|
1053
|
nuclear@0
|
1054 OVR_EXPORT ovrBool ovrHmd_DismissHSWDisplay(ovrHmd hmd)
|
nuclear@0
|
1055 {
|
nuclear@0
|
1056 OVR::CAPI::HMDState* pHMDState = (OVR::CAPI::HMDState*)hmd->Handle;
|
nuclear@0
|
1057
|
nuclear@0
|
1058 if (pHMDState)
|
nuclear@0
|
1059 {
|
nuclear@0
|
1060 OVR::CAPI::HSWDisplay* pHSWDisplay = pHMDState->pHSWDisplay;
|
nuclear@0
|
1061
|
nuclear@0
|
1062 if(pHSWDisplay)
|
nuclear@0
|
1063 return (pHSWDisplay->Dismiss() ? 1 : 0);
|
nuclear@0
|
1064 }
|
nuclear@0
|
1065
|
nuclear@0
|
1066 return false;
|
nuclear@0
|
1067 }
|
nuclear@0
|
1068
|
nuclear@0
|
1069
|
nuclear@0
|
1070 // -----------------------------------------------------------------------------------
|
nuclear@0
|
1071 // ***** Property Access
|
nuclear@0
|
1072 OVR_EXPORT ovrBool ovrHmd_GetBool(ovrHmd hmddesc,
|
nuclear@0
|
1073 const char* propertyName,
|
nuclear@0
|
1074 ovrBool defaultVal)
|
nuclear@0
|
1075 {
|
nuclear@0
|
1076 OVR_ASSERT(propertyName);
|
nuclear@0
|
1077 if (hmddesc)
|
nuclear@0
|
1078 {
|
nuclear@0
|
1079 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
1080 OVR_ASSERT(hmds);
|
nuclear@0
|
1081 if (hmds)
|
nuclear@0
|
1082 {
|
nuclear@0
|
1083 return hmds->getBoolValue(propertyName, (defaultVal != 0));
|
nuclear@0
|
1084 }
|
nuclear@0
|
1085 }
|
nuclear@0
|
1086
|
nuclear@0
|
1087 return NetClient::GetInstance()->GetBoolValue(InvalidVirtualHmdId, propertyName, (defaultVal != 0)) ? 1 : 0;
|
nuclear@0
|
1088 }
|
nuclear@0
|
1089
|
nuclear@0
|
1090 OVR_EXPORT ovrBool ovrHmd_SetBool(ovrHmd hmddesc,
|
nuclear@0
|
1091 const char* propertyName,
|
nuclear@0
|
1092 ovrBool value)
|
nuclear@0
|
1093 {
|
nuclear@0
|
1094 OVR_ASSERT(propertyName);
|
nuclear@0
|
1095 if (hmddesc)
|
nuclear@0
|
1096 {
|
nuclear@0
|
1097 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
1098 OVR_ASSERT(hmds);
|
nuclear@0
|
1099 if (hmds)
|
nuclear@0
|
1100 {
|
nuclear@0
|
1101 return hmds->setBoolValue(propertyName, value != 0) ? 1 : 0;
|
nuclear@0
|
1102 }
|
nuclear@0
|
1103 }
|
nuclear@0
|
1104
|
nuclear@0
|
1105 return NetClient::GetInstance()->SetBoolValue(InvalidVirtualHmdId, propertyName, (value != 0)) ? 1 : 0;
|
nuclear@0
|
1106 }
|
nuclear@0
|
1107
|
nuclear@0
|
1108 OVR_EXPORT int ovrHmd_GetInt(ovrHmd hmddesc,
|
nuclear@0
|
1109 const char* propertyName,
|
nuclear@0
|
1110 int defaultVal)
|
nuclear@0
|
1111 {
|
nuclear@0
|
1112 OVR_ASSERT(propertyName);
|
nuclear@0
|
1113 if (hmddesc)
|
nuclear@0
|
1114 {
|
nuclear@0
|
1115 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
1116 OVR_ASSERT(hmds);
|
nuclear@0
|
1117 if (hmds)
|
nuclear@0
|
1118 {
|
nuclear@0
|
1119 return hmds->getIntValue(propertyName, defaultVal);
|
nuclear@0
|
1120 }
|
nuclear@0
|
1121 }
|
nuclear@0
|
1122
|
nuclear@0
|
1123 return NetClient::GetInstance()->GetIntValue(InvalidVirtualHmdId, propertyName, defaultVal);
|
nuclear@0
|
1124 }
|
nuclear@0
|
1125
|
nuclear@0
|
1126 OVR_EXPORT ovrBool ovrHmd_SetInt(ovrHmd hmddesc,
|
nuclear@0
|
1127 const char* propertyName,
|
nuclear@0
|
1128 int value)
|
nuclear@0
|
1129 {
|
nuclear@0
|
1130 OVR_ASSERT(propertyName);
|
nuclear@0
|
1131 if (hmddesc)
|
nuclear@0
|
1132 {
|
nuclear@0
|
1133 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
1134 OVR_ASSERT(hmds);
|
nuclear@0
|
1135 if (hmds)
|
nuclear@0
|
1136 {
|
nuclear@0
|
1137 return hmds->setIntValue(propertyName, value) ? 1 : 0;
|
nuclear@0
|
1138 }
|
nuclear@0
|
1139 }
|
nuclear@0
|
1140
|
nuclear@0
|
1141 return NetClient::GetInstance()->SetIntValue(InvalidVirtualHmdId, propertyName, value) ? 1 : 0;
|
nuclear@0
|
1142 }
|
nuclear@0
|
1143
|
nuclear@0
|
1144 OVR_EXPORT float ovrHmd_GetFloat(ovrHmd hmddesc,
|
nuclear@0
|
1145 const char* propertyName,
|
nuclear@0
|
1146 float defaultVal)
|
nuclear@0
|
1147 {
|
nuclear@0
|
1148 OVR_ASSERT(propertyName);
|
nuclear@0
|
1149 if (hmddesc)
|
nuclear@0
|
1150 {
|
nuclear@0
|
1151 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
1152 OVR_ASSERT(hmds);
|
nuclear@0
|
1153 if (hmds)
|
nuclear@0
|
1154 {
|
nuclear@0
|
1155 return hmds->getFloatValue(propertyName, defaultVal);
|
nuclear@0
|
1156 }
|
nuclear@0
|
1157 }
|
nuclear@0
|
1158
|
nuclear@0
|
1159 return (float)NetClient::GetInstance()->GetNumberValue(InvalidVirtualHmdId, propertyName, defaultVal);
|
nuclear@0
|
1160 }
|
nuclear@0
|
1161
|
nuclear@0
|
1162 OVR_EXPORT ovrBool ovrHmd_SetFloat(ovrHmd hmddesc,
|
nuclear@0
|
1163 const char* propertyName,
|
nuclear@0
|
1164 float value)
|
nuclear@0
|
1165 {
|
nuclear@0
|
1166 OVR_ASSERT(propertyName);
|
nuclear@0
|
1167 if (hmddesc)
|
nuclear@0
|
1168 {
|
nuclear@0
|
1169 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
1170 OVR_ASSERT(hmds);
|
nuclear@0
|
1171 if (hmds)
|
nuclear@0
|
1172 {
|
nuclear@0
|
1173 return hmds->setFloatValue(propertyName, value) ? 1 : 0;
|
nuclear@0
|
1174 }
|
nuclear@0
|
1175 }
|
nuclear@0
|
1176
|
nuclear@0
|
1177 return NetClient::GetInstance()->SetNumberValue(InvalidVirtualHmdId, propertyName, value) ? 1 : 0;
|
nuclear@0
|
1178 }
|
nuclear@0
|
1179
|
nuclear@0
|
1180 OVR_EXPORT unsigned int ovrHmd_GetFloatArray(ovrHmd hmddesc,
|
nuclear@0
|
1181 const char* propertyName,
|
nuclear@0
|
1182 float values[],
|
nuclear@0
|
1183 unsigned int arraySize)
|
nuclear@0
|
1184 {
|
nuclear@0
|
1185 OVR_ASSERT(propertyName);
|
nuclear@0
|
1186 OVR_ASSERT(hmddesc);
|
nuclear@0
|
1187 if (hmddesc)
|
nuclear@0
|
1188 {
|
nuclear@0
|
1189 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
1190 OVR_ASSERT(hmds);
|
nuclear@0
|
1191 if (hmds)
|
nuclear@0
|
1192 {
|
nuclear@0
|
1193 return hmds->getFloatArray(propertyName, values, arraySize);
|
nuclear@0
|
1194 }
|
nuclear@0
|
1195 }
|
nuclear@0
|
1196
|
nuclear@0
|
1197 // FIXME: Currently it takes a few lines of code to do this, so just not supported for now.
|
nuclear@0
|
1198 return 0;
|
nuclear@0
|
1199 }
|
nuclear@0
|
1200
|
nuclear@0
|
1201 // Modify float[] property; false if property doesn't exist or is readonly.
|
nuclear@0
|
1202 OVR_EXPORT ovrBool ovrHmd_SetFloatArray(ovrHmd hmddesc,
|
nuclear@0
|
1203 const char* propertyName,
|
nuclear@0
|
1204 float values[],
|
nuclear@0
|
1205 unsigned int arraySize)
|
nuclear@0
|
1206 {
|
nuclear@0
|
1207 OVR_ASSERT(propertyName);
|
nuclear@0
|
1208 OVR_ASSERT(hmddesc);
|
nuclear@0
|
1209 if (hmddesc)
|
nuclear@0
|
1210 {
|
nuclear@0
|
1211 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
1212 OVR_ASSERT(hmds);
|
nuclear@0
|
1213 if (hmds)
|
nuclear@0
|
1214 {
|
nuclear@0
|
1215 return hmds->setFloatArray(propertyName, values, arraySize) ? 1 : 0;
|
nuclear@0
|
1216 }
|
nuclear@0
|
1217 }
|
nuclear@0
|
1218
|
nuclear@0
|
1219 // FIXME: Currently it takes a few lines of code to do this, so just not supported for now.
|
nuclear@0
|
1220 return 0;
|
nuclear@0
|
1221 }
|
nuclear@0
|
1222
|
nuclear@0
|
1223 OVR_EXPORT const char* ovrHmd_GetString(ovrHmd hmddesc,
|
nuclear@0
|
1224 const char* propertyName,
|
nuclear@0
|
1225 const char* defaultVal)
|
nuclear@0
|
1226 {
|
nuclear@0
|
1227 OVR_ASSERT(propertyName);
|
nuclear@0
|
1228 if (hmddesc)
|
nuclear@0
|
1229 {
|
nuclear@0
|
1230 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
1231 if (hmds)
|
nuclear@0
|
1232 {
|
nuclear@0
|
1233 return hmds->getString(propertyName, defaultVal);
|
nuclear@0
|
1234 }
|
nuclear@0
|
1235 }
|
nuclear@0
|
1236
|
nuclear@0
|
1237 return NetClient::GetInstance()->GetStringValue(InvalidVirtualHmdId, propertyName, defaultVal);
|
nuclear@0
|
1238 }
|
nuclear@0
|
1239
|
nuclear@0
|
1240 OVR_EXPORT ovrBool ovrHmd_SetString(ovrHmd hmddesc,
|
nuclear@0
|
1241 const char* propertyName,
|
nuclear@0
|
1242 const char* value)
|
nuclear@0
|
1243 {
|
nuclear@0
|
1244 OVR_ASSERT(propertyName);
|
nuclear@0
|
1245 if (hmddesc)
|
nuclear@0
|
1246 {
|
nuclear@0
|
1247 HMDState* hmds = (HMDState*)hmddesc->Handle;
|
nuclear@0
|
1248 if (hmds)
|
nuclear@0
|
1249 {
|
nuclear@0
|
1250 return hmds->setString(propertyName, value) ? 1 : 0;
|
nuclear@0
|
1251 }
|
nuclear@0
|
1252 }
|
nuclear@0
|
1253
|
nuclear@0
|
1254 return NetClient::GetInstance()->SetStringValue(InvalidVirtualHmdId, propertyName, value) ? 1 : 0;
|
nuclear@0
|
1255 }
|
nuclear@0
|
1256
|
nuclear@0
|
1257 // -----------------------------------------------------------------------------------
|
nuclear@0
|
1258 // ***** Logging
|
nuclear@0
|
1259
|
nuclear@0
|
1260 OVR_EXPORT ovrBool ovrHmd_StartPerfLog(ovrHmd hmd, const char* fileName, const char* userData1)
|
nuclear@0
|
1261 {
|
nuclear@0
|
1262 OVR_ASSERT(fileName && fileName[0]);
|
nuclear@0
|
1263
|
nuclear@0
|
1264 OVR::CAPI::HMDState* pHMDState = (OVR::CAPI::HMDState*)hmd->Handle;
|
nuclear@0
|
1265
|
nuclear@0
|
1266 if (pHMDState)
|
nuclear@0
|
1267 {
|
nuclear@0
|
1268 ovrBool started = pHMDState->LagStatsCSV.Start(fileName, userData1) ? 1 : 0;
|
nuclear@0
|
1269 if (started)
|
nuclear@0
|
1270 pHMDState->LagStats.AddResultsObserver(pHMDState->LagStatsCSV.GetObserver());
|
nuclear@0
|
1271 return started;
|
nuclear@0
|
1272 }
|
nuclear@0
|
1273 return 0;
|
nuclear@0
|
1274 }
|
nuclear@0
|
1275 OVR_EXPORT ovrBool ovrHmd_StopPerfLog(ovrHmd hmd)
|
nuclear@0
|
1276 {
|
nuclear@0
|
1277 OVR::CAPI::HMDState* pHMDState = (OVR::CAPI::HMDState*)hmd->Handle;
|
nuclear@0
|
1278
|
nuclear@0
|
1279 if (pHMDState)
|
nuclear@0
|
1280 {
|
nuclear@0
|
1281 return pHMDState->LagStatsCSV.Stop() ? 1 : 0;
|
nuclear@0
|
1282 }
|
nuclear@0
|
1283 return false;
|
nuclear@0
|
1284 }
|
nuclear@0
|
1285
|
nuclear@0
|
1286
|
nuclear@0
|
1287 #ifdef __cplusplus
|
nuclear@0
|
1288 } // extern "C"
|
nuclear@0
|
1289 #endif
|