1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "device/vr/windows_mixed_reality/wrappers/wmr_wrapper_factories.h"
6 
7 #include <HolographicSpaceInterop.h>
8 #include <SpatialInteractionManagerInterop.h>
9 #include <windows.perception.h>
10 #include <windows.perception.spatial.h>
11 #include <wrl.h>
12 
13 #include "base/strings/string_util.h"
14 #include "base/win/core_winrt_util.h"
15 #include "base/win/scoped_hstring.h"
16 #include "device/vr/windows_mixed_reality/mixed_reality_statics.h"
17 #include "device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_space.h"
18 #include "device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.h"
19 #include "device/vr/windows_mixed_reality/wrappers/test/mock_wmr_origins.h"
20 #include "device/vr/windows_mixed_reality/wrappers/wmr_logging.h"
21 
22 namespace WFN = ABI::Windows::Foundation::Numerics;
23 using SpatialMovementRange =
24     ABI::Windows::Perception::Spatial::SpatialMovementRange;
25 using ABI::Windows::Foundation::IEventHandler;
26 using ABI::Windows::Foundation::IReference;
27 using ABI::Windows::Graphics::Holographic::IHolographicSpace;
28 using ABI::Windows::Perception::Spatial::ISpatialAnchor;
29 using ABI::Windows::Perception::Spatial::ISpatialAnchorStatics;
30 using ABI::Windows::Perception::Spatial::ISpatialCoordinateSystem;
31 using ABI::Windows::Perception::Spatial::ISpatialLocator;
32 using ABI::Windows::Perception::Spatial::
33     ISpatialLocatorAttachedFrameOfReference;
34 using ABI::Windows::Perception::Spatial::ISpatialLocatorStatics;
35 using ABI::Windows::Perception::Spatial::ISpatialStageFrameOfReference;
36 using ABI::Windows::Perception::Spatial::ISpatialStageFrameOfReferenceStatics;
37 using ABI::Windows::Perception::Spatial::ISpatialStationaryFrameOfReference;
38 using ABI::Windows::UI::Input::Spatial::ISpatialInteractionManager;
39 using Microsoft::WRL::ComPtr;
40 
41 namespace {
GetSpatialLocator()42 ComPtr<ISpatialLocator> GetSpatialLocator() {
43   ComPtr<ISpatialLocatorStatics> spatial_locator_statics;
44   base::win::ScopedHString spatial_locator_string =
45       base::win::ScopedHString::Create(
46           RuntimeClass_Windows_Perception_Spatial_SpatialLocator);
47   HRESULT hr = base::win::RoGetActivationFactory(
48       spatial_locator_string.get(), IID_PPV_ARGS(&spatial_locator_statics));
49   if (FAILED(hr)) {
50     device::WMRLogging::TraceError(device::WMRErrorLocation::kGetSpatialLocator,
51                                    hr);
52     return nullptr;
53   }
54 
55   ComPtr<ISpatialLocator> locator;
56   hr = spatial_locator_statics->GetDefault(&locator);
57   if (FAILED(hr)) {
58     device::WMRLogging::TraceError(device::WMRErrorLocation::kGetSpatialLocator,
59                                    hr);
60     return nullptr;
61   }
62 
63   return locator;
64 }
65 }  // anonymous namespace
66 
67 namespace device {
68 
69 std::unique_ptr<WMRStationaryOrigin>
CreateAtCurrentLocation()70 WMRStationaryOriginFactory::CreateAtCurrentLocation() {
71   if (MixedRealityDeviceStatics::ShouldUseMocks()) {
72     return std::make_unique<MockWMRStationaryOrigin>();
73   }
74 
75   ComPtr<ISpatialLocator> locator = GetSpatialLocator();
76   if (!locator)
77     return nullptr;
78 
79   ComPtr<ISpatialStationaryFrameOfReference> origin;
80   HRESULT hr =
81       locator->CreateStationaryFrameOfReferenceAtCurrentLocation(&origin);
82   if (FAILED(hr)) {
83     WMRLogging::TraceError(WMRErrorLocation::kStationaryReferenceCreation, hr);
84     return nullptr;
85   }
86 
87   return std::make_unique<WMRStationaryOriginImpl>(origin);
88 }
89 
90 std::unique_ptr<WMRAttachedOrigin>
CreateAtCurrentLocation()91 WMRAttachedOriginFactory::CreateAtCurrentLocation() {
92   if (MixedRealityDeviceStatics::ShouldUseMocks()) {
93     return std::make_unique<MockWMRAttachedOrigin>();
94   }
95 
96   ComPtr<ISpatialLocator> locator = GetSpatialLocator();
97   if (!locator)
98     return nullptr;
99 
100   ComPtr<ISpatialLocatorAttachedFrameOfReference> origin;
101   HRESULT hr = locator->CreateAttachedFrameOfReferenceAtCurrentHeading(&origin);
102   if (FAILED(hr)) {
103     WMRLogging::TraceError(WMRErrorLocation::kAttachedReferenceCreation, hr);
104     return nullptr;
105   }
106 
107   return std::make_unique<WMRAttachedOriginImpl>(origin);
108 }
109 
Create()110 std::unique_ptr<WMRStageStatics> WMRStageStaticsFactory::Create() {
111   if (MixedRealityDeviceStatics::ShouldUseMocks()) {
112     return std::make_unique<MockWMRStageStatics>();
113   }
114 
115   ComPtr<ISpatialStageFrameOfReferenceStatics> stage_statics;
116   base::win::ScopedHString spatial_stage_string =
117       base::win::ScopedHString::Create(
118           RuntimeClass_Windows_Perception_Spatial_SpatialStageFrameOfReference);
119   HRESULT hr = base::win::RoGetActivationFactory(spatial_stage_string.get(),
120                                                  IID_PPV_ARGS(&stage_statics));
121   if (FAILED(hr))
122     return nullptr;
123 
124   return std::make_unique<WMRStageStaticsImpl>(stage_statics);
125 }
126 
127 std::unique_ptr<WMRCoordinateSystem>
TryCreateRelativeTo(WMRCoordinateSystem * origin)128 WMRSpatialAnchorFactory::TryCreateRelativeTo(WMRCoordinateSystem* origin) {
129   if (MixedRealityDeviceStatics::ShouldUseMocks()) {
130     MockWMRStationaryOrigin origin;
131     return origin.CoordinateSystem();
132   }
133 
134   ComPtr<ISpatialAnchorStatics> anchor_statics;
135   base::win::ScopedHString spatial_anchor_string =
136       base::win::ScopedHString::Create(
137           RuntimeClass_Windows_Perception_Spatial_SpatialAnchor);
138   HRESULT hr = base::win::RoGetActivationFactory(spatial_anchor_string.get(),
139                                                  IID_PPV_ARGS(&anchor_statics));
140   if (FAILED(hr))
141     return nullptr;
142 
143   ComPtr<ISpatialAnchor> anchor;
144   hr = anchor_statics->TryCreateRelativeTo(origin->GetRawPtr(), &anchor);
145   if (FAILED(hr) || !anchor)
146     return nullptr;
147 
148   // Make a WMRCoordinateSystemImpl wrapping the coordinate system.
149   ComPtr<ISpatialCoordinateSystem> coordinate_system;
150   hr = anchor->get_CoordinateSystem(&coordinate_system);
151   DCHECK(SUCCEEDED(hr));
152   return std::make_unique<WMRCoordinateSystemImpl>(coordinate_system);
153 }
154 
GetForWindow(HWND hwnd)155 std::unique_ptr<WMRInputManager> WMRInputManagerFactory::GetForWindow(
156     HWND hwnd) {
157   if (MixedRealityDeviceStatics::ShouldUseMocks()) {
158     return std::make_unique<MockWMRInputManager>();
159   }
160   if (!hwnd)
161     return nullptr;
162 
163   ComPtr<ISpatialInteractionManagerInterop> spatial_interaction_interop;
164   base::win::ScopedHString spatial_interaction_interop_string =
165       base::win::ScopedHString::Create(
166           RuntimeClass_Windows_UI_Input_Spatial_SpatialInteractionManager);
167   HRESULT hr = base::win::RoGetActivationFactory(
168       spatial_interaction_interop_string.get(),
169       IID_PPV_ARGS(&spatial_interaction_interop));
170   if (FAILED(hr))
171     return nullptr;
172 
173   ComPtr<ISpatialInteractionManager> manager;
174   hr = spatial_interaction_interop->GetForWindow(hwnd, IID_PPV_ARGS(&manager));
175   if (FAILED(hr))
176     return nullptr;
177 
178   return std::make_unique<WMRInputManagerImpl>(manager);
179 }
180 
181 std::unique_ptr<WMRHolographicSpace>
CreateForWindow(HWND hwnd)182 WMRHolographicSpaceFactory::CreateForWindow(HWND hwnd) {
183   if (MixedRealityDeviceStatics::ShouldUseMocks()) {
184     return std::make_unique<MockWMRHolographicSpace>();
185   }
186   if (!hwnd)
187     return nullptr;
188 
189   ComPtr<IHolographicSpaceInterop> holographic_space_interop;
190   base::win::ScopedHString holographic_space_string =
191       base::win::ScopedHString::Create(
192           RuntimeClass_Windows_Graphics_Holographic_HolographicSpace);
193   HRESULT hr = base::win::RoGetActivationFactory(
194       holographic_space_string.get(), IID_PPV_ARGS(&holographic_space_interop));
195 
196   if (FAILED(hr))
197     return nullptr;
198 
199   ComPtr<IHolographicSpace> holographic_space;
200   hr = holographic_space_interop->CreateForWindow(
201       hwnd, IID_PPV_ARGS(&holographic_space));
202 
203   if (FAILED(hr))
204     return nullptr;
205 
206   return std::make_unique<WMRHolographicSpaceImpl>(holographic_space);
207 }
208 
209 }  // namespace device
210