Windows 10 Creators Update - March 2017 Update 3
This commit is contained in:
Коммит
66db4fc91c
|
@ -229,14 +229,15 @@ For additional Windows samples, see [Windows on GitHub](http://microsoft.github.
|
|||
<tr>
|
||||
<td><a href="Samples/BasicInput">Basic input</a></td>
|
||||
<td><a href="Samples/ComplexInk">Complex inking</a></td>
|
||||
<td><a href="Samples/Ink">Inking</a></td>
|
||||
<td><a href="Samples/InkAnalysis">Ink analysis/a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="Samples/Ink">Inking</a></td>
|
||||
<td><a href="Samples/LowLatencyInput">Low latency input</a></td>
|
||||
<td><a href="Samples/SimpleInk">Simple inking</a></td>
|
||||
<td><a href="Samples/TouchKeyboard">Touch keyboard</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="Samples/TouchKeyboard">Touch keyboard</a></td>
|
||||
<td><a href="Samples/TouchKeyboardTextInput">Touch keyboard text input</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -427,6 +428,7 @@ For additional Windows samples, see [Windows on GitHub](http://microsoft.github.
|
|||
</tr>
|
||||
<tr>
|
||||
<td><a href="Samples/HolographicSpatialMapping">Holographic spatial mapping</a></td>
|
||||
<td><a href="Samples/HolographicVoiceInput">Holographic voice input</a></td>
|
||||
<td><a href="Samples/HolographicTagAlong">Tag-along hologram</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -55,10 +55,8 @@ using Windows::Graphics::Display::DisplayInformation;
|
|||
|
||||
|
||||
Scenario_Document1::Scenario_Document1()
|
||||
: rootPage(MainPage::Current)
|
||||
: m_rootPage(MainPage::Current)
|
||||
{
|
||||
m_eventToken.Value = 0;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
String^ text =
|
||||
|
@ -81,32 +79,35 @@ Scenario_Document1::Scenario_Document1()
|
|||
// Initialize FontDownloadListener, register the event handler, and initiate
|
||||
// the download.
|
||||
FontDownloadListener::Initialize();
|
||||
m_eventToken = FontDownloadListener::DownloadCompleted += ref new FontDownloadCompletedHandler(this, &Scenario_Document1::FontDownloadListener_DownloadCompleted);
|
||||
m_downloadCompletedEventToken = FontDownloadListener::DownloadCompleted += ref new FontDownloadCompletedHandler(this, &Scenario_Document1::FontDownloadListener_DownloadCompleted);
|
||||
FontDownloadListener::BeginDownload();
|
||||
|
||||
// When the SurfaceImageSource is created, we'll need to know the current DPI.
|
||||
// We'll also need an event handler to re-create the image source if the DPI changes.
|
||||
DisplayInformation^ displayInformation = DisplayInformation::GetForCurrentView();
|
||||
m_dpi = displayInformation->LogicalDpi;
|
||||
displayInformation->DpiChanged += ref new TypedEventHandler<DisplayInformation^, Object^>([this](DisplayInformation^ sender, Object^)
|
||||
{
|
||||
this->HandleDpiChanged(sender);
|
||||
});
|
||||
m_displayInformation = DisplayInformation::GetForCurrentView();
|
||||
m_dpi = m_displayInformation->LogicalDpi;
|
||||
m_dpiChangedEventToken = m_displayInformation->DpiChanged += ref new TypedEventHandler<DisplayInformation^, Object^>(this, &Scenario_Document1::DisplayInformation_DpiChanged);
|
||||
|
||||
// When the app window is hidden, XAML may release resource used by the
|
||||
// SurfaceImageSource. We'll need to make sure it gets re-created if the
|
||||
// window was hidden and then becomes visible again.
|
||||
Window::Current->VisibilityChanged += ref new Windows::UI::Xaml::WindowVisibilityChangedEventHandler(this, &SDKTemplate::Scenario_Document1::OnVisibilityChanged);
|
||||
m_visibilityChangedEventToken = Window::Current->VisibilityChanged += ref new WindowVisibilityChangedEventHandler(this, &Scenario_Document1::Window_VisibilityChanged);
|
||||
|
||||
// As the page is loaded, after this constructor has exited, XAML will be
|
||||
// re-sizing the TextLayoutFrame scroll viewer element and the SizeChanged
|
||||
// handler will get invoked. That's when the image source will first get created.
|
||||
}
|
||||
|
||||
void Scenario_Document1::OnNavigatedFrom(NavigationEventArgs^ e)
|
||||
{
|
||||
FontDownloadListener::DownloadCompleted -= m_downloadCompletedEventToken;
|
||||
m_displayInformation->DpiChanged -= m_dpiChangedEventToken;
|
||||
Window::Current->VisibilityChanged -= m_visibilityChangedEventToken;
|
||||
}
|
||||
|
||||
// Event handlers:
|
||||
|
||||
void Scenario_Document1::TextLayoutFrame_SizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e)
|
||||
void Scenario_Document1::TextLayoutFrame_SizeChanged(Object^ sender, SizeChangedEventArgs^ e)
|
||||
{
|
||||
// Get the current available width and update the TextLayout if different.
|
||||
// The available width will be the actual width less the left and right padding.
|
||||
|
@ -142,15 +143,6 @@ void Scenario_Document1::TextLayoutFrame_SizeChanged(Platform::Object^ sender, W
|
|||
}
|
||||
|
||||
|
||||
void Scenario_Document1::OnNavigatedFrom(NavigationEventArgs^ e)
|
||||
{
|
||||
if (m_eventToken.Value != 0)
|
||||
{
|
||||
FontDownloadListener::DownloadCompleted -= m_eventToken;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Scenario_Document1::FontDownloadListener_DownloadCompleted()
|
||||
{
|
||||
// DownloadCompleted is called from a worker thread, so schedule work
|
||||
|
@ -178,13 +170,24 @@ void Scenario_Document1::FontDownloadListener_DownloadCompleted()
|
|||
}
|
||||
|
||||
|
||||
void Scenario_Document1::HandleDpiChanged(DisplayInformation^ displayInformation)
|
||||
void Scenario_Document1::DisplayInformation_DpiChanged(DisplayInformation^ displayInformation, Object^ e)
|
||||
{
|
||||
m_dpi = displayInformation->LogicalDpi;
|
||||
PresentTextLayout();
|
||||
}
|
||||
|
||||
|
||||
void Scenario_Document1::Window_VisibilityChanged(Object^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ e)
|
||||
{
|
||||
// Re-create the SurfaceImageSource if the window has just become visible.
|
||||
if (e->Visible)
|
||||
{
|
||||
PresentTextLayout();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Private helper methods:
|
||||
|
||||
void Scenario_Document1::RequestTextLayoutUpdate()
|
||||
|
@ -249,15 +252,5 @@ void Scenario_Document1::UpdateStatus()
|
|||
NotifyType statusType = (fontsUsed == m_downloadableFontName) ? NotifyType::StatusMessage : NotifyType::ErrorMessage;
|
||||
|
||||
// Now update the status.
|
||||
rootPage->NotifyUser("Fonts actually used: " + fontsUsed, statusType);
|
||||
}
|
||||
|
||||
|
||||
void Scenario_Document1::OnVisibilityChanged(Platform::Object ^sender, Windows::UI::Core::VisibilityChangedEventArgs ^e)
|
||||
{
|
||||
// Re-create the SurfaceImageSource if the window has just become visible.
|
||||
if (e->Visible)
|
||||
{
|
||||
PresentTextLayout();
|
||||
}
|
||||
m_rootPage->NotifyUser("Fonts actually used: " + fontsUsed, statusType);
|
||||
}
|
||||
|
|
|
@ -25,29 +25,33 @@ namespace SDKTemplate
|
|||
{
|
||||
public:
|
||||
Scenario_Document1();
|
||||
void HandleDpiChanged(DisplayInformation^ displayInformation);
|
||||
|
||||
protected:
|
||||
virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override;
|
||||
|
||||
private:
|
||||
MainPage^ rootPage;
|
||||
MainPage^ m_rootPage;
|
||||
TextLayout^ m_textLayout;
|
||||
TextLayoutImageSource^ m_textLayoutImageSource;
|
||||
FontDownloadListener^ m_fontDownloadListener;
|
||||
Windows::Foundation::EventRegistrationToken m_eventToken;
|
||||
Windows::UI::Color m_textColor;
|
||||
Windows::UI::Color m_textBackgroundColor;
|
||||
Platform::String^ m_downloadableFontName;
|
||||
bool m_layoutUpdateInProgress = false;
|
||||
Windows::Graphics::Display::DisplayInformation^ m_displayInformation;
|
||||
float m_dpi = 96.0f;
|
||||
|
||||
void TextLayoutFrame_SizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e);
|
||||
void FontDownloadListener_DownloadCompleted();
|
||||
Windows::Foundation::EventRegistrationToken m_downloadCompletedEventToken{};
|
||||
Windows::Foundation::EventRegistrationToken m_dpiChangedEventToken{};
|
||||
Windows::Foundation::EventRegistrationToken m_visibilityChangedEventToken{};
|
||||
|
||||
void RequestTextLayoutUpdate();
|
||||
void UpdateTextLayout();
|
||||
void PresentTextLayout();
|
||||
void UpdateStatus();
|
||||
void OnVisibilityChanged(Platform::Object ^sender, Windows::UI::Core::VisibilityChangedEventArgs ^e);
|
||||
void DisplayInformation_DpiChanged(DisplayInformation^ sender, Object^ e);
|
||||
void FontDownloadListener_DownloadCompleted();
|
||||
void TextLayoutFrame_SizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e);
|
||||
void Window_VisibilityChanged(Platform::Object^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ e);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -32,10 +32,8 @@ using Windows::Graphics::Display::DisplayInformation;
|
|||
|
||||
|
||||
Scenario_Document2::Scenario_Document2()
|
||||
: rootPage(MainPage::Current)
|
||||
: m_rootPage(MainPage::Current)
|
||||
{
|
||||
m_eventToken.Value = 0;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
String^ text =
|
||||
|
@ -58,25 +56,28 @@ Scenario_Document2::Scenario_Document2()
|
|||
// Initialize FontDownloadListener, register the event handler, and initiate
|
||||
// the download.
|
||||
FontDownloadListener::Initialize();
|
||||
m_eventToken = FontDownloadListener::DownloadCompleted += ref new FontDownloadCompletedHandler(this, &Scenario_Document2::FontDownloadListener_DownloadCompleted);
|
||||
m_downloadCompletedEventToken = FontDownloadListener::DownloadCompleted += ref new FontDownloadCompletedHandler(this, &Scenario_Document2::FontDownloadListener_DownloadCompleted);
|
||||
FontDownloadListener::BeginDownload();
|
||||
|
||||
// Handle DPI.
|
||||
DisplayInformation^ displayInformation = DisplayInformation::GetForCurrentView();
|
||||
m_dpi = displayInformation->LogicalDpi;
|
||||
displayInformation->DpiChanged += ref new TypedEventHandler<DisplayInformation^, Object^>([this](DisplayInformation^ sender, Object^)
|
||||
{
|
||||
this->HandleDpiChanged(sender);
|
||||
});
|
||||
m_displayInformation = DisplayInformation::GetForCurrentView();
|
||||
m_dpi = m_displayInformation->LogicalDpi;
|
||||
m_dpiChangedEventToken = m_displayInformation->DpiChanged += ref new TypedEventHandler<DisplayInformation^, Object^>(this, &Scenario_Document2::DisplayInformation_DpiChanged);
|
||||
|
||||
// Handle window visibility change.
|
||||
Window::Current->VisibilityChanged += ref new Windows::UI::Xaml::WindowVisibilityChangedEventHandler(this, &SDKTemplate::Scenario_Document2::OnVisibilityChanged);
|
||||
m_visibilityChangedEventToken = Window::Current->VisibilityChanged += ref new WindowVisibilityChangedEventHandler(this, &SDKTemplate::Scenario_Document2::Window_VisibilityChanged);
|
||||
}
|
||||
|
||||
void Scenario_Document2::OnNavigatedFrom(NavigationEventArgs^ e)
|
||||
{
|
||||
FontDownloadListener::DownloadCompleted -= m_downloadCompletedEventToken;
|
||||
m_displayInformation->DpiChanged -= m_dpiChangedEventToken;
|
||||
Window::Current->VisibilityChanged -= m_visibilityChangedEventToken;
|
||||
}
|
||||
|
||||
// Event handlers:
|
||||
|
||||
void Scenario_Document2::TextLayoutFrame_SizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e)
|
||||
void Scenario_Document2::TextLayoutFrame_SizeChanged(Object^ sender, SizeChangedEventArgs^ e)
|
||||
{
|
||||
// Get the current available width and update the TextLayout if different.
|
||||
// The available width will be the actual width less the left and right padding.
|
||||
|
@ -98,14 +99,6 @@ void Scenario_Document2::TextLayoutFrame_SizeChanged(Platform::Object^ sender, W
|
|||
}
|
||||
|
||||
|
||||
void Scenario_Document2::OnNavigatedFrom(NavigationEventArgs^ e)
|
||||
{
|
||||
if (m_eventToken.Value != 0)
|
||||
{
|
||||
FontDownloadListener::DownloadCompleted -= m_eventToken;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Scenario_Document2::FontDownloadListener_DownloadCompleted()
|
||||
{
|
||||
|
@ -118,13 +111,24 @@ void Scenario_Document2::FontDownloadListener_DownloadCompleted()
|
|||
}
|
||||
|
||||
|
||||
void Scenario_Document2::HandleDpiChanged(DisplayInformation^ displayInformation)
|
||||
void Scenario_Document2::DisplayInformation_DpiChanged(DisplayInformation^ displayInformation, Object^ e)
|
||||
{
|
||||
m_dpi = displayInformation->LogicalDpi;
|
||||
PresentTextLayout();
|
||||
}
|
||||
|
||||
|
||||
void Scenario_Document2::Window_VisibilityChanged(Object^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ e)
|
||||
{
|
||||
// Re-create the SurfaceImageSource if the window has just become visible.
|
||||
if (e->Visible)
|
||||
{
|
||||
PresentTextLayout();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Private helper methods:
|
||||
|
||||
void Scenario_Document2::RequestTextLayoutUpdate()
|
||||
|
@ -151,6 +155,8 @@ void Scenario_Document2::UpdateTextLayout()
|
|||
|
||||
// Update the status bar to show what fonts have actually been used.
|
||||
UpdateStatus();
|
||||
|
||||
m_layoutUpdateInProgress = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -173,15 +179,5 @@ void Scenario_Document2::UpdateStatus()
|
|||
NotifyType statusType = (fontsUsed == m_downloadableFontName) ? NotifyType::StatusMessage : NotifyType::ErrorMessage;
|
||||
|
||||
// Now update the status.
|
||||
rootPage->NotifyUser("Fonts actually used: " + fontsUsed, statusType);
|
||||
}
|
||||
|
||||
|
||||
void Scenario_Document2::OnVisibilityChanged(Platform::Object ^sender, Windows::UI::Core::VisibilityChangedEventArgs ^e)
|
||||
{
|
||||
// Re-create the SurfaceImageSource if the window has just become visible.
|
||||
if (e->Visible)
|
||||
{
|
||||
PresentTextLayout();
|
||||
}
|
||||
m_rootPage->NotifyUser("Fonts actually used: " + fontsUsed, statusType);
|
||||
}
|
||||
|
|
|
@ -25,29 +25,33 @@ namespace SDKTemplate
|
|||
{
|
||||
public:
|
||||
Scenario_Document2();
|
||||
void HandleDpiChanged(DisplayInformation^ displayInformation);
|
||||
|
||||
protected:
|
||||
virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override;
|
||||
|
||||
private:
|
||||
MainPage^ rootPage;
|
||||
MainPage^ m_rootPage;
|
||||
TextLayout^ m_textLayout;
|
||||
TextLayoutImageSource^ m_textLayoutImageSource;
|
||||
FontDownloadListener^ m_fontDownloadListener;
|
||||
Windows::Foundation::EventRegistrationToken m_eventToken;
|
||||
Windows::UI::Color m_textColor;
|
||||
Windows::UI::Color m_textBackgroundColor;
|
||||
Platform::String^ m_downloadableFontName;
|
||||
bool m_layoutUpdateInProgress = false;
|
||||
Windows::Graphics::Display::DisplayInformation^ m_displayInformation;
|
||||
float m_dpi = 96.0f;
|
||||
|
||||
void TextLayoutFrame_SizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e);
|
||||
void FontDownloadListener_DownloadCompleted();
|
||||
Windows::Foundation::EventRegistrationToken m_downloadCompletedEventToken{};
|
||||
Windows::Foundation::EventRegistrationToken m_dpiChangedEventToken{};
|
||||
Windows::Foundation::EventRegistrationToken m_visibilityChangedEventToken{};
|
||||
|
||||
void RequestTextLayoutUpdate();
|
||||
void UpdateTextLayout();
|
||||
void PresentTextLayout();
|
||||
void UpdateStatus();
|
||||
void OnVisibilityChanged(Platform::Object ^sender, Windows::UI::Core::VisibilityChangedEventArgs ^e);
|
||||
void DisplayInformation_DpiChanged(DisplayInformation^ sender, Object^ e);
|
||||
void FontDownloadListener_DownloadCompleted();
|
||||
void TextLayoutFrame_SizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e);
|
||||
void Window_VisibilityChanged(Platform::Object^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ e);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -32,10 +32,8 @@ using Windows::Graphics::Display::DisplayInformation;
|
|||
|
||||
|
||||
Scenario_Document3::Scenario_Document3()
|
||||
: rootPage(MainPage::Current)
|
||||
: m_rootPage(MainPage::Current)
|
||||
{
|
||||
m_eventToken.Value = 0;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
String^ text =
|
||||
|
@ -58,24 +56,29 @@ Scenario_Document3::Scenario_Document3()
|
|||
// Initialize FontDownloadListener, register the event handler, and initiate
|
||||
// the download.
|
||||
FontDownloadListener::Initialize();
|
||||
m_eventToken = FontDownloadListener::DownloadCompleted += ref new FontDownloadCompletedHandler(this, &Scenario_Document3::FontDownloadListener_DownloadCompleted);
|
||||
m_downloadCompletedEventToken = FontDownloadListener::DownloadCompleted += ref new FontDownloadCompletedHandler(this, &Scenario_Document3::FontDownloadListener_DownloadCompleted);
|
||||
FontDownloadListener::BeginDownload();
|
||||
|
||||
// Handle DPI.
|
||||
DisplayInformation^ displayInformation = DisplayInformation::GetForCurrentView();
|
||||
m_dpi = displayInformation->LogicalDpi;
|
||||
displayInformation->DpiChanged += ref new TypedEventHandler<DisplayInformation^, Object^>([this](DisplayInformation^ sender, Object^)
|
||||
{
|
||||
this->HandleDpiChanged(sender);
|
||||
});
|
||||
m_displayInformation = DisplayInformation::GetForCurrentView();
|
||||
m_dpi = m_displayInformation->LogicalDpi;
|
||||
m_dpiChangedEventToken = m_displayInformation->DpiChanged += ref new TypedEventHandler<DisplayInformation^, Object^>(this, &Scenario_Document3::DisplayInformation_DpiChanged);
|
||||
|
||||
// Handle window visibility change.
|
||||
Window::Current->VisibilityChanged += ref new Windows::UI::Xaml::WindowVisibilityChangedEventHandler(this, &SDKTemplate::Scenario_Document3::OnVisibilityChanged);
|
||||
m_visibilityChangedEventToken = Window::Current->VisibilityChanged += ref new WindowVisibilityChangedEventHandler(this, &Scenario_Document3::Window_VisibilityChanged);
|
||||
}
|
||||
|
||||
void Scenario_Document3::OnNavigatedFrom(NavigationEventArgs^ e)
|
||||
{
|
||||
FontDownloadListener::DownloadCompleted -= m_downloadCompletedEventToken;
|
||||
m_displayInformation->DpiChanged -= m_dpiChangedEventToken;
|
||||
Window::Current->VisibilityChanged -= m_visibilityChangedEventToken;
|
||||
}
|
||||
|
||||
|
||||
// Event handlers:
|
||||
|
||||
void Scenario_Document3::TextLayoutFrame_SizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e)
|
||||
void Scenario_Document3::TextLayoutFrame_SizeChanged(Object^ sender, SizeChangedEventArgs^ e)
|
||||
{
|
||||
// Get the current available width and update the TextLayout if different.
|
||||
// The available width will be the actual width less the left and right padding.
|
||||
|
@ -97,15 +100,6 @@ void Scenario_Document3::TextLayoutFrame_SizeChanged(Platform::Object^ sender, W
|
|||
}
|
||||
|
||||
|
||||
void Scenario_Document3::OnNavigatedFrom(NavigationEventArgs^ e)
|
||||
{
|
||||
if (m_eventToken.Value != 0)
|
||||
{
|
||||
FontDownloadListener::DownloadCompleted -= m_eventToken;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Scenario_Document3::FontDownloadListener_DownloadCompleted()
|
||||
{
|
||||
// DownloadCompleted is called from a worker thread, so schedule work
|
||||
|
@ -117,13 +111,24 @@ void Scenario_Document3::FontDownloadListener_DownloadCompleted()
|
|||
}
|
||||
|
||||
|
||||
void Scenario_Document3::HandleDpiChanged(DisplayInformation^ displayInformation)
|
||||
void Scenario_Document3::DisplayInformation_DpiChanged(DisplayInformation^ displayInformation, Object^ e)
|
||||
{
|
||||
m_dpi = displayInformation->LogicalDpi;
|
||||
PresentTextLayout();
|
||||
}
|
||||
|
||||
|
||||
void Scenario_Document3::Window_VisibilityChanged(Object^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ e)
|
||||
{
|
||||
// Re-create the SurfaceImageSource if the window has just become visible.
|
||||
if (e->Visible)
|
||||
{
|
||||
PresentTextLayout();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Private helper methods:
|
||||
|
||||
void Scenario_Document3::RequestTextLayoutUpdate()
|
||||
|
@ -150,6 +155,8 @@ void Scenario_Document3::UpdateTextLayout()
|
|||
|
||||
// Update the status bar to show what fonts have actually been used.
|
||||
UpdateStatus();
|
||||
|
||||
m_layoutUpdateInProgress = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -172,15 +179,5 @@ void Scenario_Document3::UpdateStatus()
|
|||
NotifyType statusType = (fontsUsed == m_downloadableFontName) ? NotifyType::StatusMessage : NotifyType::ErrorMessage;
|
||||
|
||||
// Now update the status.
|
||||
rootPage->NotifyUser("Fonts actually used: " + fontsUsed, statusType);
|
||||
}
|
||||
|
||||
|
||||
void Scenario_Document3::OnVisibilityChanged(Platform::Object ^sender, Windows::UI::Core::VisibilityChangedEventArgs ^e)
|
||||
{
|
||||
// Re-create the SurfaceImageSource if the window has just become visible.
|
||||
if (e->Visible)
|
||||
{
|
||||
PresentTextLayout();
|
||||
}
|
||||
m_rootPage->NotifyUser("Fonts actually used: " + fontsUsed, statusType);
|
||||
}
|
||||
|
|
|
@ -25,29 +25,33 @@ namespace SDKTemplate
|
|||
{
|
||||
public:
|
||||
Scenario_Document3();
|
||||
void HandleDpiChanged(DisplayInformation^ displayInformation);
|
||||
|
||||
protected:
|
||||
virtual void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override;
|
||||
|
||||
private:
|
||||
MainPage^ rootPage;
|
||||
MainPage^ m_rootPage;
|
||||
TextLayout^ m_textLayout;
|
||||
TextLayoutImageSource^ m_textLayoutImageSource;
|
||||
FontDownloadListener^ m_fontDownloadListener;
|
||||
Windows::Foundation::EventRegistrationToken m_eventToken;
|
||||
Windows::UI::Color m_textColor;
|
||||
Windows::UI::Color m_textBackgroundColor;
|
||||
Platform::String^ m_downloadableFontName;
|
||||
bool m_layoutUpdateInProgress = false;
|
||||
Windows::Graphics::Display::DisplayInformation^ m_displayInformation;
|
||||
float m_dpi = 96.0f;
|
||||
|
||||
void TextLayoutFrame_SizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e);
|
||||
void FontDownloadListener_DownloadCompleted();
|
||||
Windows::Foundation::EventRegistrationToken m_downloadCompletedEventToken{};
|
||||
Windows::Foundation::EventRegistrationToken m_dpiChangedEventToken{};
|
||||
Windows::Foundation::EventRegistrationToken m_visibilityChangedEventToken{};
|
||||
|
||||
void RequestTextLayoutUpdate();
|
||||
void UpdateTextLayout();
|
||||
void PresentTextLayout();
|
||||
void UpdateStatus();
|
||||
void OnVisibilityChanged(Platform::Object ^sender, Windows::UI::Core::VisibilityChangedEventArgs ^e);
|
||||
void DisplayInformation_DpiChanged(DisplayInformation^ sender, Object^ e);
|
||||
void FontDownloadListener_DownloadCompleted();
|
||||
void TextLayoutFrame_SizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e);
|
||||
void Window_VisibilityChanged(Platform::Object^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ e);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -136,7 +136,8 @@ FontDownloadListener::FontDownloadListener()
|
|||
//
|
||||
// In general, if your app has a download queue that's shared between
|
||||
// different objects that can independently call BeginDownload, you should
|
||||
// always register a global listener.
|
||||
// always register a listener so that any of your objects that may need to
|
||||
// respond will see all DownloadCompleted events.
|
||||
//
|
||||
// This does create the possibility that an object could get multiple
|
||||
// DownloadCompleted calls while it only called BeginDownload once, or that
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
<!---
|
||||
category: Holographic
|
||||
samplefwlink: http://go.microsoft.com/fwlink/p/?LinkId=844964
|
||||
--->
|
||||
|
||||
# Holographic Voice Input Sample
|
||||
|
||||
Shows how to implement continuous voice recognition and Speech Synthesis, using a keyword-based constraint list, and the Speech Synthesizer to provide an spoken prompt. The event handler is set to change the color of the cube to a different color, based on voice input (eg, the user saying "red", "green", "blue".) Due to the lack of directional lighting, this produces a uniformly colored/lit cube of the requested color.
|
||||
|
||||
> **Note:** This sample is part of a large collection of UWP feature samples.
|
||||
> If you are unfamiliar with Git and GitHub, you can download the entire collection as a
|
||||
> [ZIP file](https://github.com/Microsoft/Windows-universal-samples/archive/master.zip), but be
|
||||
> sure to unzip everything to access shared dependencies. For more info on working with the ZIP file,
|
||||
> the samples collection, and GitHub, see [Get the UWP samples from GitHub](https://aka.ms/ovu2uq).
|
||||
> For more samples, see the [Samples portal](https://aka.ms/winsamples) on the Windows Dev Center.
|
||||
|
||||
The sample demonstrates how to construct a constraint list, compile it, start continuous recognition, handle events in response to incoming speech, evaluate the confidence that the speech engine has provided, and handle errors. It also demonstrates how to construct a speech synthesizer, and hook it up to XAudio2 for output to the user.
|
||||
|
||||
This sample uses the microphone app capability in order to access the user's voice input.
|
||||
|
||||
###
|
||||
### Additional remarks
|
||||
|
||||
**Note** The Windows universal samples for Windows 10 Holographic require Visual Studio 2015 Update 3
|
||||
to build, and a Windows Holographic device to execute. Windows Holographic devices include the
|
||||
Microsoft HoloLens and the Microsoft HoloLens Emulator.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421).
|
||||
|
||||
To obtain information about the tools used for Windows Holographic development, including
|
||||
Microsoft Visual Studio 2015 Update 3 and the Microsoft HoloLens Emulator, go to
|
||||
[Install the tools](https://developer.microsoft.com/windows/holographic/install_the_tools).
|
||||
|
||||
### Reference
|
||||
|
||||
The following types are used in this code sample:
|
||||
* [Windows.Media.SpeechRecognition namespace](https://docs.microsoft.com/en-us/uwp/api/windows.media.speechrecognition)
|
||||
* [SpeechRecognizer class](https://docs.microsoft.com/en-us/uwp/api/Windows.Media.SpeechRecognition.SpeechRecognizer)
|
||||
* [SpeechContinuousRecognitionSession class](https://docs.microsoft.com/en-us/uwp/api/windows.media.speechrecognition.speechcontinuousrecognitionsession)
|
||||
* [SpeechRecognitionCompilationResult class](https://docs.microsoft.com/en-us/uwp/api/windows.media.speechrecognition.speechrecognitioncompilationresult)
|
||||
* [SpeechRecognitionResult class](https://docs.microsoft.com/en-us/uwp/api/windows.media.speechrecognition.speechrecognitionresult)
|
||||
* [SpeechRecognitionListConstraint class](https://docs.microsoft.com/en-us/uwp/api/windows.media.speechrecognition.speechrecognitionlistconstraint)
|
||||
* [SpeechSynthesizer class](https://docs.microsoft.com/en-us/uwp/api/windows.media.speechsynthesis.speechsynthesizer)
|
||||
|
||||
## System requirements
|
||||
|
||||
**Client:** Windows 10 Holographic build 14393
|
||||
|
||||
**Phone:** Not supported
|
||||
|
||||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with
|
||||
the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the
|
||||
subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or
|
||||
JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
||||
The next steps depend on whether you just want to deploy the sample or you want to both deploy and
|
||||
run it.
|
||||
|
||||
### Deploying the sample to the Microsoft HoloLens emulator
|
||||
|
||||
- Click the debug target drop-down, and select **Microsoft HoloLens Emulator**.
|
||||
- Select **Build** \> **Deploy** Solution.
|
||||
|
||||
### Deploying the sample to a Microsoft HoloLens
|
||||
|
||||
- Developer unlock your Microsoft HoloLens. For instructions, go to [Enable your device for development]
|
||||
(https://msdn.microsoft.com/windows/uwp/get-started/enable-your-device-for-development#enable-your-windows-10-devices).
|
||||
- Find the IP address of your Microsoft HoloLens. The IP address can be found in **Settings**
|
||||
\> **Network & Internet** \> **Wi-Fi** \> **Advanced options**. Or, you can ask Cortana for this
|
||||
information by saying: "Hey Cortana, what's my IP address?"
|
||||
- Right-click on your project in Visual Studio, and then select **Properties**.
|
||||
- In the Debugging pane, click the drop-down and select **Remote Machine**.
|
||||
- Enter the IP address of your Microsoft HoloLens into the field labelled **Machine Name**.
|
||||
- Click **OK**.
|
||||
- Select **Build** \> **Deploy** Solution.
|
||||
|
||||
### Pairing your developer-unlocked Microsoft HoloLens with Visual Studio
|
||||
|
||||
The first time you deploy from your development PC to your developer-unlocked Microsoft HoloLens,
|
||||
you will need to use a PIN to pair your PC with the Microsoft HoloLens.
|
||||
- When you select **Build** \> **Deploy Solution**, a dialog box will appear for Visual Studio to
|
||||
accept the PIN.
|
||||
- On your Microsoft HoloLens, go to **Settings** \> **Update** \> **For developers**, and click on
|
||||
**Pair**.
|
||||
- Type the PIN displayed by your Microsoft HoloLens into the Visual Studio dialog box and click
|
||||
**OK**.
|
||||
- On your Microsoft HoloLens, select **Done** to accept the pairing.
|
||||
- The solution will then start to deploy.
|
||||
|
||||
### Deploying and running the sample
|
||||
|
||||
- To debug the sample and then run it, follow the steps listed above to connect your
|
||||
developer-unlocked Microsoft HoloLens, then press F5 or select **Debug** \> **Start Debugging**.
|
||||
To run the sample without debugging, press Ctrl+F5 or select **Debug** \> **Start Without Debugging**.
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#include "pch.h"
|
||||
#include "AppView.h"
|
||||
|
||||
#include <ppltasks.h>
|
||||
|
||||
using namespace HolographicVoiceInput;
|
||||
|
||||
using namespace concurrency;
|
||||
using namespace Windows::ApplicationModel;
|
||||
using namespace Windows::ApplicationModel::Activation;
|
||||
using namespace Windows::ApplicationModel::Core;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Graphics::Holographic;
|
||||
using namespace Windows::UI::Core;
|
||||
|
||||
// The main function is only used to initialize our IFrameworkView class.
|
||||
// Under most circumstances, you should not need to modify this function.
|
||||
[Platform::MTAThread]
|
||||
int main(Platform::Array<Platform::String^>^)
|
||||
{
|
||||
AppViewSource^ appViewSource = ref new ::AppViewSource();
|
||||
CoreApplication::Run(appViewSource);
|
||||
return 0;
|
||||
}
|
||||
|
||||
IFrameworkView^ AppViewSource::CreateView()
|
||||
{
|
||||
return ref new AppView();
|
||||
}
|
||||
|
||||
AppView::AppView()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// 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 AppView::Initialize(CoreApplicationView^ applicationView)
|
||||
{
|
||||
applicationView->Activated +=
|
||||
ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &AppView::OnViewActivated);
|
||||
|
||||
// Register event handlers for app lifecycle.
|
||||
CoreApplication::Suspending +=
|
||||
ref new EventHandler<SuspendingEventArgs^>(this, &AppView::OnSuspending);
|
||||
|
||||
CoreApplication::Resuming +=
|
||||
ref new EventHandler<Platform::Object^>(this, &AppView::OnResuming);
|
||||
|
||||
// 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<HolographicVoiceInputMain>(m_deviceResources);
|
||||
}
|
||||
|
||||
// Called when the CoreWindow object is created (or re-created).
|
||||
void AppView::SetWindow(CoreWindow^ window)
|
||||
{
|
||||
// Register for keypress notifications.
|
||||
window->KeyDown +=
|
||||
ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &AppView::OnKeyPressed);
|
||||
|
||||
// Register for notification that the app window is being closed.
|
||||
window->Closed +=
|
||||
ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &AppView::OnWindowClosed);
|
||||
|
||||
// Register for notifications that the app window is losing focus.
|
||||
window->VisibilityChanged +=
|
||||
ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &AppView::OnVisibilityChanged);
|
||||
|
||||
// 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 AppView::Load(Platform::String^ entryPoint)
|
||||
{
|
||||
}
|
||||
|
||||
// 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 AppView::Run()
|
||||
{
|
||||
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.
|
||||
// This method is not often used, but IFrameworkView requires it and it will be called for
|
||||
// holographic apps.
|
||||
void AppView::Uninitialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Application lifecycle event handlers
|
||||
|
||||
// Called when the app view is activated. Activates the app's CoreWindow.
|
||||
void AppView::OnViewActivated(CoreApplicationView^ sender, IActivatedEventArgs^ args)
|
||||
{
|
||||
// Run() won't start until the CoreWindow is activated.
|
||||
sender->CoreWindow->Activate();
|
||||
}
|
||||
|
||||
void AppView::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ 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 AppView::OnResuming(Platform::Object^ sender, Platform::Object^ args)
|
||||
{
|
||||
// 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 AppView::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
|
||||
{
|
||||
m_windowVisible = args->Visible;
|
||||
}
|
||||
|
||||
void AppView::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
|
||||
{
|
||||
m_windowClosed = true;
|
||||
}
|
||||
|
||||
|
||||
// Input event handlers
|
||||
|
||||
void AppView::OnKeyPressed(CoreWindow^ sender, KeyEventArgs^ args)
|
||||
{
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common\DeviceResources.h"
|
||||
#include "HolographicVoiceInputMain.h"
|
||||
|
||||
namespace HolographicVoiceInput
|
||||
{
|
||||
// IFrameworkView class. Connects the app with the Windows shell and handles application lifecycle events.
|
||||
ref class AppView sealed : public Windows::ApplicationModel::Core::IFrameworkView
|
||||
{
|
||||
public:
|
||||
AppView();
|
||||
|
||||
// IFrameworkView methods.
|
||||
virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView);
|
||||
virtual void SetWindow(Windows::UI::Core::CoreWindow^ window);
|
||||
virtual void Load(Platform::String^ entryPoint);
|
||||
virtual void Run();
|
||||
virtual void Uninitialize();
|
||||
|
||||
protected:
|
||||
// Application lifecycle event handlers.
|
||||
void OnViewActivated(Windows::ApplicationModel::Core::CoreApplicationView^ sender, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args);
|
||||
void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args);
|
||||
void OnResuming(Platform::Object^ sender, Platform::Object^ args);
|
||||
|
||||
// Window event handlers.
|
||||
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
|
||||
void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args);
|
||||
|
||||
// CoreWindow input event handlers.
|
||||
void OnKeyPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);
|
||||
|
||||
private:
|
||||
std::unique_ptr<HolographicVoiceInputMain> m_main;
|
||||
|
||||
std::shared_ptr<DX::DeviceResources> m_deviceResources;
|
||||
bool m_windowClosed = false;
|
||||
bool m_windowVisible = true;
|
||||
|
||||
// The holographic space the app will use for rendering.
|
||||
Windows::Graphics::Holographic::HolographicSpace^ m_holographicSpace = nullptr;
|
||||
};
|
||||
|
||||
// The entry point for the app.
|
||||
ref class AppViewSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
|
||||
{
|
||||
public:
|
||||
virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView();
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
#include "pch.h"
|
||||
|
||||
#include "AudioFileReader.h"
|
||||
|
||||
using namespace Concurrency;
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Media::SpeechSynthesis;
|
||||
using namespace Windows::Storage::Streams;
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT AudioFileReader::Initialize(LPCWSTR filename)
|
||||
{
|
||||
BOOL mfStarted = FALSE;
|
||||
auto hr = MFStartup(MF_VERSION);
|
||||
mfStarted = SUCCEEDED(hr);
|
||||
|
||||
ComPtr<IMFSourceReader> reader;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = MFCreateSourceReaderFromURL(filename, nullptr, &reader);
|
||||
}
|
||||
|
||||
// Select the first audio stream, and deselect all other streams.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = reader->SetStreamSelection(static_cast<DWORD>(MF_SOURCE_READER_ALL_STREAMS), FALSE);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = reader->SetStreamSelection(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), TRUE);
|
||||
}
|
||||
|
||||
// Create a partial media type that specifies uncompressed PCM audio.
|
||||
ComPtr<IMFMediaType> partialType;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = MFCreateMediaType(&partialType);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = partialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = partialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
|
||||
}
|
||||
|
||||
// Set this type on the source reader. The source reader will load the necessary decoder.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = reader->SetCurrentMediaType(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), nullptr, partialType.Get());
|
||||
}
|
||||
|
||||
// Get the complete uncompressed format
|
||||
ComPtr<IMFMediaType> uncompressedAudioType;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = reader->GetCurrentMediaType(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), &uncompressedAudioType);
|
||||
}
|
||||
|
||||
// Ensure the stream is selected.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = reader->SetStreamSelection(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), TRUE);
|
||||
}
|
||||
|
||||
// Get the audio block size and number of bytes/second from the audio format.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
WAVEFORMATEX* format = nullptr;
|
||||
UINT32 size = 0;
|
||||
hr = MFCreateWaveFormatExFromMFMediaType(uncompressedAudioType.Get(), &format, &size);
|
||||
|
||||
// Only mono PCM files are supported for HRTF processing
|
||||
if (SUCCEEDED(hr) && format->wFormatTag != WAVE_FORMAT_PCM && format->nChannels != 1)
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
CopyMemory(&_format, format, sizeof WAVEFORMATEX);
|
||||
}
|
||||
|
||||
if (format)
|
||||
{
|
||||
CoTaskMemFree(format);
|
||||
}
|
||||
}
|
||||
|
||||
// Get audio samples from the source reader.
|
||||
_audioData.resize(0);
|
||||
while (SUCCEEDED(hr))
|
||||
{
|
||||
DWORD dwFlags = 0;
|
||||
|
||||
// Read the next sample.
|
||||
ComPtr<IMFSample> sample;
|
||||
hr = reader->ReadSample(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), 0, nullptr, &dwFlags, nullptr, &sample);
|
||||
|
||||
if (SUCCEEDED(hr) && (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM) != 0)
|
||||
{
|
||||
// End of stream
|
||||
break;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && sample == nullptr)
|
||||
{
|
||||
// No sample, keep going
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get a pointer to the audio data in the sample.
|
||||
ComPtr<IMFMediaBuffer> buffer;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = sample->ConvertToContiguousBuffer(&buffer);
|
||||
}
|
||||
|
||||
DWORD bufferSize = 0;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
BYTE* data;
|
||||
hr = buffer->Lock(&data, nullptr, &bufferSize);
|
||||
|
||||
auto currentDataSize = _audioData.size();
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
_audioData.resize(currentDataSize + bufferSize);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
CopyMemory(_audioData.data() + currentDataSize, data, bufferSize);
|
||||
// Unlock the buffer
|
||||
hr = buffer->Unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mfStarted)
|
||||
{
|
||||
MFShutdown();
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
//
|
||||
// Helper class uses MediaFoundation to read audio files
|
||||
//
|
||||
class AudioFileReader
|
||||
{
|
||||
public:
|
||||
virtual ~AudioFileReader() {}
|
||||
HRESULT Initialize(_In_ LPCWSTR filename);
|
||||
|
||||
const WAVEFORMATEX* GetFormat() const
|
||||
{
|
||||
return &_format;
|
||||
}
|
||||
|
||||
size_t GetSize() const
|
||||
{
|
||||
return _audioData.size();
|
||||
}
|
||||
|
||||
const BYTE* GetData() const
|
||||
{
|
||||
return _audioData.data();
|
||||
}
|
||||
|
||||
private:
|
||||
WAVEFORMATEX _format;
|
||||
std::vector<BYTE> _audioData;
|
||||
};
|
|
@ -0,0 +1,168 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
#include "pch.h"
|
||||
|
||||
#include "AudioStreamReader.h"
|
||||
|
||||
using namespace Concurrency;
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Media::SpeechSynthesis;
|
||||
using namespace Windows::Storage::Streams;
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT AudioStreamReader::Initialize(SpeechSynthesisStream^ speechSynthesisStream)
|
||||
{
|
||||
BOOL mfStarted = FALSE;
|
||||
auto hr = MFStartup(MF_VERSION);
|
||||
mfStarted = SUCCEEDED(hr);
|
||||
|
||||
ComPtr<IUnknown> streamUnknown = reinterpret_cast<IUnknown*>(speechSynthesisStream);
|
||||
ComPtr<IMFByteStream> byteStream;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = MFCreateMFByteStreamOnStreamEx(streamUnknown.Get(), &byteStream);
|
||||
}
|
||||
|
||||
ComPtr<IMFSourceReader> reader;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = MFCreateSourceReaderFromByteStream(byteStream.Get(), nullptr, &reader);
|
||||
}
|
||||
|
||||
// Select the first audio stream, and deselect all other streams.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = reader->SetStreamSelection(static_cast<DWORD>(MF_SOURCE_READER_ALL_STREAMS), FALSE);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = reader->SetStreamSelection(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), TRUE);
|
||||
}
|
||||
|
||||
// Create a partial media type that specifies uncompressed PCM audio.
|
||||
ComPtr<IMFMediaType> partialType;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = MFCreateMediaType(&partialType);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = partialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = partialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
|
||||
}
|
||||
|
||||
// Set this type on the source reader. The source reader will load the necessary decoder.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = reader->SetCurrentMediaType(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), nullptr, partialType.Get());
|
||||
}
|
||||
|
||||
// Get the complete uncompressed format
|
||||
ComPtr<IMFMediaType> uncompressedAudioType;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = reader->GetCurrentMediaType(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), &uncompressedAudioType);
|
||||
}
|
||||
|
||||
// Ensure the stream is selected.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = reader->SetStreamSelection(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), TRUE);
|
||||
}
|
||||
|
||||
// Get the audio block size and number of bytes/second from the audio format.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
WAVEFORMATEX* format = nullptr;
|
||||
UINT32 size = 0;
|
||||
hr = MFCreateWaveFormatExFromMFMediaType(uncompressedAudioType.Get(), &format, &size);
|
||||
|
||||
// Only mono PCM files are supported for HRTF processing
|
||||
if (SUCCEEDED(hr) && format->wFormatTag != WAVE_FORMAT_PCM && format->nChannels != 1)
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
CopyMemory(&_format, format, sizeof WAVEFORMATEX);
|
||||
}
|
||||
|
||||
if (format)
|
||||
{
|
||||
CoTaskMemFree(format);
|
||||
}
|
||||
}
|
||||
|
||||
// Get audio samples from the source reader.
|
||||
_audioData.resize(0);
|
||||
while (SUCCEEDED(hr))
|
||||
{
|
||||
DWORD dwFlags = 0;
|
||||
|
||||
// Read the next sample.
|
||||
ComPtr<IMFSample> sample;
|
||||
hr = reader->ReadSample(static_cast<DWORD>(MF_SOURCE_READER_FIRST_AUDIO_STREAM), 0, nullptr, &dwFlags, nullptr, &sample);
|
||||
|
||||
if (SUCCEEDED(hr) && (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM) != 0)
|
||||
{
|
||||
// End of stream
|
||||
break;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr) && sample == nullptr)
|
||||
{
|
||||
// No sample, keep going
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get a pointer to the audio data in the sample.
|
||||
ComPtr<IMFMediaBuffer> buffer;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = sample->ConvertToContiguousBuffer(&buffer);
|
||||
}
|
||||
|
||||
DWORD bufferSize = 0;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
BYTE* data;
|
||||
hr = buffer->Lock(&data, nullptr, &bufferSize);
|
||||
|
||||
auto currentDataSize = _audioData.size();
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
_audioData.resize(currentDataSize + bufferSize);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
CopyMemory(_audioData.data() + currentDataSize, data, bufferSize);
|
||||
// Unlock the buffer
|
||||
hr = buffer->Unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mfStarted)
|
||||
{
|
||||
MFShutdown();
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
//
|
||||
// Helper class uses MediaFoundation to read audio files
|
||||
//
|
||||
class AudioStreamReader
|
||||
{
|
||||
public:
|
||||
virtual ~AudioStreamReader() {}
|
||||
HRESULT Initialize(_In_ Windows::Media::SpeechSynthesis::SpeechSynthesisStream^ speechSynthesisStream);
|
||||
|
||||
const WAVEFORMATEX* GetFormat() const
|
||||
{
|
||||
return &_format;
|
||||
}
|
||||
|
||||
size_t GetSize() const
|
||||
{
|
||||
return _audioData.size();
|
||||
}
|
||||
|
||||
const BYTE* GetData() const
|
||||
{
|
||||
return _audioData.data();
|
||||
}
|
||||
|
||||
private:
|
||||
WAVEFORMATEX _format;
|
||||
std::vector<BYTE> _audioData;
|
||||
};
|
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -0,0 +1,218 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "OmnidirectionalSound.h"
|
||||
#include "XAudio2Helpers.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Foundation::Numerics;
|
||||
using namespace Windows::Media::SpeechSynthesis;
|
||||
|
||||
#define HRTF_2PI 6.283185307f
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT OmnidirectionalSound::Initialize(LPCWSTR filename, UINT32 const& loopCount)
|
||||
{
|
||||
auto hr = _audioFile.Initialize(filename);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
_sourceType = SoundSourceType::File;
|
||||
}
|
||||
|
||||
ComPtr<IXAPO> xapo;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Passing in nullptr as the first arg for HrtfApoInit initializes the APO with defaults of
|
||||
// omnidirectional sound with natural distance decay behavior.
|
||||
// CreateHrtfApo will fail with E_NOTIMPL on unsupported platforms.
|
||||
hr = CreateHrtfApo(nullptr, &xapo);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = xapo.As(&_hrtfParams);
|
||||
}
|
||||
|
||||
// Set the default environment.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = _hrtfParams->SetEnvironment(_environment);
|
||||
}
|
||||
|
||||
// Initialize an XAudio2 graph that hosts the HRTF xAPO.
|
||||
// The source voice is used to submit audio data and control playback.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = SetupXAudio2(_audioFile.GetFormat(), xapo.Get(), &_xaudio2, &_sourceVoice);
|
||||
}
|
||||
|
||||
// Submit audio data to the source voice.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
XAUDIO2_BUFFER buffer{};
|
||||
buffer.AudioBytes = static_cast<UINT32>(_audioFile.GetSize());
|
||||
buffer.pAudioData = _audioFile.GetData();
|
||||
buffer.LoopCount = loopCount;
|
||||
hr = _sourceVoice->SubmitSourceBuffer(&buffer);
|
||||
|
||||
const WAVEFORMATEX* format = _audioFile.GetFormat();
|
||||
unsigned int streamSize = _audioFile.GetSize();
|
||||
|
||||
// compute audio length, in seconds
|
||||
unsigned int numSamples =
|
||||
streamSize * 8 / // number of bits
|
||||
format->wBitsPerSample; // bits per sample
|
||||
|
||||
float numSeconds =
|
||||
static_cast<float>(numSamples) / // number of samples
|
||||
static_cast<float>(format->nSamplesPerSec); // samples per second
|
||||
|
||||
_duration = numSeconds;
|
||||
}
|
||||
|
||||
return (_initStatus = hr);
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT OmnidirectionalSound::Initialize(SpeechSynthesisStream^ stream, UINT32 const& loopCount)
|
||||
{
|
||||
auto hr = _audioStream.Initialize(stream);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
_sourceType = SoundSourceType::Stream;
|
||||
}
|
||||
|
||||
ComPtr<IXAPO> xapo;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Passing in nullptr as the first arg for HrtfApoInit initializes the APO with defaults of
|
||||
// omnidirectional sound with natural distance decay behavior.
|
||||
// CreateHrtfApo will fail with E_NOTIMPL on unsupported platforms.
|
||||
hr = CreateHrtfApo(nullptr, &xapo);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = xapo.As(&_hrtfParams);
|
||||
}
|
||||
|
||||
// Set the default environment.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = _hrtfParams->SetEnvironment(_environment);
|
||||
}
|
||||
|
||||
// Initialize an XAudio2 graph that hosts the HRTF xAPO.
|
||||
// The source voice is used to submit audio data and control playback.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = SetupXAudio2(_audioStream.GetFormat(), xapo.Get(), &_xaudio2, &_sourceVoice);
|
||||
}
|
||||
|
||||
// Set the initial position.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
auto hrtfPosition = HrtfPosition{ 0.f, 0.f, 0.f };
|
||||
hr = _hrtfParams->SetSourcePosition(&hrtfPosition);
|
||||
}
|
||||
|
||||
// Submit audio data to the source voice.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
XAUDIO2_BUFFER buffer{};
|
||||
buffer.AudioBytes = static_cast<UINT32>(_audioStream.GetSize());
|
||||
buffer.pAudioData = _audioStream.GetData();
|
||||
buffer.LoopCount = loopCount;
|
||||
hr = _sourceVoice->SubmitSourceBuffer(&buffer);
|
||||
|
||||
const WAVEFORMATEX* format = _audioStream.GetFormat();
|
||||
unsigned int streamSize = _audioStream.GetSize();
|
||||
|
||||
// compute audio length, in seconds
|
||||
unsigned int numSamples =
|
||||
streamSize * 8 / // number of bits
|
||||
format->wBitsPerSample; // bits per sample
|
||||
|
||||
float numSeconds =
|
||||
static_cast<float>(numSamples) / // number of samples
|
||||
static_cast<float>(format->nSamplesPerSec); // samples per second
|
||||
|
||||
_duration = numSeconds;
|
||||
}
|
||||
|
||||
return (_initStatus = hr);
|
||||
}
|
||||
|
||||
OmnidirectionalSound::~OmnidirectionalSound()
|
||||
{
|
||||
if (_sourceVoice)
|
||||
{
|
||||
_sourceVoice->DestroyVoice();
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT OmnidirectionalSound::Start()
|
||||
{
|
||||
_lastTick = GetTickCount64();
|
||||
return _sourceVoice->Start();
|
||||
}
|
||||
|
||||
HRESULT OmnidirectionalSound::Stop()
|
||||
{
|
||||
return _sourceVoice->Stop();
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT OmnidirectionalSound::SetEnvironment(HrtfEnvironment environment)
|
||||
{
|
||||
// Environment can be changed at any time.
|
||||
return _hrtfParams->SetEnvironment(environment);
|
||||
}
|
||||
|
||||
//
|
||||
// This method is called on every dispatcher timer tick.
|
||||
// Caller passes in the information necessary to compute the source position.
|
||||
//
|
||||
_Use_decl_annotations_
|
||||
HRESULT OmnidirectionalSound::OnUpdate(float angularVelocity, float height, float radius)
|
||||
{
|
||||
auto tick = GetTickCount64();
|
||||
auto elapsedTime = tick - _lastTick;
|
||||
_lastTick = tick;
|
||||
_angle += elapsedTime * angularVelocity;
|
||||
_angle = _angle > HRTF_2PI ? (_angle - HRTF_2PI) : _angle;
|
||||
auto position = ComputePositionInOrbit(height, radius, _angle);
|
||||
return _hrtfParams->SetSourcePosition(&position);
|
||||
}
|
||||
|
||||
|
||||
HRESULT OmnidirectionalSound::OnUpdate(_In_ float3 position)
|
||||
{
|
||||
auto hrtfPosition = HrtfPosition{ position.x, position.y, position.z };
|
||||
return _hrtfParams->SetSourcePosition(&hrtfPosition);
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HrtfPosition OmnidirectionalSound::ComputePositionInOrbit(float height, float radius, float angle)
|
||||
{
|
||||
// Calculate the position of the source based on height relative to listerner's head, radius of orbit and angle relative to the listener.
|
||||
// APO uses right-handed coordinate system where -ve z-axis is forward and +ve z-axis is backward.
|
||||
// All coordinates use real-world units (meters).
|
||||
float x = radius * sin(angle);
|
||||
float z = -radius * cos(angle);
|
||||
return HrtfPosition{x, height ,z};
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AudioFileReader.h"
|
||||
#include "AudioStreamReader.h"
|
||||
|
||||
//
|
||||
// Sound with omnidirectional radiation pattern i.e. emits sound equally in all directions.
|
||||
//
|
||||
class OmnidirectionalSound
|
||||
{
|
||||
public:
|
||||
virtual ~OmnidirectionalSound();
|
||||
HRESULT Initialize(_In_ LPCWSTR filename, UINT32 const& loopCount);
|
||||
HRESULT Initialize(Windows::Media::SpeechSynthesis::SpeechSynthesisStream^ stream, UINT32 const& loopCount);
|
||||
|
||||
HRESULT Start();
|
||||
HRESULT Stop();
|
||||
HRESULT GetInitializationStatus() { return _initStatus; }
|
||||
HRESULT OnUpdate(_In_ float angularVelocity, _In_ float height, _In_ float radius);
|
||||
HRESULT OnUpdate(_In_ Windows::Foundation::Numerics::float3 transform);
|
||||
HRESULT SetEnvironment(_In_ HrtfEnvironment environment);
|
||||
HrtfEnvironment GetEnvironment() { return _environment; }
|
||||
float GetDuration() { return _duration; };
|
||||
|
||||
private:
|
||||
HrtfPosition ComputePositionInOrbit(_In_ float height, _In_ float radius, _In_ float angle);
|
||||
|
||||
private:
|
||||
|
||||
enum SoundSourceType {
|
||||
File,
|
||||
Stream,
|
||||
};
|
||||
|
||||
HRESULT _initStatus;
|
||||
SoundSourceType _sourceType;
|
||||
AudioFileReader _audioFile;
|
||||
AudioStreamReader _audioStream;
|
||||
Microsoft::WRL::ComPtr<IXAudio2> _xaudio2;
|
||||
IXAudio2SourceVoice* _sourceVoice = nullptr;
|
||||
Microsoft::WRL::ComPtr<IXAPOHrtfParameters> _hrtfParams;
|
||||
HrtfEnvironment _environment = HrtfEnvironment::Outdoors;
|
||||
ULONGLONG _lastTick = 0;
|
||||
float _angle = 0;
|
||||
float _duration = 0.f;
|
||||
};
|
|
@ -0,0 +1,86 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
// Sets up XAudio2 for HRTF processing
|
||||
static HRESULT SetupXAudio2(_In_ const WAVEFORMATEX* format, _In_ IXAPO* xApo, _Outptr_ IXAudio2** xAudio2, _Outptr_ IXAudio2SourceVoice** sourceVoice)
|
||||
{
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
// Initialize XAudio2 for HRTF processing with "XAUDIO2_1024_QUANTUM" flag which specifies processing frame size of 1024 samples.
|
||||
ComPtr<IXAudio2> xAudio2Instance;
|
||||
auto hr = XAudio2Create(&xAudio2Instance, XAUDIO2_1024_QUANTUM);
|
||||
|
||||
// HRTF APO expects mono audio data at 48kHz and produces stereo output at 48kHz
|
||||
// so we create a stereo mastering voice with specific rendering sample rate of 48kHz.
|
||||
// Mastering voice will be automatically destroyed when XAudio2 instance is destroyed.
|
||||
IXAudio2MasteringVoice* masteringVoice = nullptr;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = xAudio2Instance->CreateMasteringVoice(&masteringVoice, 2, 48000);
|
||||
}
|
||||
|
||||
// Create a source voice to accept audio data in the specified format.
|
||||
IXAudio2SourceVoice* sourceVoiceInstance = nullptr;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = xAudio2Instance->CreateSourceVoice(&sourceVoiceInstance, format);
|
||||
}
|
||||
|
||||
// Create a submix voice that will host the xAPO.
|
||||
// This submix voice will be detroyed when XAudio2 instance is destroyed.
|
||||
IXAudio2SubmixVoice* submixVoice = nullptr;
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
XAUDIO2_EFFECT_DESCRIPTOR fxDesc{};
|
||||
fxDesc.InitialState = TRUE;
|
||||
fxDesc.OutputChannels = 2; // Stereo output
|
||||
fxDesc.pEffect = xApo; // HRTF xAPO set as the effect.
|
||||
|
||||
XAUDIO2_EFFECT_CHAIN fxChain{};
|
||||
fxChain.EffectCount = 1;
|
||||
fxChain.pEffectDescriptors = &fxDesc;
|
||||
|
||||
XAUDIO2_VOICE_SENDS sends = {};
|
||||
XAUDIO2_SEND_DESCRIPTOR sendDesc = {};
|
||||
sendDesc.pOutputVoice = masteringVoice;
|
||||
sends.SendCount = 1;
|
||||
sends.pSends = &sendDesc;
|
||||
|
||||
// HRTF APO expects mono 48kHz input, so we configure the submix voice for that format.
|
||||
hr = xAudio2Instance->CreateSubmixVoice(&submixVoice, 1, 48000, 0, 0, &sends, &fxChain);
|
||||
}
|
||||
|
||||
// Route the source voice to the submix voice.
|
||||
// The complete graph pipeline looks like this -
|
||||
// Source Voice -> Submix Voice (HRTF xAPO) -> Mastering Voice
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
XAUDIO2_VOICE_SENDS sends = {};
|
||||
XAUDIO2_SEND_DESCRIPTOR sendDesc = {};
|
||||
sendDesc.pOutputVoice = submixVoice;
|
||||
sends.SendCount = 1;
|
||||
sends.pSends = &sendDesc;
|
||||
hr = sourceVoiceInstance->SetOutputVoices(&sends);
|
||||
}
|
||||
|
||||
// Return the XAudio2 instance and the source voice.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
*sourceVoice = sourceVoiceInstance;
|
||||
*xAudio2 = xAudio2Instance.Detach();
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
@ -0,0 +1,284 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include "CameraResources.h"
|
||||
#include "Common\DirectXHelper.h"
|
||||
#include "DeviceResources.h"
|
||||
#include <windows.graphics.directx.direct3d11.interop.h>
|
||||
|
||||
using namespace DirectX;
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace Windows::Graphics::DirectX::Direct3D11;
|
||||
using namespace Windows::Graphics::Holographic;
|
||||
using namespace Windows::Perception::Spatial;
|
||||
|
||||
DX::CameraResources::CameraResources(HolographicCamera^ camera) :
|
||||
m_holographicCamera(camera),
|
||||
m_isStereo(camera->IsStereo),
|
||||
m_d3dRenderTargetSize(camera->RenderTargetSize)
|
||||
{
|
||||
m_d3dViewport = CD3D11_VIEWPORT(
|
||||
0.f, 0.f,
|
||||
m_d3dRenderTargetSize.Width,
|
||||
m_d3dRenderTargetSize.Height
|
||||
);
|
||||
};
|
||||
|
||||
// Updates resources associated with a holographic camera's swap chain.
|
||||
// The app does not access the swap chain directly, but it does create
|
||||
// resource views for the back buffer.
|
||||
void DX::CameraResources::CreateResourcesForBackBuffer(
|
||||
DX::DeviceResources* pDeviceResources,
|
||||
HolographicCameraRenderingParameters^ cameraParameters
|
||||
)
|
||||
{
|
||||
const auto device = pDeviceResources->GetD3DDevice();
|
||||
|
||||
// Get the WinRT object representing the holographic camera's back buffer.
|
||||
IDirect3DSurface^ surface = cameraParameters->Direct3D11BackBuffer;
|
||||
|
||||
// Get a DXGI interface for the holographic camera's back buffer.
|
||||
// Holographic cameras do not provide the DXGI swap chain, which is owned
|
||||
// by the system. The Direct3D back buffer resource is provided using WinRT
|
||||
// interop APIs.
|
||||
ComPtr<ID3D11Resource> resource;
|
||||
ThrowIfFailed(
|
||||
GetDXGIInterfaceFromObject(surface, IID_PPV_ARGS(&resource))
|
||||
);
|
||||
|
||||
// Get a Direct3D interface for the holographic camera's back buffer.
|
||||
ComPtr<ID3D11Texture2D> cameraBackBuffer;
|
||||
ThrowIfFailed(
|
||||
resource.As(&cameraBackBuffer)
|
||||
);
|
||||
|
||||
// Determine if the back buffer has changed. If so, ensure that the render target view
|
||||
// is for the current back buffer.
|
||||
if (m_d3dBackBuffer.Get() != cameraBackBuffer.Get())
|
||||
{
|
||||
// This can change every frame as the system moves to the next buffer in the
|
||||
// swap chain. This mode of operation will occur when certain rendering modes
|
||||
// are activated.
|
||||
m_d3dBackBuffer = cameraBackBuffer;
|
||||
|
||||
// Create a render target view of the back buffer.
|
||||
// Creating this resource is inexpensive, and is better than keeping track of
|
||||
// the back buffers in order to pre-allocate render target views for each one.
|
||||
DX::ThrowIfFailed(
|
||||
device->CreateRenderTargetView(
|
||||
m_d3dBackBuffer.Get(),
|
||||
nullptr,
|
||||
&m_d3dRenderTargetView
|
||||
)
|
||||
);
|
||||
|
||||
// Get the DXGI format for the back buffer.
|
||||
// This information can be accessed by the app using CameraResources::GetBackBufferDXGIFormat().
|
||||
D3D11_TEXTURE2D_DESC backBufferDesc;
|
||||
m_d3dBackBuffer->GetDesc(&backBufferDesc);
|
||||
m_dxgiFormat = backBufferDesc.Format;
|
||||
|
||||
// Check for render target size changes.
|
||||
Windows::Foundation::Size currentSize = m_holographicCamera->RenderTargetSize;
|
||||
if (m_d3dRenderTargetSize != currentSize)
|
||||
{
|
||||
// Set render target size.
|
||||
m_d3dRenderTargetSize = currentSize;
|
||||
|
||||
// A new depth stencil view is also needed.
|
||||
m_d3dDepthStencilView.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh depth stencil resources, if needed.
|
||||
if (m_d3dDepthStencilView == nullptr)
|
||||
{
|
||||
// Create a depth stencil view for use with 3D rendering if needed.
|
||||
CD3D11_TEXTURE2D_DESC depthStencilDesc(
|
||||
DXGI_FORMAT_D16_UNORM,
|
||||
static_cast<UINT>(m_d3dRenderTargetSize.Width),
|
||||
static_cast<UINT>(m_d3dRenderTargetSize.Height),
|
||||
m_isStereo ? 2 : 1, // Create two textures when rendering in stereo.
|
||||
1, // Use a single mipmap level.
|
||||
D3D11_BIND_DEPTH_STENCIL
|
||||
);
|
||||
|
||||
ComPtr<ID3D11Texture2D> depthStencil;
|
||||
DX::ThrowIfFailed(
|
||||
device->CreateTexture2D(
|
||||
&depthStencilDesc,
|
||||
nullptr,
|
||||
&depthStencil
|
||||
)
|
||||
);
|
||||
|
||||
CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(
|
||||
m_isStereo ? D3D11_DSV_DIMENSION_TEXTURE2DARRAY : D3D11_DSV_DIMENSION_TEXTURE2D
|
||||
);
|
||||
DX::ThrowIfFailed(
|
||||
device->CreateDepthStencilView(
|
||||
depthStencil.Get(),
|
||||
&depthStencilViewDesc,
|
||||
&m_d3dDepthStencilView
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Create the constant buffer, if needed.
|
||||
if (m_viewProjectionConstantBuffer == nullptr)
|
||||
{
|
||||
// Create a constant buffer to store view and projection matrices for the camera.
|
||||
CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);
|
||||
DX::ThrowIfFailed(
|
||||
device->CreateBuffer(
|
||||
&constantBufferDesc,
|
||||
nullptr,
|
||||
&m_viewProjectionConstantBuffer
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Releases resources associated with a back buffer.
|
||||
void DX::CameraResources::ReleaseResourcesForBackBuffer(DX::DeviceResources* pDeviceResources)
|
||||
{
|
||||
const auto context = pDeviceResources->GetD3DDeviceContext();
|
||||
|
||||
// Release camera-specific resources.
|
||||
m_d3dBackBuffer.Reset();
|
||||
m_d3dRenderTargetView.Reset();
|
||||
m_d3dDepthStencilView.Reset();
|
||||
m_viewProjectionConstantBuffer.Reset();
|
||||
|
||||
// Ensure system references to the back buffer are released by clearing the render
|
||||
// target from the graphics pipeline state, and then flushing the Direct3D context.
|
||||
ID3D11RenderTargetView* nullViews[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { nullptr };
|
||||
context->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
|
||||
context->Flush();
|
||||
}
|
||||
|
||||
// Updates the view/projection constant buffer for a holographic camera.
|
||||
void DX::CameraResources::UpdateViewProjectionBuffer(
|
||||
std::shared_ptr<DX::DeviceResources> deviceResources,
|
||||
HolographicCameraPose^ cameraPose,
|
||||
SpatialCoordinateSystem^ coordinateSystem
|
||||
)
|
||||
{
|
||||
// The system changes the viewport on a per-frame basis for system optimizations.
|
||||
m_d3dViewport = CD3D11_VIEWPORT(
|
||||
cameraPose->Viewport.Left,
|
||||
cameraPose->Viewport.Top,
|
||||
cameraPose->Viewport.Width,
|
||||
cameraPose->Viewport.Height
|
||||
);
|
||||
|
||||
// The projection transform for each frame is provided by the HolographicCameraPose.
|
||||
HolographicStereoTransform cameraProjectionTransform = cameraPose->ProjectionTransform;
|
||||
|
||||
// Get a container object with the view and projection matrices for the given
|
||||
// pose in the given coordinate system.
|
||||
Platform::IBox<HolographicStereoTransform>^ viewTransformContainer = cameraPose->TryGetViewTransform(coordinateSystem);
|
||||
|
||||
// If TryGetViewTransform returns a null pointer, that means the pose and coordinate
|
||||
// system cannot be understood relative to one another; content cannot be rendered
|
||||
// in this coordinate system for the duration of the current frame.
|
||||
// This usually means that positional tracking is not active for the current frame, in
|
||||
// which case it is possible to use a SpatialLocatorAttachedFrameOfReference to render
|
||||
// content that is not world-locked instead.
|
||||
DX::ViewProjectionConstantBuffer viewProjectionConstantBufferData;
|
||||
bool viewTransformAcquired = viewTransformContainer != nullptr;
|
||||
if (viewTransformAcquired)
|
||||
{
|
||||
// Otherwise, the set of view transforms can be retrieved.
|
||||
HolographicStereoTransform viewCoordinateSystemTransform = viewTransformContainer->Value;
|
||||
|
||||
// Update the view matrices. Holographic cameras (such as Microsoft HoloLens) are
|
||||
// constantly moving relative to the world. The view matrices need to be updated
|
||||
// every frame.
|
||||
XMStoreFloat4x4(
|
||||
&viewProjectionConstantBufferData.viewProjection[0],
|
||||
XMMatrixTranspose(XMLoadFloat4x4(&viewCoordinateSystemTransform.Left) * XMLoadFloat4x4(&cameraProjectionTransform.Left))
|
||||
);
|
||||
XMStoreFloat4x4(
|
||||
&viewProjectionConstantBufferData.viewProjection[1],
|
||||
XMMatrixTranspose(XMLoadFloat4x4(&viewCoordinateSystemTransform.Right) * XMLoadFloat4x4(&cameraProjectionTransform.Right))
|
||||
);
|
||||
}
|
||||
|
||||
// Use the D3D device context to update Direct3D device-based resources.
|
||||
const auto context = deviceResources->GetD3DDeviceContext();
|
||||
|
||||
// Loading is asynchronous. Resources must be created before they can be updated.
|
||||
if (context == nullptr || m_viewProjectionConstantBuffer == nullptr || !viewTransformAcquired)
|
||||
{
|
||||
m_framePending = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update the view and projection matrices.
|
||||
context->UpdateSubresource(
|
||||
m_viewProjectionConstantBuffer.Get(),
|
||||
0,
|
||||
nullptr,
|
||||
&viewProjectionConstantBufferData,
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
m_framePending = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the view-projection constant buffer for the HolographicCamera and attaches it
|
||||
// to the shader pipeline.
|
||||
bool DX::CameraResources::AttachViewProjectionBuffer(
|
||||
std::shared_ptr<DX::DeviceResources> deviceResources
|
||||
)
|
||||
{
|
||||
// This method uses Direct3D device-based resources.
|
||||
const auto context = deviceResources->GetD3DDeviceContext();
|
||||
|
||||
// Loading is asynchronous. Resources must be created before they can be updated.
|
||||
// Cameras can also be added asynchronously, in which case they must be initialized
|
||||
// before they can be used.
|
||||
if (context == nullptr || m_viewProjectionConstantBuffer == nullptr || m_framePending == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the viewport for this camera.
|
||||
context->RSSetViewports(1, &m_d3dViewport);
|
||||
|
||||
// Send the constant buffer to the vertex shader.
|
||||
context->VSSetConstantBuffers(
|
||||
1,
|
||||
1,
|
||||
m_viewProjectionConstantBuffer.GetAddressOf()
|
||||
);
|
||||
|
||||
// The template includes a pass-through geometry shader that is used by
|
||||
// default on systems that don't support the D3D11_FEATURE_D3D11_OPTIONS3::
|
||||
// VPAndRTArrayIndexFromAnyShaderFeedingRasterizer extension. The shader
|
||||
// will be enabled at run-time on systems that require it.
|
||||
// If your app will also use the geometry shader for other tasks and those
|
||||
// tasks require the view/projection matrix, uncomment the following line
|
||||
// of code to send the constant buffer to the geometry shader as well.
|
||||
/*context->GSSetConstantBuffers(
|
||||
1,
|
||||
1,
|
||||
m_viewProjectionConstantBuffer.GetAddressOf()
|
||||
);*/
|
||||
|
||||
m_framePending = false;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace DX
|
||||
{
|
||||
class DeviceResources;
|
||||
|
||||
// Constant buffer used to send the view-projection matrices to the shader pipeline.
|
||||
struct ViewProjectionConstantBuffer
|
||||
{
|
||||
DirectX::XMFLOAT4X4 viewProjection[2];
|
||||
};
|
||||
|
||||
// Assert that the constant buffer remains 16-byte aligned (best practice).
|
||||
static_assert((sizeof(ViewProjectionConstantBuffer) % (sizeof(float) * 4)) == 0, "ViewProjection constant buffer size must be 16-byte aligned (16 bytes is the length of four floats).");
|
||||
|
||||
// Manages DirectX device resources that are specific to a holographic camera, such as the
|
||||
// back buffer, ViewProjection constant buffer, and viewport.
|
||||
class CameraResources
|
||||
{
|
||||
public:
|
||||
CameraResources(Windows::Graphics::Holographic::HolographicCamera^ holographicCamera);
|
||||
|
||||
void CreateResourcesForBackBuffer(
|
||||
DX::DeviceResources* pDeviceResources,
|
||||
Windows::Graphics::Holographic::HolographicCameraRenderingParameters^ cameraParameters
|
||||
);
|
||||
void ReleaseResourcesForBackBuffer(
|
||||
DX::DeviceResources* pDeviceResources
|
||||
);
|
||||
|
||||
void UpdateViewProjectionBuffer(
|
||||
std::shared_ptr<DX::DeviceResources> deviceResources,
|
||||
Windows::Graphics::Holographic::HolographicCameraPose^ cameraPose,
|
||||
Windows::Perception::Spatial::SpatialCoordinateSystem^ coordinateSystem);
|
||||
|
||||
bool AttachViewProjectionBuffer(
|
||||
std::shared_ptr<DX::DeviceResources> deviceResources);
|
||||
|
||||
// Direct3D device resources.
|
||||
ID3D11RenderTargetView* GetBackBufferRenderTargetView() const { return m_d3dRenderTargetView.Get(); }
|
||||
ID3D11DepthStencilView* GetDepthStencilView() const { return m_d3dDepthStencilView.Get(); }
|
||||
ID3D11Texture2D* GetBackBufferTexture2D() const { return m_d3dBackBuffer.Get(); }
|
||||
D3D11_VIEWPORT GetViewport() const { return m_d3dViewport; }
|
||||
DXGI_FORMAT GetBackBufferDXGIFormat() const { return m_dxgiFormat; }
|
||||
|
||||
// Render target properties.
|
||||
Windows::Foundation::Size GetRenderTargetSize() const { return m_d3dRenderTargetSize; }
|
||||
bool IsRenderingStereoscopic() const { return m_isStereo; }
|
||||
|
||||
// The holographic camera these resources are for.
|
||||
Windows::Graphics::Holographic::HolographicCamera^ GetHolographicCamera() const { return m_holographicCamera; }
|
||||
|
||||
private:
|
||||
// Direct3D rendering objects. Required for 3D.
|
||||
Microsoft::WRL::ComPtr<ID3D11RenderTargetView> m_d3dRenderTargetView;
|
||||
Microsoft::WRL::ComPtr<ID3D11DepthStencilView> m_d3dDepthStencilView;
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> m_d3dBackBuffer;
|
||||
|
||||
// Device resource to store view and projection matrices.
|
||||
Microsoft::WRL::ComPtr<ID3D11Buffer> m_viewProjectionConstantBuffer;
|
||||
|
||||
// Direct3D rendering properties.
|
||||
DXGI_FORMAT m_dxgiFormat;
|
||||
Windows::Foundation::Size m_d3dRenderTargetSize;
|
||||
D3D11_VIEWPORT m_d3dViewport;
|
||||
|
||||
// Indicates whether the camera supports stereoscopic rendering.
|
||||
bool m_isStereo = false;
|
||||
|
||||
// Indicates whether this camera has a pending frame.
|
||||
bool m_framePending = false;
|
||||
|
||||
// Pointer to the holographic camera these resources are for.
|
||||
Windows::Graphics::Holographic::HolographicCamera^ m_holographicCamera = nullptr;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,360 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#include "pch.h"
|
||||
#include "DeviceResources.h"
|
||||
#include "DirectXHelper.h"
|
||||
|
||||
#include <Collection.h>
|
||||
#include <windows.graphics.directx.direct3d11.interop.h>
|
||||
|
||||
using namespace D2D1;
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace Windows::Graphics::DirectX::Direct3D11;
|
||||
using namespace Windows::Graphics::Display;
|
||||
using namespace Windows::Graphics::Holographic;
|
||||
|
||||
// Constructor for DeviceResources.
|
||||
DX::DeviceResources::DeviceResources()
|
||||
{
|
||||
CreateDeviceIndependentResources();
|
||||
}
|
||||
|
||||
// Configures resources that don't depend on the Direct3D device.
|
||||
void DX::DeviceResources::CreateDeviceIndependentResources()
|
||||
{
|
||||
// Initialize Direct2D resources.
|
||||
D2D1_FACTORY_OPTIONS options {};
|
||||
|
||||
#if defined(_DEBUG)
|
||||
// If the project is in a debug build, enable Direct2D debugging via SDK Layers.
|
||||
options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
|
||||
#endif
|
||||
|
||||
// Initialize the Direct2D Factory.
|
||||
DX::ThrowIfFailed(
|
||||
D2D1CreateFactory(
|
||||
D2D1_FACTORY_TYPE_SINGLE_THREADED,
|
||||
__uuidof(ID2D1Factory2),
|
||||
&options,
|
||||
&m_d2dFactory
|
||||
)
|
||||
);
|
||||
|
||||
// Initialize the DirectWrite Factory.
|
||||
DX::ThrowIfFailed(
|
||||
DWriteCreateFactory(
|
||||
DWRITE_FACTORY_TYPE_SHARED,
|
||||
__uuidof(IDWriteFactory2),
|
||||
&m_dwriteFactory
|
||||
)
|
||||
);
|
||||
|
||||
// Initialize the Windows Imaging Component (WIC) Factory.
|
||||
DX::ThrowIfFailed(
|
||||
CoCreateInstance(
|
||||
CLSID_WICImagingFactory2,
|
||||
nullptr,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_PPV_ARGS(&m_wicFactory)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void DX::DeviceResources::SetHolographicSpace(HolographicSpace^ holographicSpace)
|
||||
{
|
||||
// Cache the holographic space. Used to re-initalize during device-lost scenarios.
|
||||
m_holographicSpace = holographicSpace;
|
||||
|
||||
InitializeUsingHolographicSpace();
|
||||
}
|
||||
|
||||
void DX::DeviceResources::InitializeUsingHolographicSpace()
|
||||
{
|
||||
// The holographic space might need to determine which adapter supports
|
||||
// holograms, in which case it will specify a non-zero PrimaryAdapterId.
|
||||
LUID id =
|
||||
{
|
||||
m_holographicSpace->PrimaryAdapterId.LowPart,
|
||||
m_holographicSpace->PrimaryAdapterId.HighPart
|
||||
};
|
||||
|
||||
// When a primary adapter ID is given to the app, the app should find
|
||||
// the corresponding DXGI adapter and use it to create Direct3D devices
|
||||
// and device contexts. Otherwise, there is no restriction on the DXGI
|
||||
// adapter the app can use.
|
||||
if ((id.HighPart != 0) && (id.LowPart != 0))
|
||||
{
|
||||
UINT createFlags = 0;
|
||||
#ifdef DEBUG
|
||||
if (DX::SdkLayersAvailable())
|
||||
{
|
||||
createFlags |= DXGI_CREATE_FACTORY_DEBUG;
|
||||
}
|
||||
#endif
|
||||
// Create the DXGI factory.
|
||||
ComPtr<IDXGIFactory1> dxgiFactory;
|
||||
DX::ThrowIfFailed(
|
||||
CreateDXGIFactory2(
|
||||
createFlags,
|
||||
IID_PPV_ARGS(&dxgiFactory)
|
||||
)
|
||||
);
|
||||
ComPtr<IDXGIFactory4> dxgiFactory4;
|
||||
DX::ThrowIfFailed(dxgiFactory.As(&dxgiFactory4));
|
||||
|
||||
// Retrieve the adapter specified by the holographic space.
|
||||
DX::ThrowIfFailed(
|
||||
dxgiFactory4->EnumAdapterByLuid(
|
||||
id,
|
||||
IID_PPV_ARGS(&m_dxgiAdapter)
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dxgiAdapter.Reset();
|
||||
}
|
||||
|
||||
CreateDeviceResources();
|
||||
|
||||
m_holographicSpace->SetDirect3D11Device(m_d3dInteropDevice);
|
||||
}
|
||||
|
||||
// Configures the Direct3D device, and stores handles to it and the device context.
|
||||
void DX::DeviceResources::CreateDeviceResources()
|
||||
{
|
||||
// This flag adds support for surfaces with a different color channel ordering
|
||||
// than the API default. It is required for compatibility with Direct2D.
|
||||
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
||||
|
||||
#if defined(_DEBUG)
|
||||
if (DX::SdkLayersAvailable())
|
||||
{
|
||||
// If the project is in a debug build, enable debugging via SDK Layers with this flag.
|
||||
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||
}
|
||||
#endif
|
||||
|
||||
// This array defines the set of DirectX hardware feature levels this app will support.
|
||||
// Note the ordering should be preserved.
|
||||
// Note that HoloLens supports feature level 11.1. The HoloLens emulator is also capable
|
||||
// of running on graphics cards starting with feature level 10.0.
|
||||
D3D_FEATURE_LEVEL featureLevels [] =
|
||||
{
|
||||
D3D_FEATURE_LEVEL_12_1,
|
||||
D3D_FEATURE_LEVEL_12_0,
|
||||
D3D_FEATURE_LEVEL_11_1,
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
D3D_FEATURE_LEVEL_10_1,
|
||||
D3D_FEATURE_LEVEL_10_0
|
||||
};
|
||||
|
||||
// Create the Direct3D 11 API device object and a corresponding context.
|
||||
ComPtr<ID3D11Device> device;
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
|
||||
const HRESULT hr = D3D11CreateDevice(
|
||||
m_dxgiAdapter.Get(), // Either nullptr, or the primary adapter determined by Windows Holographic.
|
||||
D3D_DRIVER_TYPE_HARDWARE, // Create a device using the hardware graphics driver.
|
||||
0, // Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE.
|
||||
creationFlags, // Set debug and Direct2D compatibility flags.
|
||||
featureLevels, // List of feature levels this app can support.
|
||||
ARRAYSIZE(featureLevels), // Size of the list above.
|
||||
D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps.
|
||||
&device, // Returns the Direct3D device created.
|
||||
&m_d3dFeatureLevel, // Returns feature level of device created.
|
||||
&context // Returns the device immediate context.
|
||||
);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// If the initialization fails, fall back to the WARP device.
|
||||
// For more information on WARP, see:
|
||||
// http://go.microsoft.com/fwlink/?LinkId=286690
|
||||
DX::ThrowIfFailed(
|
||||
D3D11CreateDevice(
|
||||
nullptr, // Use the default DXGI adapter for WARP.
|
||||
D3D_DRIVER_TYPE_WARP, // Create a WARP device instead of a hardware device.
|
||||
0,
|
||||
creationFlags,
|
||||
featureLevels,
|
||||
ARRAYSIZE(featureLevels),
|
||||
D3D11_SDK_VERSION,
|
||||
&device,
|
||||
&m_d3dFeatureLevel,
|
||||
&context
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Store pointers to the Direct3D device and immediate context.
|
||||
DX::ThrowIfFailed(
|
||||
device.As(&m_d3dDevice)
|
||||
);
|
||||
|
||||
DX::ThrowIfFailed(
|
||||
context.As(&m_d3dContext)
|
||||
);
|
||||
|
||||
// Acquire the DXGI interface for the Direct3D device.
|
||||
ComPtr<IDXGIDevice3> dxgiDevice;
|
||||
DX::ThrowIfFailed(
|
||||
m_d3dDevice.As(&dxgiDevice)
|
||||
);
|
||||
|
||||
// Wrap the native device using a WinRT interop object.
|
||||
m_d3dInteropDevice = CreateDirect3DDevice(dxgiDevice.Get());
|
||||
|
||||
// Cache the DXGI adapter.
|
||||
// This is for the case of no preferred DXGI adapter, or fallback to WARP.
|
||||
ComPtr<IDXGIAdapter> dxgiAdapter;
|
||||
DX::ThrowIfFailed(
|
||||
dxgiDevice->GetAdapter(&dxgiAdapter)
|
||||
);
|
||||
DX::ThrowIfFailed(
|
||||
dxgiAdapter.As(&m_dxgiAdapter)
|
||||
);
|
||||
|
||||
// Check for device support for the optional feature that allows setting the render target array index from the vertex shader stage.
|
||||
D3D11_FEATURE_DATA_D3D11_OPTIONS3 options;
|
||||
m_d3dDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS3, &options, sizeof(options));
|
||||
if (options.VPAndRTArrayIndexFromAnyShaderFeedingRasterizer)
|
||||
{
|
||||
m_supportsVprt = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Validates the back buffer for each HolographicCamera and recreates
|
||||
// resources for back buffers that have changed.
|
||||
// Locks the set of holographic camera resources until the function exits.
|
||||
void DX::DeviceResources::EnsureCameraResources(
|
||||
HolographicFrame^ frame,
|
||||
HolographicFramePrediction^ prediction)
|
||||
{
|
||||
UseHolographicCameraResources<void>([this, frame, prediction](std::map<UINT32, std::unique_ptr<CameraResources>>& cameraResourceMap)
|
||||
{
|
||||
for (HolographicCameraPose^ pose : prediction->CameraPoses)
|
||||
{
|
||||
HolographicCameraRenderingParameters^ renderingParameters = frame->GetRenderingParameters(pose);
|
||||
CameraResources* pCameraResources = cameraResourceMap[pose->HolographicCamera->Id].get();
|
||||
|
||||
pCameraResources->CreateResourcesForBackBuffer(this, renderingParameters);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Prepares to allocate resources and adds resource views for a camera.
|
||||
// Locks the set of holographic camera resources until the function exits.
|
||||
void DX::DeviceResources::AddHolographicCamera(HolographicCamera^ camera)
|
||||
{
|
||||
UseHolographicCameraResources<void>([this, camera](std::map<UINT32, std::unique_ptr<CameraResources>>& cameraResourceMap)
|
||||
{
|
||||
cameraResourceMap[camera->Id] = std::make_unique<CameraResources>(camera);
|
||||
});
|
||||
}
|
||||
|
||||
// Deallocates resources for a camera and removes the camera from the set.
|
||||
// Locks the set of holographic camera resources until the function exits.
|
||||
void DX::DeviceResources::RemoveHolographicCamera(HolographicCamera^ camera)
|
||||
{
|
||||
UseHolographicCameraResources<void>([this, camera](std::map<UINT32, std::unique_ptr<CameraResources>>& cameraResourceMap)
|
||||
{
|
||||
CameraResources* pCameraResources = cameraResourceMap[camera->Id].get();
|
||||
|
||||
if (pCameraResources != nullptr)
|
||||
{
|
||||
pCameraResources->ReleaseResourcesForBackBuffer(this);
|
||||
cameraResourceMap.erase(camera->Id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Recreate all device resources and set them back to the current state.
|
||||
// Locks the set of holographic camera resources until the function exits.
|
||||
void DX::DeviceResources::HandleDeviceLost()
|
||||
{
|
||||
if (m_deviceNotify != nullptr)
|
||||
{
|
||||
m_deviceNotify->OnDeviceLost();
|
||||
}
|
||||
|
||||
UseHolographicCameraResources<void>([this](std::map<UINT32, std::unique_ptr<CameraResources>>& cameraResourceMap)
|
||||
{
|
||||
for (auto& pair : cameraResourceMap)
|
||||
{
|
||||
CameraResources* pCameraResources = pair.second.get();
|
||||
pCameraResources->ReleaseResourcesForBackBuffer(this);
|
||||
}
|
||||
});
|
||||
|
||||
InitializeUsingHolographicSpace();
|
||||
|
||||
if (m_deviceNotify != nullptr)
|
||||
{
|
||||
m_deviceNotify->OnDeviceRestored();
|
||||
}
|
||||
}
|
||||
|
||||
// Register our DeviceNotify to be informed on device lost and creation.
|
||||
void DX::DeviceResources::RegisterDeviceNotify(DX::IDeviceNotify* deviceNotify)
|
||||
{
|
||||
m_deviceNotify = deviceNotify;
|
||||
}
|
||||
|
||||
// Call this method when the app suspends. It provides a hint to the driver that the app
|
||||
// is entering an idle state and that temporary buffers can be reclaimed for use by other apps.
|
||||
void DX::DeviceResources::Trim()
|
||||
{
|
||||
m_d3dContext->ClearState();
|
||||
|
||||
ComPtr<IDXGIDevice3> dxgiDevice;
|
||||
DX::ThrowIfFailed(m_d3dDevice.As(&dxgiDevice));
|
||||
dxgiDevice->Trim();
|
||||
}
|
||||
|
||||
// Present the contents of the swap chain to the screen.
|
||||
// Locks the set of holographic camera resources until the function exits.
|
||||
void DX::DeviceResources::Present(HolographicFrame^ frame)
|
||||
{
|
||||
// By default, this API waits for the frame to finish before it returns.
|
||||
// Holographic apps should wait for the previous frame to finish before
|
||||
// starting work on a new frame. This allows for better results from
|
||||
// holographic frame predictions.
|
||||
HolographicFramePresentResult presentResult = frame->PresentUsingCurrentPrediction();
|
||||
|
||||
HolographicFramePrediction^ prediction = frame->CurrentPrediction;
|
||||
UseHolographicCameraResources<void>([this, prediction](std::map<UINT32, std::unique_ptr<CameraResources>>& cameraResourceMap)
|
||||
{
|
||||
for (auto cameraPose : prediction->CameraPoses)
|
||||
{
|
||||
// This represents the device-based resources for a HolographicCamera.
|
||||
DX::CameraResources* pCameraResources = cameraResourceMap[cameraPose->HolographicCamera->Id].get();
|
||||
|
||||
// Discard the contents of the render target.
|
||||
// This is a valid operation only when the existing contents will be
|
||||
// entirely overwritten. If dirty or scroll rects are used, this call
|
||||
// should be removed.
|
||||
m_d3dContext->DiscardView(pCameraResources->GetBackBufferRenderTargetView());
|
||||
|
||||
// Discard the contents of the depth stencil.
|
||||
m_d3dContext->DiscardView(pCameraResources->GetDepthStencilView());
|
||||
}
|
||||
});
|
||||
|
||||
// The PresentUsingCurrentPrediction API will detect when the graphics device
|
||||
// changes or becomes invalid. When this happens, it is considered a Direct3D
|
||||
// device lost scenario.
|
||||
if (presentResult == HolographicFramePresentResult::DeviceRemoved)
|
||||
{
|
||||
// The Direct3D device, context, and resources should be recreated.
|
||||
HandleDeviceLost();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CameraResources.h"
|
||||
|
||||
namespace DX
|
||||
{
|
||||
// Provides an interface for an application that owns DeviceResources to be notified of the device being lost or created.
|
||||
interface IDeviceNotify
|
||||
{
|
||||
virtual void OnDeviceLost() = 0;
|
||||
virtual void OnDeviceRestored() = 0;
|
||||
};
|
||||
|
||||
// Creates and manages a Direct3D device and immediate context, Direct2D device and context (for debug), and the holographic swap chain.
|
||||
class DeviceResources
|
||||
{
|
||||
public:
|
||||
DeviceResources();
|
||||
|
||||
// Public methods related to Direct3D devices.
|
||||
void HandleDeviceLost();
|
||||
void RegisterDeviceNotify(IDeviceNotify* deviceNotify);
|
||||
void Trim();
|
||||
void Present(Windows::Graphics::Holographic::HolographicFrame^ frame);
|
||||
|
||||
// Public methods related to holographic devices.
|
||||
void SetHolographicSpace(Windows::Graphics::Holographic::HolographicSpace^ space);
|
||||
void EnsureCameraResources(
|
||||
Windows::Graphics::Holographic::HolographicFrame^ frame,
|
||||
Windows::Graphics::Holographic::HolographicFramePrediction^ prediction);
|
||||
|
||||
void AddHolographicCamera(Windows::Graphics::Holographic::HolographicCamera^ camera);
|
||||
void RemoveHolographicCamera(Windows::Graphics::Holographic::HolographicCamera^ camera);
|
||||
|
||||
// Holographic accessors.
|
||||
template<typename RetType, typename LCallback>
|
||||
RetType UseHolographicCameraResources(const LCallback& callback);
|
||||
|
||||
Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice^
|
||||
GetD3DInteropDevice() const { return m_d3dInteropDevice; }
|
||||
|
||||
// D3D accessors.
|
||||
ID3D11Device4* GetD3DDevice() const { return m_d3dDevice.Get(); }
|
||||
ID3D11DeviceContext3* GetD3DDeviceContext() const { return m_d3dContext.Get(); }
|
||||
D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const { return m_d3dFeatureLevel; }
|
||||
bool GetDeviceSupportsVprt() const { return m_supportsVprt; }
|
||||
|
||||
// DXGI acessors.
|
||||
IDXGIAdapter3* GetDXGIAdapter() const { return m_dxgiAdapter.Get(); }
|
||||
|
||||
// D2D accessors.
|
||||
ID2D1Factory2* GetD2DFactory() const { return m_d2dFactory.Get(); }
|
||||
IDWriteFactory2* GetDWriteFactory() const { return m_dwriteFactory.Get(); }
|
||||
IWICImagingFactory2* GetWicImagingFactory() const { return m_wicFactory.Get(); }
|
||||
|
||||
private:
|
||||
// Private methods related to the Direct3D device, and resources based on that device.
|
||||
void CreateDeviceIndependentResources();
|
||||
void InitializeUsingHolographicSpace();
|
||||
void CreateDeviceResources();
|
||||
|
||||
// Direct3D objects.
|
||||
Microsoft::WRL::ComPtr<ID3D11Device4> m_d3dDevice;
|
||||
Microsoft::WRL::ComPtr<ID3D11DeviceContext3> m_d3dContext;
|
||||
Microsoft::WRL::ComPtr<IDXGIAdapter3> m_dxgiAdapter;
|
||||
|
||||
// Direct3D interop objects.
|
||||
Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice^ m_d3dInteropDevice;
|
||||
|
||||
// Direct2D factories.
|
||||
Microsoft::WRL::ComPtr<ID2D1Factory2> m_d2dFactory;
|
||||
Microsoft::WRL::ComPtr<IDWriteFactory2> m_dwriteFactory;
|
||||
Microsoft::WRL::ComPtr<IWICImagingFactory2> m_wicFactory;
|
||||
|
||||
// The holographic space provides a preferred DXGI adapter ID.
|
||||
Windows::Graphics::Holographic::HolographicSpace^ m_holographicSpace = nullptr;
|
||||
|
||||
// Properties of the Direct3D device currently in use.
|
||||
D3D_FEATURE_LEVEL m_d3dFeatureLevel = D3D_FEATURE_LEVEL_10_0;
|
||||
|
||||
// The IDeviceNotify can be held directly as it owns the DeviceResources.
|
||||
IDeviceNotify* m_deviceNotify = nullptr;
|
||||
|
||||
// Whether or not the current Direct3D device supports the optional feature
|
||||
// for setting the render target array index from the vertex shader stage.
|
||||
bool m_supportsVprt = false;
|
||||
|
||||
// Back buffer resources, etc. for attached holographic cameras.
|
||||
std::map<UINT32, std::unique_ptr<CameraResources>> m_cameraResources;
|
||||
std::mutex m_cameraResourcesLock;
|
||||
};
|
||||
}
|
||||
|
||||
// Device-based resources for holographic cameras are stored in a std::map. Access this list by providing a
|
||||
// callback to this function, and the std::map will be guarded from add and remove
|
||||
// events until the callback returns. The callback is processed immediately and must
|
||||
// not contain any nested calls to UseHolographicCameraResources.
|
||||
// The callback takes a parameter of type std::map<UINT32, std::unique_ptr<DX::CameraResources>>&
|
||||
// through which the list of cameras will be accessed.
|
||||
template<typename RetType, typename LCallback>
|
||||
RetType DX::DeviceResources::UseHolographicCameraResources(const LCallback& callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_cameraResourcesLock);
|
||||
return callback(m_cameraResources);
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ppltasks.h> // For create_task
|
||||
|
||||
namespace DX
|
||||
{
|
||||
inline void ThrowIfFailed(HRESULT hr)
|
||||
{
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// Set a breakpoint on this line to catch Win32 API errors.
|
||||
throw Platform::Exception::CreateException(hr);
|
||||
}
|
||||
}
|
||||
|
||||
// Function that reads from a binary file asynchronously.
|
||||
inline Concurrency::task<std::vector<byte>> ReadDataAsync(const std::wstring& filename)
|
||||
{
|
||||
using namespace Windows::Storage;
|
||||
using namespace Concurrency;
|
||||
|
||||
return create_task(PathIO::ReadBufferAsync(Platform::StringReference(filename.c_str()))).then(
|
||||
[] (Streams::IBuffer^ fileBuffer) -> std::vector<byte>
|
||||
{
|
||||
std::vector<byte> returnBuffer;
|
||||
returnBuffer.resize(fileBuffer->Length);
|
||||
Streams::DataReader::FromBuffer(fileBuffer)->ReadBytes(Platform::ArrayReference<byte>(returnBuffer.data(), returnBuffer.size()));
|
||||
return returnBuffer;
|
||||
});
|
||||
}
|
||||
|
||||
// Converts a length in device-independent pixels (DIPs) to a length in physical pixels.
|
||||
inline float ConvertDipsToPixels(float dips, float dpi)
|
||||
{
|
||||
constexpr float dipsPerInch = 96.0f;
|
||||
return floorf(dips * dpi / dipsPerInch + 0.5f); // Round to nearest integer.
|
||||
}
|
||||
|
||||
#if defined(_DEBUG)
|
||||
// Check for SDK Layer support.
|
||||
inline bool SdkLayersAvailable()
|
||||
{
|
||||
HRESULT hr = D3D11CreateDevice(
|
||||
nullptr,
|
||||
D3D_DRIVER_TYPE_NULL, // There is no need to create a real hardware device.
|
||||
0,
|
||||
D3D11_CREATE_DEVICE_DEBUG, // Check for the SDK layers.
|
||||
nullptr, // Any feature level will do.
|
||||
0,
|
||||
D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps.
|
||||
nullptr, // No need to keep the D3D device reference.
|
||||
nullptr, // No need to know the feature level.
|
||||
nullptr // No need to keep the D3D device context reference.
|
||||
);
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
|
||||
namespace HolographicVoiceInput {
|
||||
|
||||
static void PrintWstringToDebugConsole(std::wstring message)
|
||||
{
|
||||
OutputDebugString(message.c_str());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace DX
|
||||
{
|
||||
// Helper class for animation and simulation timing.
|
||||
class StepTimer
|
||||
{
|
||||
public:
|
||||
StepTimer() :
|
||||
m_elapsedTicks(0),
|
||||
m_totalTicks(0),
|
||||
m_leftOverTicks(0),
|
||||
m_frameCount(0),
|
||||
m_framesPerSecond(0),
|
||||
m_framesThisSecond(0),
|
||||
m_qpcSecondCounter(0),
|
||||
m_isFixedTimeStep(false),
|
||||
m_targetElapsedTicks(TicksPerSecond / 60)
|
||||
{
|
||||
m_qpcFrequency = GetPerformanceFrequency();
|
||||
|
||||
// Initialize max delta to 1/10 of a second.
|
||||
m_qpcMaxDelta = m_qpcFrequency / 10;
|
||||
}
|
||||
|
||||
// Get elapsed time since the previous Update call.
|
||||
uint64 GetElapsedTicks() const { return m_elapsedTicks; }
|
||||
double GetElapsedSeconds() const { return TicksToSeconds(m_elapsedTicks); }
|
||||
|
||||
// Get total time since the start of the program.
|
||||
uint64 GetTotalTicks() const { return m_totalTicks; }
|
||||
double GetTotalSeconds() const { return TicksToSeconds(m_totalTicks); }
|
||||
|
||||
// Get total number of updates since start of the program.
|
||||
uint32 GetFrameCount() const { return m_frameCount; }
|
||||
|
||||
// Get the current framerate.
|
||||
uint32 GetFramesPerSecond() const { return m_framesPerSecond; }
|
||||
|
||||
// Set whether to use fixed or variable timestep mode.
|
||||
void SetFixedTimeStep(bool isFixedTimestep) { m_isFixedTimeStep = isFixedTimestep; }
|
||||
|
||||
// Set how often to call Update when in fixed timestep mode.
|
||||
void SetTargetElapsedTicks(uint64 targetElapsed) { m_targetElapsedTicks = targetElapsed; }
|
||||
void SetTargetElapsedSeconds(double targetElapsed) { m_targetElapsedTicks = SecondsToTicks(targetElapsed); }
|
||||
|
||||
// Integer format represents time using 10,000,000 ticks per second.
|
||||
static const uint64 TicksPerSecond = 10'000'000;
|
||||
|
||||
static double TicksToSeconds(uint64 ticks) { return static_cast<double>(ticks) / TicksPerSecond; }
|
||||
static uint64 SecondsToTicks(double seconds) { return static_cast<uint64>(seconds * TicksPerSecond); }
|
||||
|
||||
// Convenient wrapper for QueryPerformanceFrequency. Throws an exception if
|
||||
// the call to QueryPerformanceFrequency fails.
|
||||
static inline uint64 GetPerformanceFrequency()
|
||||
{
|
||||
LARGE_INTEGER freq;
|
||||
if (!QueryPerformanceFrequency(&freq))
|
||||
{
|
||||
throw ref new Platform::FailureException();
|
||||
}
|
||||
return freq.QuadPart;
|
||||
}
|
||||
|
||||
// Gets the current number of ticks from QueryPerformanceCounter. Throws an
|
||||
// exception if the call to QueryPerformanceCounter fails.
|
||||
static inline int64 GetTicks()
|
||||
{
|
||||
LARGE_INTEGER ticks;
|
||||
if (!QueryPerformanceCounter(&ticks))
|
||||
{
|
||||
throw ref new Platform::FailureException();
|
||||
}
|
||||
return ticks.QuadPart;
|
||||
}
|
||||
|
||||
// After an intentional timing discontinuity (for instance a blocking IO operation)
|
||||
// call this to avoid having the fixed timestep logic attempt a set of catch-up
|
||||
// Update calls.
|
||||
|
||||
void ResetElapsedTime()
|
||||
{
|
||||
m_qpcLastTime = GetTicks();
|
||||
|
||||
m_leftOverTicks = 0;
|
||||
m_framesPerSecond = 0;
|
||||
m_framesThisSecond = 0;
|
||||
m_qpcSecondCounter = 0;
|
||||
}
|
||||
|
||||
// Update timer state, calling the specified Update function the appropriate number of times.
|
||||
template<typename TUpdate>
|
||||
void Tick(const TUpdate& update)
|
||||
{
|
||||
// Query the current time.
|
||||
uint64 currentTime = GetTicks();
|
||||
uint64 timeDelta = currentTime - m_qpcLastTime;
|
||||
|
||||
m_qpcLastTime = currentTime;
|
||||
m_qpcSecondCounter += timeDelta;
|
||||
|
||||
// Clamp excessively large time deltas (e.g. after paused in the debugger).
|
||||
if (timeDelta > m_qpcMaxDelta)
|
||||
{
|
||||
timeDelta = m_qpcMaxDelta;
|
||||
}
|
||||
|
||||
// Convert QPC units into a canonical tick format. This cannot overflow due to the previous clamp.
|
||||
timeDelta *= TicksPerSecond;
|
||||
timeDelta /= m_qpcFrequency;
|
||||
|
||||
uint32 lastFrameCount = m_frameCount;
|
||||
|
||||
if (m_isFixedTimeStep)
|
||||
{
|
||||
// Fixed timestep update logic
|
||||
|
||||
// If the app is running very close to the target elapsed time (within 1/4 of a millisecond) just clamp
|
||||
// the clock to exactly match the target value. This prevents tiny and irrelevant errors
|
||||
// from accumulating over time. Without this clamping, a game that requested a 60 fps
|
||||
// fixed update, running with vsync enabled on a 59.94 NTSC display, would eventually
|
||||
// accumulate enough tiny errors that it would drop a frame. It is better to just round
|
||||
// small deviations down to zero to leave things running smoothly.
|
||||
|
||||
if (abs(static_cast<int64>(timeDelta - m_targetElapsedTicks)) < TicksPerSecond / 4000)
|
||||
{
|
||||
timeDelta = m_targetElapsedTicks;
|
||||
}
|
||||
|
||||
m_leftOverTicks += timeDelta;
|
||||
|
||||
while (m_leftOverTicks >= m_targetElapsedTicks)
|
||||
{
|
||||
m_elapsedTicks = m_targetElapsedTicks;
|
||||
m_totalTicks += m_targetElapsedTicks;
|
||||
m_leftOverTicks -= m_targetElapsedTicks;
|
||||
m_frameCount++;
|
||||
|
||||
update();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Variable timestep update logic.
|
||||
m_elapsedTicks = timeDelta;
|
||||
m_totalTicks += timeDelta;
|
||||
m_leftOverTicks = 0;
|
||||
m_frameCount++;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
// Track the current framerate.
|
||||
if (m_frameCount != lastFrameCount)
|
||||
{
|
||||
m_framesThisSecond++;
|
||||
}
|
||||
|
||||
if (m_qpcSecondCounter >= static_cast<uint64>(m_qpcFrequency))
|
||||
{
|
||||
m_framesPerSecond = m_framesThisSecond;
|
||||
m_framesThisSecond = 0;
|
||||
m_qpcSecondCounter %= m_qpcFrequency;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Source timing data uses QPC units.
|
||||
uint64 m_qpcFrequency;
|
||||
uint64 m_qpcLastTime;
|
||||
uint64 m_qpcMaxDelta;
|
||||
|
||||
// Derived timing data uses a canonical tick format.
|
||||
uint64 m_elapsedTicks;
|
||||
uint64 m_totalTicks;
|
||||
uint64 m_leftOverTicks;
|
||||
|
||||
// Members for tracking the framerate.
|
||||
uint32 m_frameCount;
|
||||
uint32 m_framesPerSecond;
|
||||
uint32 m_framesThisSecond;
|
||||
uint64 m_qpcSecondCounter;
|
||||
|
||||
// Members for configuring fixed timestep mode.
|
||||
bool m_isFixedTimeStep;
|
||||
uint64 m_targetElapsedTicks;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
// Per-vertex data from the vertex shader.
|
||||
struct GeometryShaderInput
|
||||
{
|
||||
min16float4 pos : SV_POSITION;
|
||||
min16float3 color : COLOR0;
|
||||
uint instId : TEXCOORD0;
|
||||
};
|
||||
|
||||
// Per-vertex data passed to the rasterizer.
|
||||
struct GeometryShaderOutput
|
||||
{
|
||||
min16float4 pos : SV_POSITION;
|
||||
min16float3 color : COLOR0;
|
||||
uint rtvId : SV_RenderTargetArrayIndex;
|
||||
};
|
||||
|
||||
// This geometry shader is a pass-through that leaves the geometry unmodified
|
||||
// and sets the render target array index.
|
||||
[maxvertexcount(3)]
|
||||
void main(triangle GeometryShaderInput input[3], inout TriangleStream<GeometryShaderOutput> outStream)
|
||||
{
|
||||
GeometryShaderOutput output;
|
||||
[unroll(3)]
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
output.pos = input[i].pos;
|
||||
output.color = input[i].color;
|
||||
output.rtvId = input[i].instId;
|
||||
outStream.Append(output);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
// Per-pixel color data passed through the pixel shader.
|
||||
struct PixelShaderInput
|
||||
{
|
||||
min16float4 pos : SV_POSITION;
|
||||
min16float3 color : COLOR0;
|
||||
};
|
||||
|
||||
// The pixel shader passes through the color data. The color data from
|
||||
// is interpolated and assigned to a pixel at the rasterization step.
|
||||
min16float4 main(PixelShaderInput input) : SV_TARGET
|
||||
{
|
||||
return min16float4(input.color, 1.0f);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace HolographicVoiceInput
|
||||
{
|
||||
// Constant buffer used to send hologram position transform to the shader pipeline.
|
||||
struct ModelColorConstantBuffer
|
||||
{
|
||||
DirectX::XMFLOAT4X4 model;
|
||||
DirectX::XMFLOAT4 color;
|
||||
};
|
||||
|
||||
// Assert that the constant buffer remains 16-byte aligned (best practice).
|
||||
static_assert((sizeof(ModelColorConstantBuffer) % (sizeof(float) * 4)) == 0, "Model constant buffer size must be 16-byte aligned (16 bytes is the length of four floats).");
|
||||
|
||||
|
||||
// Used to send per-vertex data to the vertex shader.
|
||||
struct VertexPositionColor
|
||||
{
|
||||
DirectX::XMFLOAT3 pos;
|
||||
DirectX::XMFLOAT3 color;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#include "pch.h"
|
||||
#include "SpatialInputHandler.h"
|
||||
#include <functional>
|
||||
|
||||
using namespace HolographicVoiceInput;
|
||||
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::UI::Input::Spatial;
|
||||
using namespace std::placeholders;
|
||||
|
||||
// Creates and initializes a GestureRecognizer that listens to a Person.
|
||||
SpatialInputHandler::SpatialInputHandler()
|
||||
{
|
||||
// The interaction manager provides an event that informs the app when
|
||||
// spatial interactions are detected.
|
||||
m_interactionManager = SpatialInteractionManager::GetForCurrentView();
|
||||
|
||||
// Bind a handler to the SourcePressed event.
|
||||
m_sourcePressedEventToken =
|
||||
m_interactionManager->SourcePressed +=
|
||||
ref new TypedEventHandler<SpatialInteractionManager^, SpatialInteractionSourceEventArgs^>(
|
||||
bind(&SpatialInputHandler::OnSourcePressed, this, _1, _2)
|
||||
);
|
||||
|
||||
//
|
||||
// TODO: Expand this class to use other gesture-based input events as applicable to
|
||||
// your app.
|
||||
//
|
||||
}
|
||||
|
||||
SpatialInputHandler::~SpatialInputHandler()
|
||||
{
|
||||
// Unregister our handler for the OnSourcePressed event.
|
||||
m_interactionManager->SourcePressed -= m_sourcePressedEventToken;
|
||||
}
|
||||
|
||||
// Checks if the user performed an input gesture since the last call to this method.
|
||||
// Allows the main update loop to check for asynchronous changes to the user
|
||||
// input state.
|
||||
SpatialInteractionSourceState^ SpatialInputHandler::CheckForInput()
|
||||
{
|
||||
SpatialInteractionSourceState^ sourceState = m_sourceState;
|
||||
m_sourceState = nullptr;
|
||||
return sourceState;
|
||||
}
|
||||
|
||||
void SpatialInputHandler::OnSourcePressed(SpatialInteractionManager^ sender, SpatialInteractionSourceEventArgs^ args)
|
||||
{
|
||||
m_sourceState = args->State;
|
||||
|
||||
//
|
||||
// TODO: In your app or game engine, rewrite this method to queue
|
||||
// input events in your input class or event handler.
|
||||
//
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace HolographicVoiceInput
|
||||
{
|
||||
// Sample gesture handler.
|
||||
// Hooks up events to recognize a tap gesture, and keeps track of input using a boolean value.
|
||||
class SpatialInputHandler
|
||||
{
|
||||
public:
|
||||
SpatialInputHandler();
|
||||
~SpatialInputHandler();
|
||||
|
||||
Windows::UI::Input::Spatial::SpatialInteractionSourceState^ CheckForInput();
|
||||
|
||||
private:
|
||||
// Interaction event handler.
|
||||
void OnSourcePressed(
|
||||
Windows::UI::Input::Spatial::SpatialInteractionManager^ sender,
|
||||
Windows::UI::Input::Spatial::SpatialInteractionSourceEventArgs^ args);
|
||||
|
||||
// API objects used to process gesture input, and generate gesture events.
|
||||
Windows::UI::Input::Spatial::SpatialInteractionManager^ m_interactionManager;
|
||||
|
||||
// Event registration token.
|
||||
Windows::Foundation::EventRegistrationToken m_sourcePressedEventToken;
|
||||
|
||||
// Used to indicate that a Pressed input event was received this frame.
|
||||
Windows::UI::Input::Spatial::SpatialInteractionSourceState^ m_sourceState = nullptr;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,357 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#include "pch.h"
|
||||
#include "SpinningCubeRenderer.h"
|
||||
#include "Common\DirectXHelper.h"
|
||||
|
||||
using namespace HolographicVoiceInput;
|
||||
using namespace Concurrency;
|
||||
using namespace DirectX;
|
||||
using namespace Windows::Foundation::Numerics;
|
||||
using namespace Windows::UI::Input::Spatial;
|
||||
|
||||
// Loads vertex and pixel shaders from files and instantiates the cube geometry.
|
||||
SpinningCubeRenderer::SpinningCubeRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
|
||||
m_deviceResources(deviceResources)
|
||||
{
|
||||
// For speech example.
|
||||
// Set the initial color to white.
|
||||
m_modelConstantBufferData.color = { 1.f, 1.f, 0.f, 1.f };
|
||||
|
||||
CreateDeviceDependentResources();
|
||||
}
|
||||
|
||||
// This function uses a SpatialPointerPose to position the world-locked hologram
|
||||
// two meters in front of the user's heading.
|
||||
void SpinningCubeRenderer::PositionHologram(SpatialPointerPose^ pointerPose)
|
||||
{
|
||||
if (pointerPose != nullptr)
|
||||
{
|
||||
// Get the gaze direction relative to the given coordinate system.
|
||||
const float3 headPosition = pointerPose->Head->Position;
|
||||
const float3 headDirection = pointerPose->Head->ForwardDirection;
|
||||
|
||||
// The hologram is positioned two meters along the user's gaze direction.
|
||||
constexpr float distanceFromUser = 2.0f; // meters
|
||||
const float3 gazeAtTwoMeters = headPosition + (distanceFromUser * headDirection);
|
||||
|
||||
// This will be used as the translation component of the hologram's
|
||||
// model transform.
|
||||
SetPosition(gazeAtTwoMeters);
|
||||
}
|
||||
}
|
||||
|
||||
// Called once per frame. Rotates the cube, and calculates and sets the model matrix
|
||||
// relative to the position transform indicated by hologramPositionTransform.
|
||||
void SpinningCubeRenderer::Update(const DX::StepTimer& timer)
|
||||
{
|
||||
// Rotate the cube.
|
||||
// Convert degrees to radians, then convert seconds to rotation angle.
|
||||
const float radiansPerSecond = XMConvertToRadians(m_degreesPerSecond);
|
||||
const double totalRotation = timer.GetTotalSeconds() * radiansPerSecond;
|
||||
const float radians = static_cast<float>(fmod(totalRotation, XM_2PI));
|
||||
const XMMATRIX modelRotation = XMMatrixRotationY(-radians);
|
||||
|
||||
// Position the cube.
|
||||
const XMMATRIX modelTranslation = XMMatrixTranslationFromVector(XMLoadFloat3(&m_position));
|
||||
|
||||
// Multiply to get the transform matrix.
|
||||
// Note that this transform does not enforce a particular coordinate system. The calling
|
||||
// class is responsible for rendering this content in a consistent manner.
|
||||
const XMMATRIX modelTransform = XMMatrixMultiply(modelRotation, modelTranslation);
|
||||
|
||||
// The view and projection matrices are provided by the system; they are associated
|
||||
// with holographic cameras, and updated on a per-camera basis.
|
||||
// Here, we provide the model transform for the sample hologram. The model transform
|
||||
// matrix is transposed to prepare it for the shader.
|
||||
XMStoreFloat4x4(&m_modelConstantBufferData.model, XMMatrixTranspose(modelTransform));
|
||||
|
||||
// Loading is asynchronous. Resources must be created before they can be updated.
|
||||
if (!m_loadingComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the D3D device context to update Direct3D device-based resources.
|
||||
const auto context = m_deviceResources->GetD3DDeviceContext();
|
||||
|
||||
// Update the model transform buffer for the hologram.
|
||||
context->UpdateSubresource(
|
||||
m_modelConstantBuffer.Get(),
|
||||
0,
|
||||
nullptr,
|
||||
&m_modelConstantBufferData,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// Renders one frame using the vertex and pixel shaders.
|
||||
// On devices that do not support the D3D11_FEATURE_D3D11_OPTIONS3::
|
||||
// VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature,
|
||||
// a pass-through geometry shader is also used to set the render
|
||||
// target array index.
|
||||
void SpinningCubeRenderer::Render()
|
||||
{
|
||||
// Loading is asynchronous. Resources must be created before drawing can occur.
|
||||
if (!m_loadingComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto context = m_deviceResources->GetD3DDeviceContext();
|
||||
|
||||
// Each vertex is one instance of the VertexPositionColor struct.
|
||||
const UINT stride = sizeof(VertexPositionColor);
|
||||
const UINT offset = 0;
|
||||
context->IASetVertexBuffers(
|
||||
0,
|
||||
1,
|
||||
m_vertexBuffer.GetAddressOf(),
|
||||
&stride,
|
||||
&offset
|
||||
);
|
||||
context->IASetIndexBuffer(
|
||||
m_indexBuffer.Get(),
|
||||
DXGI_FORMAT_R16_UINT, // Each index is one 16-bit unsigned integer (short).
|
||||
0
|
||||
);
|
||||
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
context->IASetInputLayout(m_inputLayout.Get());
|
||||
|
||||
// Attach the vertex shader.
|
||||
context->VSSetShader(
|
||||
m_vertexShader.Get(),
|
||||
nullptr,
|
||||
0
|
||||
);
|
||||
// Apply the model constant buffer to the vertex shader.
|
||||
context->VSSetConstantBuffers(
|
||||
0,
|
||||
1,
|
||||
m_modelConstantBuffer.GetAddressOf()
|
||||
);
|
||||
|
||||
if (!m_usingVprtShaders)
|
||||
{
|
||||
// On devices that do not support the D3D11_FEATURE_D3D11_OPTIONS3::
|
||||
// VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature,
|
||||
// a pass-through geometry shader is used to set the render target
|
||||
// array index.
|
||||
context->GSSetShader(
|
||||
m_geometryShader.Get(),
|
||||
nullptr,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// Attach the pixel shader.
|
||||
context->PSSetShader(
|
||||
m_pixelShader.Get(),
|
||||
nullptr,
|
||||
0
|
||||
);
|
||||
|
||||
// Draw the objects.
|
||||
context->DrawIndexedInstanced(
|
||||
m_indexCount, // Index count per instance.
|
||||
2, // Instance count.
|
||||
0, // Start index location.
|
||||
0, // Base vertex location.
|
||||
0 // Start instance location.
|
||||
);
|
||||
}
|
||||
|
||||
void SpinningCubeRenderer::CreateDeviceDependentResources()
|
||||
{
|
||||
m_usingVprtShaders = m_deviceResources->GetDeviceSupportsVprt();
|
||||
|
||||
// On devices that do support the D3D11_FEATURE_D3D11_OPTIONS3::
|
||||
// VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature
|
||||
// we can avoid using a pass-through geometry shader to set the render
|
||||
// target array index, thus avoiding any overhead that would be
|
||||
// incurred by setting the geometry shader stage.
|
||||
std::wstring vertexShaderFileName = m_usingVprtShaders ? L"ms-appx:///VprtVertexShader.cso" : L"ms-appx:///VertexShader.cso";
|
||||
|
||||
// Load shaders asynchronously.
|
||||
task<std::vector<byte>> loadVSTask = DX::ReadDataAsync(vertexShaderFileName);
|
||||
task<std::vector<byte>> loadPSTask = DX::ReadDataAsync(L"ms-appx:///PixelShader.cso");
|
||||
|
||||
task<std::vector<byte>> loadGSTask;
|
||||
if (!m_usingVprtShaders)
|
||||
{
|
||||
// Load the pass-through geometry shader.
|
||||
loadGSTask = DX::ReadDataAsync(L"ms-appx:///GeometryShader.cso");
|
||||
}
|
||||
|
||||
// After the vertex shader file is loaded, create the shader and input layout.
|
||||
task<void> createVSTask = loadVSTask.then([this] (const std::vector<byte>& fileData)
|
||||
{
|
||||
DX::ThrowIfFailed(
|
||||
m_deviceResources->GetD3DDevice()->CreateVertexShader(
|
||||
fileData.data(),
|
||||
fileData.size(),
|
||||
nullptr,
|
||||
&m_vertexShader
|
||||
)
|
||||
);
|
||||
|
||||
constexpr std::array<D3D11_INPUT_ELEMENT_DESC, 2> vertexDesc =
|
||||
{{
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
}};
|
||||
|
||||
DX::ThrowIfFailed(
|
||||
m_deviceResources->GetD3DDevice()->CreateInputLayout(
|
||||
vertexDesc.data(),
|
||||
vertexDesc.size(),
|
||||
fileData.data(),
|
||||
fileData.size(),
|
||||
&m_inputLayout
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
// After the pixel shader file is loaded, create the shader and constant buffer.
|
||||
task<void> createPSTask = loadPSTask.then([this] (const std::vector<byte>& fileData)
|
||||
{
|
||||
DX::ThrowIfFailed(
|
||||
m_deviceResources->GetD3DDevice()->CreatePixelShader(
|
||||
fileData.data(),
|
||||
fileData.size(),
|
||||
nullptr,
|
||||
&m_pixelShader
|
||||
)
|
||||
);
|
||||
|
||||
const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelColorConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);
|
||||
DX::ThrowIfFailed(
|
||||
m_deviceResources->GetD3DDevice()->CreateBuffer(
|
||||
&constantBufferDesc,
|
||||
nullptr,
|
||||
&m_modelConstantBuffer
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
task<void> createGSTask;
|
||||
if (!m_usingVprtShaders)
|
||||
{
|
||||
// After the pass-through geometry shader file is loaded, create the shader.
|
||||
createGSTask = loadGSTask.then([this] (const std::vector<byte>& fileData)
|
||||
{
|
||||
DX::ThrowIfFailed(
|
||||
m_deviceResources->GetD3DDevice()->CreateGeometryShader(
|
||||
fileData.data(),
|
||||
fileData.size(),
|
||||
nullptr,
|
||||
&m_geometryShader
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Once all shaders are loaded, create the mesh.
|
||||
task<void> shaderTaskGroup = m_usingVprtShaders ? (createPSTask && createVSTask) : (createPSTask && createVSTask && createGSTask);
|
||||
task<void> createCubeTask = shaderTaskGroup.then([this] ()
|
||||
{
|
||||
// Load mesh vertices. Each vertex has a position and a color.
|
||||
// Note that the cube size has changed from the default DirectX app
|
||||
// template. Windows Holographic is scaled in meters, so to draw the
|
||||
// cube at a comfortable size we made the cube width 0.2 m (20 cm).
|
||||
static const std::array<VertexPositionColor, 8> cubeVertices =
|
||||
{{
|
||||
{ XMFLOAT3(-0.1f, -0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f) },
|
||||
{ XMFLOAT3(-0.1f, -0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 1.0f) },
|
||||
{ XMFLOAT3(-0.1f, 0.1f, -0.1f), XMFLOAT3(0.0f, 1.0f, 0.0f) },
|
||||
{ XMFLOAT3(-0.1f, 0.1f, 0.1f), XMFLOAT3(0.0f, 1.0f, 1.0f) },
|
||||
{ XMFLOAT3( 0.1f, -0.1f, -0.1f), XMFLOAT3(1.0f, 0.0f, 0.0f) },
|
||||
{ XMFLOAT3( 0.1f, -0.1f, 0.1f), XMFLOAT3(1.0f, 0.0f, 1.0f) },
|
||||
{ XMFLOAT3( 0.1f, 0.1f, -0.1f), XMFLOAT3(1.0f, 1.0f, 0.0f) },
|
||||
{ XMFLOAT3( 0.1f, 0.1f, 0.1f), XMFLOAT3(1.0f, 1.0f, 1.0f) },
|
||||
}};
|
||||
|
||||
D3D11_SUBRESOURCE_DATA vertexBufferData = {0};
|
||||
vertexBufferData.pSysMem = cubeVertices.data();
|
||||
vertexBufferData.SysMemPitch = 0;
|
||||
vertexBufferData.SysMemSlicePitch = 0;
|
||||
const CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(VertexPositionColor) * cubeVertices.size(), D3D11_BIND_VERTEX_BUFFER);
|
||||
DX::ThrowIfFailed(
|
||||
m_deviceResources->GetD3DDevice()->CreateBuffer(
|
||||
&vertexBufferDesc,
|
||||
&vertexBufferData,
|
||||
&m_vertexBuffer
|
||||
)
|
||||
);
|
||||
|
||||
// Load mesh indices. Each trio of indices represents
|
||||
// a triangle to be rendered on the screen.
|
||||
// For example: 2,1,0 means that the vertices with indexes
|
||||
// 2, 1, and 0 from the vertex buffer compose the
|
||||
// first triangle of this mesh.
|
||||
// Note that the winding order is clockwise by default.
|
||||
constexpr std::array<unsigned short, 36> cubeIndices =
|
||||
{{
|
||||
2,1,0, // -x
|
||||
2,3,1,
|
||||
|
||||
6,4,5, // +x
|
||||
6,5,7,
|
||||
|
||||
0,1,5, // -y
|
||||
0,5,4,
|
||||
|
||||
2,6,7, // +y
|
||||
2,7,3,
|
||||
|
||||
0,4,6, // -z
|
||||
0,6,2,
|
||||
|
||||
1,3,7, // +z
|
||||
1,7,5,
|
||||
}};
|
||||
|
||||
m_indexCount = cubeIndices.size();
|
||||
|
||||
D3D11_SUBRESOURCE_DATA indexBufferData = {0};
|
||||
indexBufferData.pSysMem = cubeIndices.data();
|
||||
indexBufferData.SysMemPitch = 0;
|
||||
indexBufferData.SysMemSlicePitch = 0;
|
||||
CD3D11_BUFFER_DESC indexBufferDesc(sizeof(unsigned short) * cubeIndices.size(), D3D11_BIND_INDEX_BUFFER);
|
||||
DX::ThrowIfFailed(
|
||||
m_deviceResources->GetD3DDevice()->CreateBuffer(
|
||||
&indexBufferDesc,
|
||||
&indexBufferData,
|
||||
&m_indexBuffer
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
// Once the cube is loaded, the object is ready to be rendered.
|
||||
createCubeTask.then([this] ()
|
||||
{
|
||||
m_loadingComplete = true;
|
||||
});
|
||||
}
|
||||
|
||||
void SpinningCubeRenderer::ReleaseDeviceDependentResources()
|
||||
{
|
||||
m_loadingComplete = false;
|
||||
m_usingVprtShaders = false;
|
||||
m_vertexShader.Reset();
|
||||
m_inputLayout.Reset();
|
||||
m_pixelShader.Reset();
|
||||
m_geometryShader.Reset();
|
||||
m_modelConstantBuffer.Reset();
|
||||
m_vertexBuffer.Reset();
|
||||
m_indexBuffer.Reset();
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "..\Common\DeviceResources.h"
|
||||
#include "..\Common\StepTimer.h"
|
||||
#include "ShaderStructures.h"
|
||||
|
||||
namespace HolographicVoiceInput
|
||||
{
|
||||
// This sample renderer instantiates a basic rendering pipeline.
|
||||
class SpinningCubeRenderer
|
||||
{
|
||||
public:
|
||||
SpinningCubeRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources);
|
||||
void CreateDeviceDependentResources();
|
||||
void ReleaseDeviceDependentResources();
|
||||
void Update(const DX::StepTimer& timer);
|
||||
void Render();
|
||||
|
||||
// Repositions the sample hologram.
|
||||
void PositionHologram(Windows::UI::Input::Spatial::SpatialPointerPose^ pointerPose);
|
||||
|
||||
// Property accessors.
|
||||
void SetPosition(Windows::Foundation::Numerics::float3 pos) { m_position = pos; }
|
||||
Windows::Foundation::Numerics::float3 GetPosition() { return m_position; }
|
||||
|
||||
// For speech example.
|
||||
void SetColor(Windows::Foundation::Numerics::float4 const& color) { m_modelConstantBufferData.color = *reinterpret_cast<DirectX::XMFLOAT4 const*>(&color); }
|
||||
|
||||
private:
|
||||
// Cached pointer to device resources.
|
||||
std::shared_ptr<DX::DeviceResources> m_deviceResources;
|
||||
|
||||
// Direct3D resources for cube geometry.
|
||||
Microsoft::WRL::ComPtr<ID3D11InputLayout> m_inputLayout;
|
||||
Microsoft::WRL::ComPtr<ID3D11Buffer> m_vertexBuffer;
|
||||
Microsoft::WRL::ComPtr<ID3D11Buffer> m_indexBuffer;
|
||||
Microsoft::WRL::ComPtr<ID3D11VertexShader> m_vertexShader;
|
||||
Microsoft::WRL::ComPtr<ID3D11GeometryShader> m_geometryShader;
|
||||
Microsoft::WRL::ComPtr<ID3D11PixelShader> m_pixelShader;
|
||||
Microsoft::WRL::ComPtr<ID3D11Buffer> m_modelConstantBuffer;
|
||||
|
||||
// System resources for cube geometry.
|
||||
ModelColorConstantBuffer m_modelConstantBufferData;
|
||||
uint32 m_indexCount = 0;
|
||||
|
||||
// Variables used with the rendering loop.
|
||||
bool m_loadingComplete = false;
|
||||
float m_degreesPerSecond = 45.f;
|
||||
Windows::Foundation::Numerics::float3 m_position = { 0.f, 0.f, -2.f };
|
||||
|
||||
// If the current D3D Device supports VPRT, we can avoid using a geometry
|
||||
// shader just to set the render target array index.
|
||||
bool m_usingVprtShaders = false;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
// A constant buffer that stores the model transform.
|
||||
cbuffer ModelConstantBuffer : register(b0)
|
||||
{
|
||||
float4x4 model;
|
||||
float4 color;
|
||||
};
|
||||
|
||||
// A constant buffer that stores each set of view and projection matrices in column-major format.
|
||||
cbuffer ViewProjectionConstantBuffer : register(b1)
|
||||
{
|
||||
float4x4 viewProjection[2];
|
||||
};
|
||||
|
||||
// Per-vertex data used as input to the vertex shader.
|
||||
struct VertexShaderInput
|
||||
{
|
||||
min16float3 pos : POSITION;
|
||||
min16float3 color : COLOR0;
|
||||
uint instId : SV_InstanceID;
|
||||
};
|
||||
|
||||
// Per-vertex data passed to the geometry shader.
|
||||
// Note that the render target array index is set here in the vertex shader.
|
||||
struct VertexShaderOutput
|
||||
{
|
||||
min16float4 pos : SV_POSITION;
|
||||
min16float3 color : COLOR0;
|
||||
uint rtvId : SV_RenderTargetArrayIndex; // SV_InstanceID % 2
|
||||
};
|
||||
|
||||
// Simple shader to do vertex processing on the GPU.
|
||||
VertexShaderOutput main(VertexShaderInput input)
|
||||
{
|
||||
VertexShaderOutput output;
|
||||
float4 pos = float4(input.pos, 1.0f);
|
||||
|
||||
// Note which view this vertex has been sent to. Used for matrix lookup.
|
||||
// Taking the modulo of the instance ID allows geometry instancing to be used
|
||||
// along with stereo instanced drawing; in that case, two copies of each
|
||||
// instance would be drawn, one for left and one for right.
|
||||
int idx = input.instId % 2;
|
||||
|
||||
// Transform the vertex position into world space.
|
||||
pos = mul(pos, model);
|
||||
|
||||
// Correct for perspective and project the vertex position onto the screen.
|
||||
pos = mul(pos, viewProjection[idx]);
|
||||
output.pos = (min16float4)pos;
|
||||
|
||||
// Pass the color through without modification.
|
||||
output.color = min16float3(color.xyz);
|
||||
|
||||
// Set the render target array index.
|
||||
output.rtvId = idx;
|
||||
|
||||
return output;
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
// A constant buffer that stores the model transform.
|
||||
cbuffer ModelConstantBuffer : register(b0)
|
||||
{
|
||||
float4x4 model;
|
||||
float4 color;
|
||||
};
|
||||
|
||||
// A constant buffer that stores each set of view and projection matrices in column-major format.
|
||||
cbuffer ViewProjectionConstantBuffer : register(b1)
|
||||
{
|
||||
float4x4 viewProjection[2];
|
||||
};
|
||||
|
||||
// Per-vertex data used as input to the vertex shader.
|
||||
struct VertexShaderInput
|
||||
{
|
||||
min16float3 pos : POSITION;
|
||||
min16float3 color : COLOR0;
|
||||
uint instId : SV_InstanceID;
|
||||
};
|
||||
|
||||
// Per-vertex data passed to the geometry shader.
|
||||
// Note that the render target array index will be set by the geometry shader
|
||||
// using the value of viewId.
|
||||
struct VertexShaderOutput
|
||||
{
|
||||
min16float4 pos : SV_POSITION;
|
||||
min16float3 color : COLOR0;
|
||||
uint viewId : TEXCOORD0; // SV_InstanceID % 2
|
||||
};
|
||||
|
||||
// Simple shader to do vertex processing on the GPU.
|
||||
VertexShaderOutput main(VertexShaderInput input)
|
||||
{
|
||||
VertexShaderOutput output;
|
||||
float4 pos = float4(input.pos, 1.0f);
|
||||
|
||||
// Note which view this vertex has been sent to. Used for matrix lookup.
|
||||
// Taking the modulo of the instance ID allows geometry instancing to be used
|
||||
// along with stereo instanced drawing; in that case, two copies of each
|
||||
// instance would be drawn, one for left and one for right.
|
||||
int idx = input.instId % 2;
|
||||
|
||||
// Transform the vertex position into world space.
|
||||
pos = mul(pos, model);
|
||||
|
||||
// Correct for perspective and project the vertex position onto the screen.
|
||||
pos = mul(pos, viewProjection[idx]);
|
||||
output.pos = (min16float4)pos;
|
||||
|
||||
// Pass the color through without modification.
|
||||
output.color = min16float3(color.xyz);
|
||||
|
||||
// Set the instance ID. The pass-through geometry shader will set the
|
||||
// render target array index to whatever value is set here.
|
||||
output.viewId = idx;
|
||||
|
||||
return output;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HolographicVoiceInput", "HolographicVoiceInput.vcxproj", "{C4FA54B1-2675-430D-93EE-789D93D50767}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C4FA54B1-2675-430D-93EE-789D93D50767}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{C4FA54B1-2675-430D-93EE-789D93D50767}.Debug|x86.Build.0 = Debug|Win32
|
||||
{C4FA54B1-2675-430D-93EE-789D93D50767}.Debug|x86.Deploy.0 = Debug|Win32
|
||||
{C4FA54B1-2675-430D-93EE-789D93D50767}.Release|x86.ActiveCfg = Release|Win32
|
||||
{C4FA54B1-2675-430D-93EE-789D93D50767}.Release|x86.Build.0 = Release|Win32
|
||||
{C4FA54B1-2675-430D-93EE-789D93D50767}.Release|x86.Deploy.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,171 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{c4fa54b1-2675-430d-93ee-789d93d50767}</ProjectGuid>
|
||||
<Keyword>HolographicApp</Keyword>
|
||||
<RootNamespace>HolographicVoiceInput</RootNamespace>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
|
||||
<AppContainerApplication>true</AppContainerApplication>
|
||||
<ApplicationType>Windows Store</ApplicationType>
|
||||
<WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.10586.0</WindowsTargetPlatformMinVersion>
|
||||
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
|
||||
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
<Import Project="$(VSINSTALLDIR)\Common7\IDE\Extensions\Microsoft\VsGraphics\ImageContentTask.props" />
|
||||
<Import Project="$(VSINSTALLDIR)\Common7\IDE\Extensions\Microsoft\VsGraphics\MeshContentTask.props" />
|
||||
<Import Project="$(VSINSTALLDIR)\Common7\IDE\Extensions\Microsoft\VsGraphics\ShaderGraphContentTask.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Link>
|
||||
<AdditionalDependencies>d2d1.lib; d3d11.lib; dxgi.lib; dwrite.lib; windowscodecs.lib; Mfuuid.lib; Mfplat.lib; %(AdditionalDependencies); </AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store; $(VCInstallDir)\lib</AdditionalLibraryDirectories>
|
||||
<IgnoreSpecificDefaultLibraries>mincore.lib;kernel32.lib;ole32.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
<ClCompile>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Link>
|
||||
<AdditionalDependencies>d2d1.lib; d3d11.lib; dxgi.lib; dwrite.lib; windowscodecs.lib; %(AdditionalDependencies); </AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store; $(VCInstallDir)\lib</AdditionalLibraryDirectories>
|
||||
<IgnoreSpecificDefaultLibraries>mincore.lib;kernel32.lib;ole32.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
<ClCompile>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="..\..\..\SharedContent\media\microsoft-sdk.png">
|
||||
<Link>Assets\microsoft-sdk.png</Link>
|
||||
</Image>
|
||||
<Image Include="..\..\..\SharedContent\media\smalltile-sdk.png">
|
||||
<Link>Assets\smallTile-sdk.png</Link>
|
||||
</Image>
|
||||
<Image Include="..\..\..\SharedContent\media\splash-sdk.png">
|
||||
<Link>Assets\splash-sdk.png</Link>
|
||||
</Image>
|
||||
<Image Include="..\..\..\SharedContent\media\squaretile-sdk.png">
|
||||
<Link>Assets\squareTile-sdk.png</Link>
|
||||
</Image>
|
||||
<Image Include="..\..\..\SharedContent\media\storelogo-sdk.png">
|
||||
<Link>Assets\storeLogo-sdk.png</Link>
|
||||
</Image>
|
||||
<Image Include="..\..\..\SharedContent\media\tile-sdk.png">
|
||||
<Link>Assets\tile-sdk.png</Link>
|
||||
</Image>
|
||||
<Image Include="..\..\..\SharedContent\media\windows-sdk.png">
|
||||
<Link>Assets\windows-sdk.png</Link>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AppView.h" />
|
||||
<ClInclude Include="Audio\AudioFileReader.h" />
|
||||
<ClInclude Include="Audio\AudioStreamReader.h" />
|
||||
<ClInclude Include="Audio\OmnidirectionalSound.h" />
|
||||
<ClInclude Include="Audio\XAudio2Helpers.h" />
|
||||
<ClInclude Include="Common\PrintWstringToDebugConsole.h" />
|
||||
<ClInclude Include="HolographicVoiceInputMain.h" />
|
||||
<ClInclude Include="Common\DeviceResources.h" />
|
||||
<ClInclude Include="Common\DirectXHelper.h" />
|
||||
<ClInclude Include="Common\CameraResources.h" />
|
||||
<ClInclude Include="Common\StepTimer.h" />
|
||||
<ClInclude Include="Content\SpatialInputHandler.h" />
|
||||
<ClInclude Include="Content\ShaderStructures.h" />
|
||||
<ClInclude Include="Content\SpinningCubeRenderer.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AppView.cpp" />
|
||||
<ClCompile Include="Audio\AudioFileReader.cpp" />
|
||||
<ClCompile Include="Audio\AudioStreamReader.cpp" />
|
||||
<ClCompile Include="Audio\OmnidirectionalSound.cpp" />
|
||||
<ClCompile Include="HolographicVoiceInputMain.cpp" />
|
||||
<ClCompile Include="Common\DeviceResources.cpp" />
|
||||
<ClCompile Include="Common\CameraResources.cpp" />
|
||||
<ClCompile Include="Content\SpatialInputHandler.cpp" />
|
||||
<ClCompile Include="Content\SpinningCubeRenderer.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</AppxManifest>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<FxCompile Include="Content\PixelShader.hlsl">
|
||||
<ShaderType>Pixel</ShaderType>
|
||||
<ShaderModel>5.0</ShaderModel>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Content\VertexShader.hlsl">
|
||||
<ShaderType>Vertex</ShaderType>
|
||||
<ShaderModel>5.0</ShaderModel>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Content\VPRTVertexShader.hlsl">
|
||||
<ShaderType>Vertex</ShaderType>
|
||||
<ShaderModel>5.0</ShaderModel>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Content\GeometryShader.hlsl">
|
||||
<ShaderType>Geometry</ShaderType>
|
||||
<ShaderModel>5.0</ShaderModel>
|
||||
</FxCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Media Include="Audio\BasicListeningEarcon.wav" />
|
||||
<Media Include="Audio\BasicResultsEarcon.wav" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="$(VSINSTALLDIR)\Common7\IDE\Extensions\Microsoft\VsGraphics\ImageContentTask.targets" />
|
||||
<Import Project="$(VSINSTALLDIR)\Common7\IDE\Extensions\Microsoft\VsGraphics\MeshContentTask.targets" />
|
||||
<Import Project="$(VSINSTALLDIR)\Common7\IDE\Extensions\Microsoft\VsGraphics\ShaderGraphContentTask.targets" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup>
|
||||
<AppxPackageSigningEnabled>true</AppxPackageSigningEnabled>
|
||||
<AppxBundle>Always</AppxBundle>
|
||||
<AppxBundlePlatforms>x86</AppxBundlePlatforms>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -0,0 +1,136 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Common">
|
||||
<UniqueIdentifier>c4fa54b1-2675-430d-93ee-789d93d50767</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Assets">
|
||||
<UniqueIdentifier>4b7d1e86-689b-40f9-8575-242d638d5a4c</UniqueIdentifier>
|
||||
<Extensions>bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Content">
|
||||
<UniqueIdentifier>d5b41d14-ee63-481d-9dbd-6b703df2f4f3</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Content\Shaders">
|
||||
<UniqueIdentifier>e0f391f4-4738-4982-9115-ff84c1ced1da</UniqueIdentifier>
|
||||
</Filter>
|
||||
<ClInclude Include="Common\DirectXHelper.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Common\StepTimer.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Common\DeviceResources.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="Common\DeviceResources.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="Common\CameraResources.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="Common\CameraResources.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<Filter Include="Audio">
|
||||
<UniqueIdentifier>{39259194-32df-452d-ba8b-5c0d73e30b7b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp" />
|
||||
<ClCompile Include="AppView.cpp" />
|
||||
<ClCompile Include="Content\SpatialInputHandler.cpp">
|
||||
<Filter>Content</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Content\SpinningCubeRenderer.cpp">
|
||||
<Filter>Content</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HolographicVoiceInputMain.cpp" />
|
||||
<ClCompile Include="Audio\AudioFileReader.cpp">
|
||||
<Filter>Audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Audio\AudioStreamReader.cpp">
|
||||
<Filter>Audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Audio\OmnidirectionalSound.cpp">
|
||||
<Filter>Audio</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="AppView.h" />
|
||||
<ClInclude Include="Content\SpatialInputHandler.h">
|
||||
<Filter>Content</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Content\SpinningCubeRenderer.h">
|
||||
<Filter>Content</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Content\ShaderStructures.h">
|
||||
<Filter>Content</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HolographicVoiceInputMain.h" />
|
||||
<ClInclude Include="Audio\AudioFileReader.h">
|
||||
<Filter>Audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Audio\AudioStreamReader.h">
|
||||
<Filter>Audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Audio\OmnidirectionalSound.h">
|
||||
<Filter>Audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Audio\XAudio2Helpers.h">
|
||||
<Filter>Audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Common\PrintWstringToDebugConsole.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<FxCompile Include="Content\VertexShader.hlsl">
|
||||
<Filter>Content\Shaders</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Content\GeometryShader.hlsl">
|
||||
<Filter>Content\Shaders</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Content\PixelShader.hlsl">
|
||||
<Filter>Content\Shaders</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Content\VPRTVertexShader.hlsl">
|
||||
<Filter>Content\Shaders</Filter>
|
||||
</FxCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="..\..\..\SharedContent\media\microsoft-sdk.png">
|
||||
<Filter>Assets</Filter>
|
||||
</Image>
|
||||
<Image Include="..\..\..\SharedContent\media\smalltile-sdk.png">
|
||||
<Filter>Assets</Filter>
|
||||
</Image>
|
||||
<Image Include="..\..\..\SharedContent\media\splash-sdk.png">
|
||||
<Filter>Assets</Filter>
|
||||
</Image>
|
||||
<Image Include="..\..\..\SharedContent\media\squaretile-sdk.png">
|
||||
<Filter>Assets</Filter>
|
||||
</Image>
|
||||
<Image Include="..\..\..\SharedContent\media\storelogo-sdk.png">
|
||||
<Filter>Assets</Filter>
|
||||
</Image>
|
||||
<Image Include="..\..\..\SharedContent\media\tile-sdk.png">
|
||||
<Filter>Assets</Filter>
|
||||
</Image>
|
||||
<Image Include="..\..\..\SharedContent\media\windows-sdk.png">
|
||||
<Filter>Assets</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Media Include="Audio\BasicListeningEarcon.wav">
|
||||
<Filter>Audio</Filter>
|
||||
</Media>
|
||||
<Media Include="Audio\BasicResultsEarcon.wav">
|
||||
<Filter>Audio</Filter>
|
||||
</Media>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,763 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#include "pch.h"
|
||||
#include "HolographicVoiceInputMain.h"
|
||||
#include "Common\DirectXHelper.h"
|
||||
|
||||
#include <windows.graphics.directx.direct3d11.interop.h>
|
||||
#include <Collection.h>
|
||||
|
||||
#include "Audio/OmnidirectionalSound.h"
|
||||
|
||||
using namespace HolographicVoiceInput;
|
||||
|
||||
using namespace concurrency;
|
||||
using namespace Platform;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Foundation::Numerics;
|
||||
using namespace Windows::Graphics::Holographic;
|
||||
using namespace Windows::Media::SpeechRecognition;
|
||||
using namespace Windows::Perception::Spatial;
|
||||
using namespace Windows::UI::Input::Spatial;
|
||||
using namespace std::placeholders;
|
||||
|
||||
// Loads and initializes application assets when the application is loaded.
|
||||
HolographicVoiceInputMain::HolographicVoiceInputMain(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
|
||||
m_deviceResources(deviceResources)
|
||||
{
|
||||
// Register to be notified if the device is lost or recreated.
|
||||
m_deviceResources->RegisterDeviceNotify(this);
|
||||
|
||||
// Initialize the map of speech commands to actions - in this case, color values.
|
||||
InitializeSpeechCommandList();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void HolographicVoiceInputMain::InitializeSpeechCommandList()
|
||||
{
|
||||
m_lastCommand = nullptr;
|
||||
m_listening = false;
|
||||
m_speechCommandData = ref new Platform::Collections::Map<String^, float4>();
|
||||
|
||||
m_speechCommandData->Insert(L"white", float4(1.0f, 1.0f, 1.0f, 1.f));
|
||||
m_speechCommandData->Insert(L"grey", float4(0.5f, 0.5f, 0.5f, 1.f));
|
||||
m_speechCommandData->Insert(L"green", float4(0.0f, 1.0f, 0.0f, 1.f));
|
||||
m_speechCommandData->Insert(L"black", float4(0.1f, 0.1f, 0.1f, 1.f));
|
||||
m_speechCommandData->Insert(L"red", float4(1.0f, 0.0f, 0.0f, 1.f));
|
||||
m_speechCommandData->Insert(L"yellow", float4(1.0f, 1.0f, 0.0f, 1.f));
|
||||
m_speechCommandData->Insert(L"aquamarine", float4(0.0f, 1.0f, 1.0f, 1.f));
|
||||
m_speechCommandData->Insert(L"blue", float4(0.0f, 0.0f, 1.0f, 1.f));
|
||||
m_speechCommandData->Insert(L"purple", float4(1.0f, 0.0f, 1.0f, 1.f));
|
||||
|
||||
// You can use non-dictionary words as speech commands.
|
||||
m_speechCommandData->Insert(L"SpeechRecognizer", float4(0.5f, 0.1f, 1.f, 1.f));
|
||||
}
|
||||
|
||||
void HolographicVoiceInputMain::BeginVoiceUIPrompt()
|
||||
{
|
||||
// RecognizeWithUIAsync provides speech recognition begin and end prompts, but it does not provide
|
||||
// synthesized speech prompts. Instead, you should provide your own speech prompts when requesting
|
||||
// phrase input.
|
||||
// Here is an example of how to do that with a speech synthesizer. You could also use a pre-recorded
|
||||
// voice clip, a visual UI, or other indicator of what to say.
|
||||
auto speechSynthesizer = ref new Windows::Media::SpeechSynthesis::SpeechSynthesizer();
|
||||
|
||||
StringReference voicePrompt;
|
||||
|
||||
// A command list is used to continuously look for one-word commands.
|
||||
// You need some way for the user to know what commands they can say. In this example, we provide
|
||||
// verbal instructions; you could also use graphical UI, etc.
|
||||
voicePrompt = L"Say the name of a color, at any time, to change the color of the cube.";
|
||||
|
||||
// Kick off speech synthesis.
|
||||
create_task(speechSynthesizer->SynthesizeTextToStreamAsync(voicePrompt), task_continuation_context::use_current())
|
||||
.then([this, speechSynthesizer](task<Windows::Media::SpeechSynthesis::SpeechSynthesisStream^> synthesisStreamTask)
|
||||
{
|
||||
try
|
||||
{
|
||||
// The speech synthesis is sent as a byte stream.
|
||||
Windows::Media::SpeechSynthesis::SpeechSynthesisStream^ stream = synthesisStreamTask.get();
|
||||
|
||||
// We can initialize an XAudio2 voice using that byte stream.
|
||||
// Here, we use it to play an HRTF audio effect.
|
||||
auto hr = m_speechSynthesisSound.Initialize(stream, 0);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
m_speechSynthesisSound.SetEnvironment(HrtfEnvironment::Small);
|
||||
m_speechSynthesisSound.Start();
|
||||
|
||||
// Amount of time to pause after the audio prompt is complete, before listening
|
||||
// for speech input.
|
||||
static const float bufferTime = 0.15f;
|
||||
|
||||
// Wait until the prompt is done before listening.
|
||||
m_secondsUntilSoundIsComplete = m_speechSynthesisSound.GetDuration() + bufferTime;
|
||||
m_waitingForSpeechPrompt = true;
|
||||
}
|
||||
}
|
||||
catch (Exception^ exception)
|
||||
{
|
||||
PrintWstringToDebugConsole(
|
||||
std::wstring(L"Exception while trying to synthesize speech: ") +
|
||||
exception->Message->Data() +
|
||||
L"\n"
|
||||
);
|
||||
|
||||
// Handle exceptions here.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void HolographicVoiceInputMain::PlayRecognitionBeginSound()
|
||||
{
|
||||
// The user needs a cue to begin speaking. We will play this sound effect just before starting
|
||||
// the recognizer.
|
||||
auto hr = m_startRecognitionSound.GetInitializationStatus();
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
m_startRecognitionSound.SetEnvironment(HrtfEnvironment::Small);
|
||||
m_startRecognitionSound.Start();
|
||||
|
||||
// Wait until the audible cue is done before starting to listen.
|
||||
m_secondsUntilSoundIsComplete = m_startRecognitionSound.GetDuration();
|
||||
m_waitingForSpeechCue = true;
|
||||
}
|
||||
}
|
||||
|
||||
void HolographicVoiceInputMain::PlayRecognitionSound()
|
||||
{
|
||||
// The user should be given a cue when recognition is complete.
|
||||
auto hr = m_recognitionSound.GetInitializationStatus();
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// re-initialize the sound so it can be replayed.
|
||||
m_recognitionSound.Initialize(L"Audio//BasicResultsEarcon.wav", 0);
|
||||
m_recognitionSound.SetEnvironment(HrtfEnvironment::Small);
|
||||
|
||||
m_recognitionSound.Start();
|
||||
}
|
||||
}
|
||||
|
||||
Concurrency::task<void> HolographicVoiceInputMain::StopCurrentRecognizerIfExists()
|
||||
{
|
||||
if (m_speechRecognizer != nullptr)
|
||||
{
|
||||
return create_task(m_speechRecognizer->StopRecognitionAsync()).then([this]()
|
||||
{
|
||||
m_speechRecognizer->RecognitionQualityDegrading -= m_speechRecognitionQualityDegradedToken;
|
||||
|
||||
if (m_speechRecognizer->ContinuousRecognitionSession != nullptr)
|
||||
{
|
||||
m_speechRecognizer->ContinuousRecognitionSession->ResultGenerated -= m_speechRecognizerResultEventToken;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
return create_task([this]() { });
|
||||
}
|
||||
}
|
||||
|
||||
bool HolographicVoiceInputMain::InitializeSpeechRecognizer()
|
||||
{
|
||||
m_speechRecognizer = ref new SpeechRecognizer();
|
||||
|
||||
if (!m_speechRecognizer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_speechRecognitionQualityDegradedToken = m_speechRecognizer->RecognitionQualityDegrading +=
|
||||
ref new TypedEventHandler<SpeechRecognizer^, SpeechRecognitionQualityDegradingEventArgs^>(
|
||||
std::bind(&HolographicVoiceInputMain::OnSpeechQualityDegraded, this, _1, _2)
|
||||
);
|
||||
|
||||
m_speechRecognizerResultEventToken = m_speechRecognizer->ContinuousRecognitionSession->ResultGenerated +=
|
||||
ref new TypedEventHandler<SpeechContinuousRecognitionSession^, SpeechContinuousRecognitionResultGeneratedEventArgs^>(
|
||||
std::bind(&HolographicVoiceInputMain::OnResultGenerated, this, _1, _2)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
task<bool> HolographicVoiceInputMain::StartRecognizeSpeechCommands()
|
||||
{
|
||||
return StopCurrentRecognizerIfExists().then([this]()
|
||||
{
|
||||
if (!InitializeSpeechRecognizer())
|
||||
{
|
||||
return task_from_result<bool>(false);
|
||||
}
|
||||
|
||||
// Here, we compile the list of voice commands by reading them from the map.
|
||||
Platform::Collections::Vector<String^>^ speechCommandList = ref new Platform::Collections::Vector<String^>();
|
||||
for each (auto pair in m_speechCommandData)
|
||||
{
|
||||
// The speech command string is what we are looking for here. Later, we can use the
|
||||
// recognition result for this string to look up a color value.
|
||||
auto command = pair->Key;
|
||||
|
||||
// Add it to the list.
|
||||
speechCommandList->Append(command);
|
||||
}
|
||||
|
||||
SpeechRecognitionListConstraint^ spConstraint = ref new SpeechRecognitionListConstraint(speechCommandList);
|
||||
m_speechRecognizer->Constraints->Clear();
|
||||
m_speechRecognizer->Constraints->Append(spConstraint);
|
||||
return create_task(m_speechRecognizer->CompileConstraintsAsync()).then([this](task<SpeechRecognitionCompilationResult^> previousTask)
|
||||
{
|
||||
try
|
||||
{
|
||||
SpeechRecognitionCompilationResult^ compilationResult = previousTask.get();
|
||||
|
||||
if (compilationResult->Status == SpeechRecognitionResultStatus::Success)
|
||||
{
|
||||
// If compilation succeeds, we can start listening for results.
|
||||
return create_task(m_speechRecognizer->ContinuousRecognitionSession->StartAsync()).then([this](task<void> startAsyncTask) {
|
||||
|
||||
try
|
||||
{
|
||||
// StartAsync may throw an exception if your app doesn't have Microphone permissions.
|
||||
// Make sure they're caught and handled appropriately (otherwise the app may silently not work as expected)
|
||||
startAsyncTask.get();
|
||||
return true;
|
||||
}
|
||||
catch (Exception^ exception)
|
||||
{
|
||||
PrintWstringToDebugConsole(
|
||||
std::wstring(L"Exception while trying to start speech Recognition: ") +
|
||||
exception->Message->Data() +
|
||||
L"\n"
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputDebugStringW(L"Could not initialize constraint-based speech engine!\n");
|
||||
|
||||
// Handle errors here.
|
||||
return create_task([this] {return false; });
|
||||
}
|
||||
}
|
||||
catch (Exception^ exception)
|
||||
{
|
||||
// Note that if you get an "Access is denied" exception, you might need to enable the microphone
|
||||
// privacy setting on the device and/or add the microphone capability to your app manifest.
|
||||
|
||||
PrintWstringToDebugConsole(
|
||||
std::wstring(L"Exception while trying to initialize speech command list:") +
|
||||
exception->Message->Data() +
|
||||
L"\n"
|
||||
);
|
||||
|
||||
// Handle exceptions here.
|
||||
return create_task([this] {return false; });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void HolographicVoiceInputMain::SetHolographicSpace(HolographicSpace^ holographicSpace)
|
||||
{
|
||||
UnregisterHolographicEventHandlers();
|
||||
|
||||
m_holographicSpace = holographicSpace;
|
||||
|
||||
//
|
||||
// TODO: Add code here to initialize your holographic content.
|
||||
//
|
||||
|
||||
// Initialize the sample hologram.
|
||||
m_spinningCubeRenderer = std::make_unique<SpinningCubeRenderer>(m_deviceResources);
|
||||
|
||||
m_spatialInputHandler = std::make_unique<SpatialInputHandler>();
|
||||
|
||||
// Use the default SpatialLocator to track the motion of the device.
|
||||
m_locator = SpatialLocator::GetDefault();
|
||||
|
||||
// Be able to respond to changes in the positional tracking state.
|
||||
m_locatabilityChangedToken =
|
||||
m_locator->LocatabilityChanged +=
|
||||
ref new Windows::Foundation::TypedEventHandler<SpatialLocator^, Object^>(
|
||||
std::bind(&HolographicVoiceInputMain::OnLocatabilityChanged, this, _1, _2)
|
||||
);
|
||||
|
||||
// Respond to camera added events by creating any resources that are specific
|
||||
// to that camera, such as the back buffer render target view.
|
||||
// When we add an event handler for CameraAdded, the API layer will avoid putting
|
||||
// the new camera in new HolographicFrames until we complete the deferral we created
|
||||
// for that handler, or return from the handler without creating a deferral. This
|
||||
// allows the app to take more than one frame to finish creating resources and
|
||||
// loading assets for the new holographic camera.
|
||||
// This function should be registered before the app creates any HolographicFrames.
|
||||
m_cameraAddedToken =
|
||||
m_holographicSpace->CameraAdded +=
|
||||
ref new Windows::Foundation::TypedEventHandler<HolographicSpace^, HolographicSpaceCameraAddedEventArgs^>(
|
||||
std::bind(&HolographicVoiceInputMain::OnCameraAdded, this, _1, _2)
|
||||
);
|
||||
|
||||
// Respond to camera removed events by releasing resources that were created for that
|
||||
// camera.
|
||||
// When the app receives a CameraRemoved event, it releases all references to the back
|
||||
// buffer right away. This includes render target views, Direct2D target bitmaps, and so on.
|
||||
// The app must also ensure that the back buffer is not attached as a render target, as
|
||||
// shown in DeviceResources::ReleaseResourcesForBackBuffer.
|
||||
m_cameraRemovedToken =
|
||||
m_holographicSpace->CameraRemoved +=
|
||||
ref new Windows::Foundation::TypedEventHandler<HolographicSpace^, HolographicSpaceCameraRemovedEventArgs^>(
|
||||
std::bind(&HolographicVoiceInputMain::OnCameraRemoved, this, _1, _2)
|
||||
);
|
||||
|
||||
// The simplest way to render world-locked holograms is to create a stationary reference frame
|
||||
// when the app is launched. This is roughly analogous to creating a "world" coordinate system
|
||||
// with the origin placed at the device's position as the app is launched.
|
||||
m_referenceFrame = m_locator->CreateStationaryFrameOfReferenceAtCurrentLocation();
|
||||
|
||||
// Notes on spatial tracking APIs:
|
||||
// * Stationary reference frames are designed to provide a best-fit position relative to the
|
||||
// overall space. Individual positions within that reference frame are allowed to drift slightly
|
||||
// as the device learns more about the environment.
|
||||
// * When precise placement of individual holograms is required, a SpatialAnchor should be used to
|
||||
// anchor the individual hologram to a position in the real world - for example, a point the user
|
||||
// indicates to be of special interest. Anchor positions do not drift, but can be corrected; the
|
||||
// anchor will use the corrected position starting in the next frame after the correction has
|
||||
// occurred.
|
||||
|
||||
// Preload audio assets for audio cues.
|
||||
m_startRecognitionSound.Initialize(L"Audio//BasicListeningEarcon.wav", 0);
|
||||
m_recognitionSound.Initialize(L"Audio//BasicResultsEarcon.wav", 0);
|
||||
|
||||
// Begin the code sample scenario.
|
||||
BeginVoiceUIPrompt();
|
||||
}
|
||||
|
||||
void HolographicVoiceInputMain::UnregisterHolographicEventHandlers()
|
||||
{
|
||||
if (m_holographicSpace != nullptr)
|
||||
{
|
||||
// Clear previous event registrations.
|
||||
|
||||
if (m_cameraAddedToken.Value != 0)
|
||||
{
|
||||
m_holographicSpace->CameraAdded -= m_cameraAddedToken;
|
||||
m_cameraAddedToken.Value = 0;
|
||||
}
|
||||
|
||||
if (m_cameraRemovedToken.Value != 0)
|
||||
{
|
||||
m_holographicSpace->CameraRemoved -= m_cameraRemovedToken;
|
||||
m_cameraRemovedToken.Value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_locator != nullptr)
|
||||
{
|
||||
m_locator->LocatabilityChanged -= m_locatabilityChangedToken;
|
||||
}
|
||||
}
|
||||
|
||||
HolographicVoiceInputMain::~HolographicVoiceInputMain()
|
||||
{
|
||||
// Deregister device notification.
|
||||
m_deviceResources->RegisterDeviceNotify(nullptr);
|
||||
|
||||
UnregisterHolographicEventHandlers();
|
||||
}
|
||||
|
||||
// Updates the application state once per frame.
|
||||
HolographicFrame^ HolographicVoiceInputMain::Update()
|
||||
{
|
||||
// Before doing the timer update, there is some work to do per-frame
|
||||
// to maintain holographic rendering. First, we will get information
|
||||
// about the current frame.
|
||||
|
||||
// The HolographicFrame has information that the app needs in order
|
||||
// to update and render the current frame. The app begins each new
|
||||
// frame by calling CreateNextFrame.
|
||||
HolographicFrame^ holographicFrame = m_holographicSpace->CreateNextFrame();
|
||||
|
||||
// Get a prediction of where holographic cameras will be when this frame
|
||||
// is presented.
|
||||
HolographicFramePrediction^ prediction = holographicFrame->CurrentPrediction;
|
||||
|
||||
// Back buffers can change from frame to frame. Validate each buffer, and recreate
|
||||
// resource views and depth buffers as needed.
|
||||
m_deviceResources->EnsureCameraResources(holographicFrame, prediction);
|
||||
|
||||
// Next, we get a coordinate system from the attached frame of reference that is
|
||||
// associated with the current frame. Later, this coordinate system is used for
|
||||
// for creating the stereo view matrices when rendering the sample content.
|
||||
SpatialCoordinateSystem^ currentCoordinateSystem = m_referenceFrame->CoordinateSystem;
|
||||
|
||||
// Check for new input state since the last frame.
|
||||
SpatialInteractionSourceState^ pointerState = m_spatialInputHandler->CheckForInput();
|
||||
if (pointerState != nullptr)
|
||||
{
|
||||
// When a Pressed gesture is detected, the sample hologram will be repositioned
|
||||
// two meters in front of the user.
|
||||
m_spinningCubeRenderer->PositionHologram(
|
||||
pointerState->TryGetPointerPose(currentCoordinateSystem)
|
||||
);
|
||||
}
|
||||
|
||||
// Check for new speech input since the last frame.
|
||||
if (m_lastCommand != nullptr)
|
||||
{
|
||||
auto command = m_lastCommand;
|
||||
m_lastCommand = nullptr;
|
||||
|
||||
// Check to see if the spoken word or phrase, matches up with any of the speech
|
||||
// commands in our speech command map.
|
||||
for each (auto& iter in m_speechCommandData)
|
||||
{
|
||||
std::wstring lastCommandString = command->Data();
|
||||
std::wstring listCommandString = iter->Key->Data();
|
||||
|
||||
if (lastCommandString.find(listCommandString) != std::wstring::npos)
|
||||
{
|
||||
// If so, we can set the cube to the color that was spoken.
|
||||
m_spinningCubeRenderer->SetColor(iter->Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_timer.Tick([&] ()
|
||||
{
|
||||
//
|
||||
// TODO: Update scene objects.
|
||||
//
|
||||
// Put time-based updates here. By default this code will run once per frame,
|
||||
// but if you change the StepTimer to use a fixed time step this code will
|
||||
// run as many times as needed to get to the current step.
|
||||
//
|
||||
|
||||
m_spinningCubeRenderer->Update(m_timer);
|
||||
|
||||
// Wait to listen for speech input until the audible UI prompts are complete.
|
||||
if ((m_waitingForSpeechPrompt == true) &&
|
||||
((m_secondsUntilSoundIsComplete -= static_cast<float>(m_timer.GetElapsedSeconds())) <= 0.f))
|
||||
{
|
||||
m_waitingForSpeechPrompt = false;
|
||||
PlayRecognitionBeginSound();
|
||||
}
|
||||
else if ((m_waitingForSpeechCue == true) &&
|
||||
((m_secondsUntilSoundIsComplete -= static_cast<float>(m_timer.GetElapsedSeconds())) <= 0.f))
|
||||
{
|
||||
m_waitingForSpeechCue = false;
|
||||
m_secondsUntilSoundIsComplete = 0.f;
|
||||
StartRecognizeSpeechCommands();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// We complete the frame update by using information about our content positioning
|
||||
// to set the focus point.
|
||||
|
||||
for (auto cameraPose : prediction->CameraPoses)
|
||||
{
|
||||
// The HolographicCameraRenderingParameters class provides access to set
|
||||
// the image stabilization parameters.
|
||||
HolographicCameraRenderingParameters^ renderingParameters = holographicFrame->GetRenderingParameters(cameraPose);
|
||||
|
||||
// SetFocusPoint informs the system about a specific point in your scene to
|
||||
// prioritize for image stabilization. The focus point is set independently
|
||||
// for each holographic camera.
|
||||
// You should set the focus point near the content that the user is looking at.
|
||||
// In this example, we put the focus point at the center of the sample hologram,
|
||||
// since that is the only hologram available for the user to focus on.
|
||||
// You can also set the relative velocity and facing of that content; the sample
|
||||
// hologram is at a fixed point so we only need to indicate its position.
|
||||
renderingParameters->SetFocusPoint(
|
||||
currentCoordinateSystem,
|
||||
m_spinningCubeRenderer->GetPosition()
|
||||
);
|
||||
}
|
||||
|
||||
// The holographic frame will be used to get up-to-date view and projection matrices and
|
||||
// to present the swap chain.
|
||||
return holographicFrame;
|
||||
}
|
||||
|
||||
// Renders the current frame to each holographic camera, according to the
|
||||
// current application and spatial positioning state. Returns true if the
|
||||
// frame was rendered to at least one camera.
|
||||
bool HolographicVoiceInputMain::Render(Windows::Graphics::Holographic::HolographicFrame^ holographicFrame)
|
||||
{
|
||||
// Don't try to render anything before the first Update.
|
||||
if (m_timer.GetFrameCount() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: Add code for pre-pass rendering here.
|
||||
//
|
||||
// Take care of any tasks that are not specific to an individual holographic
|
||||
// camera. This includes anything that doesn't need the final view or projection
|
||||
// matrix, such as lighting maps.
|
||||
//
|
||||
|
||||
// Lock the set of holographic camera resources, then draw to each camera
|
||||
// in this frame.
|
||||
return m_deviceResources->UseHolographicCameraResources<bool>(
|
||||
[this, holographicFrame](std::map<UINT32, std::unique_ptr<DX::CameraResources>>& cameraResourceMap)
|
||||
{
|
||||
// Up-to-date frame predictions enhance the effectiveness of image stablization and
|
||||
// allow more accurate positioning of holograms.
|
||||
holographicFrame->UpdateCurrentPrediction();
|
||||
HolographicFramePrediction^ prediction = holographicFrame->CurrentPrediction;
|
||||
|
||||
bool atLeastOneCameraRendered = false;
|
||||
for (auto cameraPose : prediction->CameraPoses)
|
||||
{
|
||||
// This represents the device-based resources for a HolographicCamera.
|
||||
DX::CameraResources* pCameraResources = cameraResourceMap[cameraPose->HolographicCamera->Id].get();
|
||||
|
||||
// Get the device context.
|
||||
const auto context = m_deviceResources->GetD3DDeviceContext();
|
||||
const auto depthStencilView = pCameraResources->GetDepthStencilView();
|
||||
|
||||
// Set render targets to the current holographic camera.
|
||||
ID3D11RenderTargetView *const targets[1] = { pCameraResources->GetBackBufferRenderTargetView() };
|
||||
context->OMSetRenderTargets(1, targets, depthStencilView);
|
||||
|
||||
// Clear the back buffer and depth stencil view.
|
||||
context->ClearRenderTargetView(targets[0], DirectX::Colors::Transparent);
|
||||
context->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
|
||||
|
||||
//
|
||||
// TODO: Replace the sample content with your own content.
|
||||
//
|
||||
// Notes regarding holographic content:
|
||||
// * For drawing, remember that you have the potential to fill twice as many pixels
|
||||
// in a stereoscopic render target as compared to a non-stereoscopic render target
|
||||
// of the same resolution. Avoid unnecessary or repeated writes to the same pixel,
|
||||
// and only draw holograms that the user can see.
|
||||
// * To help occlude hologram geometry, you can create a depth map using geometry
|
||||
// data obtained via the surface mapping APIs. You can use this depth map to avoid
|
||||
// rendering holograms that are intended to be hidden behind tables, walls,
|
||||
// monitors, and so on.
|
||||
// * Black pixels will appear transparent to the user wearing the device, but you
|
||||
// should still use alpha blending to draw semitransparent holograms. You should
|
||||
// also clear the screen to Transparent as shown above.
|
||||
//
|
||||
|
||||
|
||||
// The view and projection matrices for each holographic camera will change
|
||||
// every frame. This function refreshes the data in the constant buffer for
|
||||
// the holographic camera indicated by cameraPose.
|
||||
pCameraResources->UpdateViewProjectionBuffer(m_deviceResources, cameraPose, m_referenceFrame->CoordinateSystem);
|
||||
|
||||
// Attach the view/projection constant buffer for this camera to the graphics pipeline.
|
||||
bool cameraActive = pCameraResources->AttachViewProjectionBuffer(m_deviceResources);
|
||||
|
||||
// Only render world-locked content when positional tracking is active.
|
||||
if (cameraActive)
|
||||
{
|
||||
// Draw the sample hologram.
|
||||
m_spinningCubeRenderer->Render();
|
||||
}
|
||||
atLeastOneCameraRendered = true;
|
||||
}
|
||||
|
||||
return atLeastOneCameraRendered;
|
||||
});
|
||||
}
|
||||
|
||||
void HolographicVoiceInputMain::SaveAppState()
|
||||
{
|
||||
//
|
||||
// TODO: Insert code here to save your app state.
|
||||
// This method is called when the app is about to suspend.
|
||||
//
|
||||
// For example, store information in the SpatialAnchorStore.
|
||||
//
|
||||
}
|
||||
|
||||
void HolographicVoiceInputMain::LoadAppState()
|
||||
{
|
||||
//
|
||||
// TODO: Insert code here to load your app state.
|
||||
// This method is called when the app resumes.
|
||||
//
|
||||
// For example, load information from the SpatialAnchorStore.
|
||||
//
|
||||
}
|
||||
|
||||
// Notifies classes that use Direct3D device resources that the device resources
|
||||
// need to be released before this method returns.
|
||||
void HolographicVoiceInputMain::OnDeviceLost()
|
||||
{
|
||||
m_spinningCubeRenderer->ReleaseDeviceDependentResources();
|
||||
}
|
||||
|
||||
// Notifies classes that use Direct3D device resources that the device resources
|
||||
// may now be recreated.
|
||||
void HolographicVoiceInputMain::OnDeviceRestored()
|
||||
{
|
||||
m_spinningCubeRenderer->CreateDeviceDependentResources();
|
||||
}
|
||||
|
||||
void HolographicVoiceInputMain::OnLocatabilityChanged(SpatialLocator^ sender, Object^ args)
|
||||
{
|
||||
switch (sender->Locatability)
|
||||
{
|
||||
case SpatialLocatability::Unavailable:
|
||||
// Holograms cannot be rendered.
|
||||
{
|
||||
String^ message = L"Warning! Positional tracking is " +
|
||||
sender->Locatability.ToString() + L".\n";
|
||||
OutputDebugStringW(message->Data());
|
||||
}
|
||||
break;
|
||||
|
||||
// In the following three cases, it is still possible to place holograms using a
|
||||
// SpatialLocatorAttachedFrameOfReference.
|
||||
case SpatialLocatability::PositionalTrackingActivating:
|
||||
// The system is preparing to use positional tracking.
|
||||
|
||||
case SpatialLocatability::OrientationOnly:
|
||||
// Positional tracking has not been activated.
|
||||
|
||||
case SpatialLocatability::PositionalTrackingInhibited:
|
||||
// Positional tracking is temporarily inhibited. User action may be required
|
||||
// in order to restore positional tracking.
|
||||
break;
|
||||
|
||||
case SpatialLocatability::PositionalTrackingActive:
|
||||
// Positional tracking is active. World-locked content can be rendered.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void HolographicVoiceInputMain::OnCameraAdded(
|
||||
HolographicSpace^ sender,
|
||||
HolographicSpaceCameraAddedEventArgs^ args
|
||||
)
|
||||
{
|
||||
Deferral^ deferral = args->GetDeferral();
|
||||
HolographicCamera^ holographicCamera = args->Camera;
|
||||
create_task([this, deferral, holographicCamera] ()
|
||||
{
|
||||
//
|
||||
// TODO: Allocate resources for the new camera and load any content specific to
|
||||
// that camera. Note that the render target size (in pixels) is a property
|
||||
// of the HolographicCamera object, and can be used to create off-screen
|
||||
// render targets that match the resolution of the HolographicCamera.
|
||||
//
|
||||
|
||||
// Create device-based resources for the holographic camera and add it to the list of
|
||||
// cameras used for updates and rendering. Notes:
|
||||
// * Since this function may be called at any time, the AddHolographicCamera function
|
||||
// waits until it can get a lock on the set of holographic camera resources before
|
||||
// adding the new camera. At 60 frames per second this wait should not take long.
|
||||
// * A subsequent Update will take the back buffer from the RenderingParameters of this
|
||||
// camera's CameraPose and use it to create the ID3D11RenderTargetView for this camera.
|
||||
// Content can then be rendered for the HolographicCamera.
|
||||
m_deviceResources->AddHolographicCamera(holographicCamera);
|
||||
|
||||
// Holographic frame predictions will not include any information about this camera until
|
||||
// the deferral is completed.
|
||||
deferral->Complete();
|
||||
});
|
||||
}
|
||||
|
||||
void HolographicVoiceInputMain::OnCameraRemoved(
|
||||
HolographicSpace^ sender,
|
||||
HolographicSpaceCameraRemovedEventArgs^ args
|
||||
)
|
||||
{
|
||||
create_task([this]()
|
||||
{
|
||||
//
|
||||
// TODO: Asynchronously unload or deactivate content resources (not back buffer
|
||||
// resources) that are specific only to the camera that was removed.
|
||||
//
|
||||
});
|
||||
|
||||
// Before letting this callback return, ensure that all references to the back buffer
|
||||
// are released.
|
||||
// Since this function may be called at any time, the RemoveHolographicCamera function
|
||||
// waits until it can get a lock on the set of holographic camera resources before
|
||||
// deallocating resources for this camera. At 60 frames per second this wait should
|
||||
// not take long.
|
||||
m_deviceResources->RemoveHolographicCamera(args->Camera);
|
||||
}
|
||||
|
||||
|
||||
// For speech example.
|
||||
// Change the cube color, if we get a valid result.
|
||||
void HolographicVoiceInputMain::OnResultGenerated(SpeechContinuousRecognitionSession ^sender, SpeechContinuousRecognitionResultGeneratedEventArgs ^args)
|
||||
{
|
||||
// For our list of commands, medium confidence is good enough.
|
||||
// We also accept results that have high confidence.
|
||||
if ((args->Result->Confidence == SpeechRecognitionConfidence::High) ||
|
||||
(args->Result->Confidence == SpeechRecognitionConfidence::Medium))
|
||||
{
|
||||
m_lastCommand = args->Result->Text;
|
||||
|
||||
// When the debugger is attached, we can print information to the debug console.
|
||||
PrintWstringToDebugConsole(
|
||||
std::wstring(L"Last command was: ") +
|
||||
m_lastCommand->Data() +
|
||||
L"\n"
|
||||
);
|
||||
|
||||
// Play a sound to indicate a command was understood.
|
||||
PlayRecognitionSound();
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputDebugStringW(L"Recognition confidence not high enough.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void HolographicVoiceInputMain::OnSpeechQualityDegraded(Windows::Media::SpeechRecognition::SpeechRecognizer^ recognizer, Windows::Media::SpeechRecognition::SpeechRecognitionQualityDegradingEventArgs^ args)
|
||||
{
|
||||
switch (args->Problem)
|
||||
{
|
||||
case SpeechRecognitionAudioProblem::TooFast:
|
||||
OutputDebugStringW(L"The user spoke too quickly.\n");
|
||||
break;
|
||||
|
||||
case SpeechRecognitionAudioProblem::TooSlow:
|
||||
OutputDebugStringW(L"The user spoke too slowly.\n");
|
||||
break;
|
||||
|
||||
case SpeechRecognitionAudioProblem::TooQuiet:
|
||||
OutputDebugStringW(L"The user spoke too softly.\n");
|
||||
break;
|
||||
|
||||
case SpeechRecognitionAudioProblem::TooLoud:
|
||||
OutputDebugStringW(L"The user spoke too loudly.\n");
|
||||
break;
|
||||
|
||||
case SpeechRecognitionAudioProblem::TooNoisy:
|
||||
OutputDebugStringW(L"There is too much noise in the signal.\n");
|
||||
break;
|
||||
|
||||
case SpeechRecognitionAudioProblem::NoSignal:
|
||||
OutputDebugStringW(L"There is no signal.\n");
|
||||
break;
|
||||
|
||||
case SpeechRecognitionAudioProblem::None:
|
||||
default:
|
||||
OutputDebugStringW(L"An error was reported with no information.\n");
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
#pragma once
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Comment out this preprocessor definition to disable all of the
|
||||
// sample content.
|
||||
//
|
||||
// To remove the content after disabling it:
|
||||
// * Remove the unused code from your app's Main class.
|
||||
// * Delete the Content folder provided with this template.
|
||||
//
|
||||
|
||||
#include "Common\DeviceResources.h"
|
||||
#include "Common\StepTimer.h"
|
||||
|
||||
#include "Content\SpinningCubeRenderer.h"
|
||||
#include "Content\SpatialInputHandler.h"
|
||||
|
||||
#include "Audio/OmnidirectionalSound.h"
|
||||
|
||||
// Updates, renders, and presents holographic content using Direct3D.
|
||||
namespace HolographicVoiceInput
|
||||
{
|
||||
class HolographicVoiceInputMain : public DX::IDeviceNotify
|
||||
{
|
||||
public:
|
||||
HolographicVoiceInputMain(const std::shared_ptr<DX::DeviceResources>& deviceResources);
|
||||
~HolographicVoiceInputMain();
|
||||
|
||||
// Sets the holographic space. This is our closest analogue to setting a new window
|
||||
// for the app.
|
||||
void SetHolographicSpace(Windows::Graphics::Holographic::HolographicSpace^ holographicSpace);
|
||||
|
||||
// Starts the holographic frame and updates the content.
|
||||
Windows::Graphics::Holographic::HolographicFrame^ Update();
|
||||
|
||||
// Renders holograms, including world-locked content.
|
||||
bool Render(Windows::Graphics::Holographic::HolographicFrame^ holographicFrame);
|
||||
|
||||
// Handle saving and loading of app state owned by AppMain.
|
||||
void SaveAppState();
|
||||
void LoadAppState();
|
||||
|
||||
// IDeviceNotify
|
||||
virtual void OnDeviceLost();
|
||||
virtual void OnDeviceRestored();
|
||||
|
||||
private:
|
||||
// Process continuous speech recognition results.
|
||||
void OnResultGenerated(
|
||||
Windows::Media::SpeechRecognition::SpeechContinuousRecognitionSession ^sender,
|
||||
Windows::Media::SpeechRecognition::SpeechContinuousRecognitionResultGeneratedEventArgs ^args
|
||||
);
|
||||
|
||||
// Recognize when conditions might impact speech recognition quality.
|
||||
void OnSpeechQualityDegraded(
|
||||
Windows::Media::SpeechRecognition::SpeechRecognizer^ recognizer,
|
||||
Windows::Media::SpeechRecognition::SpeechRecognitionQualityDegradingEventArgs^ args
|
||||
);
|
||||
|
||||
// Initializes the speech command list.
|
||||
void InitializeSpeechCommandList();
|
||||
|
||||
// Initializes a speech recognizer.
|
||||
bool InitializeSpeechRecognizer();
|
||||
|
||||
// Provides a voice prompt, before starting the scenario.
|
||||
void BeginVoiceUIPrompt();
|
||||
void PlayRecognitionBeginSound();
|
||||
void PlayRecognitionSound();
|
||||
|
||||
// Creates a speech command recognizer, and starts listening.
|
||||
Concurrency::task<bool> StartRecognizeSpeechCommands();
|
||||
|
||||
// Resets the speech recognizer, if one exists.
|
||||
Concurrency::task<void> StopCurrentRecognizerIfExists();
|
||||
|
||||
// Asynchronously creates resources for new holographic cameras.
|
||||
void OnCameraAdded(
|
||||
Windows::Graphics::Holographic::HolographicSpace^ sender,
|
||||
Windows::Graphics::Holographic::HolographicSpaceCameraAddedEventArgs^ args);
|
||||
|
||||
// Synchronously releases resources for holographic cameras that are no longer
|
||||
// attached to the system.
|
||||
void OnCameraRemoved(
|
||||
Windows::Graphics::Holographic::HolographicSpace^ sender,
|
||||
Windows::Graphics::Holographic::HolographicSpaceCameraRemovedEventArgs^ args);
|
||||
|
||||
// Used to notify the app when the positional tracking state changes.
|
||||
void OnLocatabilityChanged(
|
||||
Windows::Perception::Spatial::SpatialLocator^ sender,
|
||||
Platform::Object^ args);
|
||||
|
||||
// Clears event registration state. Used when changing to a new HolographicSpace
|
||||
// and when tearing down AppMain.
|
||||
void UnregisterHolographicEventHandlers();
|
||||
|
||||
// Renders a colorful holographic cube that's 20 centimeters wide. This sample content
|
||||
// is used to demonstrate world-locked rendering.
|
||||
std::unique_ptr<SpinningCubeRenderer> m_spinningCubeRenderer;
|
||||
|
||||
// Listens for the Pressed spatial input event.
|
||||
std::shared_ptr<SpatialInputHandler> m_spatialInputHandler;
|
||||
|
||||
// Cached pointer to device resources.
|
||||
std::shared_ptr<DX::DeviceResources> m_deviceResources;
|
||||
|
||||
// Render loop timer.
|
||||
DX::StepTimer m_timer;
|
||||
|
||||
// Represents the holographic space around the user.
|
||||
Windows::Graphics::Holographic::HolographicSpace^ m_holographicSpace;
|
||||
|
||||
// SpatialLocator that is attached to the primary camera.
|
||||
Windows::Perception::Spatial::SpatialLocator^ m_locator;
|
||||
|
||||
// A reference frame attached to the holographic camera.
|
||||
Windows::Perception::Spatial::SpatialStationaryFrameOfReference^ m_referenceFrame;
|
||||
|
||||
// Event registration tokens.
|
||||
Windows::Foundation::EventRegistrationToken m_cameraAddedToken;
|
||||
Windows::Foundation::EventRegistrationToken m_cameraRemovedToken;
|
||||
Windows::Foundation::EventRegistrationToken m_locatabilityChangedToken;
|
||||
|
||||
Windows::Foundation::EventRegistrationToken m_speechRecognizerResultEventToken;
|
||||
Windows::Foundation::EventRegistrationToken m_speechRecognitionQualityDegradedToken;
|
||||
|
||||
bool m_listening;
|
||||
|
||||
// Speech recognizer.
|
||||
Windows::Media::SpeechRecognition::SpeechRecognizer^ m_speechRecognizer;
|
||||
|
||||
// Maps commands to color data.
|
||||
// We will create a Vector of the key values in this map for use as speech commands.
|
||||
Platform::Collections::Map<Platform::String^, Windows::Foundation::Numerics::float4>^ m_speechCommandData;
|
||||
|
||||
// The most recent speech command received.
|
||||
Platform::String^ m_lastCommand;
|
||||
|
||||
// Handles playback of speech synthesis audio.
|
||||
OmnidirectionalSound m_speechSynthesisSound;
|
||||
OmnidirectionalSound m_recognitionSound;
|
||||
OmnidirectionalSound m_startRecognitionSound;
|
||||
|
||||
bool m_waitingForSpeechPrompt = false;
|
||||
bool m_waitingForSpeechCue = false;
|
||||
float m_secondsUntilSoundIsComplete = 0.f;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
IgnorableNamespaces="uap mp"
|
||||
>
|
||||
<Identity Name="Microsoft.SDKSamples.HolographicVoiceInput.CPP" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" Version="1.0.0.0"/>
|
||||
<mp:PhoneIdentity PhoneProductId="870a364a-524b-4c78-b834-1b796f26d537" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
<Properties>
|
||||
<DisplayName>Holographic Voice Input Sample</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo-sdk.png</Logo>
|
||||
</Properties>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Holographic" MinVersion="10.0.10586.0" MaxVersionTested="10.0.14393.0"/>
|
||||
</Dependencies>
|
||||
<Resources>
|
||||
<Resource Language="x-generate"/>
|
||||
</Resources>
|
||||
<Applications>
|
||||
<Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="HolographicVoiceInputSample.AppView">
|
||||
<uap:VisualElements
|
||||
DisplayName="HolographicVoiceInputSample"
|
||||
Square150x150Logo="Assets\squareTile-sdk.png"
|
||||
Square44x44Logo="Assets\smallTile-sdk.png"
|
||||
Description="HolographicVoiceInputSample"
|
||||
BackgroundColor="#464646"
|
||||
>
|
||||
<uap:DefaultTile>
|
||||
<uap:ShowNameOnTiles>
|
||||
<uap:ShowOn Tile="square150x150Logo"/>
|
||||
</uap:ShowNameOnTiles>
|
||||
</uap:DefaultTile>
|
||||
<uap:SplashScreen Image="Assets\splash-sdk.png"/>
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
<Capabilities>
|
||||
<DeviceCapability Name="microphone"/>
|
||||
</Capabilities>
|
||||
</Package>
|
|
@ -0,0 +1,16 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
//
|
||||
// pch.cpp
|
||||
// Include the standard header and generate the precompiled header.
|
||||
//
|
||||
|
||||
#include "pch.h"
|
|
@ -0,0 +1,35 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <agile.h>
|
||||
#include <array>
|
||||
#include <d2d1_2.h>
|
||||
#include <d3d11_4.h>
|
||||
#include <DirectXColors.h>
|
||||
#include <dwrite_2.h>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <wincodec.h>
|
||||
#include <WindowsNumerics.h>
|
||||
|
||||
#include <wrl.h>
|
||||
#include <Mfidl.h>
|
||||
#include <Mfapi.h>
|
||||
#include <Mfreadwrite.h>
|
||||
#include <xaudio2.h>
|
||||
#include <xapo.h>
|
||||
#include <hrtfapoapi.h>
|
||||
|
||||
#include <collection.h>
|
||||
#include <vector>
|
||||
#include <ppltasks.h>
|
||||
#include "Common\PrintWstringToDebugConsole.h"
|
|
@ -0,0 +1,22 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
|
||||
<g transform="translate(100, 75) rotate(30)" font-family="Verdana" font-size="20">
|
||||
<ellipse rx="100" ry="50" style="stroke:black; fill:none"/>
|
||||
<g transform="translate(-100, 0) rotate(-30)">
|
||||
<circle r="3" style="stroke:black; fill:black"/>
|
||||
<text x="8" y="10">0</text>
|
||||
</g>
|
||||
<g transform="translate(0, -50) rotate(-30)">
|
||||
<circle r="3" style="stroke:black; fill:black"/>
|
||||
<text x="-10" y="25">1</text>
|
||||
</g>
|
||||
<g transform="translate(100, 0) rotate(-30)">
|
||||
<circle r="3" style="stroke:black; fill:black"/>
|
||||
<text x="-18">2</text>
|
||||
</g>
|
||||
<g transform="translate(0, 50) rotate(-30)">
|
||||
<circle r="3" style="stroke:black; fill:black"/>
|
||||
<text y="-10">3</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 793 B |
|
@ -0,0 +1,62 @@
|
|||
<!---
|
||||
category: CustomUserInteractions Inking
|
||||
samplefwlink: http://go.microsoft.com/fwlink/p/?LinkId=844937
|
||||
--->
|
||||
|
||||
# Ink Analysis sample
|
||||
|
||||
Shows how to recognize handwriting, shapes, and document structure with Ink Analysis.
|
||||
|
||||
> **Note:** This sample is part of a large collection of UWP feature samples.
|
||||
> If you are unfamiliar with Git and GitHub, you can download the entire collection as a
|
||||
> [ZIP file](https://github.com/Microsoft/Windows-universal-samples/archive/master.zip), but be
|
||||
> sure to unzip everything to access shared dependencies. For more info on working with the ZIP file,
|
||||
> the samples collection, and GitHub, see [Get the UWP samples from GitHub](https://aka.ms/ovu2uq).
|
||||
> For more samples, see the [Samples portal](https://aka.ms/winsamples) on the Windows Dev Center.
|
||||
|
||||
Specifically, this sample covers using the Windows.UI.Input.Inking.Analysis APIs to do the following:
|
||||
- Recognize shapes from ink strokes
|
||||
- Recognize document structures from ink strokes
|
||||
- Recognize handwritten text from ink strokes
|
||||
|
||||
## Related topics
|
||||
|
||||
**Samples**
|
||||
|
||||
[SimpleInk](/Samples/SimpleInk)
|
||||
[ComplexInk](/Samples/ComplexInk)
|
||||
[OCR](/Samples/OCR)
|
||||
[Family Notes sample](https://github.com/Microsoft/Windows-appsample-familynotes)
|
||||
[Coloring Book app sample](https://github.com/Microsoft/Windows-appsample-coloringbook)
|
||||
|
||||
**Reference**
|
||||
|
||||
[Windows.UI.Input.Inking](http://msdn.microsoft.com/library/windows/apps/br208524)
|
||||
|
||||
## Operating system requirements
|
||||
|
||||
**Client:** Windows 10 build 15052
|
||||
|
||||
**Server:** Windows Server 2016 Technical Preview
|
||||
|
||||
**Phone:** Windows 10 build 15052
|
||||
|
||||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
||||
The next steps depend on whether you just want to deploy the sample or you want to both deploy and run it.
|
||||
|
||||
### Deploying the sample
|
||||
|
||||
- Select Build > Deploy Solution.
|
||||
|
||||
### Deploying and running the sample
|
||||
|
||||
- To debug the sample and then run it, press F5 or select Debug > Start Debugging. To run the sample without debugging, press Ctrl+F5 or selectDebug > Start Without Debugging.
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProjectGuid>{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}</ProjectGuid>
|
||||
<OutputType>AppContainerExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SDKTemplate</RootNamespace>
|
||||
<AssemblyName>InkAnalysis</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.15052.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.15052.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\ARM\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
|
||||
<OutputPath>bin\ARM\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="project.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\..\SharedContent\cs\App.xaml.cs">
|
||||
<Link>App.xaml.cs</Link>
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\MainPage.xaml.cs">
|
||||
<Link>MainPage.xaml.cs</Link>
|
||||
<DependentUpon>MainPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\AssemblyInfo.cs">
|
||||
<Link>Properties\AssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="SampleConfiguration.cs" />
|
||||
<Compile Include="Scenario1.xaml.cs">
|
||||
<DependentUpon>Scenario1.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Scenario2.xaml.cs">
|
||||
<DependentUpon>Scenario2.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</AppxManifest>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="..\..\..\SharedContent\xaml\App.xaml">
|
||||
<Link>App.xaml</Link>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Page Include="..\..\..\SharedContent\cs\MainPage.xaml">
|
||||
<Link>MainPage.xaml</Link>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Scenario1.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="..\..\..\SharedContent\xaml\Styles.xaml">
|
||||
<Link>Styles\Styles.xaml</Link>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Scenario2.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="..\..\..\SharedContent\cs\Default.rd.xml">
|
||||
<Link>Properties\Default.rd.xml</Link>
|
||||
</Content>
|
||||
<Content Include="..\..\..\SharedContent\media\microsoft-sdk.png">
|
||||
<Link>Assets\microsoft-sdk.png</Link>
|
||||
</Content>
|
||||
<Content Include="..\..\..\SharedContent\media\smalltile-sdk.png">
|
||||
<Link>Assets\smallTile-sdk.png</Link>
|
||||
</Content>
|
||||
<Content Include="..\..\..\SharedContent\media\splash-sdk.png">
|
||||
<Link>Assets\splash-sdk.png</Link>
|
||||
</Content>
|
||||
<Content Include="..\..\..\SharedContent\media\squaretile-sdk.png">
|
||||
<Link>Assets\squareTile-sdk.png</Link>
|
||||
</Content>
|
||||
<Content Include="..\..\..\SharedContent\media\storelogo-sdk.png">
|
||||
<Link>Assets\storeLogo-sdk.png</Link>
|
||||
</Content>
|
||||
<Content Include="..\..\..\SharedContent\media\tile-sdk.png">
|
||||
<Link>Assets\tile-sdk.png</Link>
|
||||
</Content>
|
||||
<Content Include="..\..\..\SharedContent\media\windows-sdk.png">
|
||||
<Link>Assets\windows-sdk.png</Link>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InkAnalysis", "InkAnalysis.csproj", "{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|ARM = Release|ARM
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|ARM.ActiveCfg = Debug|ARM
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|ARM.Build.0 = Debug|ARM
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|ARM.Deploy.0 = Debug|ARM
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x64.Build.0 = Debug|x64
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x86.Build.0 = Debug|x86
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|ARM.ActiveCfg = Release|ARM
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|ARM.Build.0 = Release|ARM
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|ARM.Deploy.0 = Release|ARM
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x64.ActiveCfg = Release|x64
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x64.Build.0 = Release|x64
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x64.Deploy.0 = Release|x64
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x86.ActiveCfg = Release|x86
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x86.Build.0 = Release|x86
|
||||
{DC30CE66-DAEE-4CCF-BD02-8837FE918B6F}.Release|x86.Deploy.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
IgnorableNamespaces="uap mp"
|
||||
>
|
||||
<Identity Name="Microsoft.SDKSamples.InkAnalysis.CS" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" Version="1.0.0.0"/>
|
||||
<mp:PhoneIdentity PhoneProductId="d640f718-13ae-4108-934b-e3d8288513af" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
<Properties>
|
||||
<DisplayName>Ink Analysis C# Sample</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo-sdk.png</Logo>
|
||||
</Properties>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.15052.0" MaxVersionTested="10.0.15052.0"/>
|
||||
</Dependencies>
|
||||
<Resources>
|
||||
<Resource Language="x-generate"/>
|
||||
</Resources>
|
||||
<Applications>
|
||||
<Application Id="InkAnalysis.App" Executable="$targetnametoken$.exe" EntryPoint="InkAnalysis.App">
|
||||
<uap:VisualElements
|
||||
DisplayName="Ink Analysis C# sample"
|
||||
Square150x150Logo="Assets\squareTile-sdk.png"
|
||||
Square44x44Logo="Assets\SmallTile-sdk.png"
|
||||
Description="Ink Analysis C# sample"
|
||||
BackgroundColor="#00b2f0"
|
||||
>
|
||||
<uap:SplashScreen Image="Assets\Splash-sdk.png"/>
|
||||
<uap:DefaultTile>
|
||||
<uap:ShowNameOnTiles>
|
||||
<uap:ShowOn Tile="square150x150Logo"/>
|
||||
</uap:ShowNameOnTiles>
|
||||
</uap:DefaultTile>
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
</Package>
|
|
@ -0,0 +1,46 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace SDKTemplate
|
||||
{
|
||||
public partial class MainPage : Page
|
||||
{
|
||||
public const string FEATURE_NAME = "Ink Analysis C# Sample";
|
||||
|
||||
List<Scenario> scenarios = new List<Scenario>
|
||||
{
|
||||
new Scenario() { Title="Scenario 1", ClassType=typeof(Scenario1)},
|
||||
new Scenario() { Title="Scenario 2", ClassType=typeof(Scenario2)},
|
||||
};
|
||||
|
||||
public void NavigateToScenario(Type type)
|
||||
{
|
||||
for (int index = 0; index < scenarios.Count; index++)
|
||||
{
|
||||
if (scenarios[index].ClassType == type)
|
||||
{
|
||||
ScenarioControl.SelectedIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Scenario
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public Type ClassType { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
<!--
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
-->
|
||||
<Page
|
||||
x:Class="SDKTemplate.Scenario1"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid x:Name="RootGrid" Margin="12,10,12,12">
|
||||
<Grid.Resources>
|
||||
<Style x:Key="InkToolBarActionButton" TargetType="Button">
|
||||
<Setter Property="MinWidth" Value="{ThemeResource InkToolbarButtonWidth}"/>
|
||||
<Setter Property="MinHeight" Value="{ThemeResource InkToolbarButtonHeight}"/>
|
||||
<Setter Property="MaxHeight" Value="{ThemeResource InkToolbarButtonHeight}"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Background" Value="{ThemeResource InkToolbarButtonBackgroundThemeBrush}"/>
|
||||
<Setter Property="Foreground" Value="{ThemeResource InkToolbarButtonForegroundThemeBrush}"/>
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Margin="0,0,0,10">
|
||||
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
|
||||
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
|
||||
This scenario converts ink strokes to XAML shapes.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<InkToolbar x:Name="inkToolBar" HorizontalAlignment="Left" VerticalAlignment="Top" TargetInkCanvas="{x:Bind inkCanvas}" InitialControls="None">
|
||||
<InkToolbarBallpointPenButton SelectedStrokeWidth="2"/>
|
||||
<InkToolbarPencilButton/>
|
||||
<InkToolbarEraserButton/>
|
||||
<InkToolbarStencilButton/>
|
||||
</InkToolbar>
|
||||
<Line Y1="0"
|
||||
Y2="{ThemeResource InkToolbarButtonHeight}"
|
||||
HorizontalAlignment="Stretch"
|
||||
Width="2"
|
||||
Height="{ThemeResource InkToolbarButtonHeight}"
|
||||
StrokeThickness="1"
|
||||
Stroke="Gray"/>
|
||||
<Button x:Name="clearButton" Click="ClearButton_Click" Style="{StaticResource InkToolBarActionButton}" Content="Clear"/>
|
||||
</StackPanel>
|
||||
|
||||
<Grid Grid.Row ="2" BorderBrush="AliceBlue" BorderThickness="2" Background="White" x:Name="gridBox">
|
||||
<Canvas x:Name="canvas">
|
||||
<Canvas.Resources>
|
||||
<SolidColorBrush x:Key="PolygonBrush" Color="Blue" />
|
||||
<SolidColorBrush x:Key="EllipseBrush" Color="Green" />
|
||||
<Style TargetType="Polygon">
|
||||
<Setter Property="Stroke" Value="Blue"/>
|
||||
<Setter Property="StrokeThickness" Value="2"/>
|
||||
</Style>
|
||||
<Style TargetType="Ellipse">
|
||||
<Setter Property="Stroke" Value="Green"/>
|
||||
<Setter Property="StrokeThickness" Value="2"/>
|
||||
</Style>
|
||||
</Canvas.Resources>
|
||||
</Canvas>
|
||||
<InkCanvas x:Name="inkCanvas"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,224 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
using SDKTemplate;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Input.Inking;
|
||||
using Windows.UI.Input.Inking.Analysis;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Windows.UI.Xaml.Shapes;
|
||||
|
||||
namespace SDKTemplate
|
||||
{
|
||||
/// <summary>
|
||||
/// This scenerio demostrates how to do shape recognition with InkAanlyzer.
|
||||
/// </summary>
|
||||
public sealed partial class Scenario1 : Page
|
||||
{
|
||||
private MainPage rootPage = MainPage.Current;
|
||||
InkPresenter inkPresenter;
|
||||
InkAnalyzer inkAnalyzer;
|
||||
DispatcherTimer dispatcherTimer;
|
||||
|
||||
public Scenario1()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
inkPresenter = inkCanvas.InkPresenter;
|
||||
inkPresenter.StrokesCollected += InkPresenter_StrokesCollected;
|
||||
inkPresenter.StrokesErased += InkPresenter_StrokesErased;
|
||||
inkPresenter.StrokeInput.StrokeStarted += StrokeInput_StrokeStarted;
|
||||
inkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Pen | CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Touch;
|
||||
|
||||
inkAnalyzer = new InkAnalyzer();
|
||||
|
||||
dispatcherTimer = new DispatcherTimer();
|
||||
dispatcherTimer.Tick += DispatcherTimer_Tick;
|
||||
|
||||
// We perform analysis when there has been a change to the
|
||||
// ink presenter and the user has been idle for 200ms.
|
||||
dispatcherTimer.Interval = TimeSpan.FromMilliseconds(200);
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
rootPage = MainPage.Current;
|
||||
}
|
||||
|
||||
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
|
||||
{
|
||||
dispatcherTimer.Stop();
|
||||
}
|
||||
|
||||
private void StrokeInput_StrokeStarted(InkStrokeInput sender, PointerEventArgs args)
|
||||
{
|
||||
// Don't perform analysis while a stroke is in progress.
|
||||
dispatcherTimer.Stop();
|
||||
}
|
||||
|
||||
private void ClearButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Don't run analysis when there is nothing to analyze.
|
||||
dispatcherTimer.Stop();
|
||||
|
||||
inkPresenter.StrokeContainer.Clear();
|
||||
inkAnalyzer.ClearDataForAllStrokes();
|
||||
canvas.Children.Clear();
|
||||
}
|
||||
|
||||
private void InkPresenter_StrokesCollected(InkPresenter sender, InkStrokesCollectedEventArgs args)
|
||||
{
|
||||
dispatcherTimer.Stop();
|
||||
inkAnalyzer.AddDataForStrokes(args.Strokes);
|
||||
dispatcherTimer.Start();
|
||||
}
|
||||
|
||||
private void InkPresenter_StrokesErased(InkPresenter sender, InkStrokesErasedEventArgs args)
|
||||
{
|
||||
dispatcherTimer.Stop();
|
||||
foreach (var stroke in args.Strokes)
|
||||
{
|
||||
inkAnalyzer.RemoveDataForStroke(stroke.Id);
|
||||
}
|
||||
dispatcherTimer.Start();
|
||||
}
|
||||
|
||||
private async void DispatcherTimer_Tick(object sender, object e)
|
||||
{
|
||||
dispatcherTimer.Stop();
|
||||
if (!inkAnalyzer.IsAnalyzing)
|
||||
{
|
||||
InkAnalysisResult results = await inkAnalyzer.AnalyzeAsync();
|
||||
if (results.Status == InkAnalysisStatus.Updated)
|
||||
{
|
||||
ConvertShapes();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ink analyzer is busy. Wait a while and try again.
|
||||
dispatcherTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private void ConvertShapes()
|
||||
{
|
||||
IReadOnlyList<IInkAnalysisNode> drawings = inkAnalyzer.AnalysisRoot.FindNodes(InkAnalysisNodeKind.InkDrawing);
|
||||
foreach (IInkAnalysisNode drawing in drawings)
|
||||
{
|
||||
var shape = (InkAnalysisInkDrawing)drawing;
|
||||
if (shape.DrawingKind == InkAnalysisDrawingKind.Drawing)
|
||||
{
|
||||
// Omit unsupported shape
|
||||
continue;
|
||||
}
|
||||
|
||||
if (shape.DrawingKind == InkAnalysisDrawingKind.Circle || shape.DrawingKind == InkAnalysisDrawingKind.Ellipse)
|
||||
{
|
||||
// Create a Circle or Ellipse on the canvas.
|
||||
AddEllipseToCanvas(shape);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a Polygon on the canvas.
|
||||
AddPolygonToCanvas(shape);
|
||||
}
|
||||
|
||||
// Select the strokes that were recognized, so we can delete them.
|
||||
// The effect is that the shape added to the canvas replaces the strokes.
|
||||
foreach (var strokeId in shape.GetStrokeIds())
|
||||
{
|
||||
InkStroke stroke = inkPresenter.StrokeContainer.GetStrokeById(strokeId);
|
||||
stroke.Selected = true;
|
||||
}
|
||||
|
||||
// Remove the recognized strokes from the analyzer
|
||||
// so it won't re-analyze them.
|
||||
inkAnalyzer.RemoveDataForStrokes(shape.GetStrokeIds());
|
||||
}
|
||||
inkPresenter.StrokeContainer.DeleteSelected();
|
||||
}
|
||||
|
||||
private void AddPolygonToCanvas(InkAnalysisInkDrawing shape)
|
||||
{
|
||||
Polygon polygon = new Polygon();
|
||||
|
||||
// The points of the polygon are reported clockwise.
|
||||
foreach (var point in shape.Points)
|
||||
{
|
||||
polygon.Points.Add(point);
|
||||
}
|
||||
|
||||
canvas.Children.Add(polygon);
|
||||
}
|
||||
|
||||
static double Distance(Point p0, Point p1)
|
||||
{
|
||||
double dX = p1.X - p0.X;
|
||||
double dY = p1.Y - p0.Y;
|
||||
return Math.Sqrt(dX * dX + dY * dY);
|
||||
}
|
||||
|
||||
private void AddEllipseToCanvas(InkAnalysisInkDrawing shape)
|
||||
{
|
||||
Ellipse ellipse = new Ellipse();
|
||||
|
||||
// Ellipses and circles are reported as four points
|
||||
// in clockwise orientation.
|
||||
// Points 0 and 2 are the extrema of one axis,
|
||||
// and points 1 and 3 are the extrema of the other axis.
|
||||
// See Ellipse.svg for a diagram.
|
||||
IReadOnlyList<Point> points = shape.Points;
|
||||
|
||||
// Calculate the geometric center of the ellipse.
|
||||
var center = new Point((points[0].X + points[2].X) / 2.0, (points[0].Y + points[2].Y) / 2.0);
|
||||
|
||||
// Calculate the length of one axis.
|
||||
ellipse.Width = Distance(points[0], points[2]);
|
||||
|
||||
var compositeTransform = new CompositeTransform();
|
||||
if(shape.DrawingKind == InkAnalysisDrawingKind.Circle)
|
||||
{
|
||||
ellipse.Height = ellipse.Width;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculate the length of the other axis.
|
||||
ellipse.Height = Distance(points[1], points[3]);
|
||||
|
||||
// Calculate the amount by which the ellipse has been rotated
|
||||
// by looking at the angle our "width" axis has been rotated.
|
||||
// Since the Y coordinate is inverted, this calculates the amount
|
||||
// by which the ellipse has been rotated clockwise.
|
||||
double rotationAngle = Math.Atan2(points[2].Y - points[0].Y, points[2].X - points[0].X);
|
||||
|
||||
RotateTransform rotateTransform = new RotateTransform();
|
||||
// Convert radians to degrees.
|
||||
compositeTransform.Rotation = rotationAngle * 180.0 / Math.PI;
|
||||
compositeTransform.CenterX = ellipse.Width / 2.0;
|
||||
compositeTransform.CenterY = ellipse.Height / 2.0;
|
||||
}
|
||||
|
||||
compositeTransform.TranslateX = center.X - ellipse.Width / 2.0;
|
||||
compositeTransform.TranslateY = center.Y - ellipse.Height / 2.0;
|
||||
|
||||
ellipse.RenderTransform = compositeTransform;
|
||||
|
||||
canvas.Children.Add(ellipse);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
<Page
|
||||
x:Class="SDKTemplate.Scenario2"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:SDKTemplate"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid x:Name="RootGrid" Margin="12,10,12,12">
|
||||
<Grid.Resources>
|
||||
<Style x:Key="InkToolBarActionButton" TargetType="Button">
|
||||
<Setter Property="MinWidth" Value="{ThemeResource InkToolbarButtonWidth}"/>
|
||||
<Setter Property="MinHeight" Value="{ThemeResource InkToolbarButtonHeight}"/>
|
||||
<Setter Property="MaxHeight" Value="{ThemeResource InkToolbarButtonHeight}"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Background" Value="{ThemeResource InkToolbarButtonBackgroundThemeBrush}"/>
|
||||
<Setter Property="Foreground" Value="{ThemeResource InkToolbarButtonForegroundThemeBrush}"/>
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Grid.Row="0" Margin="0,0,0,10">
|
||||
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
|
||||
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
|
||||
This scenario demonstrates text recognition with InkAnalyzer:<LineBreak/>
|
||||
- write with mouse or pen<LineBreak/>
|
||||
- one tap (touch) on the ink to visualize the paragraph<LineBreak/>
|
||||
- double tap (touch) to convert the paragraph to text.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<InkToolbar x:Name="inkToolBar" HorizontalAlignment="Left" VerticalAlignment="Top" TargetInkCanvas="{x:Bind inkCanvas}" InitialControls="None">
|
||||
<InkToolbarBallpointPenButton SelectedStrokeWidth="2"/>
|
||||
<InkToolbarPencilButton/>
|
||||
</InkToolbar>
|
||||
<Line Y1="0" Y2="{ThemeResource InkToolbarButtonHeight}" HorizontalAlignment="Stretch" Width="2" Height="{ThemeResource InkToolbarButtonHeight}" StrokeThickness="1" Stroke="Gray"/>
|
||||
<Button x:Name="clearButton" Click="ClearButton_Click" Style="{StaticResource InkToolBarActionButton}" Content="Clear"/>
|
||||
</StackPanel>
|
||||
|
||||
<Grid Grid.Row ="2" BorderBrush="AliceBlue" BorderThickness="2" Background="White" x:Name="gridBox">
|
||||
<Canvas x:Name="canvas">
|
||||
<Rectangle x:Name="SelectionRect" Stroke="Gray" StrokeThickness="2" StrokeDashArray="2,2" StrokeDashCap="Round" Visibility="Collapsed"/>
|
||||
<Canvas.Resources>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Verdana"/>
|
||||
<Setter Property="FontSize" Value="18"/>
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
</Style>
|
||||
</Canvas.Resources>
|
||||
</Canvas>
|
||||
<InkCanvas x:Name="inkCanvas"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,215 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Input.Inking;
|
||||
using Windows.UI.Input.Inking.Analysis;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Windows.UI.Xaml.Shapes;
|
||||
|
||||
namespace SDKTemplate
|
||||
{
|
||||
/// <summary>
|
||||
/// This scenario demostrates text recognition with InkAnalyzer.
|
||||
/// </summary>
|
||||
public sealed partial class Scenario2 : Page
|
||||
{
|
||||
private MainPage rootPage = MainPage.Current;
|
||||
InkPresenter inkPresenter;
|
||||
InkAnalyzer inkAnalyzer;
|
||||
InkAnalysisParagraph paragraphSelected;
|
||||
DispatcherTimer dispatcherTimer;
|
||||
|
||||
public Scenario2()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
inkPresenter = inkCanvas.InkPresenter;
|
||||
inkPresenter.StrokesCollected += InkPresenter_StrokesCollected;
|
||||
inkPresenter.StrokesErased += InkPresenter_StrokesErased;
|
||||
inkPresenter.StrokeInput.StrokeStarted += StrokeInput_StrokeStarted;
|
||||
|
||||
// We exclude CoreInputDeviceTypes.Touch because we use touch to select paragraphs.
|
||||
inkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Pen | CoreInputDeviceTypes.Mouse;
|
||||
|
||||
inkCanvas.Tapped += InkCanvas_Tapped;
|
||||
inkCanvas.DoubleTapped += InkCanvas_DoubleTapped;
|
||||
|
||||
inkAnalyzer = new InkAnalyzer();
|
||||
paragraphSelected = null;
|
||||
|
||||
dispatcherTimer = new DispatcherTimer();
|
||||
dispatcherTimer.Tick += DispatcherTimer_Tick;
|
||||
|
||||
// We perform analysis when there has been a change to the
|
||||
// ink presenter and the user has been idle for 1 second.
|
||||
dispatcherTimer.Interval = TimeSpan.FromSeconds(1);
|
||||
}
|
||||
|
||||
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
|
||||
{
|
||||
dispatcherTimer.Stop();
|
||||
}
|
||||
|
||||
private void InkPresenter_StrokesErased(InkPresenter sender, InkStrokesErasedEventArgs args)
|
||||
{
|
||||
dispatcherTimer.Stop();
|
||||
foreach (var stroke in args.Strokes)
|
||||
{
|
||||
inkAnalyzer.RemoveDataForStroke(stroke.Id);
|
||||
}
|
||||
dispatcherTimer.Start();
|
||||
}
|
||||
|
||||
private void StrokeInput_StrokeStarted(InkStrokeInput sender, Windows.UI.Core.PointerEventArgs args)
|
||||
{
|
||||
// Don't perform analysis while a stroke is in progress.
|
||||
dispatcherTimer.Stop();
|
||||
}
|
||||
|
||||
private void InkPresenter_StrokesCollected(InkPresenter sender, InkStrokesCollectedEventArgs args)
|
||||
{
|
||||
dispatcherTimer.Stop();
|
||||
inkAnalyzer.AddDataForStrokes(args.Strokes);
|
||||
dispatcherTimer.Start();
|
||||
}
|
||||
|
||||
private async void DispatcherTimer_Tick(object sender, object e)
|
||||
{
|
||||
dispatcherTimer.Stop();
|
||||
if (!inkAnalyzer.IsAnalyzing)
|
||||
{
|
||||
var result = await inkAnalyzer.AnalyzeAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ink analyzer is busy. Wait a while and try again.
|
||||
dispatcherTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Don't run analysis when there is nothing to analyze.
|
||||
dispatcherTimer.Stop();
|
||||
|
||||
inkPresenter.StrokeContainer.Clear();
|
||||
inkAnalyzer.ClearDataForAllStrokes();
|
||||
canvas.Children.Clear();
|
||||
canvas.Children.Add(SelectionRect);
|
||||
SelectionRect.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void InkCanvas_Tapped(object sender, TappedRoutedEventArgs e)
|
||||
{
|
||||
var position = e.GetPosition(inkCanvas);
|
||||
|
||||
var paragraph = FindHitParagraph(position);
|
||||
if (paragraph == null)
|
||||
{
|
||||
// Did not tap on a paragraph.
|
||||
SelectionRect.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show the selection rect at the paragraph's bounding rect.
|
||||
Rect rect = paragraph.BoundingRect;
|
||||
SelectionRect.Width = rect.Width;
|
||||
SelectionRect.Height = rect.Height;
|
||||
Canvas.SetLeft(SelectionRect, rect.Left);
|
||||
Canvas.SetTop(SelectionRect, rect.Top);
|
||||
|
||||
SelectionRect.Visibility = Visibility.Visible;
|
||||
}
|
||||
paragraphSelected = paragraph;
|
||||
}
|
||||
|
||||
private void InkCanvas_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
|
||||
{
|
||||
// Convert the selected paragraph or list item
|
||||
if (paragraphSelected != null)
|
||||
{
|
||||
Rect rect = paragraphSelected.BoundingRect;
|
||||
var text = ExtractTextFromParagraph(paragraphSelected);
|
||||
|
||||
if ((rect.X > 0) && (rect.Y > 0) && (text != string.Empty))
|
||||
{
|
||||
// Create text box with recognized text
|
||||
var textBlock = new TextBlock();
|
||||
textBlock.Text = text;
|
||||
textBlock.MaxWidth = rect.Width;
|
||||
textBlock.MaxHeight = rect.Height;
|
||||
Canvas.SetLeft(textBlock, rect.X);
|
||||
Canvas.SetTop(textBlock, rect.Y);
|
||||
|
||||
// Remove strokes from InkPresenter
|
||||
IReadOnlyList<uint> strokeIds = paragraphSelected.GetStrokeIds();
|
||||
foreach (var strokeId in strokeIds)
|
||||
{
|
||||
var stroke = inkPresenter.StrokeContainer.GetStrokeById(strokeId);
|
||||
stroke.Selected = true;
|
||||
}
|
||||
inkPresenter.StrokeContainer.DeleteSelected();
|
||||
|
||||
// Remove strokes from InkAnalyzer
|
||||
inkAnalyzer.RemoveDataForStrokes(strokeIds);
|
||||
|
||||
// Hide the SelectionRect
|
||||
SelectionRect.Visibility = Visibility.Collapsed;
|
||||
|
||||
canvas.Children.Add(textBlock);
|
||||
paragraphSelected = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string ExtractTextFromParagraph(InkAnalysisParagraph paragraph)
|
||||
{
|
||||
// The paragraph.RecognizedText property also returns the text,
|
||||
// but manually walking through the lines allows us to preserve
|
||||
// line breaks.
|
||||
var lines = new List<string>();
|
||||
foreach (var child in paragraph.Children)
|
||||
{
|
||||
if (child.Kind == InkAnalysisNodeKind.Line)
|
||||
{
|
||||
var line = (InkAnalysisLine)child;
|
||||
lines.Add(line.RecognizedText);
|
||||
}
|
||||
else if (child.Kind == InkAnalysisNodeKind.ListItem)
|
||||
{
|
||||
var listItem = (InkAnalysisListItem)child;
|
||||
lines.Add(listItem.RecognizedText);
|
||||
}
|
||||
}
|
||||
return String.Join("\n", lines);
|
||||
}
|
||||
|
||||
private InkAnalysisParagraph FindHitParagraph(Point pt)
|
||||
{
|
||||
var paragraphs = inkAnalyzer.AnalysisRoot.FindNodes(InkAnalysisNodeKind.Paragraph);
|
||||
foreach (var paragraph in paragraphs)
|
||||
{
|
||||
// To support ink written with angle, RotatedBoundingRect should be used in hit testing.
|
||||
if (RectHelper.Contains(paragraph.BoundingRect, pt))
|
||||
{
|
||||
return (InkAnalysisParagraph)paragraph;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0"
|
||||
},
|
||||
"frameworks": {
|
||||
"uap10.0": {}
|
||||
},
|
||||
"runtimes": {
|
||||
"win10-arm": {},
|
||||
"win10-arm-aot": {},
|
||||
"win10-x86": {},
|
||||
"win10-x86-aot": {},
|
||||
"win10-x64": {},
|
||||
"win10-x64-aot": {}
|
||||
}
|
||||
}
|
|
@ -17,12 +17,13 @@ Shows how to use the universal map control ([MapControl]( https://msdn.microsoft
|
|||
Specifically, this sample shows:
|
||||
|
||||
* MapControl Basics: adjusting the ZoomLevel, Heading, DesiredPtich, and map style
|
||||
* Adding points of interest on the map: PushPins, images, and shapes
|
||||
* Adding points of interest on the map: PushPins, images, billboards and shapes
|
||||
* Adding XAML overlays on the map
|
||||
* Showing 3D locations in MapControl
|
||||
* Showing Streetside experience within MapControl
|
||||
* Launching Maps using URI Schemes
|
||||
* Displaying points of interest with clustering
|
||||
* Finding and downloading Offline Maps
|
||||
|
||||
This sample is written in XAML.
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
<AppContainerApplication>true</AppContainerApplication>
|
||||
<ApplicationType>Windows Store</ApplicationType>
|
||||
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
|
||||
<WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.10240.0</WindowsTargetPlatformMinVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.15052.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.15052.0</WindowsTargetPlatformMinVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
|
@ -41,35 +41,35 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
@ -168,6 +168,9 @@
|
|||
<ClInclude Include="Scenario7.xaml.h">
|
||||
<DependentUpon>..\shared\Scenario7.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Scenario8.xaml.h">
|
||||
<DependentUpon>..\shared\Scenario8.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="..\..\..\SharedContent\xaml\App.xaml">
|
||||
|
@ -197,7 +200,12 @@
|
|||
<Page Include="..\shared\Scenario6.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="..\shared\Scenario7.xaml" />
|
||||
<Page Include="..\shared\Scenario7.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="..\shared\Scenario8.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest">
|
||||
|
@ -247,6 +255,9 @@
|
|||
<ClCompile Include="Scenario7.xaml.cpp">
|
||||
<DependentUpon>..\shared\Scenario7.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Scenario8.xaml.cpp">
|
||||
<DependentUpon>..\shared\Scenario8.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="..\..\..\SharedContent\media\microsoft-sdk.png">
|
||||
|
@ -270,6 +281,9 @@
|
|||
<Image Include="..\..\..\SharedContent\media\windows-sdk.png">
|
||||
<Link>Assets\windows-sdk.png</Link>
|
||||
</Image>
|
||||
<Image Include="..\..\..\SharedContent\media\Samples\LandscapeImage10.jpg">
|
||||
<Link>Assets\billboard.jpg</Link>
|
||||
</Image>
|
||||
<Image Include="..\shared\mappin.png">
|
||||
<Link>Assets\mappin.png</Link>
|
||||
</Image>
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
<ClCompile Include="Scenario4.xaml.cpp" />
|
||||
<ClCompile Include="Scenario5.xaml.cpp" />
|
||||
<ClCompile Include="Scenario6.xaml.cpp" />
|
||||
<ClCompile Include="Scenario7.xaml.cpp" />
|
||||
<ClCompile Include="Scenario8.xaml.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
|
@ -38,6 +40,8 @@
|
|||
<ClInclude Include="Scenario4.xaml.h" />
|
||||
<ClInclude Include="Scenario5.xaml.h" />
|
||||
<ClInclude Include="Scenario6.xaml.h" />
|
||||
<ClInclude Include="Scenario7.xaml.h" />
|
||||
<ClInclude Include="Scenario8.xaml.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest" />
|
||||
|
@ -54,6 +58,7 @@
|
|||
<Page Include="..\shared\Scenario5.xaml" />
|
||||
<Page Include="..\shared\Scenario6.xaml" />
|
||||
<Page Include="..\shared\Scenario7.xaml" />
|
||||
<Page Include="..\shared\Scenario8.xaml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="..\..\..\SharedContent\media\microsoft-sdk.png">
|
||||
|
@ -104,6 +109,9 @@
|
|||
<Image Include="..\shared\9.png">
|
||||
<Filter>Assets\Numbers</Filter>
|
||||
</Image>
|
||||
<Image Include="..\..\..\SharedContent\media\Samples\LandscapeImage10.jpg">
|
||||
<Filter>Assets</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="..\shared\places.txt" />
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
IgnorableNamespaces="uap mp">
|
||||
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
|
||||
IgnorableNamespaces="uap mp uap4">
|
||||
|
||||
<Identity
|
||||
Name="Microsoft.SDKSamples.MapControl.CPP"
|
||||
|
@ -20,7 +21,7 @@
|
|||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.10240.0" MaxVersionTested="10.0.14393.0" />
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.15052.0" MaxVersionTested="10.0.15052.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
@ -49,5 +50,6 @@
|
|||
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<uap4:Capability Name="offlineMapsManagement" />
|
||||
</Capabilities>
|
||||
</Package>
|
||||
|
|
|
@ -25,6 +25,7 @@ Platform::Array<Scenario>^ MainPage::scenariosInner = ref new Platform::Array<Sc
|
|||
{ "Showing Streetside experience within the MapControl", "SDKTemplate.Scenario5" },
|
||||
{ "Launching Maps using URI Schemes", "SDKTemplate.Scenario6" },
|
||||
{ "Displaying points of interest with clustering", "SDKTemplate.Scenario7" },
|
||||
{ "Find and download Offline Maps", "SDKTemplate.Scenario8" },
|
||||
};
|
||||
|
||||
Geopoint^ MainPage::SeattleGeopoint = ref new Geopoint({ 47.604, -122.329 });
|
|
@ -24,7 +24,9 @@ using namespace Windows::UI::Xaml::Controls::Maps;
|
|||
Scenario2::Scenario2()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
mapIconStreamReference = RandomAccessStreamReference::CreateFromUri(ref new Uri("ms-appx:///Assets/MapPin.png"));
|
||||
mapBillboardStreamReference = RandomAccessStreamReference::CreateFromUri(ref new Uri("ms-appx:///Assets/billboard.jpg"));
|
||||
}
|
||||
|
||||
void Scenario2::MyMap_Loaded(Object^ sender, RoutedEventArgs^ e)
|
||||
|
@ -44,6 +46,15 @@ void Scenario2::mapIconAddButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
myMap->MapElements->Append(mapIcon);
|
||||
}
|
||||
|
||||
void Scenario2::mapBillboardAddButton_Click(Object^ sender, RoutedEventArgs^ e)
|
||||
{
|
||||
MapBillboard^ mapBillboard = ref new MapBillboard(myMap->ActualCamera);
|
||||
mapBillboard->Location = myMap->Center;
|
||||
mapBillboard->NormalizedAnchorPoint = Point(0.5, 1.0);
|
||||
mapBillboard->Image = mapBillboardStreamReference;
|
||||
myMap->MapElements->Append(mapBillboard);
|
||||
}
|
||||
|
||||
void Scenario2::mapPolygonAddButton_Click(Object^ sender, RoutedEventArgs^ e)
|
||||
{
|
||||
double centerLatitude = myMap->Center->Position.Latitude;
|
||||
|
@ -55,7 +66,7 @@ void Scenario2::mapPolygonAddButton_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
list->Append({ centerLatitude - 0.0005, centerLongitude - 0.001 });
|
||||
list->Append({ centerLatitude - 0.0005, centerLongitude + 0.001 });
|
||||
list->Append({ centerLatitude + 0.0005, centerLongitude + 0.001 });
|
||||
|
||||
|
||||
mapPolygon->Path = ref new Geopath(list);
|
||||
mapPolygon->ZIndex = 1;
|
||||
mapPolygon->FillColor = Windows::UI::Colors::Red;
|
||||
|
|
|
@ -24,8 +24,10 @@ namespace SDKTemplate
|
|||
private:
|
||||
MainPage^ rootPage = MainPage::Current;
|
||||
Windows::Storage::Streams::RandomAccessStreamReference^ mapIconStreamReference;
|
||||
Windows::Storage::Streams::RandomAccessStreamReference^ mapBillboardStreamReference;
|
||||
void MyMap_Loaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void mapIconAddButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void mapBillboardAddButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void mapPolygonAddButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void mapPolylineAddButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
#include "pch.h"
|
||||
#include "Scenario8.xaml.h"
|
||||
|
||||
using namespace SDKTemplate;
|
||||
|
||||
using namespace Concurrency;
|
||||
using namespace Platform;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Services::Maps::OfflineMaps;
|
||||
using namespace Windows::UI::Core;
|
||||
using namespace Windows::UI::Xaml;
|
||||
using namespace Windows::UI::Xaml::Controls;
|
||||
using namespace Windows::UI::Xaml::Controls::Maps;
|
||||
|
||||
Scenario8::Scenario8()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
void Scenario8::myMap_Loaded(Object^ sender, RoutedEventArgs^ e)
|
||||
{
|
||||
myMap->Center = MainPage::SeattleGeopoint;
|
||||
myMap->ZoomLevel = 12;
|
||||
}
|
||||
|
||||
void Scenario8::findAtCenterButton_Click(Object^ sender, RoutedEventArgs^ e)
|
||||
{
|
||||
resultsGrid->Children->Clear();
|
||||
resultsGrid->RowDefinitions->Clear();
|
||||
resultStatusTextBlock->Text = "";
|
||||
|
||||
// finds all available Offline Map packages at the map center geopoint
|
||||
create_task(OfflineMapPackage::FindPackagesAsync(myMap->Center))
|
||||
.then([this](OfflineMapPackageQueryResult^ result)
|
||||
{
|
||||
if (result->Status != OfflineMapPackageQueryStatus::Success)
|
||||
{
|
||||
resultStatusTextBlock->Text = "Error: " + result->Status.ToString();
|
||||
}
|
||||
else if (result->Packages->Size == 0)
|
||||
{
|
||||
resultStatusTextBlock->Text = "No maps found";
|
||||
}
|
||||
else
|
||||
{
|
||||
for (OfflineMapPackage^ package : result->Packages)
|
||||
{
|
||||
addToResultGrid(package);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Scenario8::addToResultGrid(OfflineMapPackage^ package)
|
||||
{
|
||||
// a descriptive name for the package
|
||||
// ex: "Washington, USA (160 MB)"
|
||||
String^ descriptiveName =
|
||||
package->DisplayName + ", " +
|
||||
package->EnclosingRegionName +
|
||||
" (" + nearestMegabyte(package->EstimatedSizeInBytes) + " MB)";
|
||||
|
||||
// current download status (Downloaded, NotDownloaded, Downloading, etc)
|
||||
String^ downloadStatus = package->Status.ToString();
|
||||
|
||||
TextBlock^ packageNameTextBlock = ref new TextBlock();
|
||||
packageNameTextBlock->Text = descriptiveName;
|
||||
packageNameTextBlock->Margin = Thickness(5);
|
||||
packageNameTextBlock->VerticalAlignment = Windows::UI::Xaml::VerticalAlignment::Center;
|
||||
|
||||
TextBlock^ packageStatusTextBlock = ref new TextBlock();
|
||||
packageStatusTextBlock->Text = downloadStatus;
|
||||
packageStatusTextBlock->Margin = Thickness(5);
|
||||
packageStatusTextBlock->VerticalAlignment = Windows::UI::Xaml::VerticalAlignment::Center;
|
||||
|
||||
Button^ packageDownloadButton = ref new Button();
|
||||
packageDownloadButton->Content = "Download";
|
||||
packageDownloadButton->IsEnabled = canDownload(package);
|
||||
|
||||
// click event handler for Download button
|
||||
packageDownloadButton->Click += ref new RoutedEventHandler(
|
||||
[package, packageStatusTextBlock](Object^ sender, RoutedEventArgs^ args)
|
||||
{
|
||||
// queue up the package for download
|
||||
// requires offlineMapsManagement capability (see Package.appxmanifest)
|
||||
create_task(package->RequestStartDownloadAsync())
|
||||
.then([packageStatusTextBlock](OfflineMapPackageStartDownloadResult^ result)
|
||||
{
|
||||
// show any error
|
||||
if (result->Status != OfflineMapPackageStartDownloadStatus::Success)
|
||||
{
|
||||
packageStatusTextBlock->Text = result->Status.ToString();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// listen for package status changes
|
||||
package->StatusChanged += ref new TypedEventHandler<OfflineMapPackage ^, Platform::Object ^>(
|
||||
[package, packageStatusTextBlock, packageDownloadButton](OfflineMapPackage^ sender, Platform::Object^ args)
|
||||
{
|
||||
// event might not be on the UI thread, so marshal if we need to update UI
|
||||
packageStatusTextBlock->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler(
|
||||
[package, packageStatusTextBlock, packageDownloadButton]()
|
||||
{
|
||||
// update the UI (download status, download button enable/disable)
|
||||
packageStatusTextBlock->Text = package->Status.ToString();
|
||||
packageDownloadButton->IsEnabled = canDownload(package);
|
||||
}));
|
||||
});
|
||||
|
||||
Grid::SetRow(packageNameTextBlock, resultsGrid->RowDefinitions->Size);
|
||||
Grid::SetColumn(packageNameTextBlock, 0);
|
||||
|
||||
Grid::SetRow(packageStatusTextBlock, resultsGrid->RowDefinitions->Size);
|
||||
Grid::SetColumn(packageStatusTextBlock, 1);
|
||||
|
||||
Grid::SetRow(packageDownloadButton, resultsGrid->RowDefinitions->Size);
|
||||
Grid::SetColumn(packageDownloadButton, 2);
|
||||
|
||||
RowDefinition^ rowDef = ref new RowDefinition();
|
||||
rowDef->Height = GridLength::Auto;
|
||||
resultsGrid->RowDefinitions->Append(rowDef);
|
||||
|
||||
resultsGrid->Children->Append(packageNameTextBlock);
|
||||
resultsGrid->Children->Append(packageStatusTextBlock);
|
||||
resultsGrid->Children->Append(packageDownloadButton);
|
||||
}
|
||||
|
||||
unsigned long long Scenario8::nearestMegabyte(unsigned long long bytes)
|
||||
{
|
||||
return (unsigned long long)round(bytes / (1024.0 * 1024.0));
|
||||
}
|
||||
|
||||
bool Scenario8::canDownload(OfflineMapPackage^ package)
|
||||
{
|
||||
// we can start a download if the package isn't downloaded or it's currently being deleted
|
||||
return package->Status == OfflineMapPackageStatus::NotDownloaded || package->Status == OfflineMapPackageStatus::Deleting;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Scenario8.g.h"
|
||||
#include "MainPage.xaml.h"
|
||||
|
||||
namespace SDKTemplate
|
||||
{
|
||||
[Windows::Foundation::Metadata::WebHostHidden]
|
||||
public ref class Scenario8 sealed
|
||||
{
|
||||
public:
|
||||
Scenario8();
|
||||
private:
|
||||
MainPage^ rootPage = MainPage::Current;
|
||||
void myMap_Loaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void findAtCenterButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void addToResultGrid(Windows::Services::Maps::OfflineMaps::OfflineMapPackage^ package);
|
||||
static unsigned long long nearestMegabyte(unsigned long long bytes);
|
||||
static bool canDownload(Windows::Services::Maps::OfflineMaps::OfflineMapPackage^ package);
|
||||
};
|
||||
}
|
|
@ -11,8 +11,8 @@
|
|||
<AssemblyName>MapControlSample</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.14393.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||
<TargetPlatformVersion>10.0.15052.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.15042.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
|
@ -88,6 +88,9 @@
|
|||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="..\..\..\SharedContent\media\Samples\LandscapeImage10.jpg">
|
||||
<Link>Assets\billboard.jpg</Link>
|
||||
</Content>
|
||||
<Content Include="..\shared\places.txt">
|
||||
<Link>places.txt</Link>
|
||||
</Content>
|
||||
|
@ -127,6 +130,9 @@
|
|||
<Compile Include="Scenario7.xaml.cs">
|
||||
<DependentUpon>Scenario7.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Scenario8.xaml.cs">
|
||||
<DependentUpon>Scenario8.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest">
|
||||
|
@ -184,6 +190,11 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="..\shared\Scenario8.xaml">
|
||||
<Link>Scenario8.xaml</Link>
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="..\..\..\SharedContent\cs\Default.rd.xml">
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
IgnorableNamespaces="uap mp">
|
||||
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
|
||||
IgnorableNamespaces="uap mp uap4">
|
||||
|
||||
<Identity
|
||||
Name="Microsoft.SDKSamples.MapControlSample.CS"
|
||||
|
@ -21,7 +22,7 @@
|
|||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.10240.0" MaxVersionTested="10.0.14393.0" />
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.15052.0" MaxVersionTested="10.0.15052.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
@ -50,5 +51,6 @@
|
|||
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<uap4:Capability Name="offlineMapsManagement" />
|
||||
</Capabilities>
|
||||
</Package>
|
|
@ -28,7 +28,8 @@ namespace SDKTemplate
|
|||
new Scenario() { Title="Showing 3D locations in the MapControl", ClassType=typeof(Scenario4)},
|
||||
new Scenario() { Title="Showing Streetside experience within the MapControl", ClassType=typeof(Scenario5)},
|
||||
new Scenario() { Title= "Launching Maps using URI Schemes", ClassType=typeof(Scenario6)},
|
||||
new Scenario() { Title= "Displaying points of interest with clustering", ClassType=typeof(Scenario7)}
|
||||
new Scenario() { Title= "Displaying points of interest with clustering", ClassType=typeof(Scenario7)},
|
||||
new Scenario() { Title= "Find and download Offline Maps", ClassType=typeof(Scenario8)},
|
||||
};
|
||||
|
||||
public static readonly Geopoint SeattleGeopoint = new Geopoint(new BasicGeoposition() { Latitude = 47.604, Longitude = -122.329 });
|
||||
|
|
|
@ -13,6 +13,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using Windows.Devices.Geolocation;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Metadata;
|
||||
using Windows.Storage.Streams;
|
||||
using Windows.UI;
|
||||
using Windows.UI.Xaml;
|
||||
|
@ -25,10 +26,14 @@ namespace SDKTemplate
|
|||
public sealed partial class Scenario2 : Page
|
||||
{
|
||||
RandomAccessStreamReference mapIconStreamReference;
|
||||
RandomAccessStreamReference mapBillboardStreamReference;
|
||||
|
||||
public Scenario2()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
mapIconStreamReference = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/MapPin.png"));
|
||||
mapBillboardStreamReference = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/billboard.jpg"));
|
||||
}
|
||||
|
||||
private void MyMap_Loaded(object sender, RoutedEventArgs e)
|
||||
|
@ -48,6 +53,20 @@ namespace SDKTemplate
|
|||
myMap.MapElements.Add(mapIcon1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method will create a new billboard at the center of the map with the current camera as reference
|
||||
/// </summary>
|
||||
private void mapBillboardAddButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
// MapBillboard scales with respect to the perspective projection of the 3D camera.
|
||||
// The reference camera determines at what view distance the billboard image appears at 1x scale.
|
||||
MapBillboard mapBillboard = new MapBillboard(myMap.ActualCamera);
|
||||
mapBillboard.Location = myMap.Center;
|
||||
mapBillboard.NormalizedAnchorPoint = new Point(0.5, 1.0);
|
||||
mapBillboard.Image = mapBillboardStreamReference;
|
||||
myMap.MapElements.Add(mapBillboard);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method will draw a blue rectangle around the center of the map
|
||||
/// </summary>
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
using System;
|
||||
using Windows.Foundation.Metadata;
|
||||
using Windows.Services.Maps.OfflineMaps;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace SDKTemplate
|
||||
{
|
||||
public sealed partial class Scenario8 : Page
|
||||
{
|
||||
public Scenario8()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void myMap_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
myMap.Center = MainPage.SeattleGeopoint;
|
||||
myMap.ZoomLevel = 12;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method finds all available Offline Map packages at the map center geopoint
|
||||
/// </summary>
|
||||
private async void findAtCenterButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
resultsGrid.Children.Clear();
|
||||
resultsGrid.RowDefinitions.Clear();
|
||||
resultStatusTextBlock.Text = "";
|
||||
|
||||
OfflineMapPackageQueryResult result = await OfflineMapPackage.FindPackagesAsync(myMap.Center);
|
||||
|
||||
if (result.Status != OfflineMapPackageQueryStatus.Success)
|
||||
{
|
||||
resultStatusTextBlock.Text = "Error: " + result.Status;
|
||||
}
|
||||
else if (result.Packages.Count == 0)
|
||||
{
|
||||
resultStatusTextBlock.Text = "No maps found";
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (OfflineMapPackage package in result.Packages)
|
||||
{
|
||||
addToResultGrid(package);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addToResultGrid(OfflineMapPackage package)
|
||||
{
|
||||
// a descriptive name for the package
|
||||
// ex: "Washington, USA (160 MB)"
|
||||
string descriptiveName = package.DisplayName + ", " + package.EnclosingRegionName + " (" + nearestMegabyte(package.EstimatedSizeInBytes) + " MB)";
|
||||
|
||||
// current download status (Downloaded, NotDownloaded, Downloading, etc)
|
||||
string downloadStatus = package.Status.ToString();
|
||||
|
||||
TextBlock packageNameTextBlock = new TextBlock()
|
||||
{
|
||||
Text = descriptiveName,
|
||||
Margin = new Thickness(5),
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
};
|
||||
|
||||
TextBlock packageStatusTextBlock = new TextBlock()
|
||||
{
|
||||
Text = downloadStatus,
|
||||
Margin = new Thickness(5),
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
};
|
||||
|
||||
Button packageDownloadButton = new Button()
|
||||
{
|
||||
Content = "Download",
|
||||
IsEnabled = canDownload(package),
|
||||
};
|
||||
|
||||
// event handler for Download button
|
||||
packageDownloadButton.Click += async (sender, e) =>
|
||||
{
|
||||
// queue up the package for download
|
||||
// requires offlineMapsManagement capability (see Package.appxmanifest)
|
||||
OfflineMapPackageStartDownloadResult result = await package.RequestStartDownloadAsync();
|
||||
|
||||
// show any error
|
||||
if (result.Status != OfflineMapPackageStartDownloadStatus.Success)
|
||||
{
|
||||
packageStatusTextBlock.Text = result.Status.ToString();
|
||||
}
|
||||
};
|
||||
|
||||
// listen for package status changes and update the UI (download status, download button enable/disable)
|
||||
package.StatusChanged += async (sender, args) =>
|
||||
{
|
||||
// event might not be on the UI thread, so marshal if we need to update UI
|
||||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
packageStatusTextBlock.Text = package.Status.ToString();
|
||||
packageDownloadButton.IsEnabled = canDownload(package);
|
||||
});
|
||||
};
|
||||
|
||||
Grid.SetRow(packageNameTextBlock, resultsGrid.RowDefinitions.Count);
|
||||
Grid.SetColumn(packageNameTextBlock, 0);
|
||||
|
||||
Grid.SetRow(packageStatusTextBlock, resultsGrid.RowDefinitions.Count);
|
||||
Grid.SetColumn(packageStatusTextBlock, 1);
|
||||
|
||||
Grid.SetRow(packageDownloadButton, resultsGrid.RowDefinitions.Count);
|
||||
Grid.SetColumn(packageDownloadButton, 2);
|
||||
|
||||
resultsGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
|
||||
|
||||
resultsGrid.Children.Add(packageNameTextBlock);
|
||||
resultsGrid.Children.Add(packageStatusTextBlock);
|
||||
resultsGrid.Children.Add(packageDownloadButton);
|
||||
}
|
||||
|
||||
private static long nearestMegabyte(ulong bytes)
|
||||
{
|
||||
return (long)Math.Round(bytes / (1024.0 * 1024.0));
|
||||
}
|
||||
|
||||
private static bool canDownload(OfflineMapPackage package)
|
||||
{
|
||||
// we can start a download if the package isn't downloaded or it's currently being deleted
|
||||
return package.Status == OfflineMapPackageStatus.NotDownloaded || package.Status == OfflineMapPackageStatus.Deleting;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
<StackPanel Grid.Row="1">
|
||||
<Button Content="Add MapIcon to center of Map" x:Name="mapIconAddButton" Click="mapIconAddButton_Click"/>
|
||||
<Button Content="Add MapBillboard to center of Map" x:Name="mapBillboardAddButton" Click="mapBillboardAddButton_Click"/>
|
||||
<Button Content="Add MapPolygon to center of Map" x:Name="mapPolygonAddButton" Click="mapPolygonAddButton_Click"/>
|
||||
<Button Content="Add MapPolyline to center of Map" x:Name="mapPolylineAddButton" Click="mapPolylineAddButton_Click"/>
|
||||
</StackPanel>
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<!--
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
-->
|
||||
<Page
|
||||
x:Class="SDKTemplate.Scenario8"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:maps="using:Windows.UI.Xaml.Controls.Maps"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Padding="12,10,12,12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="100"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Margin="0,0,0,10">
|
||||
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
|
||||
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
|
||||
Find and download Offline Maps
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="1">
|
||||
<Button Content="Find available Offline Maps at center of map" x:Name="findAtCenterButton" Click="findAtCenterButton_Click"/>
|
||||
<TextBlock x:Name="resultStatusTextBlock" />
|
||||
</StackPanel>
|
||||
<ScrollViewer Grid.Row="2">
|
||||
<Grid x:Name="resultsGrid" Width="400" HorizontalAlignment="Left">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- Find results will be populated here -->
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
<maps:MapControl x:Name="myMap" Loaded="myMap_Loaded" Grid.Row="3"/>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -34,6 +34,10 @@ Scenario 2: Capture image from camera and extract text.
|
|||
|
||||
## Related topics
|
||||
|
||||
**Samples**
|
||||
|
||||
[InkAnalysis](/Samples/InkAnalysis)
|
||||
|
||||
**Reference**
|
||||
|
||||
[Windows.Media.Ocr namespace](https://msdn.microsoft.com/library/windows/apps/windows.media.ocr.aspx)
|
||||
|
|
Загрузка…
Ссылка в новой задаче