aboutsummaryrefslogtreecommitdiffstats
path: root/support/hololens/ServoApp/ImmersiveView.cpp
blob: 9babc2722992338841923dde062b2af2204f4125 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/* 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();
  }
}