diff options
author | Brad Davis <[email protected]> | 2013-07-03 09:16:03 -0700 |
---|---|---|
committer | Brad Davis <[email protected]> | 2013-07-03 09:16:03 -0700 |
commit | d46694c91c2bec4eb1e282c0c0101e6dab26e082 (patch) | |
tree | eb5fba71edf1aedc0d6af9406881004289433b20 /Samples/OculusWorldDemo/OculusWorldDemo.cpp | |
parent | 7fa8be4bc565adc9911c95c814480cc48bf2d13c (diff) |
SDK 0.2.3
Diffstat (limited to 'Samples/OculusWorldDemo/OculusWorldDemo.cpp')
-rw-r--r-- | Samples/OculusWorldDemo/OculusWorldDemo.cpp | 3758 |
1 files changed, 1922 insertions, 1836 deletions
diff --git a/Samples/OculusWorldDemo/OculusWorldDemo.cpp b/Samples/OculusWorldDemo/OculusWorldDemo.cpp index 18e614c..be2e6b2 100644 --- a/Samples/OculusWorldDemo/OculusWorldDemo.cpp +++ b/Samples/OculusWorldDemo/OculusWorldDemo.cpp @@ -1,1836 +1,1922 @@ -/************************************************************************************
-
-Filename : OculusWorldDemo.cpp
-Content : First-person view test application for Oculus Rift
-Created : October 4, 2012
-Authors : Michael Antonov, Andrew Reisse, Steve LaValle
- Peter Hoff, Dan Goodman, Bryan Croteau
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-*************************************************************************************/
-
-#include "OVR.h"
-
-#include "Player.h"
-
-#include "../CommonSrc/Platform/Platform_Default.h"
-#include "../CommonSrc/Render/Render_Device.h"
-#include "../CommonSrc/Render/Render_XMLSceneLoader.h"
-#include "../CommonSrc/Render/Render_FontEmbed_DejaVu48.h"
-#include "../CommonSrc/Platform/Gamepad.h"
-
-#include <Kernel/OVR_SysFile.h>
-#include <Kernel/OVR_Log.h>
-#include <Kernel/OVR_Timer.h>
-
-// Filename to be loaded by default, searching specified paths.
-#define WORLDDEMO_ASSET_FILE "Tuscany.xml"
-#define WORLDDEMO_ASSET_PATH1 "Assets/Tuscany/"
-#define WORLDDEMO_ASSET_PATH2 "../Assets/Tuscany/"
-// This path allows the shortcut to work.
-#define WORLDDEMO_ASSET_PATH3 "Samples/OculusWorldDemo/Assets/Tuscany/"
-
-
-using namespace OVR;
-using namespace OVR::Platform;
-using namespace OVR::Render;
-
-//-------------------------------------------------------------------------------------
-// ***** OculusWorldDemo Description
-
-// This app renders a simple flat-shaded room allowing the user to move along the
-// floor and look around with an HMD, mouse and keyboard. The following keys work:
-//
-// 'W', 'S', 'A', 'D' and Arrow Keys - Move forward, back; strafe left/right.
-// F1 - No stereo, no distortion.
-// F2 - Stereo, no distortion.
-// F3 - Stereo and distortion.
-// F4 - Toggle MSAA.
-// F9 - Cycle through fullscreen and windowed modes. Necessary for previewing content with Rift.
-//
-// Important Oculus-specific logic can be found at following locations:
-//
-// OculusWorldDemoApp::OnStartup - This function will initialize OVR::DeviceManager and HMD,
-// creating SensorDevice and attaching it to SensorFusion.
-// This needs to be done before obtaining sensor data.
-//
-// OculusWorldDemoApp::OnIdle - Here we poll SensorFusion for orientation, apply it
-// to the scene and handle movement.
-// Stereo rendering is also done here, by delegating to
-// to Render function for each eye.
-//
-
-//-------------------------------------------------------------------------------------
-// ***** OculusWorldDemo Application class
-
-// An instance of this class is created on application startup (main/WinMain).
-// It then works as follows:
-// - Graphics and HMD setup is done OculusWorldDemoApp::OnStartup(). This function
-// also creates the room model from Slab declarations.
-// - Per-frame processing is done in OnIdle(). This function processes
-// sensor and movement input and then renders the frame.
-// - Additional input processing is done in OnMouse, OnKey.
-
-class OculusWorldDemoApp : public Application, public MessageHandler
-{
-public:
- OculusWorldDemoApp();
- ~OculusWorldDemoApp();
-
- virtual int OnStartup(int argc, const char** argv);
- virtual void OnIdle();
-
- virtual void OnMouseMove(int x, int y, int modifiers);
- virtual void OnKey(KeyCode key, int chr, bool down, int modifiers);
- virtual void OnResize(int width, int height);
-
- virtual void OnMessage(const Message& msg);
-
- void Render(const StereoEyeParams& stereo);
-
- // Sets temporarily displayed message for adjustments
- void SetAdjustMessage(const char* format, ...);
- // Overrides current timeout, in seconds (not the future default value);
- // intended to be called right after SetAdjustMessage.
- void SetAdjustMessageTimeout(float timeout);
-
- // Stereo setting adjustment functions.
- // Called with deltaTime when relevant key is held.
- void AdjustFov(float dt);
- void AdjustAspect(float dt);
- void AdjustIPD(float dt);
- void AdjustEyeHeight(float dt);
-
- void AdjustMotionPrediction(float dt);
-
- void AdjustDistortion(float dt, int kIndex, const char* label);
- void AdjustDistortionK0(float dt) { AdjustDistortion(dt, 0, "K0"); }
- void AdjustDistortionK1(float dt) { AdjustDistortion(dt, 1, "K1"); }
- void AdjustDistortionK2(float dt) { AdjustDistortion(dt, 2, "K2"); }
- void AdjustDistortionK3(float dt) { AdjustDistortion(dt, 3, "K3"); }
-
- // Adds room model to scene.
- void PopulateScene(const char* fileName);
- void PopulatePreloadScene();
- void ClearScene();
-
- // Magnetometer calibration procedure
- void UpdateManualMagCalibration();
-
-protected:
- RenderDevice* pRender;
- RendererParams RenderParams;
- int Width, Height;
- int Screen;
- int FirstScreenInCycle;
-
- // Magnetometer calibration and yaw correction
- Util::MagCalibration MagCal;
- bool MagAwaitingForwardLook;
-
- // *** Oculus HMD Variables
- Ptr<DeviceManager> pManager;
- Ptr<SensorDevice> pSensor;
- Ptr<HMDDevice> pHMD;
- SensorFusion SFusion;
- HMDInfo HMDInfo;
-
- Ptr<LatencyTestDevice> pLatencyTester;
- Util::LatencyTest LatencyUtil;
-
- double LastUpdate;
- int FPS;
- int FrameCounter;
- double NextFPSUpdate;
-
- Array<Ptr<CollisionModel> > CollisionModels;
- Array<Ptr<CollisionModel> > GroundCollisionModels;
-
- // Loading process displays screenshot in first frame
- // and then proceeds to load until finished.
- enum LoadingStateType
- {
- LoadingState_Frame0,
- LoadingState_DoLoad,
- LoadingState_Finished
- };
-
- // Player
- Player Player;
- Matrix4f View;
- Scene MainScene;
- Scene LoadingScene;
- Scene GridScene;
- Scene YawMarkGreenScene;
- Scene YawMarkRedScene;
- Scene YawLinesScene;
-
- LoadingStateType LoadingState;
-
- Ptr<ShaderFill> LitSolid, LitTextures[4];
-
- // Stereo view parameters.
- StereoConfig SConfig;
- PostProcessType PostProcess;
-
- // LOD
- String MainFilePath;
- Array<String> LODFilePaths;
- int ConsecutiveLowFPSFrames;
- int CurrentLODFileIndex;
-
- float DistortionK0;
- float DistortionK1;
- float DistortionK2;
- float DistortionK3;
-
- String AdjustMessage;
- double AdjustMessageTimeout;
-
- // Saved distortion state.
- float SavedK0, SavedK1, SavedK2, SavedK3;
- float SavedESD, SavedAspect, SavedEyeDistance;
-
- // Allows toggling color around distortion.
- Color DistortionClearColor;
-
- // Stereo settings adjustment state.
- typedef void (OculusWorldDemoApp::*AdjustFuncType)(float);
- bool ShiftDown;
- AdjustFuncType pAdjustFunc;
- float AdjustDirection;
-
- enum SceneRenderMode
- {
- Scene_World,
- Scene_Grid,
- Scene_Both,
- Scene_YawView
- };
- SceneRenderMode SceneMode;
-
-
- enum TextScreen
- {
- Text_None,
- Text_Orientation,
- Text_Config,
- Text_Help,
- Text_Count
- };
- TextScreen TextScreen;
-
- struct DeviceStatusNotificationDesc
- {
- DeviceHandle Handle;
- MessageType Action;
-
- DeviceStatusNotificationDesc():Action(Message_None) {}
- DeviceStatusNotificationDesc(MessageType mt, const DeviceHandle& dev)
- : Handle(dev), Action(mt) {}
- };
- Array<DeviceStatusNotificationDesc> DeviceStatusNotificationsQueue;
-
-
- Model* CreateModel(Vector3f pos, struct SlabModel* sm);
- Model* CreateBoundingModel(CollisionModel &cm);
- void PopulateLODFileNames();
- void DropLOD();
- void RaiseLOD();
- void CycleDisplay();
- void GamepadStateChanged(const GamepadState& pad);
-
- // Variable used by UpdateManualCalibration
- float FirstMagYaw;
-};
-
-//-------------------------------------------------------------------------------------
-
-OculusWorldDemoApp::OculusWorldDemoApp()
- : pRender(0),
- LastUpdate(0),
- LoadingState(LoadingState_Frame0),
- // Initial location
- SConfig(),
- PostProcess(PostProcess_Distortion),
- DistortionClearColor(0, 0, 0),
-
- ShiftDown(false),
- pAdjustFunc(0),
- AdjustDirection(1.0f),
- SceneMode(Scene_World),
- TextScreen(Text_None)
-{
- Width = 1280;
- Height = 800;
- Screen = 0;
- FirstScreenInCycle = 0;
-
- FPS = 0;
- FrameCounter = 0;
- NextFPSUpdate = 0;
-
- ConsecutiveLowFPSFrames = 0;
- CurrentLODFileIndex = 0;
-
- AdjustMessageTimeout = 0;
-}
-
-OculusWorldDemoApp::~OculusWorldDemoApp()
-{
- RemoveHandlerFromDevices();
-
- if(DejaVu.fill)
- {
- DejaVu.fill->Release();
- }
- pLatencyTester.Clear();
- pSensor.Clear();
- pHMD.Clear();
-
- CollisionModels.ClearAndRelease();
- GroundCollisionModels.ClearAndRelease();
-}
-
-int OculusWorldDemoApp::OnStartup(int argc, const char** argv)
-{
-
- // *** Oculus HMD & Sensor Initialization
-
- // Create DeviceManager and first available HMDDevice from it.
- // Sensor object is created from the HMD, to ensure that it is on the
- // correct device.
-
- pManager = *DeviceManager::Create();
-
- // We'll handle it's messages in this case.
- pManager->SetMessageHandler(this);
-
- pHMD = *pManager->EnumerateDevices<HMDDevice>().CreateDevice();
- if(pHMD)
- {
- pSensor = *pHMD->GetSensor();
-
- // This will initialize HMDInfo with information about configured IPD,
- // screen size and other variables needed for correct projection.
- // We pass HMD DisplayDeviceName into the renderer to select the
- // correct monitor in full-screen mode.
- if(pHMD->GetDeviceInfo(&HMDInfo))
- {
- //RenderParams.MonitorName = hmd.DisplayDeviceName;
- SConfig.SetHMDInfo(HMDInfo);
- }
- }
- else
- {
- // If we didn't detect an HMD, try to create the sensor directly.
- // This is useful for debugging sensor interaction; it is not needed in
- // a shipping app.
- pSensor = *pManager->EnumerateDevices<SensorDevice>().CreateDevice();
- }
-
- // Create the Latency Tester device and assign it to the LatencyTesterUtil object.
- pLatencyTester = *pManager->EnumerateDevices<LatencyTestDevice>().CreateDevice();
- if (pLatencyTester)
- {
- LatencyUtil.SetDevice(pLatencyTester);
- }
- // Make the user aware which devices are present.
- if(pHMD == NULL && pSensor == NULL)
- {
- SetAdjustMessage("---------------------------------\nNO HMD DETECTED\nNO SENSOR DETECTED\n---------------------------------");
- }
- else if(pHMD == NULL)
- {
- SetAdjustMessage("----------------------------\nNO HMD DETECTED\n----------------------------");
- }
- else if(pSensor == NULL)
- {
- SetAdjustMessage("---------------------------------\nNO SENSOR DETECTED\n---------------------------------");
- }
- else
- {
- SetAdjustMessage("--------------------------------------------\n"
- "Press F9 for Full-Screen on Rift\n"
- "--------------------------------------------");
- }
-
- // First message should be extra-long.
- SetAdjustMessageTimeout(10.0f);
-
-
- if(HMDInfo.HResolution > 0)
- {
- Width = HMDInfo.HResolution;
- Height = HMDInfo.VResolution;
- }
-
- if(!pPlatform->SetupWindow(Width, Height))
- {
- return 1;
- }
-
- String Title = "Oculus World Demo";
- if(HMDInfo.ProductName[0])
- {
- Title += " : ";
- Title += HMDInfo.ProductName;
- }
- pPlatform->SetWindowTitle(Title);
-
- // Report relative mouse motion in OnMouseMove
- pPlatform->SetMouseMode(Mouse_Relative);
-
- if(pSensor)
- {
- // We need to attach sensor to SensorFusion object for it to receive
- // body frame messages and update orientation. SFusion.GetOrientation()
- // is used in OnIdle() to orient the view.
- SFusion.AttachToSensor(pSensor);
-
- SFusion.SetDelegateMessageHandler(this);
-
- SFusion.SetPredictionEnabled(true);
- }
-
-
- // *** Initialize Rendering
-
- const char* graphics = "d3d11";
-
- // Select renderer based on command line arguments.
- for(int i = 1; i < argc; i++)
- {
- if(!strcmp(argv[i], "-r") && i < argc - 1)
- {
- graphics = argv[i + 1];
- }
- else if(!strcmp(argv[i], "-fs"))
- {
- RenderParams.Fullscreen = true;
- }
- }
-
- // Enable multi-sampling by default.
- RenderParams.Multisample = 4;
- pRender = pPlatform->SetupGraphics(OVR_DEFAULT_RENDER_DEVICE_SET,
- graphics, RenderParams);
-
-
-
- // *** Configure Stereo settings.
-
- SConfig.SetFullViewport(Viewport(0, 0, Width, Height));
- SConfig.SetStereoMode(Stereo_LeftRight_Multipass);
-
- // Configure proper Distortion Fit.
- // For 7" screen, fit to touch left side of the view, leaving a bit of
- // invisible screen on the top (saves on rendering cost).
- // For smaller screens (5.5"), fit to the top.
- if (HMDInfo.HScreenSize > 0.0f)
- {
- if (HMDInfo.HScreenSize > 0.140f) // 7"
- SConfig.SetDistortionFitPointVP(-1.0f, 0.0f);
- else
- SConfig.SetDistortionFitPointVP(0.0f, 1.0f);
- }
-
- pRender->SetSceneRenderScale(SConfig.GetDistortionScale());
- //pRender->SetSceneRenderScale(0.8f);
-
- SConfig.Set2DAreaFov(DegreeToRad(85.0f));
-
-
- // *** Identify Scene File & Prepare for Loading
-
- // This creates lights and models.
- if (argc == 2)
- {
- MainFilePath = argv[1];
- PopulateLODFileNames();
- }
- else
- {
- fprintf(stderr, "Usage: OculusWorldDemo [input XML]\n");
- MainFilePath = WORLDDEMO_ASSET_FILE;
- }
-
- // Try to modify path for correctness in case specified file is not found.
- if (!SysFile(MainFilePath).IsValid())
- {
- String prefixPath1(pPlatform->GetContentDirectory() + "/" + WORLDDEMO_ASSET_PATH1),
- prefixPath2(WORLDDEMO_ASSET_PATH2),
- prefixPath3(WORLDDEMO_ASSET_PATH3);
- if (SysFile(prefixPath1 + MainFilePath).IsValid())
- MainFilePath = prefixPath1 + MainFilePath;
- else if (SysFile(prefixPath2 + MainFilePath).IsValid())
- MainFilePath = prefixPath2 + MainFilePath;
- else if (SysFile(prefixPath3 + MainFilePath).IsValid())
- MainFilePath = prefixPath3 + MainFilePath;
- }
-
- PopulatePreloadScene();
-
- LastUpdate = pPlatform->GetAppTime();
- //pPlatform->PlayMusicFile(L"Loop.wav");
-
- return 0;
-}
-
-void OculusWorldDemoApp::OnMessage(const Message& msg)
-{
- if (msg.Type == Message_DeviceAdded || msg.Type == Message_DeviceRemoved)
- {
- if (msg.pDevice == pManager)
- {
- const MessageDeviceStatus& statusMsg =
- static_cast<const MessageDeviceStatus&>(msg);
-
- { // limit the scope of the lock
- Lock::Locker lock(pManager->GetHandlerLock());
- DeviceStatusNotificationsQueue.PushBack(
- DeviceStatusNotificationDesc(statusMsg.Type, statusMsg.Handle));
- }
-
- switch (statusMsg.Type)
- {
- case OVR::Message_DeviceAdded:
- LogText("DeviceManager reported device added.\n");
- break;
-
- case OVR::Message_DeviceRemoved:
- LogText("DeviceManager reported device removed.\n");
- break;
-
- default: OVR_ASSERT(0); // unexpected type
- }
- }
- }
-}
-
-void OculusWorldDemoApp::OnResize(int width, int height)
-{
- Width = width;
- Height = height;
- SConfig.SetFullViewport(Viewport(0, 0, Width, Height));
-}
-
-void OculusWorldDemoApp::OnMouseMove(int x, int y, int modifiers)
-{
- if(modifiers & Mod_MouseRelative)
- {
- // Get Delta
- int dx = x, dy = y;
-
- const float maxPitch = ((3.1415f / 2) * 0.98f);
-
- // Apply to rotation. Subtract for right body frame rotation,
- // since yaw rotation is positive CCW when looking down on XZ plane.
- Player.EyeYaw -= (Sensitivity * dx) / 360.0f;
-
- if(!pSensor)
- {
- Player.EyePitch -= (Sensitivity * dy) / 360.0f;
-
- if(Player.EyePitch > maxPitch)
- {
- Player.EyePitch = maxPitch;
- }
- if(Player.EyePitch < -maxPitch)
- {
- Player.EyePitch = -maxPitch;
- }
- }
- }
-}
-
-
-void OculusWorldDemoApp::OnKey(KeyCode key, int chr, bool down, int modifiers)
-{
- OVR_UNUSED(chr);
-
- switch(key)
- {
- case Key_Q:
- if (down && (modifiers & Mod_Control))
- {
- pPlatform->Exit(0);
- }
- break;
-
- // Handle player movement keys.
- // We just update movement state here, while the actual translation is done in OnIdle()
- // based on time.
- case Key_W:
- Player.MoveForward = down ? (Player.MoveForward | 1) : (Player.MoveForward & ~1);
- break;
- case Key_S:
- Player.MoveBack = down ? (Player.MoveBack | 1) : (Player.MoveBack & ~1);
- break;
- case Key_A:
- Player.MoveLeft = down ? (Player.MoveLeft | 1) : (Player.MoveLeft & ~1);
- break;
- case Key_D:
- Player.MoveRight = down ? (Player.MoveRight | 1) : (Player.MoveRight & ~1);
- break;
- case Key_Up:
- Player.MoveForward = down ? (Player.MoveForward | 2) : (Player.MoveForward & ~2);
- break;
- case Key_Down:
- Player.MoveBack = down ? (Player.MoveBack | 2) : (Player.MoveBack & ~2);
- break;
- case Key_Left:
- Player.MoveLeft = down ? (Player.MoveLeft | 2) : (Player.MoveLeft & ~2);
- break;
- case Key_Right:
- Player.MoveRight = down ? (Player.MoveRight | 2) : (Player.MoveRight & ~2);
- break;
-
- case Key_Minus:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustEyeHeight : 0;
- AdjustDirection = -1;
- break;
- case Key_Equal:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustEyeHeight : 0;
- AdjustDirection = 1;
- break;
-
- case Key_B:
- if (down)
- {
- if(SConfig.GetDistortionScale() == 1.0f)
- {
- if(SConfig.GetHMDInfo().HScreenSize > 0.140f) // 7"
- {
- SConfig.SetDistortionFitPointVP(-1.0f, 0.0f);
- }
- else
- {
- SConfig.SetDistortionFitPointVP(0.0f, 1.0f);
- }
- }
- else
- {
- // No fitting; scale == 1.0.
- SConfig.SetDistortionFitPointVP(0, 0);
- }
- }
- break;
-
- // Support toggling background color for distortion so that we can see
- // the effect on the periphery.
- case Key_V:
- if (down)
- {
- if(DistortionClearColor.B == 0)
- {
- DistortionClearColor = Color(0, 128, 255);
- }
- else
- {
- DistortionClearColor = Color(0, 0, 0);
- }
-
- pRender->SetDistortionClearColor(DistortionClearColor);
- }
- break;
-
-
- case Key_F1:
- SConfig.SetStereoMode(Stereo_None);
- PostProcess = PostProcess_None;
- SetAdjustMessage("StereoMode: None");
- break;
- case Key_F2:
- SConfig.SetStereoMode(Stereo_LeftRight_Multipass);
- PostProcess = PostProcess_None;
- SetAdjustMessage("StereoMode: Stereo + No Distortion");
- break;
- case Key_F3:
- SConfig.SetStereoMode(Stereo_LeftRight_Multipass);
- PostProcess = PostProcess_Distortion;
- SetAdjustMessage("StereoMode: Stereo + Distortion");
- break;
-
- case Key_R:
- SFusion.Reset();
- SetAdjustMessage("Sensor Fusion Reset");
- break;
-
- case Key_Space:
- if (!down)
- {
- TextScreen = (enum TextScreen)((TextScreen + 1) % Text_Count);
- }
- break;
-
- case Key_F4:
- if (!down)
- {
- RenderParams = pRender->GetParams();
- RenderParams.Multisample = RenderParams.Multisample > 1 ? 1 : 4;
- pRender->SetParams(RenderParams);
- if(RenderParams.Multisample > 1)
- {
- SetAdjustMessage("Multisampling On");
- }
- else
- {
- SetAdjustMessage("Multisampling Off");
- }
- }
- break;
- case Key_F9:
- if (!down)
- {
- CycleDisplay();
- }
- break;
-
-#ifdef OVR_OS_MAC
- case Key_F10: // F11 is reserved on Mac
-#else
- case Key_F11:
-#endif
- if (!down)
- {
- RenderParams = pRender->GetParams();
- RenderParams.Display = DisplayId(SConfig.GetHMDInfo().DisplayDeviceName,SConfig.GetHMDInfo().DisplayId);
- pRender->SetParams(RenderParams);
-
- pPlatform->SetMouseMode(Mouse_Normal);
- pPlatform->SetFullscreen(RenderParams, pRender->IsFullscreen() ? Display_Window : Display_FakeFullscreen);
- pPlatform->SetMouseMode(Mouse_Relative); // Avoid mode world rotation jump.
- // If using an HMD, enable post-process (for distortion) and stereo.
- if(RenderParams.IsDisplaySet() && pRender->IsFullscreen())
- {
- SConfig.SetStereoMode(Stereo_LeftRight_Multipass);
- PostProcess = PostProcess_Distortion;
- }
- }
- break;
-
- case Key_Escape:
- if(!down)
- {
- // switch to primary screen windowed mode
- pPlatform->SetFullscreen(RenderParams, Display_Window);
- RenderParams.Display = pPlatform->GetDisplay(0);
- pRender->SetParams(RenderParams);
- Screen = 0;
- }
- break;
-
- // Stereo adjustments.
- case Key_BracketLeft:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustFov : 0;
- AdjustDirection = 1;
- break;
- case Key_BracketRight:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustFov : 0;
- AdjustDirection = -1;
- break;
-
- case Key_Insert:
- case Key_Num0:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustIPD : 0;
- AdjustDirection = 1;
- break;
- case Key_Delete:
- case Key_Num9:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustIPD : 0;
- AdjustDirection = -1;
- break;
-
- case Key_PageUp:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustAspect : 0;
- AdjustDirection = 1;
- break;
- case Key_PageDown:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustAspect : 0;
- AdjustDirection = -1;
- break;
-
- // Distortion correction adjustments
- case Key_H:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK0 : NULL;
- AdjustDirection = -1;
- break;
- case Key_Y:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK0 : NULL;
- AdjustDirection = 1;
- break;
- case Key_J:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK1 : NULL;
- AdjustDirection = -1;
- break;
- case Key_U:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK1 : NULL;
- AdjustDirection = 1;
- break;
- case Key_K:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK2 : NULL;
- AdjustDirection = -1;
- break;
- case Key_I:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK2 : NULL;
- AdjustDirection = 1;
- break;
- case Key_L:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK3 : NULL;
- AdjustDirection = -1;
- break;
- case Key_O:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK3 : NULL;
- AdjustDirection = 1;
- break;
-
-
- case Key_Tab:
- if (down)
- {
- float t0 = SConfig.GetDistortionK(0),
- t1 = SConfig.GetDistortionK(1),
- t2 = SConfig.GetDistortionK(2),
- t3 = SConfig.GetDistortionK(3);
- float tESD = SConfig.GetEyeToScreenDistance(),
- taspect = SConfig.GetAspectMultiplier(),
- tipd = SConfig.GetIPD();
-
- if(SavedK0 > 0.0f)
- {
- SConfig.SetDistortionK(0, SavedK0);
- SConfig.SetDistortionK(1, SavedK1);
- SConfig.SetDistortionK(2, SavedK2);
- SConfig.SetDistortionK(3, SavedK3);
- SConfig.SetEyeToScreenDistance(SavedESD);
- SConfig.SetAspectMultiplier(SavedAspect);
- SConfig.SetIPD(SavedEyeDistance);
-
- SetAdjustMessage("Restored:\n"
- "ESD:\t120 %.3f\t350 Eye:\t490 %.3f\n"
- "K0: \t120 %.4f\t350 K2: \t490 %.4f\n"
- "K1: \t120 %.4f\t350 K3: \t490 %.4f",
- SavedESD, SavedEyeDistance,
- SavedK0, SavedK2,
- SavedK1, SavedK3);
- }
- else
- {
- SetAdjustMessage("Setting Saved");
- }
-
- SavedK0 = t0;
- SavedK1 = t1;
- SavedK2 = t2;
- SavedK3 = t3;
- SavedESD = tESD;
- SavedAspect = taspect;
- SavedEyeDistance = tipd;
- }
- break;
-
- case Key_G:
- if (down)
- {
- if(SceneMode == Scene_World)
- {
- SceneMode = Scene_Grid;
- SetAdjustMessage("Grid Only");
- }
- else if(SceneMode == Scene_Grid)
- {
- SceneMode = Scene_Both;
- SetAdjustMessage("Grid Overlay");
- }
- else if(SceneMode == Scene_Both)
- {
- SceneMode = Scene_World;
- SetAdjustMessage("Grid Off");
- }
- }
- break;
-
- // Holding down Shift key accelerates adjustment velocity.
- case Key_Shift:
- ShiftDown = down;
- break;
-
- // Reset the camera position in case we get stuck
- case Key_T:
- Player.EyePos = Vector3f(10.0f, 1.6f, 10.0f);
- break;
-
- case Key_F5:
- if (!down)
- {
- UPInt numNodes = MainScene.Models.GetSize();
- for(UPInt i = 0; i < numNodes; i++)
- {
- Ptr<OVR::Render::Model> nodePtr = MainScene.Models[i];
- Render::Model* pNode = nodePtr.GetPtr();
- if(pNode->IsCollisionModel)
- {
- pNode->Visible = !pNode->Visible;
- }
- }
- }
- break;
-
- case Key_N:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustMotionPrediction : NULL;
- AdjustDirection = -1;
- break;
-
- case Key_M:
- pAdjustFunc = down ? &OculusWorldDemoApp::AdjustMotionPrediction : NULL;
- AdjustDirection = 1;
- break;
-
-/*
- case Key_N:
- RaiseLOD();
- break;
- case Key_M:
- DropLOD();
- break;
-*/
- // Start calibrating magnetometer
- case Key_Z:
- if (down)
- {
- if (MagCal.IsManuallyCalibrating())
- MagAwaitingForwardLook = false;
- else
- {
- MagCal.BeginManualCalibration(SFusion);
- MagAwaitingForwardLook = true;
- }
- }
- break;
-
- case Key_X:
- if (down)
- {
- MagCal.BeginAutoCalibration(SFusion);
- SetAdjustMessage("Starting Auto Mag Calibration");
- }
- break;
-
- // Set the magnetometer reference point
- case Key_Semicolon:
- if (down)
- {
- SFusion.SetMagReference();
- SetAdjustMessage("Magnetometer Reference Set");
- if (SFusion.IsMagReady())
- SFusion.SetYawCorrectionEnabled(true);
- }
- break;
-
- // Show view of yaw angles (for mag calibration/analysis)
- case Key_F6:
- if (down)
- {
- if (SceneMode != Scene_YawView)
- {
- SceneMode = Scene_YawView;
- SetAdjustMessage("Magnetometer Yaw Angle Marks");
- }
- else
- {
- SceneMode = Scene_World;
- SetAdjustMessage("Magnetometer Marks Off");
- }
- }
- break;
-
- case Key_C:
- if (down)
- {
- // Toggle chromatic aberration correction on/off.
- RenderDevice::PostProcessShader shader = pRender->GetPostProcessShader();
-
- if (shader == RenderDevice::PostProcessShader_Distortion)
- {
- pRender->SetPostProcessShader(RenderDevice::PostProcessShader_DistortionAndChromAb);
- SetAdjustMessage("Chromatic Aberration Correction On");
- }
- else if (shader == RenderDevice::PostProcessShader_DistortionAndChromAb)
- {
- pRender->SetPostProcessShader(RenderDevice::PostProcessShader_Distortion);
- SetAdjustMessage("Chromatic Aberration Correction Off");
- }
- else
- OVR_ASSERT(false);
- }
- break;
-
- case Key_P:
- if (down)
- {
- // Toggle motion prediction.
- if (SFusion.IsPredictionEnabled())
- {
- SFusion.SetPredictionEnabled(false);
- SetAdjustMessage("Motion Prediction Off");
- }
- else
- {
- SFusion.SetPredictionEnabled(true);
- SetAdjustMessage("Motion Prediction On");
- }
- }
- break;
- default:
- break;
- }
-}
-
-void OculusWorldDemoApp::OnIdle()
-{
-
- double curtime = pPlatform->GetAppTime();
- float dt = float(curtime - LastUpdate);
- LastUpdate = curtime;
-
- // Update gamepad.
- GamepadState gamepadState;
- if (GetPlatformCore()->GetGamepadManager()->GetGamepadState(0, &gamepadState))
- {
- GamepadStateChanged(gamepadState);
- }
-
-
- if (LoadingState == LoadingState_DoLoad)
- {
- PopulateScene(MainFilePath.ToCStr());
- LoadingState = LoadingState_Finished;
- return;
- }
-
- // Check if any new devices were connected.
- {
- bool queueIsEmpty = false;
- while (!queueIsEmpty)
- {
- DeviceStatusNotificationDesc desc;
-
- {
- Lock::Locker lock(pManager->GetHandlerLock());
- if (DeviceStatusNotificationsQueue.GetSize() == 0)
- break;
- desc = DeviceStatusNotificationsQueue.Front();
-
- // We can't call Clear under the lock since this may introduce a dead lock:
- // this thread is locked by HandlerLock and the Clear might cause
- // call of Device->Release, which will use Manager->DeviceLock. The bkg
- // thread is most likely locked by opposite way:
- // Manager->DeviceLock ==> HandlerLock, therefore - a dead lock.
- // So, just grab the first element, save a copy of it and remove
- // the element (Device->Release won't be called since we made a copy).
-
- DeviceStatusNotificationsQueue.RemoveAt(0);
- queueIsEmpty = (DeviceStatusNotificationsQueue.GetSize() == 0);
- }
-
- bool wasAlreadyCreated = desc.Handle.IsCreated();
-
- if (desc.Action == Message_DeviceAdded)
- {
- switch(desc.Handle.GetType())
- {
- case Device_Sensor:
- if (desc.Handle.IsAvailable() && !desc.Handle.IsCreated())
- {
- if (!pSensor)
- {
- pSensor = *desc.Handle.CreateDeviceTyped<SensorDevice>();
- SFusion.AttachToSensor(pSensor);
- SetAdjustMessage("---------------------------\n"
- "SENSOR connected\n"
- "---------------------------");
- }
- else if (!wasAlreadyCreated)
- {
- LogText("A new SENSOR has been detected, but it is not currently used.");
- }
- }
- break;
- case Device_LatencyTester:
- if (desc.Handle.IsAvailable() && !desc.Handle.IsCreated())
- {
- if (!pLatencyTester)
- {
- pLatencyTester = *desc.Handle.CreateDeviceTyped<LatencyTestDevice>();
- LatencyUtil.SetDevice(pLatencyTester);
- if (!wasAlreadyCreated)
- SetAdjustMessage("----------------------------------------\n"
- "LATENCY TESTER connected\n"
- "----------------------------------------");
- }
- }
- break;
- case Device_HMD:
- {
- OVR::HMDInfo info;
- desc.Handle.GetDeviceInfo(&info);
- // if strlen(info.DisplayDeviceName) == 0 then
- // this HMD is 'fake' (created using sensor).
- if (strlen(info.DisplayDeviceName) > 0 && (!pHMD || !info.IsSameDisplay(HMDInfo)))
- {
- SetAdjustMessage("------------------------\n"
- "HMD connected\n"
- "------------------------");
- if (!pHMD || !desc.Handle.IsDevice(pHMD))
- pHMD = *desc.Handle.CreateDeviceTyped<HMDDevice>();
- // update stereo config with new HMDInfo
- if (pHMD && pHMD->GetDeviceInfo(&HMDInfo))
- {
- //RenderParams.MonitorName = hmd.DisplayDeviceName;
- SConfig.SetHMDInfo(HMDInfo);
- }
- LogText("HMD device added.\n");
- }
- break;
- }
- default:;
- }
- }
- else if (desc.Action == Message_DeviceRemoved)
- {
- if (desc.Handle.IsDevice(pSensor))
- {
- LogText("Sensor reported device removed.\n");
- SFusion.AttachToSensor(NULL);
- pSensor.Clear();
- SetAdjustMessage("-------------------------------\n"
- "SENSOR disconnected.\n"
- "-------------------------------");
- }
- else if (desc.Handle.IsDevice(pLatencyTester))
- {
- LogText("Latency Tester reported device removed.\n");
- LatencyUtil.SetDevice(NULL);
- pLatencyTester.Clear();
- SetAdjustMessage("---------------------------------------------\n"
- "LATENCY SENSOR disconnected.\n"
- "---------------------------------------------");
- }
- else if (desc.Handle.IsDevice(pHMD))
- {
- if (pHMD && !pHMD->IsDisconnected())
- {
- SetAdjustMessage("---------------------------\n"
- "HMD disconnected\n"
- "---------------------------");
- // Disconnect HMD. pSensor is used to restore 'fake' HMD device
- // (can be NULL).
- pHMD = pHMD->Disconnect(pSensor);
-
- // This will initialize HMDInfo with information about configured IPD,
- // screen size and other variables needed for correct projection.
- // We pass HMD DisplayDeviceName into the renderer to select the
- // correct monitor in full-screen mode.
- if (pHMD && pHMD->GetDeviceInfo(&HMDInfo))
- {
- //RenderParams.MonitorName = hmd.DisplayDeviceName;
- SConfig.SetHMDInfo(HMDInfo);
- }
- LogText("HMD device removed.\n");
- }
- }
- }
- else
- OVR_ASSERT(0); // unexpected action
- }
- }
-
- // If one of Stereo setting adjustment keys is pressed, adjust related state.
- if (pAdjustFunc)
- {
- (this->*pAdjustFunc)(dt * AdjustDirection * (ShiftDown ? 5.0f : 1.0f));
- }
-
- // Process latency tester results.
- const char* results = LatencyUtil.GetResultsString();
- if (results != NULL)
- {
- LogText("LATENCY TESTER: %s\n", results);
- }
-
- // Have to place this as close as possible to where the HMD orientation is read.
- LatencyUtil.ProcessInputs();
-
- // Magnetometer calibration procedure
- if (MagCal.IsManuallyCalibrating())
- UpdateManualMagCalibration();
-
- if (MagCal.IsAutoCalibrating())
- {
- MagCal.UpdateAutoCalibration(SFusion);
- if (MagCal.IsCalibrated())
- {
- if (SFusion.IsMagReady())
- SFusion.SetYawCorrectionEnabled(true);
- Vector3f mc = MagCal.GetMagCenter();
- SetAdjustMessage(" Magnetometer Calibration Complete \nCenter: %f %f %f",mc.x,mc.y,mc.z);
- }
- }
-
- // Handle Sensor motion.
- // We extract Yaw, Pitch, Roll instead of directly using the orientation
- // to allow "additional" yaw manipulation with mouse/controller.
- if(pSensor)
- {
- Quatf hmdOrient = SFusion.GetPredictedOrientation();
-
- float yaw = 0.0f;
- hmdOrient.GetEulerAngles<Axis_Y, Axis_X, Axis_Z>(&yaw, &Player.EyePitch, &Player.EyeRoll);
-
- Player.EyeYaw += (yaw - Player.LastSensorYaw);
- Player.LastSensorYaw = yaw;
-
- // NOTE: We can get a matrix from orientation as follows:
- // Matrix4f hmdMat(hmdOrient);
-
- // Test logic - assign quaternion result directly to view:
- // Quatf hmdOrient = SFusion.GetOrientation();
- // View = Matrix4f(hmdOrient.Inverted()) * Matrix4f::Translation(-EyePos);
- }
-
-
- if(curtime >= NextFPSUpdate)
- {
- NextFPSUpdate = curtime + 1.0;
- FPS = FrameCounter;
- FrameCounter = 0;
- }
- FrameCounter++;
-
- if(FPS < 40)
- {
- ConsecutiveLowFPSFrames++;
- }
- else
- {
- ConsecutiveLowFPSFrames = 0;
- }
-
- if(ConsecutiveLowFPSFrames > 200)
- {
- DropLOD();
- ConsecutiveLowFPSFrames = 0;
- }
-
- Player.EyeYaw -= Player.GamepadRotate.x * dt;
- Player.HandleCollision(dt, &CollisionModels, &GroundCollisionModels, ShiftDown);
-
- if(!pSensor)
- {
- Player.EyePitch -= Player.GamepadRotate.y * dt;
-
- const float maxPitch = ((3.1415f / 2) * 0.98f);
- if(Player.EyePitch > maxPitch)
- {
- Player.EyePitch = maxPitch;
- }
- if(Player.EyePitch < -maxPitch)
- {
- Player.EyePitch = -maxPitch;
- }
- }
-
- // Rotate and position View Camera, using YawPitchRoll in BodyFrame coordinates.
- //
- Matrix4f rollPitchYaw = Matrix4f::RotationY(Player.EyeYaw) * Matrix4f::RotationX(Player.EyePitch) *
- Matrix4f::RotationZ(Player.EyeRoll);
- Vector3f up = rollPitchYaw.Transform(UpVector);
- Vector3f forward = rollPitchYaw.Transform(ForwardVector);
-
-
- // Minimal head modeling; should be moved as an option to SensorFusion.
- float headBaseToEyeHeight = 0.15f; // Vertical height of eye from base of head
- float headBaseToEyeProtrusion = 0.09f; // Distance forward of eye from base of head
-
- Vector3f eyeCenterInHeadFrame(0.0f, headBaseToEyeHeight, -headBaseToEyeProtrusion);
- Vector3f shiftedEyePos = Player.EyePos + rollPitchYaw.Transform(eyeCenterInHeadFrame);
- shiftedEyePos.y -= eyeCenterInHeadFrame.y; // Bring the head back down to original height
- View = Matrix4f::LookAtRH(shiftedEyePos, shiftedEyePos + forward, up);
-
- // Transformation without head modeling.
- // View = Matrix4f::LookAtRH(EyePos, EyePos + forward, up);
-
- // This is an alternative to LookAtRH:
- // Here we transpose the rotation matrix to get its inverse.
- // View = (Matrix4f::RotationY(EyeYaw) * Matrix4f::RotationX(EyePitch) *
- // Matrix4f::RotationZ(EyeRoll)).Transposed() *
- // Matrix4f::Translation(-EyePos);
-
-
- switch(SConfig.GetStereoMode())
- {
- case Stereo_None:
- Render(SConfig.GetEyeRenderParams(StereoEye_Center));
- break;
-
- case Stereo_LeftRight_Multipass:
- //case Stereo_LeftDouble_Multipass:
- Render(SConfig.GetEyeRenderParams(StereoEye_Left));
- Render(SConfig.GetEyeRenderParams(StereoEye_Right));
- break;
-
- }
-
- pRender->Present();
- // Force GPU to flush the scene, resulting in the lowest possible latency.
- pRender->ForceFlushGPU();
-}
-
-
-
-void OculusWorldDemoApp::UpdateManualMagCalibration()
-{
- float tyaw,yaw, pitch, roll;
- Quatf hmdOrient = SFusion.GetOrientation();
- // Note that yaw and pitch are used from two different Euler angle combinations. This
- // is done so that pitch (looking "up" or "down") is not dependent on yaw angle
- hmdOrient.GetEulerAngles<Axis_X, Axis_Z, Axis_Y>(&pitch, &roll, &yaw);
- hmdOrient.GetEulerAngles<Axis_Y, Axis_Z, Axis_X>(&tyaw, &roll, &pitch);
- Vector3f mag = SFusion.GetMagnetometer();
- float dtr = Math<float>::DegreeToRadFactor;
-
- switch(MagCal.NumberOfSamples())
- {
- case 0:
- if (MagAwaitingForwardLook)
- SetAdjustMessage("Magnetometer Calibration\n** Step 1: Please Look Forward **\n** and Press Z When Ready **");
- else
- if (fabs(pitch) < 10.0f*dtr)
- {
- MagCal.InsertIfAcceptable(hmdOrient, mag);
- FirstMagYaw = yaw;
- MagAwaitingForwardLook = false;
- SFusion.SetMagReference();
- }
- break;
- case 1:
- SetAdjustMessage("Magnetometer Calibration\n** Step 2: Please Look Up **");
- yaw -= FirstMagYaw;
- if (yaw < -Math<float>::Pi)
- yaw += Math<float>::TwoPi;
- if (yaw > Math<float>::Pi)
- yaw -= Math<float>::TwoPi;
- if ((pitch > 50.0f*dtr) && (fabs(yaw) < 20.0f*dtr))
- MagCal.InsertIfAcceptable(hmdOrient, mag);
- break;
- case 2:
- SetAdjustMessage("Magnetometer Calibration\n** Step 3: Please Look Left **");
- yaw -= FirstMagYaw;
- if (yaw < -Math<float>::Pi)
- yaw += Math<float>::TwoPi;
- if (yaw > Math<float>::Pi)
- yaw -= Math<float>::TwoPi;
- if (yaw > 60.0f*dtr)
- MagCal.InsertIfAcceptable(hmdOrient, mag);
- break;
- case 3:
- SetAdjustMessage("Magnetometer Calibration\n** Step 4: Please Look Right **");
- yaw -= FirstMagYaw;
- if (yaw < -Math<float>::Pi)
- yaw += Math<float>::TwoPi;
- if (yaw > Math<float>::Pi)
- yaw -= Math<float>::TwoPi;
- if (yaw < -60.0f*dtr)
- MagCal.InsertIfAcceptable(hmdOrient, mag);
- break;
- case 4:
- if (!MagCal.IsCalibrated())
- {
- MagCal.SetCalibration(SFusion);
- if (SFusion.IsMagReady())
- SFusion.SetYawCorrectionEnabled(true);
- Vector3f mc = MagCal.GetMagCenter();
- SetAdjustMessage(" Magnetometer Calibration and Activation \nCenter: %f %f %f\nReference Yaw: %f",
- mc.x,mc.y,mc.z,SFusion.GetMagRefYaw());
- }
- }
-}
-
-static const char* HelpText =
- "F1 \t100 NoStereo \t420 Z \t520 Manual Mag Calib\n"
- "F2 \t100 Stereo \t420 X \t520 Auto Mag Calib\n"
- "F3 \t100 StereoHMD \t420 ; \t520 Mag Set Ref Point\n"
- "F4 \t100 MSAA \t420 F6 \t520 Mag Info\n"
- "F9 \t100 FullScreen \t420 R \t520 Reset SensorFusion\n"
- "F11 \t100 Fast FullScreen \t500 - + \t660 Adj EyeHeight\n"
- "C \t100 Chromatic Ab \t500 [ ] \t660 Adj FOV\n"
- "P \t100 Motion Pred \t500 Shift \t660 Adj Faster\n"
- "N/M \t180 Adj Motion Pred\n"
- "( / ) \t180 Adj EyeDistance"
- ;
-
-
-enum DrawTextCenterType
-{
- DrawText_NoCenter= 0,
- DrawText_VCenter = 0x1,
- DrawText_HCenter = 0x2,
- DrawText_Center = DrawText_VCenter | DrawText_HCenter
-};
-
-static void DrawTextBox(RenderDevice* prender, float x, float y,
- float textSize, const char* text,
- DrawTextCenterType centerType = DrawText_NoCenter)
-{
- float ssize[2] = {0.0f, 0.0f};
-
- prender->MeasureText(&DejaVu, text, textSize, ssize);
-
- // Treat 0 a VCenter.
- if (centerType & DrawText_HCenter)
- {
- x = -ssize[0]/2;
- }
- if (centerType & DrawText_VCenter)
- {
- y = -ssize[1]/2;
- }
-
- prender->FillRect(x-0.02f, y-0.02f, x+ssize[0]+0.02f, y+ssize[1]+0.02f, Color(40,40,100,210));
- prender->RenderText(&DejaVu, text, x, y, textSize, Color(255,255,0,210));
-}
-
-void OculusWorldDemoApp::Render(const StereoEyeParams& stereo)
-{
- pRender->BeginScene(PostProcess);
-
- // *** 3D - Configures Viewport/Projection and Render
- pRender->ApplyStereoParams(stereo);
- pRender->Clear();
-
- pRender->SetDepthMode(true, true);
- if (SceneMode != Scene_Grid)
- {
- MainScene.Render(pRender, stereo.ViewAdjust * View);
- }
-
- if (SceneMode == Scene_YawView)
- {
- Matrix4f calView = Matrix4f();
- float viewYaw = -Player.LastSensorYaw + SFusion.GetMagRefYaw();
- calView.M[0][0] = calView.M[2][2] = cos(viewYaw);
- calView.M[0][2] = sin(viewYaw);
- calView.M[2][0] = -sin(viewYaw);
- //LogText("yaw: %f\n",SFusion.GetMagRefYaw());
-
- if (SFusion.IsYawCorrectionInProgress())
- YawMarkGreenScene.Render(pRender, stereo.ViewAdjust);
- else
- YawMarkRedScene.Render(pRender, stereo.ViewAdjust);
-
- if (fabs(Player.EyePitch) < Math<float>::Pi * 0.33)
- YawLinesScene.Render(pRender, stereo.ViewAdjust * calView);
- }
-
- // *** 2D Text & Grid - Configure Orthographic rendering.
-
- // Render UI in 2D orthographic coordinate system that maps [-1,1] range
- // to a readable FOV area centered at your eye and properly adjusted.
- pRender->ApplyStereoParams2D(stereo);
- pRender->SetDepthMode(false, false);
-
- float unitPixel = SConfig.Get2DUnitPixel();
- float textHeight= unitPixel * 22;
-
- if ((SceneMode == Scene_Grid)||(SceneMode == Scene_Both))
- { // Draw grid two pixels thick.
- GridScene.Render(pRender, Matrix4f());
- GridScene.Render(pRender, Matrix4f::Translation(unitPixel,unitPixel,0));
- }
-
- // Display Loading screen-shot in frame 0.
- if (LoadingState != LoadingState_Finished)
- {
- LoadingScene.Render(pRender, Matrix4f());
- String loadMessage = String("Loading ") + MainFilePath;
- DrawTextBox(pRender, 0.0f, 0.25f, textHeight, loadMessage.ToCStr(), DrawText_HCenter);
- LoadingState = LoadingState_DoLoad;
- }
-
- if(AdjustMessageTimeout > pPlatform->GetAppTime())
- {
- DrawTextBox(pRender,0.0f,0.4f, textHeight, AdjustMessage.ToCStr(), DrawText_HCenter);
- }
-
- switch(TextScreen)
- {
- case Text_Orientation:
- {
- char buf[256], gpustat[256];
- OVR_sprintf(buf, sizeof(buf),
- " Yaw:%4.0f Pitch:%4.0f Roll:%4.0f \n"
- " FPS: %d Frame: %d \n Pos: %3.2f, %3.2f, %3.2f \n"
- " EyeHeight: %3.2f",
- RadToDegree(Player.EyeYaw), RadToDegree(Player.EyePitch), RadToDegree(Player.EyeRoll),
- FPS, FrameCounter, Player.EyePos.x, Player.EyePos.y, Player.EyePos.z, Player.EyePos.y);
- size_t texMemInMB = pRender->GetTotalTextureMemoryUsage() / 1058576;
- if (texMemInMB)
- {
- OVR_sprintf(gpustat, sizeof(gpustat), "\n GPU Tex: %u MB", texMemInMB);
- OVR_strcat(buf, sizeof(buf), gpustat);
- }
-
- DrawTextBox(pRender, 0.0f, -0.15f, textHeight, buf, DrawText_HCenter);
- }
- break;
-
- case Text_Config:
- {
- char textBuff[2048];
-
- OVR_sprintf(textBuff, sizeof(textBuff),
- "Fov\t300 %9.4f\n"
- "EyeDistance\t300 %9.4f\n"
- "DistortionK0\t300 %9.4f\n"
- "DistortionK1\t300 %9.4f\n"
- "DistortionK2\t300 %9.4f\n"
- "DistortionK3\t300 %9.4f\n"
- "TexScale\t300 %9.4f",
- SConfig.GetYFOVDegrees(),
- SConfig.GetIPD(),
- SConfig.GetDistortionK(0),
- SConfig.GetDistortionK(1),
- SConfig.GetDistortionK(2),
- SConfig.GetDistortionK(3),
- SConfig.GetDistortionScale());
-
- DrawTextBox(pRender, 0.0f, 0.0f, textHeight, textBuff, DrawText_Center);
- }
- break;
-
- case Text_Help:
- DrawTextBox(pRender, 0.0f, -0.1f, textHeight, HelpText, DrawText_Center);
-
- default:
- break;
- }
-
-
- // Display colored quad if we're doing a latency test.
- Color colorToDisplay;
- if (LatencyUtil.DisplayScreenColor(colorToDisplay))
- {
- pRender->FillRect(-0.4f, -0.4f, 0.4f, 0.4f, colorToDisplay);
- }
-
- pRender->FinishScene();
-}
-
-
-// Sets temporarily displayed message for adjustments
-void OculusWorldDemoApp::SetAdjustMessage(const char* format, ...)
-{
- Lock::Locker lock(pManager->GetHandlerLock());
- char textBuff[2048];
- va_list argList;
- va_start(argList, format);
- OVR_vsprintf(textBuff, sizeof(textBuff), format, argList);
- va_end(argList);
-
- // Message will time out in 4 seconds.
- AdjustMessage = textBuff;
- AdjustMessageTimeout = pPlatform->GetAppTime() + 4.0f;
-}
-
-void OculusWorldDemoApp::SetAdjustMessageTimeout(float timeout)
-{
- AdjustMessageTimeout = pPlatform->GetAppTime() + timeout;
-}
-
-// ***** View Control Adjustments
-
-void OculusWorldDemoApp::AdjustFov(float dt)
-{
- float esd = SConfig.GetEyeToScreenDistance() + 0.01f * dt;
- SConfig.SetEyeToScreenDistance(esd);
- SetAdjustMessage("ESD:%6.3f FOV: %6.3f", esd, SConfig.GetYFOVDegrees());
-}
-
-void OculusWorldDemoApp::AdjustAspect(float dt)
-{
- float rawAspect = SConfig.GetAspect() / SConfig.GetAspectMultiplier();
- float newAspect = SConfig.GetAspect() + 0.01f * dt;
- SConfig.SetAspectMultiplier(newAspect / rawAspect);
- SetAdjustMessage("Aspect: %6.3f", newAspect);
-}
-
-void OculusWorldDemoApp::AdjustDistortion(float dt, int kIndex, const char* label)
-{
- SConfig.SetDistortionK(kIndex, SConfig.GetDistortionK(kIndex) + 0.03f * dt);
- SetAdjustMessage("%s: %6.4f", label, SConfig.GetDistortionK(kIndex));
-}
-
-void OculusWorldDemoApp::AdjustIPD(float dt)
-{
- SConfig.SetIPD(SConfig.GetIPD() + 0.025f * dt);
- SetAdjustMessage("EyeDistance: %6.4f", SConfig.GetIPD());
-}
-
-void OculusWorldDemoApp::AdjustEyeHeight(float dt)
-{
- float dist = 0.5f * dt;
-
- Player.EyeHeight += dist;
- Player.EyePos.y += dist;
-
- SetAdjustMessage("EyeHeight: %4.2f", Player.EyeHeight);
-}
-
-void OculusWorldDemoApp::AdjustMotionPrediction(float dt)
-{
- float motionPred = SFusion.GetPredictionDelta() + 0.01f * dt;
-
- if (motionPred < 0.0f)
- {
- motionPred = 0.0f;
- }
-
- SFusion.SetPrediction(motionPred);
-
- SetAdjustMessage("MotionPrediction: %6.3fs", motionPred);
-}
-
-
-// Loads the scene data
-void OculusWorldDemoApp::PopulateScene(const char *fileName)
-{
- XmlHandler xmlHandler;
- if(!xmlHandler.ReadFile(fileName, pRender, &MainScene, &CollisionModels, &GroundCollisionModels))
- {
- SetAdjustMessage("---------------------------------\nFILE LOAD FAILED\n---------------------------------");
- SetAdjustMessageTimeout(10.0f);
- }
-
- MainScene.SetAmbient(Vector4f(1.0f, 1.0f, 1.0f, 1.0f));
-
- // Distortion debug grid (brought up by 'G' key).
- Ptr<Model> gridModel = *Model::CreateGrid(Vector3f(0,0,0), Vector3f(1.0f/10, 0,0), Vector3f(0,1.0f/10,0),
- 10, 10, 5,
- Color(0, 255, 0, 255), Color(255, 50, 50, 255) );
- GridScene.World.Add(gridModel);
-
- // Yaw angle marker and lines (brought up by ';' key).
- float shifty = -0.5f;
- Ptr<Model> yawMarkGreenModel = *Model::CreateBox(Color(0, 255, 0, 255), Vector3f(0.0f, shifty, -2.0f), Vector3f(0.05f, 0.05f, 0.05f));
- YawMarkGreenScene.World.Add(yawMarkGreenModel);
- Ptr<Model> yawMarkRedModel = *Model::CreateBox(Color(255, 0, 0, 255), Vector3f(0.0f, shifty, -2.0f), Vector3f(0.05f, 0.05f, 0.05f));
- YawMarkRedScene.World.Add(yawMarkRedModel);
-
- Ptr<Model> yawLinesModel = *new Model(Prim_Lines);
- float r = 2.0f;
- float theta0 = Math<float>::PiOver2;
- float theta1 = 0.0f;
- Color c = Color(255, 200, 200, 255);
- for (int i = 0; i < 35; i++)
- {
- theta1 = theta0 + Math<float>::Pi / 18.0f;
- yawLinesModel->AddLine(yawLinesModel->AddVertex(Vector3f(r*cos(theta0),shifty,-r*sin(theta0)),c),
- yawLinesModel->AddVertex(Vector3f(r*cos(theta1),shifty,-r*sin(theta1)),c));
- theta0 = theta1;
- yawLinesModel->AddLine(yawLinesModel->AddVertex(Vector3f(r*cos(theta0),shifty,-r*sin(theta0)),c),
- yawLinesModel->AddVertex(Vector3f(r*cos(theta0),shifty+0.1f,-r*sin(theta0)),c));
- theta0 = theta1;
- }
- theta1 = theta0 + Math<float>::Pi / 18.0f;
- yawLinesModel->AddLine(yawLinesModel->AddVertex(Vector3f(r*cos(theta0),shifty,-r*sin(theta0)),c),
- yawLinesModel->AddVertex(Vector3f(r*cos(theta1),shifty,-r*sin(theta1)),c));
- yawLinesModel->AddLine(yawLinesModel->AddVertex(Vector3f(0.0f,shifty+0.1f,-r),c),
- yawLinesModel->AddVertex(Vector3f(r*sin(0.02f),shifty,-r*cos(0.02f)),c));
- yawLinesModel->AddLine(yawLinesModel->AddVertex(Vector3f(0.0f,shifty+0.1f,-r),c),
- yawLinesModel->AddVertex(Vector3f(r*sin(-0.02f),shifty,-r*cos(-0.02f)),c));
- yawLinesModel->SetPosition(Vector3f(0.0f,0.0f,0.0f));
-
- YawLinesScene.World.Add(yawLinesModel);
-}
-
-
-void OculusWorldDemoApp::PopulatePreloadScene()
-{
- // Load-screen screen shot image
- String fileName = MainFilePath;
- fileName.StripExtension();
-
- Ptr<File> imageFile = *new SysFile(fileName + "_LoadScreen.tga");
- Ptr<Texture> imageTex;
- if (imageFile->IsValid())
- imageTex = *LoadTextureTga(pRender, imageFile);
-
- // Image is rendered as a single quad.
- if (imageTex)
- {
- imageTex->SetSampleMode(Sample_Anisotropic|Sample_Repeat);
- Ptr<Model> m = *new Model(Prim_Triangles);
- m->AddVertex(-0.5f, 0.5f, 0.0f, Color(255,255,255,255), 0.0f, 0.0f);
- m->AddVertex( 0.5f, 0.5f, 0.0f, Color(255,255,255,255), 1.0f, 0.0f);
- m->AddVertex( 0.5f, -0.5f, 0.0f, Color(255,255,255,255), 1.0f, 1.0f);
- m->AddVertex(-0.5f, -0.5f, 0.0f, Color(255,255,255,255), 0.0f, 1.0f);
- m->AddTriangle(2,1,0);
- m->AddTriangle(0,3,2);
-
- Ptr<ShaderFill> fill = *new ShaderFill(*pRender->CreateShaderSet());
- fill->GetShaders()->SetShader(pRender->LoadBuiltinShader(Shader_Vertex, VShader_MVP));
- fill->GetShaders()->SetShader(pRender->LoadBuiltinShader(Shader_Fragment, FShader_Texture));
- fill->SetTexture(0, imageTex);
- m->Fill = fill;
-
- LoadingScene.World.Add(m);
- }
-}
-
-void OculusWorldDemoApp::ClearScene()
-{
- MainScene.Clear();
- GridScene.Clear();
- YawMarkGreenScene.Clear();
- YawMarkRedScene.Clear();
- YawLinesScene.Clear();
-}
-
-void OculusWorldDemoApp::PopulateLODFileNames()
-{
- //OVR::String mainFilePath = MainFilePath;
- LODFilePaths.PushBack(MainFilePath);
- int LODIndex = 1;
- SPInt pos = strcspn(MainFilePath.ToCStr(), ".");
- SPInt len = strlen(MainFilePath.ToCStr());
- SPInt diff = len - pos;
-
- if (diff == 0)
- return;
-
- while(true)
- {
- char pathWithoutExt[250];
- char buffer[250];
- for(SPInt i = 0; i < pos; ++i)
- {
- pathWithoutExt[i] = MainFilePath[(int)i];
- }
- pathWithoutExt[pos] = '\0';
- OVR_sprintf(buffer, sizeof(buffer), "%s%i.xml", pathWithoutExt, LODIndex);
- FILE* fp = 0;
-#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
- errno_t err = fopen_s(&fp, buffer, "rb");
- if(!fp || err)
- {
-#else
- fp = fopen(buffer, "rb");
- if(!fp)
- {
-#endif
- break;
- }
- fclose(fp);
- OVR::String result = buffer;
- LODFilePaths.PushBack(result);
- LODIndex++;
- }
-}
-
-void OculusWorldDemoApp::DropLOD()
-{
- if(CurrentLODFileIndex < (int)(LODFilePaths.GetSize() - 1))
- {
- ClearScene();
- CurrentLODFileIndex++;
- PopulateScene(LODFilePaths[CurrentLODFileIndex].ToCStr());
- }
-}
-
-void OculusWorldDemoApp::RaiseLOD()
-{
- if(CurrentLODFileIndex > 0)
- {
- ClearScene();
- CurrentLODFileIndex--;
- PopulateScene(LODFilePaths[CurrentLODFileIndex].ToCStr());
- }
-}
-
-//-----------------------------------------------------------------------------
-void OculusWorldDemoApp::CycleDisplay()
-{
- int screenCount = pPlatform->GetDisplayCount();
-
- // If Windowed, switch to the HMD screen first in Full-Screen Mode.
- // If already Full-Screen, cycle to next screen until we reach FirstScreenInCycle.
-
- if (pRender->IsFullscreen())
- {
- // Right now, we always need to restore window before going to next screen.
- pPlatform->SetFullscreen(RenderParams, Display_Window);
-
- Screen++;
- if (Screen == screenCount)
- Screen = 0;
-
- RenderParams.Display = pPlatform->GetDisplay(Screen);
-
- if (Screen != FirstScreenInCycle)
- {
- pRender->SetParams(RenderParams);
- pPlatform->SetFullscreen(RenderParams, Display_Fullscreen);
- }
- }
- else
- {
- // Try to find HMD Screen, making it the first screen in full-screen Cycle.
- FirstScreenInCycle = 0;
-
- if (pHMD)
- {
- DisplayId HMD (SConfig.GetHMDInfo().DisplayDeviceName, SConfig.GetHMDInfo().DisplayId);
- for (int i = 0; i< screenCount; i++)
- {
- if (pPlatform->GetDisplay(i) == HMD)
- {
- FirstScreenInCycle = i;
- break;
- }
- }
- }
-
- // Switch full-screen on the HMD.
- Screen = FirstScreenInCycle;
- RenderParams.Display = pPlatform->GetDisplay(Screen);
- pRender->SetParams(RenderParams);
- pPlatform->SetFullscreen(RenderParams, Display_Fullscreen);
- }
-}
-
-void OculusWorldDemoApp::GamepadStateChanged(const GamepadState& pad)
-{
- Player.GamepadMove = Vector3f(pad.LX * pad.LX * (pad.LX > 0 ? 1 : -1),
- 0,
- pad.LY * pad.LY * (pad.LY > 0 ? -1 : 1));
- Player.GamepadRotate = Vector3f(2 * pad.RX, -2 * pad.RY, 0);
-}
-
-
-//-------------------------------------------------------------------------------------
-
-OVR_PLATFORM_APP(OculusWorldDemoApp);
+/************************************************************************************ + +Filename : OculusWorldDemo.cpp +Content : First-person view test application for Oculus Rift +Created : October 4, 2012 +Authors : Michael Antonov, Andrew Reisse, Steve LaValle + Peter Hoff, Dan Goodman, Bryan Croteau + +Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +*************************************************************************************/ + +#include "OVR.h" + +#include "../CommonSrc/Platform/Platform_Default.h" +#include "../CommonSrc/Render/Render_Device.h" +#include "../CommonSrc/Render/Render_XmlSceneLoader.h" +#include "../CommonSrc/Render/Render_FontEmbed_DejaVu48.h" +#include "../CommonSrc/Platform/Gamepad.h" + +#include <Kernel/OVR_SysFile.h> +#include <Kernel/OVR_Log.h> +#include <Kernel/OVR_Timer.h> + +#include "Player.h" + +// Filename to be loaded by default, searching specified paths. +#define WORLDDEMO_ASSET_FILE "Tuscany.xml" +#define WORLDDEMO_ASSET_PATH1 "Assets/Tuscany/" +#define WORLDDEMO_ASSET_PATH2 "../Assets/Tuscany/" +// This path allows the shortcut to work. +#define WORLDDEMO_ASSET_PATH3 "Samples/OculusWorldDemo/Assets/Tuscany/" + + +using namespace OVR; +using namespace OVR::Platform; +using namespace OVR::Render; + +//------------------------------------------------------------------------------------- +// ***** OculusWorldDemo Description + +// This app renders a simple flat-shaded room allowing the user to move along the +// floor and look around with an HMD, mouse and keyboard. The following keys work: +// +// 'W', 'S', 'A', 'D' and Arrow Keys - Move forward, back; strafe left/right. +// F1 - No stereo, no distortion. +// F2 - Stereo, no distortion. +// F3 - Stereo and distortion. +// F4 - Toggle MSAA. +// F9 - Cycle through fullscreen and windowed modes. Necessary for previewing content with Rift. +// +// Important Oculus-specific logic can be found at following locations: +// +// OculusWorldDemoApp::OnStartup - This function will initialize OVR::DeviceManager and HMD, +// creating SensorDevice and attaching it to SensorFusion. +// This needs to be done before obtaining sensor data. +// +// OculusWorldDemoApp::OnIdle - Here we poll SensorFusion for orientation, apply it +// to the scene and handle movement. +// Stereo rendering is also done here, by delegating to +// to Render function for each eye. +// + +//------------------------------------------------------------------------------------- +// ***** OculusWorldDemo Application class + +// An instance of this class is created on application startup (main/WinMain). +// It then works as follows: +// - Graphics and HMD setup is done OculusWorldDemoApp::OnStartup(). This function +// also creates the room model from Slab declarations. +// - Per-frame processing is done in OnIdle(). This function processes +// sensor and movement input and then renders the frame. +// - Additional input processing is done in OnMouse, OnKey. + +class OculusWorldDemoApp : public Application, public MessageHandler +{ +public: + OculusWorldDemoApp(); + ~OculusWorldDemoApp(); + + virtual int OnStartup(int argc, const char** argv); + virtual void OnIdle(); + + virtual void OnMouseMove(int x, int y, int modifiers); + virtual void OnKey(OVR::KeyCode key, int chr, bool down, int modifiers); + virtual void OnResize(int width, int height); + + virtual void OnMessage(const Message& msg); + + void Render(const StereoEyeParams& stereo); + + // Sets temporarily displayed message for adjustments + void SetAdjustMessage(const char* format, ...); + // Overrides current timeout, in seconds (not the future default value); + // intended to be called right after SetAdjustMessage. + void SetAdjustMessageTimeout(float timeout); + + // Stereo setting adjustment functions. + // Called with deltaTime when relevant key is held. + void AdjustFov(float dt); + void AdjustAspect(float dt); + void AdjustIPD(float dt); + void AdjustEyeHeight(float dt); + + void AdjustMotionPrediction(float dt); + + void AdjustDistortion(float dt, int kIndex, const char* label); + void AdjustDistortionK0(float dt) { AdjustDistortion(dt, 0, "K0"); } + void AdjustDistortionK1(float dt) { AdjustDistortion(dt, 1, "K1"); } + void AdjustDistortionK2(float dt) { AdjustDistortion(dt, 2, "K2"); } + void AdjustDistortionK3(float dt) { AdjustDistortion(dt, 3, "K3"); } + + // Adds room model to scene. + void PopulateScene(const char* fileName); + void PopulatePreloadScene(); + void ClearScene(); + + // Magnetometer calibration procedure + void UpdateManualMagCalibration(); + +protected: + RenderDevice* pRender; + RendererParams RenderParams; + int Width, Height; + int Screen; + int FirstScreenInCycle; + + // Magnetometer calibration and yaw correction + Util::MagCalibration MagCal; + bool MagAwaitingForwardLook; + + // *** Oculus HMD Variables + Ptr<DeviceManager> pManager; + Ptr<SensorDevice> pSensor; + Ptr<HMDDevice> pHMD; + Ptr<Profile> pUserProfile; + SensorFusion SFusion; + HMDInfo TheHMDInfo; + + Ptr<LatencyTestDevice> pLatencyTester; + Util::LatencyTest LatencyUtil; + + double LastUpdate; + int FPS; + int FrameCounter; + double NextFPSUpdate; + + Array<Ptr<CollisionModel> > CollisionModels; + Array<Ptr<CollisionModel> > GroundCollisionModels; + + // Loading process displays screenshot in first frame + // and then proceeds to load until finished. + enum LoadingStateType + { + LoadingState_Frame0, + LoadingState_DoLoad, + LoadingState_Finished + }; + + // Player + Player ThePlayer; + Matrix4f View; + Scene MainScene; + Scene LoadingScene; + Scene GridScene; + Scene YawMarkGreenScene; + Scene YawMarkRedScene; + Scene YawLinesScene; + + LoadingStateType LoadingState; + + Ptr<ShaderFill> LitSolid, LitTextures[4]; + + // Stereo view parameters. + StereoConfig SConfig; + PostProcessType PostProcess; + + // LOD + String MainFilePath; + Array<String> LODFilePaths; + int ConsecutiveLowFPSFrames; + int CurrentLODFileIndex; + + float DistortionK0; + float DistortionK1; + float DistortionK2; + float DistortionK3; + + String AdjustMessage; + double AdjustMessageTimeout; + + // Saved distortion state. + float SavedK0, SavedK1, SavedK2, SavedK3; + float SavedESD, SavedAspect, SavedEyeDistance; + + // Allows toggling color around distortion. + Color DistortionClearColor; + + // Stereo settings adjustment state. + typedef void (OculusWorldDemoApp::*AdjustFuncType)(float); + bool ShiftDown; + AdjustFuncType pAdjustFunc; + float AdjustDirection; + + enum SceneRenderMode + { + Scene_World, + Scene_Grid, + Scene_Both, + Scene_YawView + }; + SceneRenderMode SceneMode; + + + enum TextScreen + { + Text_None, + Text_Orientation, + Text_Config, + Text_Help, + Text_Count + }; + TextScreen TextScreen; + + struct DeviceStatusNotificationDesc + { + DeviceHandle Handle; + MessageType Action; + + DeviceStatusNotificationDesc():Action(Message_None) {} + DeviceStatusNotificationDesc(MessageType mt, const DeviceHandle& dev) + : Handle(dev), Action(mt) {} + }; + Array<DeviceStatusNotificationDesc> DeviceStatusNotificationsQueue; + + + Model* CreateModel(Vector3f pos, struct SlabModel* sm); + Model* CreateBoundingModel(CollisionModel &cm); + void PopulateLODFileNames(); + void DropLOD(); + void RaiseLOD(); + void CycleDisplay(); + void GamepadStateChanged(const GamepadState& pad); + + // Variable used by UpdateManualCalibration + Anglef FirstMagYaw; + int ManualMagCalStage; + int ManualMagFailures; +}; + +//------------------------------------------------------------------------------------- + +OculusWorldDemoApp::OculusWorldDemoApp() + : pRender(0), + LastUpdate(0), + LoadingState(LoadingState_Frame0), + // Initial location + SConfig(), + PostProcess(PostProcess_Distortion), + DistortionClearColor(0, 0, 0), + + ShiftDown(false), + pAdjustFunc(0), + AdjustDirection(1.0f), + SceneMode(Scene_World), + TextScreen(Text_None) +{ + Width = 1280; + Height = 800; + Screen = 0; + FirstScreenInCycle = 0; + + FPS = 0; + FrameCounter = 0; + NextFPSUpdate = 0; + + ConsecutiveLowFPSFrames = 0; + CurrentLODFileIndex = 0; + + AdjustMessageTimeout = 0; +} + +OculusWorldDemoApp::~OculusWorldDemoApp() +{ + RemoveHandlerFromDevices(); + + if(DejaVu.fill) + { + DejaVu.fill->Release(); + } + pLatencyTester.Clear(); + pSensor.Clear(); + pHMD.Clear(); + + CollisionModels.ClearAndRelease(); + GroundCollisionModels.ClearAndRelease(); +} + +int OculusWorldDemoApp::OnStartup(int argc, const char** argv) +{ + + // *** Oculus HMD & Sensor Initialization + + // Create DeviceManager and first available HMDDevice from it. + // Sensor object is created from the HMD, to ensure that it is on the + // correct device. + + pManager = *DeviceManager::Create(); + + // We'll handle it's messages in this case. + pManager->SetMessageHandler(this); + + + pHMD = *pManager->EnumerateDevices<HMDDevice>().CreateDevice(); + if (pHMD) + { + pSensor = *pHMD->GetSensor(); + + // This will initialize HMDInfo with information about configured IPD, + // screen size and other variables needed for correct projection. + // We pass HMD DisplayDeviceName into the renderer to select the + // correct monitor in full-screen mode. + if(pHMD->GetDeviceInfo(&TheHMDInfo)) + { + //RenderParams.MonitorName = hmd.DisplayDeviceName; + SConfig.SetHMDInfo(TheHMDInfo); + } + + // Retrieve relevant profile settings. + pUserProfile = pHMD->GetProfile(); + if (pUserProfile) + { + ThePlayer.EyeHeight = pUserProfile->GetEyeHeight(); + ThePlayer.EyePos.y = ThePlayer.EyeHeight; + } + } + else + { + // If we didn't detect an HMD, try to create the sensor directly. + // This is useful for debugging sensor interaction; it is not needed in + // a shipping app. + pSensor = *pManager->EnumerateDevices<SensorDevice>().CreateDevice(); + } + + // Create the Latency Tester device and assign it to the LatencyTesterUtil object. + pLatencyTester = *pManager->EnumerateDevices<LatencyTestDevice>().CreateDevice(); + if (pLatencyTester) + { + LatencyUtil.SetDevice(pLatencyTester); + } + // Make the user aware which devices are present. + if(pHMD == NULL && pSensor == NULL) + { + SetAdjustMessage("---------------------------------\nNO HMD DETECTED\nNO SENSOR DETECTED\n---------------------------------"); + } + else if(pHMD == NULL) + { + SetAdjustMessage("----------------------------\nNO HMD DETECTED\n----------------------------"); + } + else if(pSensor == NULL) + { + SetAdjustMessage("---------------------------------\nNO SENSOR DETECTED\n---------------------------------"); + } + else + { + SetAdjustMessage("--------------------------------------------\n" + "Press F9 for Full-Screen on Rift\n" + "--------------------------------------------"); + } + + // First message should be extra-long. + SetAdjustMessageTimeout(10.0f); + + + if(TheHMDInfo.HResolution > 0) + { + Width = TheHMDInfo.HResolution; + Height = TheHMDInfo.VResolution; + } + + if(!pPlatform->SetupWindow(Width, Height)) + { + return 1; + } + + String Title = "Oculus World Demo"; + if(TheHMDInfo.ProductName[0]) + { + Title += " : "; + Title += TheHMDInfo.ProductName; + } + pPlatform->SetWindowTitle(Title); + + // Report relative mouse motion in OnMouseMove + pPlatform->SetMouseMode(Mouse_Relative); + + if(pSensor) + { + // We need to attach sensor to SensorFusion object for it to receive + // body frame messages and update orientation. SFusion.GetOrientation() + // is used in OnIdle() to orient the view. + SFusion.AttachToSensor(pSensor); + + SFusion.SetDelegateMessageHandler(this); + + SFusion.SetPredictionEnabled(true); + } + + + // *** Initialize Rendering + + const char* graphics = "d3d11"; + + // Select renderer based on command line arguments. + for(int i = 1; i < argc; i++) + { + if(!strcmp(argv[i], "-r") && i < argc - 1) + { + graphics = argv[i + 1]; + } + else if(!strcmp(argv[i], "-fs")) + { + RenderParams.Fullscreen = true; + } + } + + // Enable multi-sampling by default. + RenderParams.Multisample = 4; + pRender = pPlatform->SetupGraphics(OVR_DEFAULT_RENDER_DEVICE_SET, + graphics, RenderParams); + + + + // *** Configure Stereo settings. + + SConfig.SetFullViewport(Viewport(0, 0, Width, Height)); + SConfig.SetStereoMode(Stereo_LeftRight_Multipass); + + // Configure proper Distortion Fit. + // For 7" screen, fit to touch left side of the view, leaving a bit of + // invisible screen on the top (saves on rendering cost). + // For smaller screens (5.5"), fit to the top. + if (TheHMDInfo.HScreenSize > 0.0f) + { + if (TheHMDInfo.HScreenSize > 0.140f) // 7" + SConfig.SetDistortionFitPointVP(-1.0f, 0.0f); + else + SConfig.SetDistortionFitPointVP(0.0f, 1.0f); + } + + pRender->SetSceneRenderScale(SConfig.GetDistortionScale()); + //pRender->SetSceneRenderScale(1.0f); + + SConfig.Set2DAreaFov(DegreeToRad(85.0f)); + + + // *** Identify Scene File & Prepare for Loading + + // This creates lights and models. + if (argc == 2) + { + MainFilePath = argv[1]; + PopulateLODFileNames(); + } + else + { + fprintf(stderr, "Usage: OculusWorldDemo [input XML]\n"); + MainFilePath = WORLDDEMO_ASSET_FILE; + } + + // Try to modify path for correctness in case specified file is not found. + if (!SysFile(MainFilePath).IsValid()) + { + String prefixPath1(pPlatform->GetContentDirectory() + "/" + WORLDDEMO_ASSET_PATH1), + prefixPath2(WORLDDEMO_ASSET_PATH2), + prefixPath3(WORLDDEMO_ASSET_PATH3); + if (SysFile(prefixPath1 + MainFilePath).IsValid()) + MainFilePath = prefixPath1 + MainFilePath; + else if (SysFile(prefixPath2 + MainFilePath).IsValid()) + MainFilePath = prefixPath2 + MainFilePath; + else if (SysFile(prefixPath3 + MainFilePath).IsValid()) + MainFilePath = prefixPath3 + MainFilePath; + } + + PopulatePreloadScene(); + + LastUpdate = pPlatform->GetAppTime(); + //pPlatform->PlayMusicFile(L"Loop.wav"); + + return 0; +} + +void OculusWorldDemoApp::OnMessage(const Message& msg) +{ + if (msg.Type == Message_DeviceAdded || msg.Type == Message_DeviceRemoved) + { + if (msg.pDevice == pManager) + { + const MessageDeviceStatus& statusMsg = + static_cast<const MessageDeviceStatus&>(msg); + + { // limit the scope of the lock + Lock::Locker lock(pManager->GetHandlerLock()); + DeviceStatusNotificationsQueue.PushBack( + DeviceStatusNotificationDesc(statusMsg.Type, statusMsg.Handle)); + } + + switch (statusMsg.Type) + { + case OVR::Message_DeviceAdded: + LogText("DeviceManager reported device added.\n"); + break; + + case OVR::Message_DeviceRemoved: + LogText("DeviceManager reported device removed.\n"); + break; + + default: OVR_ASSERT(0); // unexpected type + } + } + } +} + +void OculusWorldDemoApp::OnResize(int width, int height) +{ + Width = width; + Height = height; + SConfig.SetFullViewport(Viewport(0, 0, Width, Height)); +} + +void OculusWorldDemoApp::OnMouseMove(int x, int y, int modifiers) +{ + if(modifiers & Mod_MouseRelative) + { + // Get Delta + int dx = x, dy = y; + + const float maxPitch = ((3.1415f / 2) * 0.98f); + + // Apply to rotation. Subtract for right body frame rotation, + // since yaw rotation is positive CCW when looking down on XZ plane. + ThePlayer.EyeYaw -= (Sensitivity * dx) / 360.0f; + + if(!pSensor) + { + ThePlayer.EyePitch -= (Sensitivity * dy) / 360.0f; + + if(ThePlayer.EyePitch > maxPitch) + { + ThePlayer.EyePitch = maxPitch; + } + if(ThePlayer.EyePitch < -maxPitch) + { + ThePlayer.EyePitch = -maxPitch; + } + } + } +} + + +void OculusWorldDemoApp::OnKey(OVR::KeyCode key, int chr, bool down, int modifiers) +{ + OVR_UNUSED(chr); + + switch(key) + { + case Key_Q: + if (down && (modifiers & Mod_Control)) + { + pPlatform->Exit(0); + } + break; + + // Handle player movement keys. + // We just update movement state here, while the actual translation is done in OnIdle() + // based on time. + case Key_W: + ThePlayer.MoveForward = down ? (ThePlayer.MoveForward | 1) : (ThePlayer.MoveForward & ~1); + break; + case Key_S: + ThePlayer.MoveBack = down ? (ThePlayer.MoveBack | 1) : (ThePlayer.MoveBack & ~1); + break; + case Key_A: + ThePlayer.MoveLeft = down ? (ThePlayer.MoveLeft | 1) : (ThePlayer.MoveLeft & ~1); + break; + case Key_D: + ThePlayer.MoveRight = down ? (ThePlayer.MoveRight | 1) : (ThePlayer.MoveRight & ~1); + break; + case Key_Up: + ThePlayer.MoveForward = down ? (ThePlayer.MoveForward | 2) : (ThePlayer.MoveForward & ~2); + break; + case Key_Down: + ThePlayer.MoveBack = down ? (ThePlayer.MoveBack | 2) : (ThePlayer.MoveBack & ~2); + break; + case Key_Left: + ThePlayer.MoveLeft = down ? (ThePlayer.MoveLeft | 2) : (ThePlayer.MoveLeft & ~2); + break; + case Key_Right: + ThePlayer.MoveRight = down ? (ThePlayer.MoveRight | 2) : (ThePlayer.MoveRight & ~2); + break; + + case Key_Minus: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustEyeHeight : 0; + AdjustDirection = -1; + break; + case Key_Equal: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustEyeHeight : 0; + AdjustDirection = 1; + break; + + case Key_B: + if (down) + { + if(SConfig.GetDistortionScale() == 1.0f) + { + if(SConfig.GetHMDInfo().HScreenSize > 0.140f) // 7" + { + SConfig.SetDistortionFitPointVP(-1.0f, 0.0f); + } + else + { + SConfig.SetDistortionFitPointVP(0.0f, 1.0f); + } + } + else + { + // No fitting; scale == 1.0. + SConfig.SetDistortionFitPointVP(0, 0); + } + } + break; + + // Support toggling background color for distortion so that we can see + // the effect on the periphery. + case Key_V: + if (down) + { + if(DistortionClearColor.B == 0) + { + DistortionClearColor = Color(0, 128, 255); + } + else + { + DistortionClearColor = Color(0, 0, 0); + } + + pRender->SetDistortionClearColor(DistortionClearColor); + } + break; + + + case Key_F1: + SConfig.SetStereoMode(Stereo_None); + PostProcess = PostProcess_None; + SetAdjustMessage("StereoMode: None"); + break; + case Key_F2: + SConfig.SetStereoMode(Stereo_LeftRight_Multipass); + PostProcess = PostProcess_None; + SetAdjustMessage("StereoMode: Stereo + No Distortion"); + break; + case Key_F3: + SConfig.SetStereoMode(Stereo_LeftRight_Multipass); + PostProcess = PostProcess_Distortion; + SetAdjustMessage("StereoMode: Stereo + Distortion"); + break; + + case Key_R: + SFusion.Reset(); + if (MagCal.IsAutoCalibrating() || MagCal.IsManuallyCalibrating()) + MagCal.AbortCalibration(); + + SetAdjustMessage("Sensor Fusion Reset"); + break; + + case Key_Space: + if (!down) + { + TextScreen = (enum TextScreen)((TextScreen + 1) % Text_Count); + } + break; + + case Key_F4: + if (!down) + { + RenderParams = pRender->GetParams(); + RenderParams.Multisample = RenderParams.Multisample > 1 ? 1 : 4; + pRender->SetParams(RenderParams); + if(RenderParams.Multisample > 1) + { + SetAdjustMessage("Multisampling On"); + } + else + { + SetAdjustMessage("Multisampling Off"); + } + } + break; + case Key_F9: +#ifndef OVR_OS_LINUX // On Linux F9 does the same as F11. + if (!down) + { + CycleDisplay(); + } + break; +#endif +#ifdef OVR_OS_MAC + case Key_F10: // F11 is reserved on Mac +#else + case Key_F11: +#endif + if (!down) + { + RenderParams = pRender->GetParams(); + RenderParams.Display = DisplayId(SConfig.GetHMDInfo().DisplayDeviceName,SConfig.GetHMDInfo().DisplayId); + pRender->SetParams(RenderParams); + + pPlatform->SetMouseMode(Mouse_Normal); + pPlatform->SetFullscreen(RenderParams, pRender->IsFullscreen() ? Display_Window : Display_FakeFullscreen); + pPlatform->SetMouseMode(Mouse_Relative); // Avoid mode world rotation jump. + // If using an HMD, enable post-process (for distortion) and stereo. + if(RenderParams.IsDisplaySet() && pRender->IsFullscreen()) + { + SConfig.SetStereoMode(Stereo_LeftRight_Multipass); + PostProcess = PostProcess_Distortion; + } + } + break; + + case Key_Escape: + if(!down) + { + if (MagCal.IsAutoCalibrating() || MagCal.IsManuallyCalibrating()) + { + MagCal.AbortCalibration(); + SetAdjustMessage("Aborting Magnetometer Calibration"); + } + else + { + // switch to primary screen windowed mode + pPlatform->SetFullscreen(RenderParams, Display_Window); + RenderParams.Display = pPlatform->GetDisplay(0); + pRender->SetParams(RenderParams); + Screen = 0; + } + } + break; + + // Stereo adjustments. + case Key_BracketLeft: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustFov : 0; + AdjustDirection = 1; + break; + case Key_BracketRight: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustFov : 0; + AdjustDirection = -1; + break; + + case Key_Insert: + case Key_Num0: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustIPD : 0; + AdjustDirection = 1; + break; + case Key_Delete: + case Key_Num9: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustIPD : 0; + AdjustDirection = -1; + break; + + case Key_PageUp: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustAspect : 0; + AdjustDirection = 1; + break; + case Key_PageDown: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustAspect : 0; + AdjustDirection = -1; + break; + + // Distortion correction adjustments + case Key_H: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK0 : NULL; + AdjustDirection = -1; + break; + case Key_Y: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK0 : NULL; + AdjustDirection = 1; + break; + case Key_J: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK1 : NULL; + AdjustDirection = -1; + break; + case Key_U: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK1 : NULL; + AdjustDirection = 1; + break; + case Key_K: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK2 : NULL; + AdjustDirection = -1; + break; + case Key_I: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK2 : NULL; + AdjustDirection = 1; + break; + case Key_L: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK3 : NULL; + AdjustDirection = -1; + break; + case Key_O: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustDistortionK3 : NULL; + AdjustDirection = 1; + break; + + case Key_Tab: + if (down) + { + float t0 = SConfig.GetDistortionK(0), + t1 = SConfig.GetDistortionK(1), + t2 = SConfig.GetDistortionK(2), + t3 = SConfig.GetDistortionK(3); + float tESD = SConfig.GetEyeToScreenDistance(), + taspect = SConfig.GetAspectMultiplier(), + tipd = SConfig.GetIPD(); + + if(SavedK0 > 0.0f) + { + SConfig.SetDistortionK(0, SavedK0); + SConfig.SetDistortionK(1, SavedK1); + SConfig.SetDistortionK(2, SavedK2); + SConfig.SetDistortionK(3, SavedK3); + SConfig.SetEyeToScreenDistance(SavedESD); + SConfig.SetAspectMultiplier(SavedAspect); + SConfig.SetIPD(SavedEyeDistance); + + if ( ShiftDown ) + { + // Swap saved and current values. Good for doing direct comparisons. + SetAdjustMessage("Swapped current and saved. New settings:\n" + "ESD:\t120 %.3f\t350 Eye:\t490 %.3f\n" + "K0: \t120 %.4f\t350 K2: \t490 %.4f\n" + "K1: \t120 %.4f\t350 K3: \t490 %.4f\n", + SavedESD, SavedEyeDistance, + SavedK0, SavedK2, + SavedK1, SavedK3); + SavedK0 = t0; + SavedK1 = t1; + SavedK2 = t2; + SavedK3 = t3; + SavedESD = tESD; + SavedAspect = taspect; + SavedEyeDistance = tipd; + } + else + { + SetAdjustMessage("Restored:\n" + "ESD:\t120 %.3f\t350 Eye:\t490 %.3f\n" + "K0: \t120 %.4f\t350 K2: \t490 %.4f\n" + "K1: \t120 %.4f\t350 K3: \t490 %.4f\n", + SavedESD, SavedEyeDistance, + SavedK0, SavedK2, + SavedK1, SavedK3); + } + } + else + { + SetAdjustMessage("Setting Saved"); + SavedK0 = t0; + SavedK1 = t1; + SavedK2 = t2; + SavedK3 = t3; + SavedESD = tESD; + SavedAspect = taspect; + SavedEyeDistance = tipd; + } + + } + break; + + case Key_G: + if (down) + { + if(SceneMode == Scene_World) + { + SceneMode = Scene_Grid; + SetAdjustMessage("Grid Only"); + } + else if(SceneMode == Scene_Grid) + { + SceneMode = Scene_Both; + SetAdjustMessage("Grid Overlay"); + } + else if(SceneMode == Scene_Both) + { + SceneMode = Scene_World; + SetAdjustMessage("Grid Off"); + } + } + break; + + // Holding down Shift key accelerates adjustment velocity. + case Key_Shift: + ShiftDown = down; + break; + + // Reset the camera position in case we get stuck + case Key_T: + ThePlayer.EyePos = Vector3f(10.0f, 1.6f, 10.0f); + break; + + case Key_F5: + if (!down) + { + UPInt numNodes = MainScene.Models.GetSize(); + for(UPInt i = 0; i < numNodes; i++) + { + Ptr<OVR::Render::Model> nodePtr = MainScene.Models[i]; + Render::Model* pNode = nodePtr.GetPtr(); + if(pNode->IsCollisionModel) + { + pNode->Visible = !pNode->Visible; + } + } + } + break; + + case Key_N: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustMotionPrediction : NULL; + AdjustDirection = -1; + break; + + case Key_M: + pAdjustFunc = down ? &OculusWorldDemoApp::AdjustMotionPrediction : NULL; + AdjustDirection = 1; + break; + +/* + case Key_N: + RaiseLOD(); + break; + case Key_M: + DropLOD(); + break; +*/ + // Start calibrating magnetometer + case Key_Z: + if (down) + { + ManualMagCalStage = 0; + if (MagCal.IsManuallyCalibrating()) + MagAwaitingForwardLook = false; + else + { + MagCal.BeginManualCalibration(SFusion); + MagAwaitingForwardLook = true; + } + } + break; + + case Key_X: + if (down) + { + MagCal.BeginAutoCalibration(SFusion); + SetAdjustMessage("Starting Auto Mag Calibration"); + } + break; + + // Show view of yaw angles (for mag calibration/analysis) + case Key_F6: + if (down) + { + if (SceneMode != Scene_YawView) + { + SceneMode = Scene_YawView; + SetAdjustMessage("Magnetometer Yaw Angle Marks"); + } + else + { + SceneMode = Scene_World; + SetAdjustMessage("Magnetometer Marks Off"); + } + } + break; + + case Key_C: + if (down) + { + // Toggle chromatic aberration correction on/off. + RenderDevice::PostProcessShader shader = pRender->GetPostProcessShader(); + + if (shader == RenderDevice::PostProcessShader_Distortion) + { + pRender->SetPostProcessShader(RenderDevice::PostProcessShader_DistortionAndChromAb); + SetAdjustMessage("Chromatic Aberration Correction On"); + } + else if (shader == RenderDevice::PostProcessShader_DistortionAndChromAb) + { + pRender->SetPostProcessShader(RenderDevice::PostProcessShader_Distortion); + SetAdjustMessage("Chromatic Aberration Correction Off"); + } + else + OVR_ASSERT(false); + } + break; + + case Key_P: + if (down) + { + // Toggle motion prediction. + if (SFusion.IsPredictionEnabled()) + { + SFusion.SetPredictionEnabled(false); + SetAdjustMessage("Motion Prediction Off"); + } + else + { + SFusion.SetPredictionEnabled(true); + SetAdjustMessage("Motion Prediction On"); + } + } + break; + default: + break; + } +} + +void OculusWorldDemoApp::OnIdle() +{ + + double curtime = pPlatform->GetAppTime(); + float dt = float(curtime - LastUpdate); + LastUpdate = curtime; + + // Update gamepad. + GamepadState gamepadState; + if (GetPlatformCore()->GetGamepadManager()->GetGamepadState(0, &gamepadState)) + { + GamepadStateChanged(gamepadState); + } + + + if (LoadingState == LoadingState_DoLoad) + { + PopulateScene(MainFilePath.ToCStr()); + LoadingState = LoadingState_Finished; + return; + } + + // Check if any new devices were connected. + { + bool queueIsEmpty = false; + while (!queueIsEmpty) + { + DeviceStatusNotificationDesc desc; + + { + Lock::Locker lock(pManager->GetHandlerLock()); + if (DeviceStatusNotificationsQueue.GetSize() == 0) + break; + desc = DeviceStatusNotificationsQueue.Front(); + + // We can't call Clear under the lock since this may introduce a dead lock: + // this thread is locked by HandlerLock and the Clear might cause + // call of Device->Release, which will use Manager->DeviceLock. The bkg + // thread is most likely locked by opposite way: + // Manager->DeviceLock ==> HandlerLock, therefore - a dead lock. + // So, just grab the first element, save a copy of it and remove + // the element (Device->Release won't be called since we made a copy). + + DeviceStatusNotificationsQueue.RemoveAt(0); + queueIsEmpty = (DeviceStatusNotificationsQueue.GetSize() == 0); + } + + bool wasAlreadyCreated = desc.Handle.IsCreated(); + + if (desc.Action == Message_DeviceAdded) + { + switch(desc.Handle.GetType()) + { + case Device_Sensor: + if (desc.Handle.IsAvailable() && !desc.Handle.IsCreated()) + { + if (!pSensor) + { + pSensor = *desc.Handle.CreateDeviceTyped<SensorDevice>(); + SFusion.AttachToSensor(pSensor); + SetAdjustMessage("---------------------------\n" + "SENSOR connected\n" + "---------------------------"); + } + else if (!wasAlreadyCreated) + { + LogText("A new SENSOR has been detected, but it is not currently used."); + } + } + break; + case Device_LatencyTester: + if (desc.Handle.IsAvailable() && !desc.Handle.IsCreated()) + { + if (!pLatencyTester) + { + pLatencyTester = *desc.Handle.CreateDeviceTyped<LatencyTestDevice>(); + LatencyUtil.SetDevice(pLatencyTester); + if (!wasAlreadyCreated) + SetAdjustMessage("----------------------------------------\n" + "LATENCY TESTER connected\n" + "----------------------------------------"); + } + } + break; + case Device_HMD: + { + OVR::HMDInfo info; + desc.Handle.GetDeviceInfo(&info); + // if strlen(info.DisplayDeviceName) == 0 then + // this HMD is 'fake' (created using sensor). + if (strlen(info.DisplayDeviceName) > 0 && (!pHMD || !info.IsSameDisplay(TheHMDInfo))) + { + SetAdjustMessage("------------------------\n" + "HMD connected\n" + "------------------------"); + if (!pHMD || !desc.Handle.IsDevice(pHMD)) + pHMD = *desc.Handle.CreateDeviceTyped<HMDDevice>(); + // update stereo config with new HMDInfo + if (pHMD && pHMD->GetDeviceInfo(&TheHMDInfo)) + { + //RenderParams.MonitorName = hmd.DisplayDeviceName; + SConfig.SetHMDInfo(TheHMDInfo); + } + LogText("HMD device added.\n"); + } + break; + } + default:; + } + } + else if (desc.Action == Message_DeviceRemoved) + { + if (desc.Handle.IsDevice(pSensor)) + { + LogText("Sensor reported device removed.\n"); + SFusion.AttachToSensor(NULL); + pSensor.Clear(); + SetAdjustMessage("-------------------------------\n" + "SENSOR disconnected.\n" + "-------------------------------"); + } + else if (desc.Handle.IsDevice(pLatencyTester)) + { + LogText("Latency Tester reported device removed.\n"); + LatencyUtil.SetDevice(NULL); + pLatencyTester.Clear(); + SetAdjustMessage("---------------------------------------------\n" + "LATENCY SENSOR disconnected.\n" + "---------------------------------------------"); + } + else if (desc.Handle.IsDevice(pHMD)) + { + if (pHMD && !pHMD->IsDisconnected()) + { + SetAdjustMessage("---------------------------\n" + "HMD disconnected\n" + "---------------------------"); + // Disconnect HMD. pSensor is used to restore 'fake' HMD device + // (can be NULL). + pHMD = pHMD->Disconnect(pSensor); + + // This will initialize TheHMDInfo with information about configured IPD, + // screen size and other variables needed for correct projection. + // We pass HMD DisplayDeviceName into the renderer to select the + // correct monitor in full-screen mode. + if (pHMD && pHMD->GetDeviceInfo(&TheHMDInfo)) + { + //RenderParams.MonitorName = hmd.DisplayDeviceName; + SConfig.SetHMDInfo(TheHMDInfo); + } + LogText("HMD device removed.\n"); + } + } + } + else + OVR_ASSERT(0); // unexpected action + } + } + + // If one of Stereo setting adjustment keys is pressed, adjust related state. + if (pAdjustFunc) + { + (this->*pAdjustFunc)(dt * AdjustDirection * (ShiftDown ? 5.0f : 1.0f)); + } + + // Process latency tester results. + const char* results = LatencyUtil.GetResultsString(); + if (results != NULL) + { + LogText("LATENCY TESTER: %s\n", results); + } + + // Have to place this as close as possible to where the HMD orientation is read. + LatencyUtil.ProcessInputs(); + + // Magnetometer calibration procedure + if (MagCal.IsManuallyCalibrating()) + UpdateManualMagCalibration(); + + if (MagCal.IsAutoCalibrating()) + { + MagCal.UpdateAutoCalibration(SFusion); + int n = MagCal.NumberOfSamples(); + if (n == 1) + SetAdjustMessage(" Magnetometer Calibration Has 1 Sample \n %d Remaining - Please Keep Looking Around ",4-n); + else if (n < 4) + SetAdjustMessage(" Magnetometer Calibration Has %d Samples \n %d Remaining - Please Keep Looking Around ",n,4-n); + if (MagCal.IsCalibrated()) + { + SFusion.SetYawCorrectionEnabled(true); + Vector3f mc = MagCal.GetMagCenter(); + SetAdjustMessage(" Magnetometer Calibration Complete \nCenter: %f %f %f",mc.x,mc.y,mc.z); + } + } + + // Handle Sensor motion. + // We extract Yaw, Pitch, Roll instead of directly using the orientation + // to allow "additional" yaw manipulation with mouse/controller. + if(pSensor) + { + Quatf hmdOrient = SFusion.GetPredictedOrientation(); + + float yaw = 0.0f; + hmdOrient.GetEulerAngles<Axis_Y, Axis_X, Axis_Z>(&yaw, &ThePlayer.EyePitch, &ThePlayer.EyeRoll); + + ThePlayer.EyeYaw += (yaw - ThePlayer.LastSensorYaw); + ThePlayer.LastSensorYaw = yaw; + + // NOTE: We can get a matrix from orientation as follows: + // Matrix4f hmdMat(hmdOrient); + + // Test logic - assign quaternion result directly to view: + // Quatf hmdOrient = SFusion.GetOrientation(); + // View = Matrix4f(hmdOrient.Inverted()) * Matrix4f::Translation(-EyePos); + } + + + if(curtime >= NextFPSUpdate) + { + NextFPSUpdate = curtime + 1.0; + FPS = FrameCounter; + FrameCounter = 0; + } + FrameCounter++; + + if(FPS < 40) + { + ConsecutiveLowFPSFrames++; + } + else + { + ConsecutiveLowFPSFrames = 0; + } + + if(ConsecutiveLowFPSFrames > 200) + { + DropLOD(); + ConsecutiveLowFPSFrames = 0; + } + + ThePlayer.EyeYaw -= ThePlayer.GamepadRotate.x * dt; + ThePlayer.HandleCollision(dt, &CollisionModels, &GroundCollisionModels, ShiftDown); + + if(!pSensor) + { + ThePlayer.EyePitch -= ThePlayer.GamepadRotate.y * dt; + + const float maxPitch = ((3.1415f / 2) * 0.98f); + if(ThePlayer.EyePitch > maxPitch) + { + ThePlayer.EyePitch = maxPitch; + } + if(ThePlayer.EyePitch < -maxPitch) + { + ThePlayer.EyePitch = -maxPitch; + } + } + + // Rotate and position View Camera, using YawPitchRoll in BodyFrame coordinates. + // + Matrix4f rollPitchYaw = Matrix4f::RotationY(ThePlayer.EyeYaw) * Matrix4f::RotationX(ThePlayer.EyePitch) * + Matrix4f::RotationZ(ThePlayer.EyeRoll); + Vector3f up = rollPitchYaw.Transform(UpVector); + Vector3f forward = rollPitchYaw.Transform(ForwardVector); + + + // Minimal head modeling; should be moved as an option to SensorFusion. + float headBaseToEyeHeight = 0.15f; // Vertical height of eye from base of head + float headBaseToEyeProtrusion = 0.09f; // Distance forward of eye from base of head + + Vector3f eyeCenterInHeadFrame(0.0f, headBaseToEyeHeight, -headBaseToEyeProtrusion); + Vector3f shiftedEyePos = ThePlayer.EyePos + rollPitchYaw.Transform(eyeCenterInHeadFrame); + shiftedEyePos.y -= eyeCenterInHeadFrame.y; // Bring the head back down to original height + View = Matrix4f::LookAtRH(shiftedEyePos, shiftedEyePos + forward, up); + + // Transformation without head modeling. + // View = Matrix4f::LookAtRH(EyePos, EyePos + forward, up); + + // This is an alternative to LookAtRH: + // Here we transpose the rotation matrix to get its inverse. + // View = (Matrix4f::RotationY(EyeYaw) * Matrix4f::RotationX(EyePitch) * + // Matrix4f::RotationZ(EyeRoll)).Transposed() * + // Matrix4f::Translation(-EyePos); + + + switch(SConfig.GetStereoMode()) + { + case Stereo_None: + Render(SConfig.GetEyeRenderParams(StereoEye_Center)); + break; + + case Stereo_LeftRight_Multipass: + //case Stereo_LeftDouble_Multipass: + Render(SConfig.GetEyeRenderParams(StereoEye_Left)); + Render(SConfig.GetEyeRenderParams(StereoEye_Right)); + break; + + } + + pRender->Present(); + // Force GPU to flush the scene, resulting in the lowest possible latency. + pRender->ForceFlushGPU(); +} + + +void OculusWorldDemoApp::UpdateManualMagCalibration() +{ + float tyaw, pitch, roll; + Anglef yaw; + Quatf hmdOrient = SFusion.GetOrientation(); + hmdOrient.GetEulerAngles<Axis_Y, Axis_X, Axis_Z>(&tyaw, &pitch, &roll); + Vector3f mag = SFusion.GetMagnetometer(); + float dtr = Math<float>::DegreeToRadFactor; + yaw.Set(tyaw); // Using Angle class to handle angle wraparound arithmetic + + const int timeout = 100; + + switch(ManualMagCalStage) + { + case 0: + if (MagAwaitingForwardLook) + SetAdjustMessage("Magnetometer Calibration\n** Step 1: Please Look Forward **\n** and Press Z When Ready **"); + else + if (fabs(pitch) < 10.0f*dtr) + { + MagCal.InsertIfAcceptable(hmdOrient, mag); + FirstMagYaw = yaw; + MagAwaitingForwardLook = false; + if (MagCal.NumberOfSamples() == 1) + { + ManualMagCalStage = 1; + ManualMagFailures = 0; + } + } + else + MagAwaitingForwardLook = true; + break; + case 1: + SetAdjustMessage("Magnetometer Calibration\n** Step 2: Please Look Up **"); + yaw -= FirstMagYaw; + if ((pitch > 50.0f*dtr) && (yaw.Abs() < 20.0f*dtr)) + { + MagCal.InsertIfAcceptable(hmdOrient, mag); + ManualMagFailures++; + if ((MagCal.NumberOfSamples() == 2)||(ManualMagFailures > timeout)) + { + ManualMagCalStage = 2; + ManualMagFailures = 0; + } + } + break; + case 2: + SetAdjustMessage("Magnetometer Calibration\n** Step 3: Please Look Left **"); + yaw -= FirstMagYaw; + if (yaw.Get() > 60.0f*dtr) + { + MagCal.InsertIfAcceptable(hmdOrient, mag); + ManualMagFailures++; + if ((MagCal.NumberOfSamples() == 3)||(ManualMagFailures > timeout)) + { + ManualMagCalStage = 3; + ManualMagFailures = 0; + } + } + break; + case 3: + SetAdjustMessage("Magnetometer Calibration\n** Step 4: Please Look Right **"); + yaw -= FirstMagYaw; + if (yaw.Get() < -60.0f*dtr) + { + MagCal.InsertIfAcceptable(hmdOrient, mag); + ManualMagFailures++; + if (MagCal.NumberOfSamples() == 4) + ManualMagCalStage = 6; + else + { + if (ManualMagFailures > timeout) + { + ManualMagCalStage = 4; + ManualMagFailures = 0; + } + } + } + break; + case 4: + SetAdjustMessage("Magnetometer Calibration\n** Step 5: Please Look Upper Right **"); + yaw -= FirstMagYaw; + if ((yaw.Get() < -50.0f*dtr) && (pitch > 40.0f*dtr)) + { + MagCal.InsertIfAcceptable(hmdOrient, mag); + if (MagCal.NumberOfSamples() == 4) + ManualMagCalStage = 6; + else + { + if (ManualMagFailures > timeout) + { + ManualMagCalStage = 5; + ManualMagFailures = 0; + } + else + ManualMagFailures++; + } + } + break; + case 5: + SetAdjustMessage("Calibration Failed\n** Try Again From Another Location **"); + MagCal.AbortCalibration(); + break; + case 6: + if (!MagCal.IsCalibrated()) + { + MagCal.SetCalibration(SFusion); + SFusion.SetYawCorrectionEnabled(true); + Vector3f mc = MagCal.GetMagCenter(); + SetAdjustMessage(" Magnetometer Calibration and Activation \nCenter: %f %f %f", + mc.x,mc.y,mc.z); + } + } +} + + + +static const char* HelpText = + "F1 \t100 NoStereo \t420 Z \t520 Manual Mag Calib\n" + "F2 \t100 Stereo \t420 X \t520 Auto Mag Calib\n" + "F3 \t100 StereoHMD \t420 ; \t520 Mag Set Ref Point\n" + "F4 \t100 MSAA \t420 F6 \t520 Mag Info\n" + "F9 \t100 FullScreen \t420 R \t520 Reset SensorFusion\n" + "F11 \t100 Fast FullScreen \t500 - + \t660 Adj EyeHeight\n" + "C \t100 Chromatic Ab \t500 [ ] \t660 Adj FOV\n" + "P \t100 Motion Pred \t500 Shift \t660 Adj Faster\n" + "N/M \t180 Adj Motion Pred\n" + "( / ) \t180 Adj EyeDistance" + ; + + +enum DrawTextCenterType +{ + DrawText_NoCenter= 0, + DrawText_VCenter = 0x1, + DrawText_HCenter = 0x2, + DrawText_Center = DrawText_VCenter | DrawText_HCenter +}; + +static void DrawTextBox(RenderDevice* prender, float x, float y, + float textSize, const char* text, + DrawTextCenterType centerType = DrawText_NoCenter) +{ + float ssize[2] = {0.0f, 0.0f}; + + prender->MeasureText(&DejaVu, text, textSize, ssize); + + // Treat 0 a VCenter. + if (centerType & DrawText_HCenter) + { + x = -ssize[0]/2; + } + if (centerType & DrawText_VCenter) + { + y = -ssize[1]/2; + } + + prender->FillRect(x-0.02f, y-0.02f, x+ssize[0]+0.02f, y+ssize[1]+0.02f, Color(40,40,100,210)); + prender->RenderText(&DejaVu, text, x, y, textSize, Color(255,255,0,210)); +} + +void OculusWorldDemoApp::Render(const StereoEyeParams& stereo) +{ + pRender->BeginScene(PostProcess); + + // *** 3D - Configures Viewport/Projection and Render + pRender->ApplyStereoParams(stereo); + pRender->Clear(); + + pRender->SetDepthMode(true, true); + if (SceneMode != Scene_Grid) + { + MainScene.Render(pRender, stereo.ViewAdjust * View); + } + + if (SceneMode == Scene_YawView) + { + Matrix4f calView = Matrix4f(); + float viewYaw = -ThePlayer.LastSensorYaw + SFusion.GetMagRefYaw(); + calView.M[0][0] = calView.M[2][2] = cos(viewYaw); + calView.M[0][2] = sin(viewYaw); + calView.M[2][0] = -sin(viewYaw); + //LogText("yaw: %f\n",SFusion.GetMagRefYaw()); + + if (SFusion.IsYawCorrectionInProgress()) + YawMarkGreenScene.Render(pRender, stereo.ViewAdjust); + else + YawMarkRedScene.Render(pRender, stereo.ViewAdjust); + + if (fabs(ThePlayer.EyePitch) < Math<float>::Pi * 0.33) + YawLinesScene.Render(pRender, stereo.ViewAdjust * calView); + } + + // *** 2D Text & Grid - Configure Orthographic rendering. + + // Render UI in 2D orthographic coordinate system that maps [-1,1] range + // to a readable FOV area centered at your eye and properly adjusted. + pRender->ApplyStereoParams2D(stereo); + pRender->SetDepthMode(false, false); + + float unitPixel = SConfig.Get2DUnitPixel(); + float textHeight= unitPixel * 22; + + if ((SceneMode == Scene_Grid)||(SceneMode == Scene_Both)) + { // Draw grid two pixels thick. + GridScene.Render(pRender, Matrix4f()); + GridScene.Render(pRender, Matrix4f::Translation(unitPixel,unitPixel,0)); + } + + // Display Loading screen-shot in frame 0. + if (LoadingState != LoadingState_Finished) + { + LoadingScene.Render(pRender, Matrix4f()); + String loadMessage = String("Loading ") + MainFilePath; + DrawTextBox(pRender, 0.0f, 0.25f, textHeight, loadMessage.ToCStr(), DrawText_HCenter); + LoadingState = LoadingState_DoLoad; + } + + if(!AdjustMessage.IsEmpty() && AdjustMessageTimeout > pPlatform->GetAppTime()) + { + DrawTextBox(pRender,0.0f,0.4f, textHeight, AdjustMessage.ToCStr(), DrawText_HCenter); + } + + switch(TextScreen) + { + case Text_Orientation: + { + char buf[256], gpustat[256]; + OVR_sprintf(buf, sizeof(buf), + " Yaw:%4.0f Pitch:%4.0f Roll:%4.0f \n" + " FPS: %d Frame: %d \n Pos: %3.2f, %3.2f, %3.2f \n" + " EyeHeight: %3.2f", + RadToDegree(ThePlayer.EyeYaw), RadToDegree(ThePlayer.EyePitch), RadToDegree(ThePlayer.EyeRoll), + FPS, FrameCounter, ThePlayer.EyePos.x, ThePlayer.EyePos.y, ThePlayer.EyePos.z, ThePlayer.EyePos.y); + size_t texMemInMB = pRender->GetTotalTextureMemoryUsage() / 1058576; + if (texMemInMB) + { + OVR_sprintf(gpustat, sizeof(gpustat), "\n GPU Tex: %u MB", texMemInMB); + OVR_strcat(buf, sizeof(buf), gpustat); + } + + DrawTextBox(pRender, 0.0f, -0.15f, textHeight, buf, DrawText_HCenter); + } + break; + + case Text_Config: + { + char textBuff[2048]; + + OVR_sprintf(textBuff, sizeof(textBuff), + "Fov\t300 %9.4f\n" + "EyeDistance\t300 %9.4f\n" + "DistortionK0\t300 %9.4f\n" + "DistortionK1\t300 %9.4f\n" + "DistortionK2\t300 %9.4f\n" + "DistortionK3\t300 %9.4f\n" + "TexScale\t300 %9.4f", + SConfig.GetYFOVDegrees(), + SConfig.GetIPD(), + SConfig.GetDistortionK(0), + SConfig.GetDistortionK(1), + SConfig.GetDistortionK(2), + SConfig.GetDistortionK(3), + SConfig.GetDistortionScale()); + + DrawTextBox(pRender, 0.0f, 0.0f, textHeight, textBuff, DrawText_Center); + } + break; + + case Text_Help: + DrawTextBox(pRender, 0.0f, -0.1f, textHeight, HelpText, DrawText_Center); + + default: + break; + } + + + // Display colored quad if we're doing a latency test. + Color colorToDisplay; + if (LatencyUtil.DisplayScreenColor(colorToDisplay)) + { + pRender->FillRect(-0.4f, -0.4f, 0.4f, 0.4f, colorToDisplay); + } + + pRender->FinishScene(); +} + + +// Sets temporarily displayed message for adjustments +void OculusWorldDemoApp::SetAdjustMessage(const char* format, ...) +{ + Lock::Locker lock(pManager->GetHandlerLock()); + char textBuff[2048]; + va_list argList; + va_start(argList, format); + OVR_vsprintf(textBuff, sizeof(textBuff), format, argList); + va_end(argList); + + // Message will time out in 4 seconds. + AdjustMessage = textBuff; + AdjustMessageTimeout = pPlatform->GetAppTime() + 4.0f; +} + +void OculusWorldDemoApp::SetAdjustMessageTimeout(float timeout) +{ + AdjustMessageTimeout = pPlatform->GetAppTime() + timeout; +} + +// ***** View Control Adjustments + +void OculusWorldDemoApp::AdjustFov(float dt) +{ + float esd = SConfig.GetEyeToScreenDistance() + 0.01f * dt; + SConfig.SetEyeToScreenDistance(esd); + SetAdjustMessage("ESD:%6.3f FOV: %6.3f", esd, SConfig.GetYFOVDegrees()); +} + +void OculusWorldDemoApp::AdjustAspect(float dt) +{ + float rawAspect = SConfig.GetAspect() / SConfig.GetAspectMultiplier(); + float newAspect = SConfig.GetAspect() + 0.01f * dt; + SConfig.SetAspectMultiplier(newAspect / rawAspect); + SetAdjustMessage("Aspect: %6.3f", newAspect); +} + +void OculusWorldDemoApp::AdjustDistortion(float dt, int kIndex, const char* label) +{ + SConfig.SetDistortionK(kIndex, SConfig.GetDistortionK(kIndex) + 0.03f * dt); + SetAdjustMessage("%s: %6.4f", label, SConfig.GetDistortionK(kIndex)); +} + +void OculusWorldDemoApp::AdjustIPD(float dt) +{ + SConfig.SetIPD(SConfig.GetIPD() + 0.025f * dt); + SetAdjustMessage("EyeDistance: %6.4f", SConfig.GetIPD()); +} + +void OculusWorldDemoApp::AdjustEyeHeight(float dt) +{ + float dist = 0.5f * dt; + + ThePlayer.EyeHeight += dist; + ThePlayer.EyePos.y += dist; + + SetAdjustMessage("EyeHeight: %4.2f", ThePlayer.EyeHeight); +} + +void OculusWorldDemoApp::AdjustMotionPrediction(float dt) +{ + float motionPred = SFusion.GetPredictionDelta() + 0.01f * dt; + + if (motionPred < 0.0f) + { + motionPred = 0.0f; + } + + SFusion.SetPrediction(motionPred); + + SetAdjustMessage("MotionPrediction: %6.3fs", motionPred); +} + + +// Loads the scene data +void OculusWorldDemoApp::PopulateScene(const char *fileName) +{ + XmlHandler xmlHandler; + if(!xmlHandler.ReadFile(fileName, pRender, &MainScene, &CollisionModels, &GroundCollisionModels)) + { + SetAdjustMessage("---------------------------------\nFILE LOAD FAILED\n---------------------------------"); + SetAdjustMessageTimeout(10.0f); + } + + MainScene.SetAmbient(Vector4f(1.0f, 1.0f, 1.0f, 1.0f)); + + // Distortion debug grid (brought up by 'G' key). + Ptr<Model> gridModel = *Model::CreateGrid(Vector3f(0,0,0), Vector3f(1.0f/10, 0,0), Vector3f(0,1.0f/10,0), + 10, 10, 5, + Color(0, 255, 0, 255), Color(255, 50, 50, 255) ); + GridScene.World.Add(gridModel); + + // Yaw angle marker and lines (brought up by ';' key). + float shifty = -0.5f; + Ptr<Model> yawMarkGreenModel = *Model::CreateBox(Color(0, 255, 0, 255), Vector3f(0.0f, shifty, -2.0f), Vector3f(0.05f, 0.05f, 0.05f)); + YawMarkGreenScene.World.Add(yawMarkGreenModel); + Ptr<Model> yawMarkRedModel = *Model::CreateBox(Color(255, 0, 0, 255), Vector3f(0.0f, shifty, -2.0f), Vector3f(0.05f, 0.05f, 0.05f)); + YawMarkRedScene.World.Add(yawMarkRedModel); + + Ptr<Model> yawLinesModel = *new Model(Prim_Lines); + float r = 2.0f; + float theta0 = Math<float>::PiOver2; + float theta1 = 0.0f; + Color c = Color(255, 200, 200, 255); + for (int i = 0; i < 35; i++) + { + theta1 = theta0 + Math<float>::Pi / 18.0f; + yawLinesModel->AddLine(yawLinesModel->AddVertex(Vector3f(r*cos(theta0),shifty,-r*sin(theta0)),c), + yawLinesModel->AddVertex(Vector3f(r*cos(theta1),shifty,-r*sin(theta1)),c)); + theta0 = theta1; + yawLinesModel->AddLine(yawLinesModel->AddVertex(Vector3f(r*cos(theta0),shifty,-r*sin(theta0)),c), + yawLinesModel->AddVertex(Vector3f(r*cos(theta0),shifty+0.1f,-r*sin(theta0)),c)); + theta0 = theta1; + } + theta1 = theta0 + Math<float>::Pi / 18.0f; + yawLinesModel->AddLine(yawLinesModel->AddVertex(Vector3f(r*cos(theta0),shifty,-r*sin(theta0)),c), + yawLinesModel->AddVertex(Vector3f(r*cos(theta1),shifty,-r*sin(theta1)),c)); + yawLinesModel->AddLine(yawLinesModel->AddVertex(Vector3f(0.0f,shifty+0.1f,-r),c), + yawLinesModel->AddVertex(Vector3f(r*sin(0.02f),shifty,-r*cos(0.02f)),c)); + yawLinesModel->AddLine(yawLinesModel->AddVertex(Vector3f(0.0f,shifty+0.1f,-r),c), + yawLinesModel->AddVertex(Vector3f(r*sin(-0.02f),shifty,-r*cos(-0.02f)),c)); + yawLinesModel->SetPosition(Vector3f(0.0f,0.0f,0.0f)); + + YawLinesScene.World.Add(yawLinesModel); +} + + +void OculusWorldDemoApp::PopulatePreloadScene() +{ + // Load-screen screen shot image + String fileName = MainFilePath; + fileName.StripExtension(); + + Ptr<File> imageFile = *new SysFile(fileName + "_LoadScreen.tga"); + Ptr<Texture> imageTex; + if (imageFile->IsValid()) + imageTex = *LoadTextureTga(pRender, imageFile); + + // Image is rendered as a single quad. + if (imageTex) + { + imageTex->SetSampleMode(Sample_Anisotropic|Sample_Repeat); + Ptr<Model> m = *new Model(Prim_Triangles); + m->AddVertex(-0.5f, 0.5f, 0.0f, Color(255,255,255,255), 0.0f, 0.0f); + m->AddVertex( 0.5f, 0.5f, 0.0f, Color(255,255,255,255), 1.0f, 0.0f); + m->AddVertex( 0.5f, -0.5f, 0.0f, Color(255,255,255,255), 1.0f, 1.0f); + m->AddVertex(-0.5f, -0.5f, 0.0f, Color(255,255,255,255), 0.0f, 1.0f); + m->AddTriangle(2,1,0); + m->AddTriangle(0,3,2); + + Ptr<ShaderFill> fill = *new ShaderFill(*pRender->CreateShaderSet()); + fill->GetShaders()->SetShader(pRender->LoadBuiltinShader(Shader_Vertex, VShader_MVP)); + fill->GetShaders()->SetShader(pRender->LoadBuiltinShader(Shader_Fragment, FShader_Texture)); + fill->SetTexture(0, imageTex); + m->Fill = fill; + + LoadingScene.World.Add(m); + } +} + +void OculusWorldDemoApp::ClearScene() +{ + MainScene.Clear(); + GridScene.Clear(); + YawMarkGreenScene.Clear(); + YawMarkRedScene.Clear(); + YawLinesScene.Clear(); +} + +void OculusWorldDemoApp::PopulateLODFileNames() +{ + //OVR::String mainFilePath = MainFilePath; + LODFilePaths.PushBack(MainFilePath); + int LODIndex = 1; + SPInt pos = strcspn(MainFilePath.ToCStr(), "."); + SPInt len = strlen(MainFilePath.ToCStr()); + SPInt diff = len - pos; + + if (diff == 0) + return; + + while(true) + { + char pathWithoutExt[250]; + char buffer[250]; + for(SPInt i = 0; i < pos; ++i) + { + pathWithoutExt[i] = MainFilePath[(int)i]; + } + pathWithoutExt[pos] = '\0'; + OVR_sprintf(buffer, sizeof(buffer), "%s%i.xml", pathWithoutExt, LODIndex); + FILE* fp = 0; +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) + errno_t err = fopen_s(&fp, buffer, "rb"); + if(!fp || err) + { +#else + fp = fopen(buffer, "rb"); + if(!fp) + { +#endif + break; + } + fclose(fp); + OVR::String result = buffer; + LODFilePaths.PushBack(result); + LODIndex++; + } +} + +void OculusWorldDemoApp::DropLOD() +{ + if(CurrentLODFileIndex < (int)(LODFilePaths.GetSize() - 1)) + { + ClearScene(); + CurrentLODFileIndex++; + PopulateScene(LODFilePaths[CurrentLODFileIndex].ToCStr()); + } +} + +void OculusWorldDemoApp::RaiseLOD() +{ + if(CurrentLODFileIndex > 0) + { + ClearScene(); + CurrentLODFileIndex--; + PopulateScene(LODFilePaths[CurrentLODFileIndex].ToCStr()); + } +} + +//----------------------------------------------------------------------------- +void OculusWorldDemoApp::CycleDisplay() +{ + int screenCount = pPlatform->GetDisplayCount(); + + // If Windowed, switch to the HMD screen first in Full-Screen Mode. + // If already Full-Screen, cycle to next screen until we reach FirstScreenInCycle. + + if (pRender->IsFullscreen()) + { + // Right now, we always need to restore window before going to next screen. + pPlatform->SetFullscreen(RenderParams, Display_Window); + + Screen++; + if (Screen == screenCount) + Screen = 0; + + RenderParams.Display = pPlatform->GetDisplay(Screen); + + if (Screen != FirstScreenInCycle) + { + pRender->SetParams(RenderParams); + pPlatform->SetFullscreen(RenderParams, Display_Fullscreen); + } + } + else + { + // Try to find HMD Screen, making it the first screen in full-screen Cycle. + FirstScreenInCycle = 0; + + if (pHMD) + { + DisplayId HMD (SConfig.GetHMDInfo().DisplayDeviceName, SConfig.GetHMDInfo().DisplayId); + for (int i = 0; i< screenCount; i++) + { + if (pPlatform->GetDisplay(i) == HMD) + { + FirstScreenInCycle = i; + break; + } + } + } + + // Switch full-screen on the HMD. + Screen = FirstScreenInCycle; + RenderParams.Display = pPlatform->GetDisplay(Screen); + pRender->SetParams(RenderParams); + pPlatform->SetFullscreen(RenderParams, Display_Fullscreen); + } +} + +void OculusWorldDemoApp::GamepadStateChanged(const GamepadState& pad) +{ + ThePlayer.GamepadMove = Vector3f(pad.LX * pad.LX * (pad.LX > 0 ? 1 : -1), + 0, + pad.LY * pad.LY * (pad.LY > 0 ? -1 : 1)); + ThePlayer.GamepadRotate = Vector3f(2 * pad.RX, -2 * pad.RY, 0); +} + + +//------------------------------------------------------------------------------------- + +OVR_PLATFORM_APP(OculusWorldDemoApp); |