diff options
author | Brad Davis <[email protected]> | 2013-07-03 10:28:24 -0700 |
---|---|---|
committer | Brad Davis <[email protected]> | 2013-07-03 10:28:24 -0700 |
commit | b71a796bd6efc9fffd78045025eabd4b276adc69 (patch) | |
tree | dec98b43ce0b59b0eb4a778ac7c6c516007524fe /Samples/OculusRoomTiny/Win32_OculusRoomTiny.cpp | |
parent | d46694c91c2bec4eb1e282c0c0101e6dab26e082 (diff) |
Fixed crlf issue
Diffstat (limited to 'Samples/OculusRoomTiny/Win32_OculusRoomTiny.cpp')
-rw-r--r-- | Samples/OculusRoomTiny/Win32_OculusRoomTiny.cpp | 1424 |
1 files changed, 712 insertions, 712 deletions
diff --git a/Samples/OculusRoomTiny/Win32_OculusRoomTiny.cpp b/Samples/OculusRoomTiny/Win32_OculusRoomTiny.cpp index 2e6dd3e..c27723f 100644 --- a/Samples/OculusRoomTiny/Win32_OculusRoomTiny.cpp +++ b/Samples/OculusRoomTiny/Win32_OculusRoomTiny.cpp @@ -1,712 +1,712 @@ -/************************************************************************************
-
-Filename : Win32_OculusRoomTiny.cpp
-Content : First-person view test application for Oculus Rift
-Created : October 4, 2012
-Authors : Michael Antonov, Andrew Reisse
-
-Copyright : Copyright 2012 Oculus, 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 "Win32_OculusRoomTiny.h"
-#include "RenderTiny_D3D1X_Device.h"
-
-//-------------------------------------------------------------------------------------
-// ***** OculusRoomTiny Class
-
-// Static pApp simplifies routing the window function.
-OculusRoomTinyApp* OculusRoomTinyApp::pApp = 0;
-
-
-OculusRoomTinyApp::OculusRoomTinyApp(HINSTANCE hinst)
- : pRender(0),
- LastUpdate(0),
-
- // Win32
- hWnd(NULL),
- hInstance(hinst), Quit(0), MouseCaptured(true),
- hXInputModule(0), pXInputGetState(0),
-
- // Initial location
- EyePos(0.0f, 1.6f, -5.0f),
- EyeYaw(YawInitial), EyePitch(0), EyeRoll(0),
- LastSensorYaw(0),
- SConfig(),
- PostProcess(PostProcess_Distortion),
- ShiftDown(false),
- ControlDown(false)
-{
- pApp = this;
-
- Width = 1280;
- Height = 800;
-
- StartupTicks = OVR::Timer::GetTicks();
- LastPadPacketNo = 0;
-
- MoveForward = MoveBack = MoveLeft = MoveRight = 0;
- GamepadMove = Vector3f(0);
- GamepadRotate = Vector3f(0);
-}
-
-OculusRoomTinyApp::~OculusRoomTinyApp()
-{
- RemoveHandlerFromDevices();
- pSensor.Clear();
- pHMD.Clear();
- destroyWindow();
- pApp = 0;
-}
-
-
-int OculusRoomTinyApp::OnStartup(const char* args)
-{
- OVR_UNUSED(args);
-
-
- // *** 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);
-
-
- int detectionResult = IDCONTINUE;
- const char* detectionMessage;
-
- do
- {
- // Release Sensor/HMD in case this is a retry.
- pSensor.Clear();
- pHMD.Clear();
- RenderParams.MonitorName.Clear();
-
- 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 = HMDInfo.DisplayDeviceName;
- RenderParams.DisplayId = HMDInfo.DisplayId;
- 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();
- }
-
-
- // If there was a problem detecting the Rift, display appropriate message.
- detectionResult = IDCONTINUE;
-
- if (!pHMD && !pSensor)
- detectionMessage = "Oculus Rift not detected.";
- else if (!pHMD)
- detectionMessage = "Oculus Sensor detected; HMD Display not detected.";
- else if (!pSensor)
- detectionMessage = "Oculus HMD Display detected; Sensor not detected.";
- else if (HMDInfo.DisplayDeviceName[0] == '\0')
- detectionMessage = "Oculus Sensor detected; HMD display EDID not detected.";
- else
- detectionMessage = 0;
-
- if (detectionMessage)
- {
- String messageText(detectionMessage);
- messageText += "\n\n"
- "Press 'Try Again' to run retry detection.\n"
- "Press 'Continue' to run full-screen anyway.";
-
- detectionResult = ::MessageBoxA(0, messageText.ToCStr(), "Oculus Rift Detection",
- MB_CANCELTRYCONTINUE|MB_ICONWARNING);
-
- if (detectionResult == IDCANCEL)
- return 1;
- }
-
- } while (detectionResult != IDCONTINUE);
-
-
- if (HMDInfo.HResolution > 0)
- {
- Width = HMDInfo.HResolution;
- Height = HMDInfo.VResolution;
- }
-
-
- if (!setupWindow())
- return 1;
-
- 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
-
- // Enable multi-sampling by default.
- RenderParams.Multisample = 4;
- RenderParams.Fullscreen = true;
-
- // Setup Graphics.
- pRender = *RenderTiny::D3D10::RenderDevice::CreateDevice(RenderParams, (void*)hWnd);
- if (!pRender)
- return 1;
-
-
- // *** 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());
-
- SConfig.Set2DAreaFov(DegreeToRad(85.0f));
-
-
- // *** Populate Room Scene
-
- // This creates lights and models.
- PopulateRoomScene(&Scene, pRender);
-
-
- LastUpdate = GetAppTime();
- return 0;
-}
-
-void OculusRoomTinyApp::OnMessage(const Message& msg)
-{
- if (msg.Type == Message_DeviceAdded && msg.pDevice == pManager)
- {
- LogText("DeviceManager reported device added.\n");
- }
- else if (msg.Type == Message_DeviceRemoved && msg.pDevice == pManager)
- {
- LogText("DeviceManager reported device removed.\n");
- }
- else if (msg.Type == Message_DeviceAdded && msg.pDevice == pSensor)
- {
- LogText("Sensor reported device added.\n");
- }
- else if (msg.Type == Message_DeviceRemoved && msg.pDevice == pSensor)
- {
- LogText("Sensor reported device removed.\n");
- }
-}
-
-
-void OculusRoomTinyApp::OnGamepad(float padLx, float padLy, float padRx, float padRy)
-{
- GamepadMove = Vector3f(padLx * padLx * (padLx > 0 ? 1 : -1),
- 0,
- padLy * padLy * (padLy > 0 ? -1 : 1));
- GamepadRotate = Vector3f(2 * padRx, -2 * padRy, 0);
-}
-
-void OculusRoomTinyApp::OnMouseMove(int x, int y, int modifiers)
-{
- OVR_UNUSED(modifiers);
-
- // Mouse motion here is always relative.
- 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.
- EyeYaw -= (Sensitivity * dx)/ 360.0f;
-
- if (!pSensor)
- {
- EyePitch -= (Sensitivity * dy)/ 360.0f;
-
- if (EyePitch > maxPitch)
- EyePitch = maxPitch;
- if (EyePitch < -maxPitch)
- EyePitch = -maxPitch;
- }
-}
-
-void OculusRoomTinyApp::OnKey(unsigned vk, bool down)
-{
- switch (vk)
- {
- case 'Q':
- if (down && ControlDown)
- Quit = true;
- break;
- case VK_ESCAPE:
- if (!down)
- Quit = true;
- break;
-
- // Handle player movement keys.
- // We just update movement state here, while the actual translation is done in OnIdle()
- // based on time.
- case 'W': MoveForward = down ? (MoveForward | 1) : (MoveForward & ~1); break;
- case 'S': MoveBack = down ? (MoveBack | 1) : (MoveBack & ~1); break;
- case 'A': MoveLeft = down ? (MoveLeft | 1) : (MoveLeft & ~1); break;
- case 'D': MoveRight = down ? (MoveRight | 1) : (MoveRight & ~1); break;
- case VK_UP: MoveForward = down ? (MoveForward | 2) : (MoveForward & ~2); break;
- case VK_DOWN: MoveBack = down ? (MoveBack | 2) : (MoveBack & ~2); break;
-
- case 'R':
- SFusion.Reset();
- break;
-
- case 'P':
- if (down)
- {
- // Toggle chromatic aberration correction on/off.
- RenderDevice::PostProcessShader shader = pRender->GetPostProcessShader();
-
- if (shader == RenderDevice::PostProcessShader_Distortion)
- {
- pRender->SetPostProcessShader(RenderDevice::PostProcessShader_DistortionAndChromAb);
- }
- else if (shader == RenderDevice::PostProcessShader_DistortionAndChromAb)
- {
- pRender->SetPostProcessShader(RenderDevice::PostProcessShader_Distortion);
- }
- else
- OVR_ASSERT(false);
- }
- break;
-
- // Switch rendering modes/distortion.
- case VK_F1:
- SConfig.SetStereoMode(Stereo_None);
- PostProcess = PostProcess_None;
- break;
- case VK_F2:
- SConfig.SetStereoMode(Stereo_LeftRight_Multipass);
- PostProcess = PostProcess_None;
- break;
- case VK_F3:
- SConfig.SetStereoMode(Stereo_LeftRight_Multipass);
- PostProcess = PostProcess_Distortion;
- break;
-
- // Stereo IPD adjustments, in meter (default IPD is 64mm).
- case VK_OEM_PLUS:
- case VK_INSERT:
- if (down)
- SConfig.SetIPD(SConfig.GetIPD() + 0.0005f * (ShiftDown ? 5.0f : 1.0f));
- break;
- case VK_OEM_MINUS:
- case VK_DELETE:
- if (down)
- SConfig.SetIPD(SConfig.GetIPD() - 0.0005f * (ShiftDown ? 5.0f : 1.0f));
- break;
-
- // Holding down Shift key accelerates adjustment velocity.
- case VK_SHIFT:
- ShiftDown = down;
- break;
- case VK_CONTROL:
- ControlDown = down;
- break;
- }
-}
-
-
-void OculusRoomTinyApp::OnIdle()
-{
- double curtime = GetAppTime();
- float dt = float(curtime - LastUpdate);
- LastUpdate = curtime;
-
-
- // 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.GetOrientation();
- float yaw = 0.0f;
-
- hmdOrient.GetEulerAngles<Axis_Y, Axis_X, Axis_Z>(&yaw, &EyePitch, &EyeRoll);
-
- EyeYaw += (yaw - LastSensorYaw);
- LastSensorYaw = yaw;
- }
-
-
- // Gamepad rotation.
- EyeYaw -= GamepadRotate.x * dt;
-
- if (!pSensor)
- {
- // Allow gamepad to look up/down, but only if there is no Rift sensor.
- EyePitch -= GamepadRotate.y * dt;
-
- const float maxPitch = ((3.1415f/2)*0.98f);
- if (EyePitch > maxPitch)
- EyePitch = maxPitch;
- if (EyePitch < -maxPitch)
- EyePitch = -maxPitch;
- }
-
- // Handle keyboard movement.
- // This translates EyePos based on Yaw vector direction and keys pressed.
- // Note that Pitch and Roll do not affect movement (they only affect view).
- if (MoveForward || MoveBack || MoveLeft || MoveRight)
- {
- Vector3f localMoveVector(0,0,0);
- Matrix4f yawRotate = Matrix4f::RotationY(EyeYaw);
-
- if (MoveForward)
- localMoveVector = ForwardVector;
- else if (MoveBack)
- localMoveVector = -ForwardVector;
-
- if (MoveRight)
- localMoveVector += RightVector;
- else if (MoveLeft)
- localMoveVector -= RightVector;
-
- // Normalize vector so we don't move faster diagonally.
- localMoveVector.Normalize();
- Vector3f orientationVector = yawRotate.Transform(localMoveVector);
- orientationVector *= MoveSpeed * dt * (ShiftDown ? 3.0f : 1.0f);
-
- EyePos += orientationVector;
- }
-
- else if (GamepadMove.LengthSq() > 0)
- {
- Matrix4f yawRotate = Matrix4f::RotationY(EyeYaw);
- Vector3f orientationVector = yawRotate.Transform(GamepadMove);
- orientationVector *= MoveSpeed * dt;
- EyePos += orientationVector;
- }
-
-
- // Rotate and position View Camera, using YawPitchRoll in BodyFrame coordinates.
- //
- Matrix4f rollPitchYaw = Matrix4f::RotationY(EyeYaw) * Matrix4f::RotationX(EyePitch) *
- Matrix4f::RotationZ(EyeRoll);
- Vector3f up = rollPitchYaw.Transform(UpVector);
- Vector3f forward = rollPitchYaw.Transform(ForwardVector);
-
-
- // Minimal head modelling.
- 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 = EyePos + rollPitchYaw.Transform(eyeCenterInHeadFrame);
- shiftedEyePos.y -= eyeCenterInHeadFrame.y; // Bring the head back down to original height
-
- View = Matrix4f::LookAtRH(shiftedEyePos, shiftedEyePos + forward, up);
-
- // This is what transformation would be without head modeling.
- // View = Matrix4f::LookAtRH(EyePos, EyePos + forward, up);
-
- switch(SConfig.GetStereoMode())
- {
- case Stereo_None:
- Render(SConfig.GetEyeRenderParams(StereoEye_Center));
- break;
-
- case Stereo_LeftRight_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();
-}
-
-
-// Render the scene for one eye.
-void OculusRoomTinyApp::Render(const StereoEyeParams& stereo)
-{
- pRender->BeginScene(PostProcess);
-
- // Apply Viewport/Projection for the eye.
- pRender->ApplyStereoParams(stereo);
- pRender->Clear();
- pRender->SetDepthMode(true, true);
-
- Scene.Render(pRender, stereo.ViewAdjust * View);
-
- pRender->FinishScene();
-}
-
-
-//-------------------------------------------------------------------------------------
-// ***** Win32-Specific Logic
-
-bool OculusRoomTinyApp::setupWindow()
-{
-
- WNDCLASS wc;
- memset(&wc, 0, sizeof(wc));
- wc.lpszClassName = L"OVRAppWindow";
- wc.style = CS_OWNDC;
- wc.lpfnWndProc = systemWindowProc;
- wc.cbWndExtra = sizeof(OculusRoomTinyApp*);
- RegisterClass(&wc);
-
-
- RECT winSize = { 0, 0, Width, Height };
- AdjustWindowRect(&winSize, WS_POPUP, false);
- hWnd = CreateWindowA("OVRAppWindow", "OculusRoomTiny", WS_POPUP|WS_VISIBLE,
- HMDInfo.DesktopX, HMDInfo.DesktopY,
- winSize.right-winSize.left, winSize.bottom-winSize.top,
- NULL, NULL, hInstance, (LPVOID)this);
-
-
- // Initialize Window center in screen coordinates
- POINT center = { Width / 2, Height / 2 };
- ::ClientToScreen(hWnd, ¢er);
- WindowCenter = center;
-
-
- return (hWnd != NULL);
-}
-
-void OculusRoomTinyApp::destroyWindow()
-{
- pRender.Clear();
-
- if (hWnd)
- {
- // Release window resources.
- ::DestroyWindow(hWnd);
- UnregisterClass(L"OVRAppWindow", hInstance);
- hWnd = 0;
- Width = Height = 0;
- }
-}
-
-
-LRESULT CALLBACK OculusRoomTinyApp::systemWindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
-{
- if (msg == WM_NCCREATE)
- pApp->hWnd = hwnd;
- return pApp->windowProc(msg, wp, lp);
-}
-
-void OculusRoomTinyApp::giveUsFocus(bool setFocus)
-{
- if (setFocus)
- {
- ::SetCursorPos(WindowCenter.x, WindowCenter.y);
-
- MouseCaptured = true;
- ::SetCapture(hWnd);
- ::ShowCursor(FALSE);
-
- }
- else
- {
- MouseCaptured = false;
- ::ReleaseCapture();
- ::ShowCursor(TRUE);
- }
-}
-
-LRESULT OculusRoomTinyApp::windowProc(UINT msg, WPARAM wp, LPARAM lp)
-{
- switch (msg)
- {
- case WM_MOUSEMOVE:
- {
- if (MouseCaptured)
- {
- // Convert mouse motion to be relative (report the offset and re-center).
- POINT newPos = { LOWORD(lp), HIWORD(lp) };
- ::ClientToScreen(hWnd, &newPos);
- if ((newPos.x == WindowCenter.x) && (newPos.y == WindowCenter.y))
- break;
- ::SetCursorPos(WindowCenter.x, WindowCenter.y);
-
- LONG dx = newPos.x - WindowCenter.x;
- LONG dy = newPos.y - WindowCenter.y;
- pApp->OnMouseMove(dx, dy, 0);
- }
- }
- break;
-
- case WM_MOVE:
- {
- RECT r;
- GetClientRect(hWnd, &r);
- WindowCenter.x = r.right/2;
- WindowCenter.y = r.bottom/2;
- ::ClientToScreen(hWnd, &WindowCenter);
- }
- break;
-
- case WM_KEYDOWN:
- OnKey((unsigned)wp, true);
- break;
- case WM_KEYUP:
- OnKey((unsigned)wp, false);
- break;
-
- case WM_SETFOCUS:
- giveUsFocus(true);
- break;
-
- case WM_KILLFOCUS:
- giveUsFocus(false);
- break;
-
- case WM_CREATE:
- // Hack to position mouse in fullscreen window shortly after startup.
- SetTimer(hWnd, 0, 100, NULL);
- break;
-
- case WM_TIMER:
- KillTimer(hWnd, 0);
- giveUsFocus(true);
- break;
-
- case WM_QUIT:
- case WM_CLOSE:
- Quit = true;
- return 0;
- }
-
- return DefWindowProc(hWnd, msg, wp, lp);
-}
-
-static inline float GamepadStick(short in)
-{
- float v;
- if (abs(in) < 9000)
- return 0;
- else if (in > 9000)
- v = (float) in - 9000;
- else
- v = (float) in + 9000;
- return v / (32767 - 9000);
-}
-
-static inline float GamepadTrigger(BYTE in)
-{
- return (in < 30) ? 0.0f : (float(in-30) / 225);
-}
-
-
-int OculusRoomTinyApp::Run()
-{
- // Loop processing messages until Quit flag is set,
- // rendering game scene inside of OnIdle().
-
- while (!Quit)
- {
- MSG msg;
- if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- else
- {
- // Read game-pad.
- XINPUT_STATE xis;
-
- if (pXInputGetState && !pXInputGetState(0, &xis) &&
- (xis.dwPacketNumber != LastPadPacketNo))
- {
- OnGamepad(GamepadStick(xis.Gamepad.sThumbLX),
- GamepadStick(xis.Gamepad.sThumbLY),
- GamepadStick(xis.Gamepad.sThumbRX),
- GamepadStick(xis.Gamepad.sThumbRY));
- //pad.LT = GamepadTrigger(xis.Gamepad.bLeftTrigger);
- LastPadPacketNo = xis.dwPacketNumber;
- }
-
- pApp->OnIdle();
-
- // Keep sleeping when we're minimized.
- if (IsIconic(hWnd))
- Sleep(10);
- }
- }
-
- return 0;
-}
-
-
-//-------------------------------------------------------------------------------------
-// ***** Program Startup
-
-int WINAPI WinMain(HINSTANCE hinst, HINSTANCE, LPSTR inArgs, int)
-{
- int exitCode = 0;
-
- // Initializes LibOVR. This LogMask_All enables maximum logging.
- // Custom allocator can also be specified here.
- OVR::System::Init(OVR::Log::ConfigureDefaultLog(OVR::LogMask_All));
-
- // Scope to force application destructor before System::Destroy.
- {
- OculusRoomTinyApp app(hinst);
- //app.hInstance = hinst;
-
- exitCode = app.OnStartup(inArgs);
- if (!exitCode)
- {
- // Processes messages and calls OnIdle() to do rendering.
- exitCode = app.Run();
- }
- }
-
- // No OVR functions involving memory are allowed after this.
- OVR::System::Destroy();
-
- OVR_DEBUG_STATEMENT(_CrtDumpMemoryLeaks());
- return exitCode;
-}
+/************************************************************************************ + +Filename : Win32_OculusRoomTiny.cpp +Content : First-person view test application for Oculus Rift +Created : October 4, 2012 +Authors : Michael Antonov, Andrew Reisse + +Copyright : Copyright 2012 Oculus, 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 "Win32_OculusRoomTiny.h" +#include "RenderTiny_D3D1X_Device.h" + +//------------------------------------------------------------------------------------- +// ***** OculusRoomTiny Class + +// Static pApp simplifies routing the window function. +OculusRoomTinyApp* OculusRoomTinyApp::pApp = 0; + + +OculusRoomTinyApp::OculusRoomTinyApp(HINSTANCE hinst) + : pRender(0), + LastUpdate(0), + + // Win32 + hWnd(NULL), + hInstance(hinst), Quit(0), MouseCaptured(true), + hXInputModule(0), pXInputGetState(0), + + // Initial location + EyePos(0.0f, 1.6f, -5.0f), + EyeYaw(YawInitial), EyePitch(0), EyeRoll(0), + LastSensorYaw(0), + SConfig(), + PostProcess(PostProcess_Distortion), + ShiftDown(false), + ControlDown(false) +{ + pApp = this; + + Width = 1280; + Height = 800; + + StartupTicks = OVR::Timer::GetTicks(); + LastPadPacketNo = 0; + + MoveForward = MoveBack = MoveLeft = MoveRight = 0; + GamepadMove = Vector3f(0); + GamepadRotate = Vector3f(0); +} + +OculusRoomTinyApp::~OculusRoomTinyApp() +{ + RemoveHandlerFromDevices(); + pSensor.Clear(); + pHMD.Clear(); + destroyWindow(); + pApp = 0; +} + + +int OculusRoomTinyApp::OnStartup(const char* args) +{ + OVR_UNUSED(args); + + + // *** 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); + + + int detectionResult = IDCONTINUE; + const char* detectionMessage; + + do + { + // Release Sensor/HMD in case this is a retry. + pSensor.Clear(); + pHMD.Clear(); + RenderParams.MonitorName.Clear(); + + 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 = HMDInfo.DisplayDeviceName; + RenderParams.DisplayId = HMDInfo.DisplayId; + 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(); + } + + + // If there was a problem detecting the Rift, display appropriate message. + detectionResult = IDCONTINUE; + + if (!pHMD && !pSensor) + detectionMessage = "Oculus Rift not detected."; + else if (!pHMD) + detectionMessage = "Oculus Sensor detected; HMD Display not detected."; + else if (!pSensor) + detectionMessage = "Oculus HMD Display detected; Sensor not detected."; + else if (HMDInfo.DisplayDeviceName[0] == '\0') + detectionMessage = "Oculus Sensor detected; HMD display EDID not detected."; + else + detectionMessage = 0; + + if (detectionMessage) + { + String messageText(detectionMessage); + messageText += "\n\n" + "Press 'Try Again' to run retry detection.\n" + "Press 'Continue' to run full-screen anyway."; + + detectionResult = ::MessageBoxA(0, messageText.ToCStr(), "Oculus Rift Detection", + MB_CANCELTRYCONTINUE|MB_ICONWARNING); + + if (detectionResult == IDCANCEL) + return 1; + } + + } while (detectionResult != IDCONTINUE); + + + if (HMDInfo.HResolution > 0) + { + Width = HMDInfo.HResolution; + Height = HMDInfo.VResolution; + } + + + if (!setupWindow()) + return 1; + + 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 + + // Enable multi-sampling by default. + RenderParams.Multisample = 4; + RenderParams.Fullscreen = true; + + // Setup Graphics. + pRender = *RenderTiny::D3D10::RenderDevice::CreateDevice(RenderParams, (void*)hWnd); + if (!pRender) + return 1; + + + // *** 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()); + + SConfig.Set2DAreaFov(DegreeToRad(85.0f)); + + + // *** Populate Room Scene + + // This creates lights and models. + PopulateRoomScene(&Scene, pRender); + + + LastUpdate = GetAppTime(); + return 0; +} + +void OculusRoomTinyApp::OnMessage(const Message& msg) +{ + if (msg.Type == Message_DeviceAdded && msg.pDevice == pManager) + { + LogText("DeviceManager reported device added.\n"); + } + else if (msg.Type == Message_DeviceRemoved && msg.pDevice == pManager) + { + LogText("DeviceManager reported device removed.\n"); + } + else if (msg.Type == Message_DeviceAdded && msg.pDevice == pSensor) + { + LogText("Sensor reported device added.\n"); + } + else if (msg.Type == Message_DeviceRemoved && msg.pDevice == pSensor) + { + LogText("Sensor reported device removed.\n"); + } +} + + +void OculusRoomTinyApp::OnGamepad(float padLx, float padLy, float padRx, float padRy) +{ + GamepadMove = Vector3f(padLx * padLx * (padLx > 0 ? 1 : -1), + 0, + padLy * padLy * (padLy > 0 ? -1 : 1)); + GamepadRotate = Vector3f(2 * padRx, -2 * padRy, 0); +} + +void OculusRoomTinyApp::OnMouseMove(int x, int y, int modifiers) +{ + OVR_UNUSED(modifiers); + + // Mouse motion here is always relative. + 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. + EyeYaw -= (Sensitivity * dx)/ 360.0f; + + if (!pSensor) + { + EyePitch -= (Sensitivity * dy)/ 360.0f; + + if (EyePitch > maxPitch) + EyePitch = maxPitch; + if (EyePitch < -maxPitch) + EyePitch = -maxPitch; + } +} + +void OculusRoomTinyApp::OnKey(unsigned vk, bool down) +{ + switch (vk) + { + case 'Q': + if (down && ControlDown) + Quit = true; + break; + case VK_ESCAPE: + if (!down) + Quit = true; + break; + + // Handle player movement keys. + // We just update movement state here, while the actual translation is done in OnIdle() + // based on time. + case 'W': MoveForward = down ? (MoveForward | 1) : (MoveForward & ~1); break; + case 'S': MoveBack = down ? (MoveBack | 1) : (MoveBack & ~1); break; + case 'A': MoveLeft = down ? (MoveLeft | 1) : (MoveLeft & ~1); break; + case 'D': MoveRight = down ? (MoveRight | 1) : (MoveRight & ~1); break; + case VK_UP: MoveForward = down ? (MoveForward | 2) : (MoveForward & ~2); break; + case VK_DOWN: MoveBack = down ? (MoveBack | 2) : (MoveBack & ~2); break; + + case 'R': + SFusion.Reset(); + break; + + case 'P': + if (down) + { + // Toggle chromatic aberration correction on/off. + RenderDevice::PostProcessShader shader = pRender->GetPostProcessShader(); + + if (shader == RenderDevice::PostProcessShader_Distortion) + { + pRender->SetPostProcessShader(RenderDevice::PostProcessShader_DistortionAndChromAb); + } + else if (shader == RenderDevice::PostProcessShader_DistortionAndChromAb) + { + pRender->SetPostProcessShader(RenderDevice::PostProcessShader_Distortion); + } + else + OVR_ASSERT(false); + } + break; + + // Switch rendering modes/distortion. + case VK_F1: + SConfig.SetStereoMode(Stereo_None); + PostProcess = PostProcess_None; + break; + case VK_F2: + SConfig.SetStereoMode(Stereo_LeftRight_Multipass); + PostProcess = PostProcess_None; + break; + case VK_F3: + SConfig.SetStereoMode(Stereo_LeftRight_Multipass); + PostProcess = PostProcess_Distortion; + break; + + // Stereo IPD adjustments, in meter (default IPD is 64mm). + case VK_OEM_PLUS: + case VK_INSERT: + if (down) + SConfig.SetIPD(SConfig.GetIPD() + 0.0005f * (ShiftDown ? 5.0f : 1.0f)); + break; + case VK_OEM_MINUS: + case VK_DELETE: + if (down) + SConfig.SetIPD(SConfig.GetIPD() - 0.0005f * (ShiftDown ? 5.0f : 1.0f)); + break; + + // Holding down Shift key accelerates adjustment velocity. + case VK_SHIFT: + ShiftDown = down; + break; + case VK_CONTROL: + ControlDown = down; + break; + } +} + + +void OculusRoomTinyApp::OnIdle() +{ + double curtime = GetAppTime(); + float dt = float(curtime - LastUpdate); + LastUpdate = curtime; + + + // 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.GetOrientation(); + float yaw = 0.0f; + + hmdOrient.GetEulerAngles<Axis_Y, Axis_X, Axis_Z>(&yaw, &EyePitch, &EyeRoll); + + EyeYaw += (yaw - LastSensorYaw); + LastSensorYaw = yaw; + } + + + // Gamepad rotation. + EyeYaw -= GamepadRotate.x * dt; + + if (!pSensor) + { + // Allow gamepad to look up/down, but only if there is no Rift sensor. + EyePitch -= GamepadRotate.y * dt; + + const float maxPitch = ((3.1415f/2)*0.98f); + if (EyePitch > maxPitch) + EyePitch = maxPitch; + if (EyePitch < -maxPitch) + EyePitch = -maxPitch; + } + + // Handle keyboard movement. + // This translates EyePos based on Yaw vector direction and keys pressed. + // Note that Pitch and Roll do not affect movement (they only affect view). + if (MoveForward || MoveBack || MoveLeft || MoveRight) + { + Vector3f localMoveVector(0,0,0); + Matrix4f yawRotate = Matrix4f::RotationY(EyeYaw); + + if (MoveForward) + localMoveVector = ForwardVector; + else if (MoveBack) + localMoveVector = -ForwardVector; + + if (MoveRight) + localMoveVector += RightVector; + else if (MoveLeft) + localMoveVector -= RightVector; + + // Normalize vector so we don't move faster diagonally. + localMoveVector.Normalize(); + Vector3f orientationVector = yawRotate.Transform(localMoveVector); + orientationVector *= MoveSpeed * dt * (ShiftDown ? 3.0f : 1.0f); + + EyePos += orientationVector; + } + + else if (GamepadMove.LengthSq() > 0) + { + Matrix4f yawRotate = Matrix4f::RotationY(EyeYaw); + Vector3f orientationVector = yawRotate.Transform(GamepadMove); + orientationVector *= MoveSpeed * dt; + EyePos += orientationVector; + } + + + // Rotate and position View Camera, using YawPitchRoll in BodyFrame coordinates. + // + Matrix4f rollPitchYaw = Matrix4f::RotationY(EyeYaw) * Matrix4f::RotationX(EyePitch) * + Matrix4f::RotationZ(EyeRoll); + Vector3f up = rollPitchYaw.Transform(UpVector); + Vector3f forward = rollPitchYaw.Transform(ForwardVector); + + + // Minimal head modelling. + 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 = EyePos + rollPitchYaw.Transform(eyeCenterInHeadFrame); + shiftedEyePos.y -= eyeCenterInHeadFrame.y; // Bring the head back down to original height + + View = Matrix4f::LookAtRH(shiftedEyePos, shiftedEyePos + forward, up); + + // This is what transformation would be without head modeling. + // View = Matrix4f::LookAtRH(EyePos, EyePos + forward, up); + + switch(SConfig.GetStereoMode()) + { + case Stereo_None: + Render(SConfig.GetEyeRenderParams(StereoEye_Center)); + break; + + case Stereo_LeftRight_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(); +} + + +// Render the scene for one eye. +void OculusRoomTinyApp::Render(const StereoEyeParams& stereo) +{ + pRender->BeginScene(PostProcess); + + // Apply Viewport/Projection for the eye. + pRender->ApplyStereoParams(stereo); + pRender->Clear(); + pRender->SetDepthMode(true, true); + + Scene.Render(pRender, stereo.ViewAdjust * View); + + pRender->FinishScene(); +} + + +//------------------------------------------------------------------------------------- +// ***** Win32-Specific Logic + +bool OculusRoomTinyApp::setupWindow() +{ + + WNDCLASS wc; + memset(&wc, 0, sizeof(wc)); + wc.lpszClassName = L"OVRAppWindow"; + wc.style = CS_OWNDC; + wc.lpfnWndProc = systemWindowProc; + wc.cbWndExtra = sizeof(OculusRoomTinyApp*); + RegisterClass(&wc); + + + RECT winSize = { 0, 0, Width, Height }; + AdjustWindowRect(&winSize, WS_POPUP, false); + hWnd = CreateWindowA("OVRAppWindow", "OculusRoomTiny", WS_POPUP|WS_VISIBLE, + HMDInfo.DesktopX, HMDInfo.DesktopY, + winSize.right-winSize.left, winSize.bottom-winSize.top, + NULL, NULL, hInstance, (LPVOID)this); + + + // Initialize Window center in screen coordinates + POINT center = { Width / 2, Height / 2 }; + ::ClientToScreen(hWnd, ¢er); + WindowCenter = center; + + + return (hWnd != NULL); +} + +void OculusRoomTinyApp::destroyWindow() +{ + pRender.Clear(); + + if (hWnd) + { + // Release window resources. + ::DestroyWindow(hWnd); + UnregisterClass(L"OVRAppWindow", hInstance); + hWnd = 0; + Width = Height = 0; + } +} + + +LRESULT CALLBACK OculusRoomTinyApp::systemWindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + if (msg == WM_NCCREATE) + pApp->hWnd = hwnd; + return pApp->windowProc(msg, wp, lp); +} + +void OculusRoomTinyApp::giveUsFocus(bool setFocus) +{ + if (setFocus) + { + ::SetCursorPos(WindowCenter.x, WindowCenter.y); + + MouseCaptured = true; + ::SetCapture(hWnd); + ::ShowCursor(FALSE); + + } + else + { + MouseCaptured = false; + ::ReleaseCapture(); + ::ShowCursor(TRUE); + } +} + +LRESULT OculusRoomTinyApp::windowProc(UINT msg, WPARAM wp, LPARAM lp) +{ + switch (msg) + { + case WM_MOUSEMOVE: + { + if (MouseCaptured) + { + // Convert mouse motion to be relative (report the offset and re-center). + POINT newPos = { LOWORD(lp), HIWORD(lp) }; + ::ClientToScreen(hWnd, &newPos); + if ((newPos.x == WindowCenter.x) && (newPos.y == WindowCenter.y)) + break; + ::SetCursorPos(WindowCenter.x, WindowCenter.y); + + LONG dx = newPos.x - WindowCenter.x; + LONG dy = newPos.y - WindowCenter.y; + pApp->OnMouseMove(dx, dy, 0); + } + } + break; + + case WM_MOVE: + { + RECT r; + GetClientRect(hWnd, &r); + WindowCenter.x = r.right/2; + WindowCenter.y = r.bottom/2; + ::ClientToScreen(hWnd, &WindowCenter); + } + break; + + case WM_KEYDOWN: + OnKey((unsigned)wp, true); + break; + case WM_KEYUP: + OnKey((unsigned)wp, false); + break; + + case WM_SETFOCUS: + giveUsFocus(true); + break; + + case WM_KILLFOCUS: + giveUsFocus(false); + break; + + case WM_CREATE: + // Hack to position mouse in fullscreen window shortly after startup. + SetTimer(hWnd, 0, 100, NULL); + break; + + case WM_TIMER: + KillTimer(hWnd, 0); + giveUsFocus(true); + break; + + case WM_QUIT: + case WM_CLOSE: + Quit = true; + return 0; + } + + return DefWindowProc(hWnd, msg, wp, lp); +} + +static inline float GamepadStick(short in) +{ + float v; + if (abs(in) < 9000) + return 0; + else if (in > 9000) + v = (float) in - 9000; + else + v = (float) in + 9000; + return v / (32767 - 9000); +} + +static inline float GamepadTrigger(BYTE in) +{ + return (in < 30) ? 0.0f : (float(in-30) / 225); +} + + +int OculusRoomTinyApp::Run() +{ + // Loop processing messages until Quit flag is set, + // rendering game scene inside of OnIdle(). + + while (!Quit) + { + MSG msg; + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + { + // Read game-pad. + XINPUT_STATE xis; + + if (pXInputGetState && !pXInputGetState(0, &xis) && + (xis.dwPacketNumber != LastPadPacketNo)) + { + OnGamepad(GamepadStick(xis.Gamepad.sThumbLX), + GamepadStick(xis.Gamepad.sThumbLY), + GamepadStick(xis.Gamepad.sThumbRX), + GamepadStick(xis.Gamepad.sThumbRY)); + //pad.LT = GamepadTrigger(xis.Gamepad.bLeftTrigger); + LastPadPacketNo = xis.dwPacketNumber; + } + + pApp->OnIdle(); + + // Keep sleeping when we're minimized. + if (IsIconic(hWnd)) + Sleep(10); + } + } + + return 0; +} + + +//------------------------------------------------------------------------------------- +// ***** Program Startup + +int WINAPI WinMain(HINSTANCE hinst, HINSTANCE, LPSTR inArgs, int) +{ + int exitCode = 0; + + // Initializes LibOVR. This LogMask_All enables maximum logging. + // Custom allocator can also be specified here. + OVR::System::Init(OVR::Log::ConfigureDefaultLog(OVR::LogMask_All)); + + // Scope to force application destructor before System::Destroy. + { + OculusRoomTinyApp app(hinst); + //app.hInstance = hinst; + + exitCode = app.OnStartup(inArgs); + if (!exitCode) + { + // Processes messages and calls OnIdle() to do rendering. + exitCode = app.Run(); + } + } + + // No OVR functions involving memory are allowed after this. + OVR::System::Destroy(); + + OVR_DEBUG_STATEMENT(_CrtDumpMemoryLeaks()); + return exitCode; +} |