servo/support/hololens/ServoApp/ImmersiveView.cpp

236 lines
8 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "pch.h"
#include "logs.h"
#include "ImmersiveView.h"
#include "ImmersiveMain.h"
using namespace winrt::ServoApp;
using namespace concurrency;
using namespace std::placeholders;
using namespace winrt::Windows::ApplicationModel;
using namespace winrt::Windows::ApplicationModel::Activation;
using namespace winrt::Windows::ApplicationModel::Core;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Graphics::Holographic;
using namespace winrt::Windows::UI::Core;
// Immediatly start immersive mode:
// int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
//{
// winrt::init_apartment();
// CoreApplication::Run(ImmersiveViewSource());
// return 0;
//}
// IFrameworkViewSource methods
IFrameworkView ImmersiveViewSource::CreateView() { return holographicView; }
// IFrameworkView methods
// The first method called when the IFrameworkView is being created.
// Use this method to subscribe for Windows shell events and to initialize your
// app.
void ImmersiveView::Initialize(CoreApplicationView const &applicationView) {
applicationView.Activated(
std::bind(&ImmersiveView::OnViewActivated, this, _1, _2));
// Register event handlers for app lifecycle.
m_suspendingEventToken = CoreApplication::Suspending(
bind(&ImmersiveView::OnSuspending, this, _1, _2));
m_resumingEventToken =
CoreApplication::Resuming(bind(&ImmersiveView::OnResuming, this, _1, _2));
// At this point we have access to the device and we can create
// device-dependent resources.
m_deviceResources = std::make_shared<DX::DeviceResources>();
m_main = std::make_unique<Immersive::ImmersiveMain>(m_deviceResources);
}
// Called when the CoreWindow object is created (or re-created).
void ImmersiveView::SetWindow(CoreWindow const &window) {
if (m_main == nullptr) {
winrt::hstring message(L"main program not intialized.\n");
OutputDebugStringW(message.data());
return;
}
// Register for keypress notifications.
m_keyDownEventToken =
window.KeyDown(bind(&ImmersiveView::OnKeyPressed, this, _1, _2));
// Register for pointer pressed notifications.
m_pointerPressedEventToken = window.PointerPressed(
bind(&ImmersiveView::OnPointerPressed, this, _1, _2));
// Register for notification that the app window is being closed.
m_windowClosedEventToken =
window.Closed(bind(&ImmersiveView::OnWindowClosed, this, _1, _2));
// Register for notifications that the app window is losing focus.
m_visibilityChangedEventToken = window.VisibilityChanged(
bind(&ImmersiveView::OnVisibilityChanged, this, _1, _2));
// Create a holographic space for the core window for the current view.
// Presenting holographic frames that are created by this holographic space
// will put the app into exclusive mode.
m_holographicSpace = HolographicSpace::CreateForCoreWindow(window);
// The DeviceResources class uses the preferred DXGI adapter ID from the
// holographic space (when available) to create a Direct3D device. The
// HolographicSpace uses this ID3D11Device to create and manage device-based
// resources such as swap chains.
m_deviceResources->SetHolographicSpace(m_holographicSpace);
// The main class uses the holographic space for updates and rendering.
m_main->SetHolographicSpace(m_holographicSpace);
}
// The Load method can be used to initialize scene resources or to load a
// previously saved app state.
void ImmersiveView::Load(winrt::hstring const &) {}
// This method is called after the window becomes active. It oversees the
// update, draw, and present loop, and it also oversees window message
// processing.
void ImmersiveView::Run() {
if (m_main == nullptr) {
winrt::hstring message(L"main program not intialized.\n");
OutputDebugStringW(message.data());
return;
}
CoreWindow::GetForCurrentThread().Activate();
while (!m_windowClosed) {
if (m_windowVisible && (m_holographicSpace != nullptr)) {
CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(
CoreProcessEventsOption::ProcessAllIfPresent);
HolographicFrame holographicFrame = m_main->Update();
if (m_main->Render(holographicFrame)) {
// The holographic frame has an API that presents the swap chain for
// each holographic camera.
m_deviceResources->Present(holographicFrame);
}
} else {
CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(
CoreProcessEventsOption::ProcessOneAndAllPending);
}
}
}
// Terminate events do not cause Uninitialize to be called. It will be called if
// your IFrameworkView class is torn down while the app is in the foreground,
// for example if the Run method exits.
void ImmersiveView::Uninitialize() {
m_main.reset();
m_deviceResources.reset();
CoreApplication::Suspending(m_suspendingEventToken);
CoreApplication::Resuming(m_resumingEventToken);
auto const &window = CoreWindow::GetForCurrentThread();
window.KeyDown(m_keyDownEventToken);
window.PointerPressed(m_pointerPressedEventToken);
window.Closed(m_windowClosedEventToken);
window.VisibilityChanged(m_visibilityChangedEventToken);
}
// Application lifecycle event handlers
// Called when the app is prelaunched. Use this method to load resources ahead
// of time and enable faster launch times.
void ImmersiveView::OnLaunched(LaunchActivatedEventArgs const &args) {
if (args.PrelaunchActivated()) {
//
// TODO: Insert code to preload resources here.
//
}
}
// Called when the app view is activated. Activates the app's CoreWindow.
void ImmersiveView::OnViewActivated(CoreApplicationView const &sender,
IActivatedEventArgs const &) {
// Run() won't start until the CoreWindow is activated.
sender.CoreWindow().Activate();
}
void ImmersiveView::OnSuspending(
winrt::Windows::Foundation::IInspectable const &,
SuspendingEventArgs const &args) {
// Save app state asynchronously after requesting a deferral. Holding a
// deferral indicates that the application is busy performing suspending
// operations. Be aware that a deferral may not be held indefinitely; after
// about five seconds, the app will be forced to exit.
SuspendingDeferral deferral = args.SuspendingOperation().GetDeferral();
create_task([this, deferral]() {
m_deviceResources->Trim();
if (m_main != nullptr) {
m_main->SaveAppState();
}
//
// TODO: Insert code here to save your app state.
//
deferral.Complete();
});
}
void ImmersiveView::OnResuming(
winrt::Windows::Foundation::IInspectable const &,
winrt::Windows::Foundation::IInspectable const &) {
// Restore any data or state that was unloaded on suspend. By default, data
// and state are persisted when resuming from suspend. Note that this event
// does not occur if the app was previously terminated.
if (m_main != nullptr) {
m_main->LoadAppState();
}
//
// TODO: Insert code here to load your app state.
//
}
// Window event handlers
void ImmersiveView::OnVisibilityChanged(
CoreWindow const &, VisibilityChangedEventArgs const &args) {
m_windowVisible = args.Visible();
}
void ImmersiveView::OnWindowClosed(CoreWindow const &,
CoreWindowEventArgs const &) {
m_windowClosed = true;
}
// Input event handlers
void ImmersiveView::OnKeyPressed(CoreWindow const &, KeyEventArgs const &) {
//
// TODO: Bluetooth keyboards are supported by HoloLens. You can use this
// method for
// keyboard input if you want to support it as an optional input method
// for your holographic app.
//
}
void ImmersiveView::OnPointerPressed(CoreWindow const &,
PointerEventArgs const &) {
// Allow the user to interact with the holographic world using the mouse.
if (m_main != nullptr) {
m_main->OnPointerPressed();
}
}