ovr_sdk
view LibOVR/Src/CAPI/CAPI_HSWDisplay.cpp @ 3:f12a8f74fe1f
added the Xcode project
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 21 Jan 2015 11:37:50 +0200 |
parents | |
children |
line source
1 /************************************************************************************
3 Filename : CAPI_HSWDisplay.cpp
4 Content : Implements Health and Safety Warning system.
5 Created : July 3, 2014
6 Authors : Paul Pedriana
8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
11 you may not use the Oculus VR Rift SDK except in compliance with the License,
12 which is provided at the time of installation or download, or which
13 otherwise accompanies this software in either electronic or hard copy form.
15 You may obtain a copy of the License at
17 http://www.oculusvr.com/licenses/LICENSE-3.2
19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
25 ************************************************************************************/
27 #include "CAPI_HSWDisplay.h"
28 #include "CAPI_HMDState.h"
29 #include "../Kernel/OVR_Log.h"
30 #include "../Kernel/OVR_String.h"
31 #include "Textures/healthAndSafety.tga.h" // TGA file as a C array declaration.
32 #include <stdlib.h>
34 //-------------------------------------------------------------------------------------
35 // ***** HSWDISPLAY_DEBUGGING
36 //
37 // Defined as 0 or 1. Enables debugging features of this module.
39 #if !defined(HSWDISPLAY_DEBUGGING)
40 #if defined(AUTHOR_PPEDRIANA)
41 #define HSWDISPLAY_DEBUGGING 1
42 #else
43 #define HSWDISPLAY_DEBUGGING 0
44 #endif
45 #endif
47 #if HSWDISPLAY_DEBUGGING
48 OVR_DISABLE_ALL_MSVC_WARNINGS()
49 #include <winsock2.h>
50 #include <Windows.h>
51 OVR_RESTORE_ALL_MSVC_WARNINGS()
52 #endif
54 OVR_DISABLE_MSVC_WARNING(4996) // "This function or variable may be unsafe..."
57 //-------------------------------------------------------------------------------------
58 // ***** HSWDISPLAY_DEFAULT_ENABLED
59 //
60 // Defined as 0 or 1. 1 is default. If 0 then by default HSWDisplay is disabled.
61 // Developers can set it to 0 to disable HSW display.
62 //
63 #if !defined(HSWDISPLAY_DEFAULT_ENABLED)
64 #define HSWDISPLAY_DEFAULT_ENABLED 1
65 #endif
69 //-------------------------------------------------------------------------------------
70 // ***** Experimental C API functions
71 //
73 extern "C"
74 {
75 OVR_EXPORT void ovrhmd_EnableHSWDisplaySDKRender(ovrHmd hmd, ovrBool enabled)
76 {
77 OVR::CAPI::HMDState* pHMDState = (OVR::CAPI::HMDState*)hmd->Handle;
79 if (pHMDState)
80 {
81 OVR::CAPI::HSWDisplay* pHSWDisplay = pHMDState->pHSWDisplay;
83 if(pHSWDisplay)
84 pHSWDisplay->EnableRender((enabled == 0) ? false : true);
85 }
86 }
87 }
92 //-------------------------------------------------------------------------------------
93 // ***** HSWDisplay implementation
94 //
96 namespace OVR { namespace CAPI {
99 static const time_t HSWDisplayTimeNever = (time_t)0; // Constant which denotes the time of "never", as in the display has never been shown yet.
101 #define HSWDISPLAY_POLL_INTERVAL 0.400 // Seconds between polling for whether the display should be shown.
102 #define OVR_KEY_HSWDISPLAYLASTDISPLAYEDTIME "HASWLastDisplayedTime"
105 #if defined(OVR_BUILD_DEBUG)
106 #define HSWDISPLAY_FIRST_DISMISSAL_TIME 4 // Earliest time in seconds until the user can dismiss the display.
107 #define HSWDISPLAY_REGULAR_DISMISSAL_TIME 2
108 #else
109 #define HSWDISPLAY_FIRST_DISMISSAL_TIME 15
110 #define HSWDISPLAY_REGULAR_DISMISSAL_TIME 6
111 #endif
114 HSWDisplay::HSWDisplay(ovrRenderAPIType renderAPIType, ovrHmd hmd, const HMDRenderState& hmdRenderState)
115 : Enabled(HSWDISPLAY_DEFAULT_ENABLED ? true : false),
116 Displayed(false),
117 SDKRendered(false),
118 DismissRequested(false),
119 RenderEnabled(true),
120 UnloadGraphicsRequested(false),
121 StartTime(0.0),
122 DismissibleTime(0.0),
123 LastPollTime(0.0),
124 HMD(hmd),
125 HMDMounted(false),
126 HMDNewlyMounted(false),
127 RenderAPIType(renderAPIType),
128 RenderState(hmdRenderState),
129 LastProfileName(),
130 LastHSWTime(0)
131 {
132 }
135 HSWDisplay::~HSWDisplay()
136 {
137 // To consider: assert that we are already shut down.
138 HSWDisplay::Shutdown();
139 }
142 void HSWDisplay::Enable(bool enable)
143 {
144 Enabled = enable;
146 if(!enable && Displayed) // If it's visible but should not be...
147 Dismiss();
148 }
151 void HSWDisplay::EnableRender(bool enable)
152 {
153 RenderEnabled = enable;
154 }
157 void HSWDisplay::Display()
158 {
159 HSWDISPLAY_LOG(("[HSWDisplay] Display()"));
161 DisplayInternal();
163 HMDNewlyMounted = false;
164 Displayed = true;
165 SDKRendered = RenderEnabled;
166 StartTime = ovr_GetTimeInSeconds();
168 const time_t lastDisplayedTime = HSWDisplay::GetCurrentProfileLastHSWTime();
169 DismissibleTime = StartTime + ((lastDisplayedTime == HSWDisplayTimeNever) ? HSWDISPLAY_FIRST_DISMISSAL_TIME : HSWDISPLAY_REGULAR_DISMISSAL_TIME);
171 SetCurrentProfileLastHSWTime(time(NULL));
172 }
175 bool HSWDisplay::IsDisplayViewable() const
176 {
177 // This function is called IsDisplayViewable, but currently it refers only to whether the
178 // HMD is mounted on the user's head.
180 return HMDMounted;
181 }
184 bool HSWDisplay::Dismiss()
185 {
186 #if HSWDISPLAY_DEBUGGING && defined(OVR_OS_WIN32)
187 if(GetKeyState(VK_SCROLL) & 0x0001) // If the scroll lock key is toggled on...
188 return false; // Make it so that the display doesn't dismiss, so we can debug this.
189 #endif
191 // If dismissal is not requested yet, mark it as such.
192 bool newlyRequested = false;
194 if(!DismissRequested)
195 {
196 DismissRequested = true;
197 newlyRequested = true;
198 }
200 // If displayed and time has elapsed, do the dismissal.
201 OVR_ASSERT(DismissibleTime <= (ovr_GetTimeInSeconds() + HSWDISPLAY_FIRST_DISMISSAL_TIME)); // Make sure the dismissal time is sane.
202 if (Displayed && (ovr_GetTimeInSeconds() >= DismissibleTime))
203 {
204 DismissInternal();
205 Displayed = false;
206 DismissRequested = false;
207 SDKRendered = false;
208 return true;
209 }
211 if(newlyRequested)
212 { HSWDISPLAY_LOG(("[HSWDisplay] Dismiss(): Not permitted yet. Queued for timeout in %.1f seconds.", DismissibleTime - ovr_GetTimeInSeconds())); }
214 return false; // Cannot dismiss yet.
215 }
218 bool HSWDisplay::TickState(ovrHSWDisplayState *hswDisplayState, bool graphicsContext)
219 {
220 bool newlyDisplayed = false;
221 const double currentTime = ovr_GetTimeInSeconds();
223 // See if we need to be currently displayed. By design we automatically display but don't automatically dismiss.
224 if (Displayed)
225 {
226 if (DismissRequested) // If dismiss was previously requested, see if it can be executed.
227 Dismiss();
229 if (Displayed) // If not already dismissed above...
230 {
231 // We currently have the debug behavior that we permit dismiss very soon after launch.
232 #if defined(OVR_BUILD_DEBUG)
233 if(currentTime >= (StartTime + 2))
234 {
235 DismissibleTime = StartTime;
236 //Dismiss();
237 }
238 #endif
239 }
241 if (Displayed) // If not already dismissed above...
242 {
243 const ovrTrackingState ts = ((OVR::CAPI::HMDState*)HMD->Handle)->PredictedTrackingState(currentTime);
245 if (ts.StatusFlags & ovrStatus_OrientationTracked) // If the Accelerometer data is valid...
246 {
247 const OVR::Vector3f v(ts.HeadPose.LinearAcceleration.x, ts.HeadPose.LinearAcceleration.y, ts.HeadPose.LinearAcceleration.z);
249 const float minTapMagnitude = 350.0f; // Empirically determined by some testing.
251 if (v.LengthSq() > minTapMagnitude)
252 Dismiss(); // This will do nothing if the display is not present.
253 }
254 }
255 }
256 else if (Enabled && (currentTime >= (LastPollTime + HSWDISPLAY_POLL_INTERVAL)))
257 {
258 LastPollTime = currentTime;
260 // We need to display if any of the following are true:
261 // - The application is just started in Event Mode while the HMD is mounted (warning display would be viewable) and this app was not spawned from a launcher.
262 // - The current user has never seen the display yet while the HMD is mounted (warning display would be viewable).
263 // - The HMD is newly mounted (or the warning display is otherwise newly viewable).
264 // - The warning display hasn't shown in 24 hours (need to verify this as a requirement).
265 // Event Mode refers to when the app is being run in a public demo event such as a trade show.
267 OVR::CAPI::HMDState* pHMDState = (OVR::CAPI::HMDState*)HMD->Handle;
269 if(pHMDState)
270 {
271 const time_t lastDisplayedTime = HSWDisplay::GetCurrentProfileLastHSWTime();
273 // We currently unilaterally set HMDMounted to true because we don't yet have the ability to detect this. To do: Implement this when possible.
274 const bool previouslyMounted = HMDMounted;
275 HMDMounted = true;
276 HMDNewlyMounted = (!previouslyMounted && HMDMounted); // We set this back to false in the Display function or if the HMD is unmounted before then.
278 if((lastDisplayedTime == HSWDisplayTimeNever) || HMDNewlyMounted)
279 {
280 if(IsDisplayViewable()) // If the HMD is mounted and otherwise being viewed by the user...
281 {
282 Display();
283 newlyDisplayed = true;
284 }
285 }
286 }
287 }
288 else if(graphicsContext && UnloadGraphicsRequested)
289 {
290 UnloadGraphics();
291 UnloadGraphicsRequested = false;
292 }
294 if(hswDisplayState)
295 GetState(hswDisplayState);
297 return newlyDisplayed;
298 }
301 void HSWDisplay::GetState(ovrHSWDisplayState *hswDisplayState) const
302 {
303 // Return the state to the caller.
304 OVR_ASSERT(hswDisplayState != NULL);
305 if(hswDisplayState)
306 {
307 hswDisplayState->Displayed = Displayed;
308 hswDisplayState->StartTime = StartTime;
309 hswDisplayState->DismissibleTime = DismissibleTime;
310 }
311 }
314 void HSWDisplay::Render(ovrEyeType eye, const ovrTexture* eyeTexture)
315 {
316 SDKRendered = true;
317 RenderInternal(eye, eyeTexture);
318 }
320 // Persist the HSW settings on the server, since it needs to be synchronized across all applications.
321 // Note that the profile manager singleton cannot be used for this task because it overwrites the global
322 // settings for which the rift config tool is supposed to be authoritative. That also would step on the
323 // settings generated by other rift apps. The server settings, however, are synchronized for all apps
324 // and so are appropriate for this task.
325 static String getHSWTimeKey(const char* userName)
326 {
327 String keyName = "server:";
328 keyName += OVR_KEY_HSWDISPLAYLASTDISPLAYEDTIME;
329 keyName += ":";
330 if (userName)
331 {
332 keyName += userName;
333 }
334 return keyName;
335 }
337 // Returns HSWDisplayTimeNever (0) if there is no profile or this is the first time we are seeing this profile.
338 time_t HSWDisplay::GetCurrentProfileLastHSWTime() const
339 {
340 // We store the timeout value in HMDState's pProfile.
341 HMDState* pHMDState = (HMDState*)HMD->Handle;
343 if (pHMDState)
344 {
345 const char* profileName = pHMDState->pProfile ? pHMDState->pProfile->GetValue(OVR_KEY_USER) : NULL;
347 if (profileName)
348 {
349 if (LastProfileName == profileName)
350 {
351 return LastHSWTime;
352 }
354 LastProfileName = profileName;
355 String timeKey = getHSWTimeKey(profileName);
356 int lastTime = pHMDState->getIntValue(timeKey.ToCStr(), (int)HSWDisplayTimeNever);
358 LastHSWTime = lastTime;
359 return lastTime;
360 }
361 }
363 return HSWDisplayTimeNever;
364 }
366 void HSWDisplay::SetCurrentProfileLastHSWTime(time_t t)
367 {
368 // The timeout value is stored in HMDState's pProfile.
369 HMDState* pHMDState = (HMDState*)HMD->Handle;
371 if (pHMDState)
372 {
373 const char* profileName = pHMDState->pProfile ? pHMDState->pProfile->GetValue(OVR_KEY_USER) : NULL;
375 if (profileName)
376 {
377 LastProfileName = profileName;
378 LastHSWTime = (int)t;
380 String timeKey = getHSWTimeKey(profileName);
381 pHMDState->setIntValue(timeKey.ToCStr(), (int)t);
382 }
383 }
384 }
387 // Generates an appropriate stereo ortho projection matrix.
388 void HSWDisplay::GetOrthoProjection(const HMDRenderState& RenderState, Matrix4f OrthoProjection[2])
389 {
390 Matrix4f perspectiveProjection[2];
391 perspectiveProjection[0] = ovrMatrix4f_Projection(RenderState.EyeRenderDesc[0].Fov, 0.01f, 10000.f, true);
392 perspectiveProjection[1] = ovrMatrix4f_Projection(RenderState.EyeRenderDesc[1].Fov, 0.01f, 10000.f, true);
394 const float orthoDistance = HSWDISPLAY_DISTANCE; // This is meters from the camera (viewer) that we place the ortho plane.
395 const Vector2f orthoScale0 = Vector2f(1.f) / Vector2f(RenderState.EyeRenderDesc[0].PixelsPerTanAngleAtCenter);
396 const Vector2f orthoScale1 = Vector2f(1.f) / Vector2f(RenderState.EyeRenderDesc[1].PixelsPerTanAngleAtCenter);
398 OrthoProjection[0] = ovrMatrix4f_OrthoSubProjection(perspectiveProjection[0], orthoScale0, orthoDistance, RenderState.EyeRenderDesc[0].HmdToEyeViewOffset.x);
399 OrthoProjection[1] = ovrMatrix4f_OrthoSubProjection(perspectiveProjection[1], orthoScale1, orthoDistance, RenderState.EyeRenderDesc[1].HmdToEyeViewOffset.x);
400 }
403 const uint8_t* HSWDisplay::GetDefaultTexture(size_t& TextureSize)
404 {
405 TextureSize = sizeof(healthAndSafety_tga);
406 return healthAndSafety_tga;
407 }
411 }} // namespace OVR::CAPI
416 //-------------------------------------------------------------------------------------
417 // ***** HSWDisplay factory
418 //
420 #if defined (OVR_OS_WIN32)
421 #define OVR_D3D_VERSION 9
422 #include "D3D9/CAPI_D3D9_HSWDisplay.h"
423 #undef OVR_D3D_VERSION
425 #define OVR_D3D_VERSION 10
426 #include "D3D1X/CAPI_D3D10_HSWDisplay.h"
427 #undef OVR_D3D_VERSION
429 #define OVR_D3D_VERSION 11
430 #include "D3D1X/CAPI_D3D11_HSWDisplay.h"
431 #undef OVR_D3D_VERSION
432 #endif
434 #include "GL/CAPI_GL_HSWDisplay.h"
437 OVR::CAPI::HSWDisplay* OVR::CAPI::HSWDisplay::Factory(ovrRenderAPIType apiType, ovrHmd hmd, const OVR::CAPI::HMDRenderState& renderState)
438 {
439 OVR::CAPI::HSWDisplay* pHSWDisplay = NULL;
441 switch (apiType)
442 {
443 case ovrRenderAPI_None:
444 pHSWDisplay = new OVR::CAPI::HSWDisplay(apiType, hmd, renderState);
445 break;
447 case ovrRenderAPI_OpenGL:
448 pHSWDisplay = new OVR::CAPI::GL::HSWDisplay(apiType, hmd, renderState);
449 break;
451 #if defined(OVR_OS_WIN32)
452 case ovrRenderAPI_D3D9:
453 pHSWDisplay = new OVR::CAPI::D3D9::HSWDisplay(apiType, hmd, renderState);
454 break;
456 case ovrRenderAPI_D3D10:
457 pHSWDisplay = new OVR::CAPI::D3D10::HSWDisplay(apiType, hmd, renderState);
458 break;
460 case ovrRenderAPI_D3D11:
461 pHSWDisplay = new OVR::CAPI::D3D11::HSWDisplay(apiType, hmd, renderState);
462 break;
463 #else
464 case ovrRenderAPI_D3D9:
465 case ovrRenderAPI_D3D10:
466 case ovrRenderAPI_D3D11: // Fall through
467 #endif
469 // Handle unsupported cases.
470 case ovrRenderAPI_Android_GLES:
471 case ovrRenderAPI_Count: // This is not actually a type.
472 default:
473 break;
474 }
476 return pHSWDisplay;
477 }