diff --git a/.gitignore b/.gitignore index 3e759b7..bd9db1b 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,9 @@ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ +*.dir/ +player/sample/shaders/ +remote/uwp/src/ # Visual Studio 2015/2017 cache/options directory .vs/ diff --git a/hostsampleapp/desktop/Common/CameraResources.cpp b/hostsampleapp/desktop/Common/CameraResources.cpp deleted file mode 100644 index eb3255b..0000000 --- a/hostsampleapp/desktop/Common/CameraResources.cpp +++ /dev/null @@ -1,251 +0,0 @@ -//********************************************************* -// -// 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 "CameraResources.h" -#include "DeviceResources.h" -#include "DirectXHelper.h" - -#include - -using namespace DirectX; -using namespace winrt::Windows::Graphics::Holographic; -using namespace winrt::Windows::Perception::Spatial; - -DXHelper::CameraResources::CameraResources(const 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 DXHelper::CameraResources::CreateResourcesForBackBuffer( - DXHelper::DeviceResources* pDeviceResources, const HolographicCameraRenderingParameters& cameraParameters) -{ - const auto device = pDeviceResources->GetD3DDevice(); - - // 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. - winrt::com_ptr resource; - { - winrt::com_ptr<::IInspectable> inspectable = cameraParameters.Direct3D11BackBuffer().as<::IInspectable>(); - winrt::com_ptr dxgiInterfaceAccess; - - HRESULT hr = inspectable->QueryInterface(__uuidof(dxgiInterfaceAccess), dxgiInterfaceAccess.put_void()); - if (FAILED(hr)) - { - winrt::throw_hresult(hr); - } - - hr = dxgiInterfaceAccess->GetInterface(__uuidof(resource), resource.put_void()); - if (FAILED(hr)) - { - winrt::throw_hresult(hr); - } - } - - // Get a Direct3D interface for the holographic camera's back buffer. - winrt::com_ptr cameraBackBuffer; - 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 != cameraBackBuffer) - { - // 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; - - // 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; - - D3D11_RENDER_TARGET_VIEW_DESC viewDesc = {}; - viewDesc.ViewDimension = backBufferDesc.ArraySize > 1 ? D3D11_RTV_DIMENSION_TEXTURE2DARRAY : D3D11_RTV_DIMENSION_TEXTURE2D; - viewDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; - if (backBufferDesc.ArraySize > 1) - { - viewDesc.Texture2DArray.ArraySize = backBufferDesc.ArraySize; - } - - // 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. - m_d3dRenderTargetView = nullptr; - winrt::check_hresult(device->CreateRenderTargetView(m_d3dBackBuffer.get(), &viewDesc, m_d3dRenderTargetView.put())); - - // Check for render target size changes. - winrt::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 = nullptr; - } - } - - // 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(m_d3dRenderTargetSize.Width), - static_cast(m_d3dRenderTargetSize.Height), - m_isStereo ? 2 : 1, // Create two textures when rendering in stereo. - 1, // Use a single mipmap level. - D3D11_BIND_DEPTH_STENCIL); - - winrt::com_ptr depthStencil; - winrt::check_hresult(device->CreateTexture2D(&depthStencilDesc, nullptr, depthStencil.put())); - - CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc( - m_isStereo ? D3D11_DSV_DIMENSION_TEXTURE2DARRAY : D3D11_DSV_DIMENSION_TEXTURE2D); - - winrt::check_hresult(device->CreateDepthStencilView(depthStencil.get(), &depthStencilViewDesc, m_d3dDepthStencilView.put())); - } - - // 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); - winrt::check_hresult(device->CreateBuffer(&constantBufferDesc, nullptr, m_viewProjectionConstantBuffer.put())); - } -} - -// Releases resources associated with a back buffer. -void DXHelper::CameraResources::ReleaseResourcesForBackBuffer(DXHelper::DeviceResources* pDeviceResources) -{ - // Release camera-specific resources. - m_d3dBackBuffer = nullptr; - m_d3dRenderTargetView = nullptr; - m_d3dDepthStencilView = nullptr; - m_viewProjectionConstantBuffer = nullptr; - - // 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. - pDeviceResources->UseD3DDeviceContext([](auto 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 DXHelper::CameraResources::UpdateViewProjectionBuffer( - std::shared_ptr deviceResources, - const HolographicCameraPose& cameraPose, - const SpatialCoordinateSystem& coordinateSystem) -{ - // The system changes the viewport on a per-frame basis for system optimizations. - m_d3dViewport = - CD3D11_VIEWPORT(cameraPose.Viewport().X, cameraPose.Viewport().Y, cameraPose.Viewport().Width, cameraPose.Viewport().Height); - - // The projection transform for each frame is provided by the HolographicCameraPose. - auto cameraProjectionTransform = cameraPose.ProjectionTransform(); - - // Get a container object with the view and projection matrices for the given - // pose in the given coordinate system. - auto 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. - DXHelper::ViewProjectionConstantBuffer viewProjectionConstantBufferData = {}; - bool viewTransformAcquired = viewTransformContainer != nullptr; - if (viewTransformAcquired) - { - // Otherwise, the set of view transforms can be retrieved. - auto 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. - deviceResources->UseD3DDeviceContext([&](auto context) { - // 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 DXHelper::CameraResources::AttachViewProjectionBuffer(std::shared_ptr deviceResources) -{ - // This method uses Direct3D device-based resources. - return deviceResources->UseD3DDeviceContext([&](auto context) { - // 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. - ID3D11Buffer* pBuffer = m_viewProjectionConstantBuffer.get(); - context->VSSetConstantBuffers(1, 1, &pBuffer); - - // 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; - }); -} diff --git a/hostsampleapp/desktop/HolographicHostSample.sln b/hostsampleapp/desktop/HolographicHostSample.sln deleted file mode 100644 index ccf9a4f..0000000 --- a/hostsampleapp/desktop/HolographicHostSample.sln +++ /dev/null @@ -1,32 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.645 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HolographicHostSample", "HolographicHostSample.vcxproj", "{59F48F16-7CF3-36AB-AE6D-B56A9DA89747}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 - RelWithDebInfo|x64 = RelWithDebInfo|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {59F48F16-7CF3-36AB-AE6D-B56A9DA89747}.Debug|x64.ActiveCfg = Debug|x64 - {59F48F16-7CF3-36AB-AE6D-B56A9DA89747}.Debug|x64.Build.0 = Debug|x64 - {59F48F16-7CF3-36AB-AE6D-B56A9DA89747}.Debug|x64.Deploy.0 = Debug|x64 - {59F48F16-7CF3-36AB-AE6D-B56A9DA89747}.Release|x64.ActiveCfg = Release|x64 - {59F48F16-7CF3-36AB-AE6D-B56A9DA89747}.Release|x64.Build.0 = Release|x64 - {59F48F16-7CF3-36AB-AE6D-B56A9DA89747}.Release|x64.Deploy.0 = Release|x64 - {59F48F16-7CF3-36AB-AE6D-B56A9DA89747}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {59F48F16-7CF3-36AB-AE6D-B56A9DA89747}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {59F48F16-7CF3-36AB-AE6D-B56A9DA89747}.RelWithDebInfo|x64.Deploy.0 = RelWithDebInfo|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {E8A3A1EC-E636-40D6-9E3D-C22347CC8162} - EndGlobalSection -EndGlobal - diff --git a/hostsampleapp/desktop/Package.appxmanifest b/hostsampleapp/desktop/Package.appxmanifest deleted file mode 100644 index 2f1f652..0000000 --- a/hostsampleapp/desktop/Package.appxmanifest +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - RemotingHostSample - Microsoft Corporation - Assets\StoreLogo.png - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hostsampleapp/desktop/SampleHostWindowWin32.cpp b/hostsampleapp/desktop/SampleHostWindowWin32.cpp deleted file mode 100644 index c9ffd7e..0000000 --- a/hostsampleapp/desktop/SampleHostWindowWin32.cpp +++ /dev/null @@ -1,242 +0,0 @@ -//********************************************************* -// -// 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 "SampleHostWindowWin32.h" - -#include - -#include "Common\DbgLog.h" -#include - -#include - -#define WINDOWCLASSNAME L"SampleHostWindowWin32Class" - -LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - static SampleHostWindowWin32* s_sampleHostWindow; - - LRESULT result = 0; - - switch (msg) - { - case WM_CREATE: { - CREATESTRUCT* cs = reinterpret_cast(lParam); - s_sampleHostWindow = reinterpret_cast(cs->lpCreateParams); - - RECT clientRect; - GetClientRect(hWnd, &clientRect); - - s_sampleHostWindow->OnResize(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top); - result = 0; - } - break; - case WM_WINDOWPOSCHANGED: { - auto windowPos = reinterpret_cast(lParam); - if ((windowPos->flags & SWP_NOSIZE) == 0) - { - RECT clientRect; - GetClientRect(hWnd, &clientRect); - - s_sampleHostWindow->OnResize(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top); - } - result = 0; - } - break; - case WM_DESTROY: { - s_sampleHostWindow = nullptr; - result = 0; - PostQuitMessage(0); - } - break; - case WM_CLOSE: { - DestroyWindow(hWnd); - result = 0; - } - break; - case WM_CHAR: { - const int key = tolower(static_cast(wParam)); - s_sampleHostWindow->OnKeyPress(static_cast(key)); - } - break; - default: - result = DefWindowProc(hWnd, msg, wParam, lParam); - break; - } - - return result; -} - -void SampleHostWindowWin32::Initialize(bool listen, const std::wstring& hostname, uint32_t port) -{ - m_main = std::make_shared(weak_from_this()); - m_main->SetHostOptions(listen, hostname, port); -} - -void SampleHostWindowWin32::InitializeHwnd(HWND hWnd) -{ - m_hWnd = hWnd; -} - -void SampleHostWindowWin32::Tick() -{ - if (const HolographicFrame& holographicFrame = m_main->Update()) - { - m_main->Render(holographicFrame); - } -} - -void SampleHostWindowWin32::OnKeyPress(char key) -{ - m_main->OnKeyPress(key); -} - - -void SampleHostWindowWin32::OnResize(int width, int height) -{ - m_main->OnResize(width, height); -} - -winrt::com_ptr - SampleHostWindowWin32::CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) -{ - winrt::com_ptr dxgiDevice; - device.as(dxgiDevice); - - winrt::com_ptr dxgiAdapter; - winrt::check_hresult(dxgiDevice->GetAdapter(dxgiAdapter.put())); - - winrt::com_ptr dxgiFactory; - winrt::check_hresult(dxgiAdapter->GetParent(__uuidof(IDXGIFactory2), dxgiFactory.put_void())); - - winrt::check_hresult(dxgiFactory->MakeWindowAssociation(m_hWnd, DXGI_MWA_NO_ALT_ENTER)); - - winrt::com_ptr swapChain = nullptr; - winrt::check_hresult(dxgiFactory->CreateSwapChainForHwnd(device.get(), m_hWnd, desc, nullptr, nullptr, swapChain.put())); - - return swapChain; -} - -void SampleHostWindowWin32::SetWindowTitle(std::wstring title) -{ - if (m_hWnd) - { - if (!SetWindowTextW(m_hWnd, title.c_str())) - { - winrt::check_hresult(HRESULT_FROM_WIN32(GetLastError())); - } - } -} - -int main(Platform::Array ^ args) -{ - winrt::init_apartment(); - - bool listen{false}; - std::wstring host; - uint32_t port{0}; - - for (unsigned int i = 1; i < args->Length; ++i) - { - if (args[i]->Length() == 0) - continue; - - std::wstring arg = args[i]->Data(); - if (arg[0] == '-') - { - std::wstring param = arg.substr(1); - std::transform(param.begin(), param.end(), param.begin(), ::tolower); - - if (param == L"listen") - { - listen = true; - } - - continue; - } - - size_t colonPos = arg.find(L':'); - if (colonPos != std::wstring::npos) - { - std::wstring portStr = arg.substr(colonPos + 1); - - host = arg.substr(0, colonPos); - port = std::wcstol(portStr.c_str(), nullptr, 10); - } - else - { - host = arg.c_str(); - port = 0; - } - } - - std::shared_ptr sampleHostWindow = std::make_shared(); - sampleHostWindow->Initialize(listen, host, port); - - WNDCLASSEXW wcex = {}; - wcex.cbSize = sizeof(wcex); - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = wndProc; - wcex.hInstance = 0; - wcex.hIcon = LoadIcon(0, IDI_APPLICATION); - wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); - wcex.hbrBackground = static_cast(GetStockObject(NULL_BRUSH)); - wcex.lpszClassName = WINDOWCLASSNAME; - RegisterClassExW(&wcex); - - RECT rc = {0, 0, INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT}; - AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW, FALSE, 0); - - std::wstring windowName = TITLE_TEXT; - - HWND hWnd = CreateWindowW( - WINDOWCLASSNAME, - windowName.c_str(), - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, - CW_USEDEFAULT, - rc.right - rc.left, - rc.bottom - rc.top, - nullptr, - nullptr, - 0, - sampleHostWindow.get()); - - RECT clientRect; - GetClientRect(hWnd, &clientRect); - - sampleHostWindow->InitializeHwnd(hWnd); - - ShowWindow(hWnd, SW_SHOWNORMAL); - bool quit = false; - while (!quit) - { - MSG msg = {0}; - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - { - quit = true; - } - - TranslateMessage(&msg); - DispatchMessage(&msg); - } - else - { - sampleHostWindow->Tick(); - } - } - - return 0; -} diff --git a/hostsampleapp/desktop/packages.config b/hostsampleapp/desktop/packages.config deleted file mode 100644 index 7e842e8..0000000 --- a/hostsampleapp/desktop/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/hostsampleapp/uwp/Assets/LockScreenLogo.scale-200.png b/hostsampleapp/uwp/Assets/LockScreenLogo.scale-200.png deleted file mode 100644 index 735f57a..0000000 Binary files a/hostsampleapp/uwp/Assets/LockScreenLogo.scale-200.png and /dev/null differ diff --git a/hostsampleapp/uwp/Assets/SplashScreen.scale-200.png b/hostsampleapp/uwp/Assets/SplashScreen.scale-200.png deleted file mode 100644 index 023e7f1..0000000 Binary files a/hostsampleapp/uwp/Assets/SplashScreen.scale-200.png and /dev/null differ diff --git a/hostsampleapp/uwp/Assets/Square150x150Logo.scale-200.png b/hostsampleapp/uwp/Assets/Square150x150Logo.scale-200.png deleted file mode 100644 index af49fec..0000000 Binary files a/hostsampleapp/uwp/Assets/Square150x150Logo.scale-200.png and /dev/null differ diff --git a/hostsampleapp/uwp/Assets/Square44x44Logo.scale-200.png b/hostsampleapp/uwp/Assets/Square44x44Logo.scale-200.png deleted file mode 100644 index ce342a2..0000000 Binary files a/hostsampleapp/uwp/Assets/Square44x44Logo.scale-200.png and /dev/null differ diff --git a/hostsampleapp/uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/hostsampleapp/uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png deleted file mode 100644 index f6c02ce..0000000 Binary files a/hostsampleapp/uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png and /dev/null differ diff --git a/hostsampleapp/uwp/Assets/StoreLogo.png b/hostsampleapp/uwp/Assets/StoreLogo.png deleted file mode 100644 index 7385b56..0000000 Binary files a/hostsampleapp/uwp/Assets/StoreLogo.png and /dev/null differ diff --git a/hostsampleapp/uwp/Assets/Wide310x150Logo.scale-200.png b/hostsampleapp/uwp/Assets/Wide310x150Logo.scale-200.png deleted file mode 100644 index 288995b..0000000 Binary files a/hostsampleapp/uwp/Assets/Wide310x150Logo.scale-200.png and /dev/null differ diff --git a/hostsampleapp/uwp/Common/CameraResources.cpp b/hostsampleapp/uwp/Common/CameraResources.cpp deleted file mode 100644 index eb3255b..0000000 --- a/hostsampleapp/uwp/Common/CameraResources.cpp +++ /dev/null @@ -1,251 +0,0 @@ -//********************************************************* -// -// 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 "CameraResources.h" -#include "DeviceResources.h" -#include "DirectXHelper.h" - -#include - -using namespace DirectX; -using namespace winrt::Windows::Graphics::Holographic; -using namespace winrt::Windows::Perception::Spatial; - -DXHelper::CameraResources::CameraResources(const 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 DXHelper::CameraResources::CreateResourcesForBackBuffer( - DXHelper::DeviceResources* pDeviceResources, const HolographicCameraRenderingParameters& cameraParameters) -{ - const auto device = pDeviceResources->GetD3DDevice(); - - // 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. - winrt::com_ptr resource; - { - winrt::com_ptr<::IInspectable> inspectable = cameraParameters.Direct3D11BackBuffer().as<::IInspectable>(); - winrt::com_ptr dxgiInterfaceAccess; - - HRESULT hr = inspectable->QueryInterface(__uuidof(dxgiInterfaceAccess), dxgiInterfaceAccess.put_void()); - if (FAILED(hr)) - { - winrt::throw_hresult(hr); - } - - hr = dxgiInterfaceAccess->GetInterface(__uuidof(resource), resource.put_void()); - if (FAILED(hr)) - { - winrt::throw_hresult(hr); - } - } - - // Get a Direct3D interface for the holographic camera's back buffer. - winrt::com_ptr cameraBackBuffer; - 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 != cameraBackBuffer) - { - // 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; - - // 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; - - D3D11_RENDER_TARGET_VIEW_DESC viewDesc = {}; - viewDesc.ViewDimension = backBufferDesc.ArraySize > 1 ? D3D11_RTV_DIMENSION_TEXTURE2DARRAY : D3D11_RTV_DIMENSION_TEXTURE2D; - viewDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; - if (backBufferDesc.ArraySize > 1) - { - viewDesc.Texture2DArray.ArraySize = backBufferDesc.ArraySize; - } - - // 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. - m_d3dRenderTargetView = nullptr; - winrt::check_hresult(device->CreateRenderTargetView(m_d3dBackBuffer.get(), &viewDesc, m_d3dRenderTargetView.put())); - - // Check for render target size changes. - winrt::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 = nullptr; - } - } - - // 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(m_d3dRenderTargetSize.Width), - static_cast(m_d3dRenderTargetSize.Height), - m_isStereo ? 2 : 1, // Create two textures when rendering in stereo. - 1, // Use a single mipmap level. - D3D11_BIND_DEPTH_STENCIL); - - winrt::com_ptr depthStencil; - winrt::check_hresult(device->CreateTexture2D(&depthStencilDesc, nullptr, depthStencil.put())); - - CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc( - m_isStereo ? D3D11_DSV_DIMENSION_TEXTURE2DARRAY : D3D11_DSV_DIMENSION_TEXTURE2D); - - winrt::check_hresult(device->CreateDepthStencilView(depthStencil.get(), &depthStencilViewDesc, m_d3dDepthStencilView.put())); - } - - // 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); - winrt::check_hresult(device->CreateBuffer(&constantBufferDesc, nullptr, m_viewProjectionConstantBuffer.put())); - } -} - -// Releases resources associated with a back buffer. -void DXHelper::CameraResources::ReleaseResourcesForBackBuffer(DXHelper::DeviceResources* pDeviceResources) -{ - // Release camera-specific resources. - m_d3dBackBuffer = nullptr; - m_d3dRenderTargetView = nullptr; - m_d3dDepthStencilView = nullptr; - m_viewProjectionConstantBuffer = nullptr; - - // 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. - pDeviceResources->UseD3DDeviceContext([](auto 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 DXHelper::CameraResources::UpdateViewProjectionBuffer( - std::shared_ptr deviceResources, - const HolographicCameraPose& cameraPose, - const SpatialCoordinateSystem& coordinateSystem) -{ - // The system changes the viewport on a per-frame basis for system optimizations. - m_d3dViewport = - CD3D11_VIEWPORT(cameraPose.Viewport().X, cameraPose.Viewport().Y, cameraPose.Viewport().Width, cameraPose.Viewport().Height); - - // The projection transform for each frame is provided by the HolographicCameraPose. - auto cameraProjectionTransform = cameraPose.ProjectionTransform(); - - // Get a container object with the view and projection matrices for the given - // pose in the given coordinate system. - auto 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. - DXHelper::ViewProjectionConstantBuffer viewProjectionConstantBufferData = {}; - bool viewTransformAcquired = viewTransformContainer != nullptr; - if (viewTransformAcquired) - { - // Otherwise, the set of view transforms can be retrieved. - auto 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. - deviceResources->UseD3DDeviceContext([&](auto context) { - // 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 DXHelper::CameraResources::AttachViewProjectionBuffer(std::shared_ptr deviceResources) -{ - // This method uses Direct3D device-based resources. - return deviceResources->UseD3DDeviceContext([&](auto context) { - // 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. - ID3D11Buffer* pBuffer = m_viewProjectionConstantBuffer.get(); - context->VSSetConstantBuffers(1, 1, &pBuffer); - - // 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; - }); -} diff --git a/hostsampleapp/uwp/HolographicHostSample.sln b/hostsampleapp/uwp/HolographicHostSample.sln deleted file mode 100644 index f299014..0000000 --- a/hostsampleapp/uwp/HolographicHostSample.sln +++ /dev/null @@ -1,32 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.645 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HolographicHostSample", "HolographicHostSample.vcxproj", "{8933B2A2-C780-3CC9-8B26-0CCB3E806E54}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 - RelWithDebInfo|x64 = RelWithDebInfo|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8933B2A2-C780-3CC9-8B26-0CCB3E806E54}.Debug|x64.ActiveCfg = Debug|x64 - {8933B2A2-C780-3CC9-8B26-0CCB3E806E54}.Debug|x64.Build.0 = Debug|x64 - {8933B2A2-C780-3CC9-8B26-0CCB3E806E54}.Debug|x64.Deploy.0 = Debug|x64 - {8933B2A2-C780-3CC9-8B26-0CCB3E806E54}.Release|x64.ActiveCfg = Release|x64 - {8933B2A2-C780-3CC9-8B26-0CCB3E806E54}.Release|x64.Build.0 = Release|x64 - {8933B2A2-C780-3CC9-8B26-0CCB3E806E54}.Release|x64.Deploy.0 = Release|x64 - {8933B2A2-C780-3CC9-8B26-0CCB3E806E54}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {8933B2A2-C780-3CC9-8B26-0CCB3E806E54}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {8933B2A2-C780-3CC9-8B26-0CCB3E806E54}.RelWithDebInfo|x64.Deploy.0 = RelWithDebInfo|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {E8A3A1EC-E636-40D6-9E3D-C22347CC8162} - EndGlobalSection -EndGlobal - diff --git a/hostsampleapp/uwp/Package.appxmanifest b/hostsampleapp/uwp/Package.appxmanifest deleted file mode 100644 index 2f1f652..0000000 --- a/hostsampleapp/uwp/Package.appxmanifest +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - RemotingHostSample - Microsoft Corporation - Assets\StoreLogo.png - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/hostsampleapp/uwp/SampleHostWindowWin32.cpp b/hostsampleapp/uwp/SampleHostWindowWin32.cpp deleted file mode 100644 index c9ffd7e..0000000 --- a/hostsampleapp/uwp/SampleHostWindowWin32.cpp +++ /dev/null @@ -1,242 +0,0 @@ -//********************************************************* -// -// 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 "SampleHostWindowWin32.h" - -#include - -#include "Common\DbgLog.h" -#include - -#include - -#define WINDOWCLASSNAME L"SampleHostWindowWin32Class" - -LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - static SampleHostWindowWin32* s_sampleHostWindow; - - LRESULT result = 0; - - switch (msg) - { - case WM_CREATE: { - CREATESTRUCT* cs = reinterpret_cast(lParam); - s_sampleHostWindow = reinterpret_cast(cs->lpCreateParams); - - RECT clientRect; - GetClientRect(hWnd, &clientRect); - - s_sampleHostWindow->OnResize(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top); - result = 0; - } - break; - case WM_WINDOWPOSCHANGED: { - auto windowPos = reinterpret_cast(lParam); - if ((windowPos->flags & SWP_NOSIZE) == 0) - { - RECT clientRect; - GetClientRect(hWnd, &clientRect); - - s_sampleHostWindow->OnResize(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top); - } - result = 0; - } - break; - case WM_DESTROY: { - s_sampleHostWindow = nullptr; - result = 0; - PostQuitMessage(0); - } - break; - case WM_CLOSE: { - DestroyWindow(hWnd); - result = 0; - } - break; - case WM_CHAR: { - const int key = tolower(static_cast(wParam)); - s_sampleHostWindow->OnKeyPress(static_cast(key)); - } - break; - default: - result = DefWindowProc(hWnd, msg, wParam, lParam); - break; - } - - return result; -} - -void SampleHostWindowWin32::Initialize(bool listen, const std::wstring& hostname, uint32_t port) -{ - m_main = std::make_shared(weak_from_this()); - m_main->SetHostOptions(listen, hostname, port); -} - -void SampleHostWindowWin32::InitializeHwnd(HWND hWnd) -{ - m_hWnd = hWnd; -} - -void SampleHostWindowWin32::Tick() -{ - if (const HolographicFrame& holographicFrame = m_main->Update()) - { - m_main->Render(holographicFrame); - } -} - -void SampleHostWindowWin32::OnKeyPress(char key) -{ - m_main->OnKeyPress(key); -} - - -void SampleHostWindowWin32::OnResize(int width, int height) -{ - m_main->OnResize(width, height); -} - -winrt::com_ptr - SampleHostWindowWin32::CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) -{ - winrt::com_ptr dxgiDevice; - device.as(dxgiDevice); - - winrt::com_ptr dxgiAdapter; - winrt::check_hresult(dxgiDevice->GetAdapter(dxgiAdapter.put())); - - winrt::com_ptr dxgiFactory; - winrt::check_hresult(dxgiAdapter->GetParent(__uuidof(IDXGIFactory2), dxgiFactory.put_void())); - - winrt::check_hresult(dxgiFactory->MakeWindowAssociation(m_hWnd, DXGI_MWA_NO_ALT_ENTER)); - - winrt::com_ptr swapChain = nullptr; - winrt::check_hresult(dxgiFactory->CreateSwapChainForHwnd(device.get(), m_hWnd, desc, nullptr, nullptr, swapChain.put())); - - return swapChain; -} - -void SampleHostWindowWin32::SetWindowTitle(std::wstring title) -{ - if (m_hWnd) - { - if (!SetWindowTextW(m_hWnd, title.c_str())) - { - winrt::check_hresult(HRESULT_FROM_WIN32(GetLastError())); - } - } -} - -int main(Platform::Array ^ args) -{ - winrt::init_apartment(); - - bool listen{false}; - std::wstring host; - uint32_t port{0}; - - for (unsigned int i = 1; i < args->Length; ++i) - { - if (args[i]->Length() == 0) - continue; - - std::wstring arg = args[i]->Data(); - if (arg[0] == '-') - { - std::wstring param = arg.substr(1); - std::transform(param.begin(), param.end(), param.begin(), ::tolower); - - if (param == L"listen") - { - listen = true; - } - - continue; - } - - size_t colonPos = arg.find(L':'); - if (colonPos != std::wstring::npos) - { - std::wstring portStr = arg.substr(colonPos + 1); - - host = arg.substr(0, colonPos); - port = std::wcstol(portStr.c_str(), nullptr, 10); - } - else - { - host = arg.c_str(); - port = 0; - } - } - - std::shared_ptr sampleHostWindow = std::make_shared(); - sampleHostWindow->Initialize(listen, host, port); - - WNDCLASSEXW wcex = {}; - wcex.cbSize = sizeof(wcex); - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = wndProc; - wcex.hInstance = 0; - wcex.hIcon = LoadIcon(0, IDI_APPLICATION); - wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); - wcex.hbrBackground = static_cast(GetStockObject(NULL_BRUSH)); - wcex.lpszClassName = WINDOWCLASSNAME; - RegisterClassExW(&wcex); - - RECT rc = {0, 0, INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT}; - AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW, FALSE, 0); - - std::wstring windowName = TITLE_TEXT; - - HWND hWnd = CreateWindowW( - WINDOWCLASSNAME, - windowName.c_str(), - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, - CW_USEDEFAULT, - rc.right - rc.left, - rc.bottom - rc.top, - nullptr, - nullptr, - 0, - sampleHostWindow.get()); - - RECT clientRect; - GetClientRect(hWnd, &clientRect); - - sampleHostWindow->InitializeHwnd(hWnd); - - ShowWindow(hWnd, SW_SHOWNORMAL); - bool quit = false; - while (!quit) - { - MSG msg = {0}; - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - { - quit = true; - } - - TranslateMessage(&msg); - DispatchMessage(&msg); - } - else - { - sampleHostWindow->Tick(); - } - } - - return 0; -} diff --git a/hostsampleapp/uwp/packages.config b/hostsampleapp/uwp/packages.config deleted file mode 100644 index 7e842e8..0000000 --- a/hostsampleapp/uwp/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/player/common/CameraResources.cpp b/player/common/CameraResources.cpp index a76d1d3..7cd83a3 100644 --- a/player/common/CameraResources.cpp +++ b/player/common/CameraResources.cpp @@ -12,7 +12,7 @@ #include "pch.h" #include "CameraResources.h" -#include "DeviceResources.h" +#include "DeviceResourcesUWP.h" using namespace DirectX; using namespace winrt::Windows::Foundation::Numerics; @@ -35,7 +35,7 @@ namespace DXHelper // The app does not access the swap chain directly, but it does create // resource views for the back buffer. void CameraResources::CreateResourcesForBackBuffer( - DeviceResources* pDeviceResources, HolographicCameraRenderingParameters const& cameraParameters) + DeviceResourcesUWP* pDeviceResources, HolographicCameraRenderingParameters const& cameraParameters) { ID3D11Device* device = pDeviceResources->GetD3DDevice(); @@ -105,6 +105,10 @@ namespace DXHelper 1, // Use a single mipmap level. D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE); + // Allow sharing by default for easier interop with future D3D12 components for processing the remote or local frame. + // This is optional, but without the flag any D3D12 components need to perform an additional copy. + depthStencilDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; + m_d3dDepthStencil = nullptr; winrt::check_hresult(device->CreateTexture2D(&depthStencilDesc, nullptr, m_d3dDepthStencil.put())); @@ -119,12 +123,14 @@ namespace DXHelper { // Create a constant buffer to store view and projection matrices for the camera. CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); + constantBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + constantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; winrt::check_hresult(device->CreateBuffer(&constantBufferDesc, nullptr, m_viewProjectionConstantBuffer.put())); } } // Releases resources associated with a back buffer. - void CameraResources::ReleaseResourcesForBackBuffer(DeviceResources* pDeviceResources) + void CameraResources::ReleaseResourcesForBackBuffer(DeviceResourcesUWP* pDeviceResources) { // Release camera-specific resources. m_d3dBackBuffer = nullptr; @@ -144,7 +150,7 @@ namespace DXHelper // Updates the view/projection constant buffer for a holographic camera. void CameraResources::UpdateViewProjectionBuffer( - std::shared_ptr deviceResources, + std::shared_ptr deviceResources, HolographicCameraPose const& cameraPose, SpatialCoordinateSystem const& coordinateSystem) { @@ -153,7 +159,7 @@ namespace DXHelper m_d3dViewport = CD3D11_VIEWPORT(viewport.X, viewport.Y, viewport.Width, viewport.Height); // The projection transform for each frame is provided by the HolographicCameraPose. - HolographicStereoTransform cameraProjectionTransform = cameraPose.ProjectionTransform(); + m_cameraProjectionTransform = cameraPose.ProjectionTransform(); // Get a container object with the view and projection matrices for the given // pose in the given coordinate system. @@ -166,6 +172,7 @@ namespace DXHelper // which case it is possible to use a SpatialLocatorAttachedFrameOfReference to render // content that is not world-locked instead. ViewProjectionConstantBuffer viewProjectionConstantBufferData; + bool viewTransformAcquired = viewTransformContainer != nullptr; if (viewTransformAcquired) { @@ -175,12 +182,14 @@ namespace DXHelper // 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))); + XMMatrixTranspose(XMLoadFloat4x4(&viewCoordinateSystemTransform.Left) * XMLoadFloat4x4(&m_cameraProjectionTransform.Left))); XMStoreFloat4x4( &viewProjectionConstantBufferData.viewProjection[1], - XMMatrixTranspose(XMLoadFloat4x4(&viewCoordinateSystemTransform.Right) * XMLoadFloat4x4(&cameraProjectionTransform.Right))); + XMMatrixTranspose( + XMLoadFloat4x4(&viewCoordinateSystemTransform.Right) * XMLoadFloat4x4(&m_cameraProjectionTransform.Right))); } // Use the D3D device context to update Direct3D device-based resources. @@ -193,7 +202,10 @@ namespace DXHelper else { // Update the view and projection matrices. - context->UpdateSubresource(m_viewProjectionConstantBuffer.get(), 0, nullptr, &viewProjectionConstantBufferData, 0, 0); + D3D11_MAPPED_SUBRESOURCE resource; + context->Map(m_viewProjectionConstantBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); + memcpy(resource.pData, &viewProjectionConstantBufferData, sizeof(viewProjectionConstantBufferData)); + context->Unmap(m_viewProjectionConstantBuffer.get(), 0); m_framePending = true; } @@ -202,7 +214,7 @@ namespace DXHelper // Gets the view-projection constant buffer for the HolographicCamera and attaches it // to the shader pipeline. - bool CameraResources::AttachViewProjectionBuffer(std::shared_ptr& deviceResources) + bool CameraResources::AttachViewProjectionBuffer(std::shared_ptr& deviceResources) { // This method uses Direct3D device-based resources. return deviceResources->UseD3DDeviceContext([&](auto context) { @@ -221,22 +233,22 @@ namespace DXHelper ID3D11Buffer* viewProjectionConstantBuffers[1] = {m_viewProjectionConstantBuffer.get()}; context->VSSetConstantBuffers(1, 1, viewProjectionConstantBuffers); - // 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; }); } + + winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface CameraResources::GetDepthStencilTextureInteropObject() + { + // Direct3D interop APIs are used to provide the buffer to the WinRT API. + winrt::com_ptr depthStencilResource; + winrt::check_bool(m_d3dDepthStencil.try_as(depthStencilResource)); + winrt::com_ptr depthDxgiSurface; + winrt::check_hresult(depthStencilResource->CreateSubresourceSurface(0, depthDxgiSurface.put())); + winrt::com_ptr<::IInspectable> inspectableSurface; + winrt::check_hresult(CreateDirect3D11SurfaceFromDXGISurface( + depthDxgiSurface.get(), reinterpret_cast(winrt::put_abi(inspectableSurface)))); + return inspectableSurface.as(); + } } // namespace DXHelper diff --git a/player/common/CameraResources.h b/player/common/CameraResources.h index 70dfcf4..e03a312 100644 --- a/player/common/CameraResources.h +++ b/player/common/CameraResources.h @@ -12,7 +12,7 @@ namespace DXHelper { - class DeviceResources; + class DeviceResourcesUWP; // Constant buffer used to send the view-projection matrices to the shader pipeline. struct ViewProjectionConstantBuffer @@ -33,16 +33,16 @@ namespace DXHelper CameraResources(winrt::Windows::Graphics::Holographic::HolographicCamera const& holographicCamera); void CreateResourcesForBackBuffer( - DeviceResources* pDeviceResources, + DeviceResourcesUWP* pDeviceResources, winrt::Windows::Graphics::Holographic::HolographicCameraRenderingParameters const& cameraParameters); - void ReleaseResourcesForBackBuffer(DeviceResources* pDeviceResources); + void ReleaseResourcesForBackBuffer(DeviceResourcesUWP* pDeviceResources); void UpdateViewProjectionBuffer( - std::shared_ptr deviceResources, + std::shared_ptr deviceResources, winrt::Windows::Graphics::Holographic::HolographicCameraPose const& cameraPose, winrt::Windows::Perception::Spatial::SpatialCoordinateSystem const& coordinateSystem); - bool AttachViewProjectionBuffer(std::shared_ptr& deviceResources); + bool AttachViewProjectionBuffer(std::shared_ptr& deviceResources); // Direct3D device resources. ID3D11RenderTargetView* GetBackBufferRenderTargetView() const @@ -86,6 +86,12 @@ namespace DXHelper return m_holographicCamera; } + winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface GetDepthStencilTextureInteropObject(); + winrt::Windows::Graphics::Holographic::HolographicStereoTransform GetProjectionTransform() + { + return m_cameraProjectionTransform; + } + private: // Direct3D rendering objects. Required for 3D. winrt::com_ptr m_d3dRenderTargetView; @@ -109,5 +115,7 @@ namespace DXHelper // Pointer to the holographic camera these resources are for. winrt::Windows::Graphics::Holographic::HolographicCamera m_holographicCamera = nullptr; + + winrt::Windows::Graphics::Holographic::HolographicStereoTransform m_cameraProjectionTransform; }; } // namespace DXHelper diff --git a/player/common/Content/DDSTextureLoader.cpp b/player/common/Content/DDSTextureLoader.cpp index 5c6c75e..7b42c3f 100644 --- a/player/common/Content/DDSTextureLoader.cpp +++ b/player/common/Content/DDSTextureLoader.cpp @@ -21,8 +21,8 @@ #include "pch.h" -#include #include +#include #include #include "DDSTextureLoader.h" @@ -256,7 +256,6 @@ static HRESULT LoadTextureDataFromFile( return S_OK; } - //-------------------------------------------------------------------------------------- // Return the BPP for a particular format //-------------------------------------------------------------------------------------- @@ -419,7 +418,6 @@ static size_t BitsPerPixel(_In_ DXGI_FORMAT fmt) } } - //-------------------------------------------------------------------------------------- // Get surface information for a particular format //-------------------------------------------------------------------------------------- @@ -563,7 +561,6 @@ static void GetSurfaceInfo( } } - //-------------------------------------------------------------------------------------- #define ISBITMASK(r, g, b, a) (ddpf.RBitMask == r && ddpf.GBitMask == g && ddpf.BBitMask == b && ddpf.ABitMask == a) @@ -777,7 +774,6 @@ static DXGI_FORMAT GetDXGIFormat(const DDS_PIXELFORMAT& ddpf) return DXGI_FORMAT_UNKNOWN; } - //-------------------------------------------------------------------------------------- static DXGI_FORMAT MakeSRGB(_In_ DXGI_FORMAT format) { @@ -809,7 +805,6 @@ static DXGI_FORMAT MakeSRGB(_In_ DXGI_FORMAT format) } } - //-------------------------------------------------------------------------------------- static HRESULT FillInitData( _In_ size_t width, @@ -902,7 +897,6 @@ static HRESULT FillInitData( return (index > 0) ? S_OK : E_FAIL; } - //-------------------------------------------------------------------------------------- static HRESULT CreateD3DResources( _In_ ID3D11Device* d3dDevice, @@ -1122,7 +1116,6 @@ static HRESULT CreateD3DResources( return hr; } - //-------------------------------------------------------------------------------------- static HRESULT CreateTextureFromDDS( _In_ ID3D11Device* d3dDevice, @@ -1528,7 +1521,6 @@ static HRESULT CreateTextureFromDDS( return hr; } - //-------------------------------------------------------------------------------------- static DDS_ALPHA_MODE GetAlphaMode(_In_ const DDS_HEADER* header) { @@ -1556,7 +1548,6 @@ static DDS_ALPHA_MODE GetAlphaMode(_In_ const DDS_HEADER* header) return DDS_ALPHA_MODE_UNKNOWN; } - //-------------------------------------------------------------------------------------- _Use_decl_annotations_ HRESULT DirectX::CreateDDSTextureFromMemory( ID3D11Device* d3dDevice, diff --git a/player/common/Content/ErrorHelper.cpp b/player/common/Content/ErrorHelper.cpp index 71cec39..08f4619 100644 --- a/player/common/Content/ErrorHelper.cpp +++ b/player/common/Content/ErrorHelper.cpp @@ -46,67 +46,81 @@ bool ErrorHelper::ProcessOnDisconnect(const ConnectionFailureReason& reason) { switch (reason) { - case ConnectionFailureReason::Unknown: - AddError(L"Disconnect: Unknown reason"); - return true; + case ConnectionFailureReason::Unknown: + AddError(L"Disconnect: Unknown reason"); + return true; - case ConnectionFailureReason::HandshakeUnreachable: - AddError(L"Disconnect: Handshake server is unreachable"); - return true; + case ConnectionFailureReason::HandshakeUnreachable: + AddError(L"Disconnect: Handshake server is unreachable"); + return true; - case ConnectionFailureReason::HandshakeConnectionFailed: - AddError(L"Disconnect: Handshake server closed the connection prematurely; likely due to TLS/Plain mismatch " - L"or invalid certificate"); - return true; + case ConnectionFailureReason::HandshakeConnectionFailed: + AddError(L"Disconnect: Handshake server closed the connection prematurely; likely due to TLS/Plain mismatch " + L"or invalid certificate"); + return true; - case ConnectionFailureReason::AuthenticationFailed: - AddError(L"Disconnect: Authentication with the handshake server failed"); - return true; + case ConnectionFailureReason::AuthenticationFailed: + AddError(L"Disconnect: Authentication with the handshake server failed"); + return true; - case ConnectionFailureReason::RemotingVersionMismatch: - AddError(L"Disconnect: No common compatible remoting version could be determined during handshake"); - return true; + case ConnectionFailureReason::RemotingVersionMismatch: + AddError(L"Disconnect: No common compatible remoting version could be determined during handshake"); + return true; - case ConnectionFailureReason::IncompatibleTransportProtocols: - AddError(L"Disconnect: No common transport protocol could be determined during handshake"); - return true; + case ConnectionFailureReason::IncompatibleTransportProtocols: + AddError(L"Disconnect: No common transport protocol could be determined during handshake"); + return true; - case ConnectionFailureReason::HandshakeFailed: - AddError(L"Disconnect: Handshake failed for any other reason"); - return true; + case ConnectionFailureReason::HandshakeFailed: + AddError(L"Disconnect: Handshake failed for any other reason"); + return true; - case ConnectionFailureReason::TransportUnreachable: - AddError(L"Disconnect: Transport server is unreachable"); - return true; + case ConnectionFailureReason::TransportUnreachable: + AddError(L"Disconnect: Transport server is unreachable"); + return true; - case ConnectionFailureReason::TransportConnectionFailed: - AddError(L"Disconnect: Transport connection was closed before all communication channels had been set up"); - return true; + case ConnectionFailureReason::TransportConnectionFailed: + AddError(L"Disconnect: Transport connection was closed before all communication channels had been set up"); + return true; - case ConnectionFailureReason::ProtocolVersionMismatch: - AddError(L"Disconnect: Transport connection was closed due to protocol version mismatch"); - return true; + case ConnectionFailureReason::ProtocolVersionMismatch: + AddError(L"Disconnect: Transport connection was closed due to protocol version mismatch. " + L"Please go to the store app and check for any updates and install them to potentially resolve " + L"this error."); + return true; - case ConnectionFailureReason::ProtocolError: - AddError(L"Disconnect: A protocol error occurred that was severe enough to invalidate the current connection " - L"or connection attempt"); - return true; + case ConnectionFailureReason::ProtocolError: + AddError(L"Disconnect: A protocol error occurred that was severe enough to invalidate the current connection " + L"or connection attempt"); + return true; - case ConnectionFailureReason::VideoCodecNotAvailable: - AddError(L"Disconnect: Transport connection was closed due to the requested video codec not being available"); - return true; + case ConnectionFailureReason::VideoCodecNotAvailable: + AddError(L"Disconnect: Transport connection was closed due to the requested video codec not being available"); + return true; - case ConnectionFailureReason::Canceled: - AddError(L"Disconnect: Connection attempt has been canceled"); - return true; + case ConnectionFailureReason::Canceled: + AddError(L"Disconnect: Connection attempt has been canceled"); + return true; - case ConnectionFailureReason::ConnectionLost: - AddError(L"Disconnect: Connection has been lost or closed by remote side"); - return false; + case ConnectionFailureReason::ConnectionLost: + AddError(L"Disconnect: Connection has been lost or closed by remote side"); + return false; - case ConnectionFailureReason::DeviceLost: - AddError(L"Disconnect: Connection has been closed due to graphics device loss"); - return true; + case ConnectionFailureReason::DeviceLost: + AddError(L"Disconnect: Connection has been closed due to graphics device loss"); + return true; + + case ConnectionFailureReason::HandshakeNetworkUnreachable: + AddError(L"Disconnect: Handshake - Network unreachable"); + return true; + + case ConnectionFailureReason::HandshakeConnectionRefused: + AddError(L"Disconnect: Handshake - Connection has been refused by remote host"); + return true; + + case ConnectionFailureReason::VideoFormatNotAvailable: + AddError(L"Disconnect: Transport connection was closed due to the requested video format not being available"); + return true; } return false; diff --git a/player/common/Content/ShaderStructures.h b/player/common/Content/ShaderStructures.h index fbf2289..7a1c9db 100644 --- a/player/common/Content/ShaderStructures.h +++ b/player/common/Content/ShaderStructures.h @@ -22,7 +22,6 @@ static_assert( (sizeof(ModelConstantBuffer) % (sizeof(float) * 4)) == 0, "Model constant buffer size must be multiple of 16-bytes (16 bytes is the length of four floats)."); - // Used to send per-vertex data to the vertex shader. struct VertexBufferElement { diff --git a/player/common/Content/StatusDisplay.cpp b/player/common/Content/StatusDisplay.cpp index 7531202..98b9422 100644 --- a/player/common/Content/StatusDisplay.cpp +++ b/player/common/Content/StatusDisplay.cpp @@ -18,13 +18,14 @@ #include #include -#define TEXTURE_WIDTH 650 -#define TEXTURE_HEIGHT 650 - -#define Font L"Segoe UI" -#define FontSizeLarge 32.0f -#define FontSizeSmall 22.0f -#define FontLanguage L"en-US" +constexpr const wchar_t Font[] = L"Segoe UI"; +// Font size in percent. +constexpr float FontSizeLarge = 0.06f; +constexpr float FontSizeMedium = 0.04f; +constexpr float FontSizeSmall = 0.035f; +constexpr const wchar_t FontLanguage[] = L"en-US"; +constexpr const float Degree2Rad = 3.14159265359f / 180.0f; +constexpr const float Meter2Inch = 39.37f; using namespace DirectX; using namespace Concurrency; @@ -32,7 +33,7 @@ using namespace winrt::Windows::Foundation::Numerics; using namespace winrt::Windows::UI::Input::Spatial; // Initializes D2D resources used for text rendering. -StatusDisplay::StatusDisplay(const std::shared_ptr& deviceResources) +StatusDisplay::StatusDisplay(const std::shared_ptr& deviceResources) : m_deviceResources(deviceResources) { CreateDeviceDependentResources(); @@ -55,134 +56,142 @@ void StatusDisplay::Render() return; } - // First render all text using direct2D - m_deviceResources->UseD3DDeviceContext( - [&](auto context) { context->ClearRenderTargetView(m_textRenderTarget.get(), DirectX::Colors::Transparent); }); - - m_d2dTextRenderTarget->BeginDraw(); + bool linesChanged = false; + // First render all text using direct2D. { std::scoped_lock lock(m_lineMutex); if (m_lines.size() > 0) { - float top = m_lines[0].metrics.height; + linesChanged = true; + m_deviceResources->UseD3DDeviceContext( + [&](auto context) { context->ClearRenderTargetView(m_textRenderTarget.get(), DirectX::Colors::Transparent); }); + + m_d2dTextRenderTarget->BeginDraw(); + float height = 0; + for (auto& line : m_lines) + { + height += line.metrics.height * line.lineHeightMultiplier; + } + + // Vertical centered for the whole text with ~1/4 logical inch offset. In DIP. + float top = ((m_virtualDisplaySizeInchY / 2.0f) * 96.0f) - (height / 2.0f) - 48; for (auto& line : m_lines) { if (line.alignBottom) { - top = TEXTURE_HEIGHT - line.metrics.height; + top = m_textTextureHeight - line.metrics.height; } + m_d2dTextRenderTarget->DrawTextLayout(D2D1::Point2F(0, top), line.layout.get(), m_brushes[line.color].get()); top += line.metrics.height * line.lineHeightMultiplier; } + + // Ignore D2DERR_RECREATE_TARGET here. This error indicates that the device + // is lost. It will be handled during the next call to Present. + const HRESULT hr = m_d2dTextRenderTarget->EndDraw(); + if (hr != D2DERR_RECREATE_TARGET) + { + winrt::check_hresult(hr); + } } } - // Ignore D2DERR_RECREATE_TARGET here. This error indicates that the device - // is lost. It will be handled during the next call to Present. - const HRESULT hr = m_d2dTextRenderTarget->EndDraw(); - if (hr != D2DERR_RECREATE_TARGET) - { - winrt::check_hresult(hr); - } - // Now render the quads into 3d space m_deviceResources->UseD3DDeviceContext([&](auto context) { - // Each vertex is one instance of the VertexBufferElement struct. - const UINT stride = sizeof(VertexBufferElement); - const UINT offset = 0; - ID3D11Buffer* pBufferToSet = m_vertexBufferImage.get(); - context->IASetVertexBuffers(0, 1, &pBufferToSet, &stride, &offset); - context->IASetIndexBuffer( - m_indexBuffer.get(), - DXGI_FORMAT_R16_UINT, // Each index is one 16-bit unsigned integer (short). - 0); + DXHelper::D3D11StoreAndRestoreState(context, [&]() { + // Each vertex is one instance of the VertexBufferElement struct. + const UINT stride = sizeof(VertexBufferElement); + const UINT offset = 0; + ID3D11Buffer* pBufferToSet = m_vertexBufferImage.get(); + context->IASetVertexBuffers(0, 1, &pBufferToSet, &stride, &offset); + context->IASetIndexBuffer(m_indexBuffer.get(), DXGI_FORMAT_R16_UINT, 0); - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - context->IASetInputLayout(m_inputLayout.get()); - context->OMSetBlendState(m_textAlphaBlendState.get(), nullptr, 0xffffffff); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + context->IASetInputLayout(m_inputLayout.get()); + context->OMSetBlendState(m_textAlphaBlendState.get(), nullptr, 0xffffffff); + context->OMSetDepthStencilState(m_depthStencilState.get(), 0); - // Attach the vertex shader. - context->VSSetShader(m_vertexShader.get(), nullptr, 0); + context->UpdateSubresource(m_modelConstantBuffer.get(), 0, nullptr, &m_modelConstantBufferDataImage, 0, 0); - context->UpdateSubresource(m_modelConstantBuffer.get(), 0, nullptr, &m_modelConstantBufferDataImage, 0, 0); + // Apply the model constant buffer to the vertex shader. + pBufferToSet = m_modelConstantBuffer.get(); + context->VSSetConstantBuffers(0, 1, &pBufferToSet); - // Apply the model constant buffer to the vertex shader. - pBufferToSet = m_modelConstantBuffer.get(); - context->VSSetConstantBuffers(0, 1, &pBufferToSet); + // Attach the vertex shader. + context->VSSetShader(m_vertexShader.get(), nullptr, 0); - // On devices that do not support the D3D11_FEATURE_D3D11_OPTIONS3:: - // VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature, - // a pass-through geometry shader sets the render target ID. - context->GSSetShader(!m_usingVprtShaders ? m_geometryShader.get() : nullptr, nullptr, 0); + // On devices that do not support the D3D11_FEATURE_D3D11_OPTIONS3:: + // VPAndRTArrayIndexFromAnyShaderFeedingRasterizer optional feature, + // a pass-through geometry shader sets the render target ID. + context->GSSetShader(!m_usingVprtShaders ? m_geometryShader.get() : nullptr, nullptr, 0); - // Attach the pixel shader. - context->PSSetShader(m_pixelShader.get(), nullptr, 0); + // Attach the pixel shader. + context->PSSetShader(m_pixelShader.get(), nullptr, 0); - // Draw the image. - if (m_imageEnabled && m_imageView) - { - ID3D11ShaderResourceView* pShaderViewToSet = m_imageView.get(); - context->PSSetShaderResources(0, 1, &pShaderViewToSet); + // Draw the image. + if (m_imageEnabled && m_imageView) + { + ID3D11ShaderResourceView* pShaderViewToSet = m_imageView.get(); + context->PSSetShaderResources(0, 1, &pShaderViewToSet); - ID3D11SamplerState* pSamplerToSet = m_imageSamplerState.get(); - context->PSSetSamplers(0, 1, &pSamplerToSet); + ID3D11SamplerState* pSamplerToSet = m_imageSamplerState.get(); + context->PSSetSamplers(0, 1, &pSamplerToSet); - context->DrawIndexedInstanced( - m_indexCount, // Index count per instance. - 2, // Instance count. - 0, // Start index location. - 0, // Base vertex location. - 0 // Start instance location. - ); - } + context->DrawIndexedInstanced( + m_indexCount, // Index count per instance. + 2, // Instance count. + 0, // Start index location. + 0, // Base vertex location. + 0 // Start instance location. + ); + } - // Set up for rendering the texture that contains the text - pBufferToSet = m_vertexBufferText.get(); - context->IASetVertexBuffers(0, 1, &pBufferToSet, &stride, &offset); + // Draw the text. + { + if (linesChanged == true) + { + // Set up for rendering the texture that contains the text + pBufferToSet = m_vertexBufferText.get(); + context->IASetVertexBuffers(0, 1, &pBufferToSet, &stride, &offset); - ID3D11ShaderResourceView* pShaderViewToSet = m_textShaderResourceView.get(); - context->PSSetShaderResources(0, 1, &pShaderViewToSet); + ID3D11ShaderResourceView* pShaderViewToSet = m_textShaderResourceView.get(); + context->PSSetShaderResources(0, 1, &pShaderViewToSet); - ID3D11SamplerState* pSamplerToSet = m_textSamplerState.get(); - context->PSSetSamplers(0, 1, &pSamplerToSet); + ID3D11SamplerState* pSamplerToSet = m_textSamplerState.get(); + context->PSSetSamplers(0, 1, &pSamplerToSet); - context->UpdateSubresource(m_modelConstantBuffer.get(), 0, nullptr, &m_modelConstantBufferDataText, 0, 0); + context->UpdateSubresource(m_modelConstantBuffer.get(), 0, nullptr, &m_modelConstantBufferDataText, 0, 0); - // Draw the text. - context->DrawIndexedInstanced( - m_indexCount, // Index count per instance. - 2, // Instance count. - 0, // Start index location. - 0, // Base vertex location. - 0 // Start instance location. - ); - - // Reset the blend state. - context->OMSetBlendState(nullptr, nullptr, 0xffffffff); - - // Detach our texture. - ID3D11ShaderResourceView* emptyResource = nullptr; - context->PSSetShaderResources(0, 1, &emptyResource); + context->DrawIndexedInstanced( + m_indexCount, // Index count per instance. + 2, // Instance count. + 0, // Start index location. + 0, // Base vertex location. + 0 // Start instance location. + ); + } + } + }); }); } void StatusDisplay::CreateDeviceDependentResources() { - CD3D11_SAMPLER_DESC desc(D3D11_DEFAULT); + auto device = m_deviceResources->GetD3DDevice(); CD3D11_TEXTURE2D_DESC textureDesc( - DXGI_FORMAT_B8G8R8A8_UNORM, TEXTURE_WIDTH, TEXTURE_HEIGHT, 1, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); + DXGI_FORMAT_B8G8R8A8_UNORM, m_textTextureWidth, m_textTextureHeight, 1, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); m_textTexture = nullptr; - m_deviceResources->GetD3DDevice()->CreateTexture2D(&textureDesc, nullptr, m_textTexture.put()); + device->CreateTexture2D(&textureDesc, nullptr, m_textTexture.put()); m_textShaderResourceView = nullptr; - m_deviceResources->GetD3DDevice()->CreateShaderResourceView(m_textTexture.get(), nullptr, m_textShaderResourceView.put()); + device->CreateShaderResourceView(m_textTexture.get(), nullptr, m_textShaderResourceView.put()); m_textRenderTarget = nullptr; - m_deviceResources->GetD3DDevice()->CreateRenderTargetView(m_textTexture.get(), nullptr, m_textRenderTarget.put()); + device->CreateRenderTargetView(m_textTexture.get(), nullptr, m_textRenderTarget.put()); D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties( D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED), 96, 96); @@ -190,7 +199,6 @@ void StatusDisplay::CreateDeviceDependentResources() winrt::com_ptr dxgiSurface; m_textTexture.as(dxgiSurface); - m_d2dTextRenderTarget = nullptr; winrt::check_hresult( m_deviceResources->GetD2DFactory()->CreateDxgiSurfaceRenderTarget(dxgiSurface.get(), &props, m_d2dTextRenderTarget.put())); @@ -206,78 +214,38 @@ void StatusDisplay::CreateDeviceDependentResources() const auto vertexShaderDataSize = m_usingVprtShaders ? sizeof(VPRTVertexShader) : sizeof(VertexShader); // create the vertex shader and input layout. - task createVSTask = task([this, vertexShaderData, vertexShaderDataSize]() { - winrt::check_hresult( - m_deviceResources->GetD3DDevice()->CreateVertexShader(vertexShaderData, vertexShaderDataSize, nullptr, m_vertexShader.put())); + task createVSTask = task([this, device, vertexShaderData, vertexShaderDataSize]() { + winrt::check_hresult(device->CreateVertexShader(vertexShaderData, vertexShaderDataSize, nullptr, m_vertexShader.put())); static const D3D11_INPUT_ELEMENT_DESC vertexDesc[] = { {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, }; - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateInputLayout( - vertexDesc, ARRAYSIZE(vertexDesc), vertexShaderData, vertexShaderDataSize, m_inputLayout.put())); + winrt::check_hresult( + device->CreateInputLayout(vertexDesc, ARRAYSIZE(vertexDesc), vertexShaderData, vertexShaderDataSize, m_inputLayout.put())); }); // create the pixel shader and constant buffer. - task createPSTask([this]() { - winrt::check_hresult( - m_deviceResources->GetD3DDevice()->CreatePixelShader(PixelShader, sizeof(PixelShader), nullptr, m_pixelShader.put())); + task createPSTask([this, device]() { + winrt::check_hresult(device->CreatePixelShader(PixelShader, sizeof(PixelShader), nullptr, m_pixelShader.put())); const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, m_modelConstantBuffer.put())); + winrt::check_hresult(device->CreateBuffer(&constantBufferDesc, nullptr, m_modelConstantBuffer.put())); }); task createGSTask; if (!m_usingVprtShaders) { // create the geometry shader. - createGSTask = task([this]() { - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateGeometryShader( - GeometryShader, sizeof(GeometryShader), nullptr, m_geometryShader.put())); + createGSTask = task([this, device]() { + winrt::check_hresult(device->CreateGeometryShader(GeometryShader, sizeof(GeometryShader), nullptr, m_geometryShader.put())); }); } // Once all shaders are loaded, create the mesh. task shaderTaskGroup = m_usingVprtShaders ? (createPSTask && createVSTask) : (createPSTask && createVSTask && createGSTask); - task createQuadTask = shaderTaskGroup.then([this]() { - // Load mesh vertices. Each vertex has a position and a color. - // Note that the quad size has changed from the default DirectX app - // template. Windows Holographic is scaled in meters, so to draw the - // quad at a comfortable size we made the quad width 0.2 m (20 cm). - static const float imageQuadExtent = 0.23f; - static const VertexBufferElement quadVertices[] = { - {XMFLOAT3(-imageQuadExtent, imageQuadExtent, 0.f), XMFLOAT2(0.f, 0.f)}, - {XMFLOAT3(imageQuadExtent, imageQuadExtent, 0.f), XMFLOAT2(1.f, 0.f)}, - {XMFLOAT3(imageQuadExtent, -imageQuadExtent, 0.f), XMFLOAT2(1.f, 1.f)}, - {XMFLOAT3(-imageQuadExtent, -imageQuadExtent, 0.f), XMFLOAT2(0.f, 1.f)}, - }; - - D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; - vertexBufferData.pSysMem = quadVertices; - vertexBufferData.SysMemPitch = 0; - vertexBufferData.SysMemSlicePitch = 0; - const CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(quadVertices), D3D11_BIND_VERTEX_BUFFER); - winrt::check_hresult( - m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, m_vertexBufferImage.put())); - - static const float textQuadExtent = 0.3f; - static const VertexBufferElement quadVerticesText[] = { - {XMFLOAT3(-textQuadExtent, textQuadExtent, 0.f), XMFLOAT2(0.f, 0.f)}, - {XMFLOAT3(textQuadExtent, textQuadExtent, 0.f), XMFLOAT2(1.f, 0.f)}, - {XMFLOAT3(textQuadExtent, -textQuadExtent, 0.f), XMFLOAT2(1.f, 1.f)}, - {XMFLOAT3(-textQuadExtent, -textQuadExtent, 0.f), XMFLOAT2(0.f, 1.f)}, - }; - - D3D11_SUBRESOURCE_DATA vertexBufferDataText = {0}; - vertexBufferDataText.pSysMem = quadVerticesText; - vertexBufferDataText.SysMemPitch = 0; - vertexBufferDataText.SysMemSlicePitch = 0; - const CD3D11_BUFFER_DESC vertexBufferDescText(sizeof(quadVerticesText), D3D11_BIND_VERTEX_BUFFER); - winrt::check_hresult( - m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDescText, &vertexBufferDataText, m_vertexBufferText.put())); - - + task createQuadTask = shaderTaskGroup.then([this, device]() { // 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 @@ -300,34 +268,32 @@ void StatusDisplay::CreateDeviceDependentResources() indexBufferData.SysMemPitch = 0; indexBufferData.SysMemSlicePitch = 0; const CD3D11_BUFFER_DESC indexBufferDesc(sizeof(quadIndices), D3D11_BIND_INDEX_BUFFER); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&indexBufferDesc, &indexBufferData, m_indexBuffer.put())); + winrt::check_hresult(device->CreateBuffer(&indexBufferDesc, &indexBufferData, m_indexBuffer.put())); }); // Create image sampler state { - D3D11_SAMPLER_DESC desc = {}; - - desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - desc.MaxAnisotropy = 1; - desc.MinLOD = 0; - desc.MaxLOD = 3; - desc.MipLODBias = 0.f; - desc.BorderColor[0] = 0.f; - desc.BorderColor[1] = 0.f; - desc.BorderColor[2] = 0.f; - desc.BorderColor[3] = 0.f; - desc.ComparisonFunc = D3D11_COMPARISON_NEVER; - - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateSamplerState(&desc, m_imageSamplerState.put())); + D3D11_SAMPLER_DESC samplerDesc = {}; + samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.MaxAnisotropy = 1; + samplerDesc.MinLOD = 0; + samplerDesc.MaxLOD = 3; + samplerDesc.MipLODBias = 0.f; + samplerDesc.BorderColor[0] = 0.f; + samplerDesc.BorderColor[1] = 0.f; + samplerDesc.BorderColor[2] = 0.f; + samplerDesc.BorderColor[3] = 0.f; + samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + winrt::check_hresult(device->CreateSamplerState(&samplerDesc, m_imageSamplerState.put())); } // Create text sampler state { CD3D11_SAMPLER_DESC samplerDesc(D3D11_DEFAULT); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateSamplerState(&samplerDesc, m_textSamplerState.put())); + winrt::check_hresult(device->CreateSamplerState(&samplerDesc, m_textSamplerState.put())); } // Create the blend state. This sets up a blend state for pre-multiplied alpha produced by TextRenderer.cpp's Direct2D text @@ -352,7 +318,10 @@ void StatusDisplay::CreateDeviceDependentResources() blendStateDesc.RenderTarget[i] = rtBlendDesc; } - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBlendState(&blendStateDesc, m_textAlphaBlendState.put())); + winrt::check_hresult(device->CreateBlendState(&blendStateDesc, m_textAlphaBlendState.put())); + + D3D11_DEPTH_STENCIL_DESC depthStencilDesc = {}; + device->CreateDepthStencilState(&depthStencilDesc, m_depthStencilState.put()); // Once the quad is loaded, the object is ready to be rendered. auto loadCompleteCallback = createQuadTask.then([this]() { m_loadingComplete = true; }); @@ -412,7 +381,10 @@ void StatusDisplay::SetLines(winrt::array_view lines) void StatusDisplay::UpdateLineText(size_t index, std::wstring text) { std::scoped_lock lock(m_lineMutex); - assert(index < m_lines.size() && "Line index out of bounds"); + if (index >= m_lines.size()) + { + return; + } auto& runtimeLine = m_lines[index]; @@ -423,7 +395,7 @@ void StatusDisplay::UpdateLineText(size_t index, std::wstring text) size_t StatusDisplay::AddLine(const Line& line) { std::scoped_lock lock(m_lineMutex); - auto newIndex = m_lines.size(); + size_t newIndex = m_lines.size(); m_lines.resize(newIndex + 1); UpdateLineInternal(m_lines[newIndex], line); return newIndex; @@ -437,6 +409,11 @@ bool StatusDisplay::HasLine(size_t index) void StatusDisplay::CreateFonts() { + // DIP font size, based on the horizontal size of the virtual display. + float fontSizeLargeDIP = (m_virtualDisplaySizeInchX * FontSizeLarge) * 96; + float fontSizeMediumDIP = (m_virtualDisplaySizeInchX * FontSizeMedium) * 96; + float fontSizeSmallDIP = (m_virtualDisplaySizeInchX * FontSizeSmall) * 96; + // Create Large font m_textFormats[Large] = nullptr; winrt::check_hresult(m_deviceResources->GetDWriteFactory()->CreateTextFormat( @@ -445,7 +422,7 @@ void StatusDisplay::CreateFonts() DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, - FontSizeLarge, + fontSizeLargeDIP, FontLanguage, m_textFormats[Large].put())); winrt::check_hresult(m_textFormats[Large]->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR)); @@ -459,7 +436,7 @@ void StatusDisplay::CreateFonts() DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, - FontSizeLarge, + fontSizeLargeDIP, FontLanguage, m_textFormats[LargeBold].put())); winrt::check_hresult(m_textFormats[LargeBold]->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR)); @@ -473,13 +450,27 @@ void StatusDisplay::CreateFonts() DWRITE_FONT_WEIGHT_MEDIUM, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, - FontSizeSmall, + fontSizeSmallDIP, FontLanguage, m_textFormats[Small].put())); winrt::check_hresult(m_textFormats[Small]->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR)); winrt::check_hresult(m_textFormats[Small]->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER)); - static_assert(TextFormatCount == 3, "Expected 3 text formats"); + // Create medium font + m_textFormats[Medium] = nullptr; + winrt::check_hresult(m_deviceResources->GetDWriteFactory()->CreateTextFormat( + Font, + nullptr, + DWRITE_FONT_WEIGHT_MEDIUM, + DWRITE_FONT_STYLE_NORMAL, + DWRITE_FONT_STRETCH_NORMAL, + fontSizeMediumDIP, + FontLanguage, + m_textFormats[Medium].put())); + winrt::check_hresult(m_textFormats[Medium]->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR)); + winrt::check_hresult(m_textFormats[Medium]->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER)); + + static_assert(TextFormatCount == 4, "Expected 4 text formats"); } void StatusDisplay::CreateBrushes() @@ -504,13 +495,19 @@ void StatusDisplay::UpdateLineInternal(RuntimeLine& runtimeLine, const Line& lin runtimeLine.format = line.format; runtimeLine.text = line.text; + const float virtualDisplayDPIx = m_textTextureWidth / m_virtualDisplaySizeInchX; + const float virtualDisplayDPIy = m_textTextureHeight / m_virtualDisplaySizeInchY; + + const float dpiScaleX = virtualDisplayDPIx / 96.0f; + const float dpiScaleY = virtualDisplayDPIy / 96.0f; + runtimeLine.layout = nullptr; winrt::check_hresult(m_deviceResources->GetDWriteFactory()->CreateTextLayout( line.text.c_str(), static_cast(line.text.length()), m_textFormats[line.format].get(), - TEXTURE_WIDTH, // Max width of the input text. - TEXTURE_HEIGHT, // Max height of the input text. + static_cast(m_textTextureWidth / dpiScaleX), // Max width of the input text. + static_cast(m_textTextureHeight / dpiScaleY), // Max height of the input text. runtimeLine.layout.put())); winrt::check_hresult(runtimeLine.layout->GetMetrics(&runtimeLine.metrics)); @@ -536,11 +533,11 @@ void StatusDisplay::PositionDisplay(float deltaTimeInSeconds, const SpatialPoint const float3 headPosition = pointerPose.Head().Position(); const float3 headDirection = pointerPose.Head().ForwardDirection(); - const float3 offsetImage = float3(0.0f, -0.02f, 0.0f); - const float3 gazeAtTwoMetersImage = headPosition + (2.05f * (headDirection + offsetImage)); + const float3 offsetImage = float3(0.0f, m_virtualDisplaySizeInchY * 0.002f, 0.0f); + const float3 gazeAtTwoMetersImage = headPosition + ((m_statusDisplayDistance + 0.05f) * (headDirection + offsetImage)); - const float3 offsetText = float3(0.0f, -0.035f, 0.0f); - const float3 gazeAtTwoMetersText = headPosition + (2.0f * (headDirection + offsetText)); + const float3 offsetText = float3(0.0f, 0.0f, 0.0f); + const float3 gazeAtTwoMetersText = headPosition + (m_statusDisplayDistance * (headDirection + offsetText)); // Lerp the position, to keep the hologram comfortably stable. auto imagePosition = lerp(m_positionImage, gazeAtTwoMetersImage, deltaTimeInSeconds * c_lerpRate); @@ -597,3 +594,159 @@ void StatusDisplay::UpdateConstantBuffer( auto& deltaX = position - lastPosition; // meters m_velocity = deltaX / deltaTimeInSeconds; // meters per second } + +void StatusDisplay::UpdateTextScale( + winrt::Windows::Graphics::Holographic::HolographicStereoTransform holoTransform, + float screenWidth, + float screenHeight, + float quadFov, + float heightRatio) +{ + DirectX::XMMATRIX projMat = XMLoadFloat4x4(&holoTransform.Left); + DirectX::XMFLOAT4X4 proj; + DirectX::XMStoreFloat4x4(&proj, projMat); + // Check if the projection matrix has changed. + bool projHasChanged = false; + for (int x = 0; x < 4; ++x) + { + for (int y = 0; y < 4; ++y) + { + if (proj.m[x][y] != m_projection.m[x][y]) + { + projHasChanged = true; + break; + } + } + if (projHasChanged) + { + break; + } + } + + const float fovDiff = m_currentQuadFov - quadFov; + const float fovEpsilon = 0.1f; + const bool quadFovHasChanged = std::abs(fovDiff) > fovEpsilon; + m_currentQuadFov = quadFov; + + const float heightRatioDiff = m_currentHeightRatio - heightRatio; + const float heightRatioEpsilon = 0.1f; + const bool quadRatioHasChanged = std::abs(heightRatioDiff) > heightRatioEpsilon; + m_currentHeightRatio = heightRatio; + + // Only update the StatusDisplay resolution and size if something has changed. + if (projHasChanged || quadFovHasChanged || quadRatioHasChanged) + { + // Quad extent based on FOV. + const float quadExtentX = tan((m_currentQuadFov / 2.0f) * Degree2Rad) * m_statusDisplayDistance; + const float quadExtentY = m_currentHeightRatio * quadExtentX; + + // Calculate the virtual display size in inch. + m_virtualDisplaySizeInchX = (quadExtentX * 2.0f) * Meter2Inch; + m_virtualDisplaySizeInchY = (quadExtentY * 2.0f) * Meter2Inch; + + // Pixel perfect resolution. + const float resX = screenWidth * quadExtentX / m_statusDisplayDistance * proj._11; + const float resY = screenHeight * quadExtentY / m_statusDisplayDistance * proj._22; + + // sample with double resolution for multi sampling. + m_textTextureWidth = static_cast(resX * 2.0f); + m_textTextureHeight = static_cast(resY * 2.0f); + + m_projection = proj; + + // Create the new texture. + auto device = m_deviceResources->GetD3DDevice(); + + // Load mesh vertices. Each vertex has a position and a color. + // Note that the quad size has changed from the default DirectX app + // template. The quad size is based on the target FOV. + const VertexBufferElement quadVerticesText[] = { + {XMFLOAT3(-quadExtentX, quadExtentY, 0.f), XMFLOAT2(0.f, 0.f)}, + {XMFLOAT3(quadExtentX, quadExtentY, 0.f), XMFLOAT2(1.f, 0.f)}, + {XMFLOAT3(quadExtentX, -quadExtentY, 0.f), XMFLOAT2(1.f, 1.f)}, + {XMFLOAT3(-quadExtentX, -quadExtentY, 0.f), XMFLOAT2(0.f, 1.f)}, + }; + + D3D11_SUBRESOURCE_DATA vertexBufferDataText = {0}; + vertexBufferDataText.pSysMem = quadVerticesText; + vertexBufferDataText.SysMemPitch = 0; + vertexBufferDataText.SysMemSlicePitch = 0; + const CD3D11_BUFFER_DESC vertexBufferDescText(sizeof(quadVerticesText), D3D11_BIND_VERTEX_BUFFER); + + m_vertexBufferText = nullptr; + winrt::check_hresult(device->CreateBuffer(&vertexBufferDescText, &vertexBufferDataText, m_vertexBufferText.put())); + + // Create image buffer + // The image contains 50% of the textFOV. + const float imageFOVDegree = 0.4f * (m_currentQuadFov * 0.5f); + const float imageQuadExtent = m_statusDisplayDistance / tan((90.0f - imageFOVDegree) * Degree2Rad); + + const VertexBufferElement quadVertices[] = { + {XMFLOAT3(-imageQuadExtent, imageQuadExtent, 0.f), XMFLOAT2(0.f, 0.f)}, + {XMFLOAT3(imageQuadExtent, imageQuadExtent, 0.f), XMFLOAT2(1.f, 0.f)}, + {XMFLOAT3(imageQuadExtent, -imageQuadExtent, 0.f), XMFLOAT2(1.f, 1.f)}, + {XMFLOAT3(-imageQuadExtent, -imageQuadExtent, 0.f), XMFLOAT2(0.f, 1.f)}, + }; + + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = quadVertices; + vertexBufferData.SysMemPitch = 0; + vertexBufferData.SysMemSlicePitch = 0; + const CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(quadVertices), D3D11_BIND_VERTEX_BUFFER); + m_vertexBufferImage = nullptr; + winrt::check_hresult(device->CreateBuffer(&vertexBufferDesc, &vertexBufferData, m_vertexBufferImage.put())); + + CD3D11_TEXTURE2D_DESC textureDesc( + DXGI_FORMAT_B8G8R8A8_UNORM, + m_textTextureWidth, + m_textTextureHeight, + 1, + 1, + D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); + + m_textTexture = nullptr; + device->CreateTexture2D(&textureDesc, nullptr, m_textTexture.put()); + + m_textShaderResourceView = nullptr; + device->CreateShaderResourceView(m_textTexture.get(), nullptr, m_textShaderResourceView.put()); + + m_textRenderTarget = nullptr; + device->CreateRenderTargetView(m_textTexture.get(), nullptr, m_textRenderTarget.put()); + + const float virtualDisplayDPIx = m_textTextureWidth / m_virtualDisplaySizeInchX; + const float virtualDisplayDPIy = m_textTextureHeight / m_virtualDisplaySizeInchY; + + D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties( + D2D1_RENDER_TARGET_TYPE_DEFAULT, + D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED), + virtualDisplayDPIx, + virtualDisplayDPIy); + + winrt::com_ptr dxgiSurface; + m_textTexture.as(dxgiSurface); + + m_d2dTextRenderTarget = nullptr; + winrt::check_hresult( + m_deviceResources->GetD2DFactory()->CreateDxgiSurfaceRenderTarget(dxgiSurface.get(), &props, m_d2dTextRenderTarget.put())); + + // Update the fonts. + CreateFonts(); + + // Update the text layout. + for (RuntimeLine& runtimeLine : m_lines) + { + + const float dpiScaleX = virtualDisplayDPIx / 96.0f; + const float dpiScaleY = virtualDisplayDPIy / 96.0f; + runtimeLine.layout = nullptr; + winrt::check_hresult(m_deviceResources->GetDWriteFactory()->CreateTextLayout( + runtimeLine.text.c_str(), + static_cast(runtimeLine.text.length()), + m_textFormats[runtimeLine.format].get(), + static_cast(m_textTextureWidth / dpiScaleX), // Max width of the input text. + static_cast(m_textTextureHeight / dpiScaleY), // Max height of the input text. + runtimeLine.layout.put())); + winrt::check_hresult(runtimeLine.layout->GetMetrics(&runtimeLine.metrics)); + } + } +} diff --git a/player/common/Content/StatusDisplay.h b/player/common/Content/StatusDisplay.h index 9806e98..18fbb64 100644 --- a/player/common/Content/StatusDisplay.h +++ b/player/common/Content/StatusDisplay.h @@ -11,7 +11,7 @@ #pragma once -#include "..\Common\DeviceResources.h" +#include "..\Common\DeviceResourcesCommon.h" #include "ShaderStructures.h" #include @@ -27,6 +27,7 @@ public: Small = 0, Large, LargeBold, + Medium, TextFormatCount }; @@ -52,7 +53,7 @@ public: }; public: - StatusDisplay(const std::shared_ptr& deviceResources); + StatusDisplay(const std::shared_ptr& deviceResources); void Update(float deltaTimeInSeconds); @@ -102,6 +103,29 @@ public: return m_positionImage; } + void UpdateTextScale( + winrt::Windows::Graphics::Holographic::HolographicStereoTransform holoTransform, + float screenWidth, + float screenHeight, + float quadFov, + float heightRatio = 1.0f); + + // Get default FOV for the text quad in degree. + float GetDefaultQuadFov() + { + return m_defaultQuadFov; + } + // Get statistics FOV for the text quad in degree. + float GetStatisticsFov() + { + return m_statisticsFov; + } + // Get the statistics height ratio. + float GetStatisticsHeightRatio() + { + return m_statisticsHeightRatio; + } + private: // Runtime representation of a text line. struct RuntimeLine @@ -124,14 +148,13 @@ private: winrt::Windows::Foundation::Numerics::float3 position, winrt::Windows::Foundation::Numerics::float3 lastPosition); - winrt::com_ptr m_brushes[TextColorCount] = {}; winrt::com_ptr m_textFormats[TextFormatCount] = {}; std::vector m_lines; std::mutex m_lineMutex; // Cached pointer to device resources. - std::shared_ptr m_deviceResources; + std::shared_ptr m_deviceResources; // Resources related to text rendering. winrt::com_ptr m_textTexture; @@ -155,6 +178,7 @@ private: winrt::com_ptr m_textSamplerState; winrt::com_ptr m_textAlphaBlendState; + winrt::com_ptr m_depthStencilState; // System resources for quad geometry. ModelConstantBuffer m_modelConstantBufferDataImage = {}; @@ -178,4 +202,28 @@ private: const float c_lerpRate = 4.0f; bool m_imageEnabled = true; + + // The distance to the camera in fwd-direction. + float m_statusDisplayDistance = 1.0f; + // The view Projection matrix. + DirectX::XMFLOAT4X4 m_projection; + + // Default size, gets adjusted based on HMD. + int m_textTextureWidth = 128; + int m_textTextureHeight = 128; + + // Default size, gets adjusted based on the HMD and FOV. + float m_virtualDisplaySizeInchX = 10.0f; + float m_virtualDisplaySizeInchY = 10.0f; + + // The current FOV for the text quad in degree. + float m_currentQuadFov{}; + // The current height ratio of the quad. + float m_currentHeightRatio{}; + // The default FOV for the text quad in degree. + float m_defaultQuadFov = 25.0f; + // The statistics FOV for the text quad in degree. + float m_statisticsFov = 23.0f; + // The height ratio for the statistics quad in percent. + float m_statisticsHeightRatio = 0.4f; }; diff --git a/player/common/DeviceResources.cpp b/player/common/DeviceResources.cpp deleted file mode 100644 index 443723d..0000000 --- a/player/common/DeviceResources.cpp +++ /dev/null @@ -1,395 +0,0 @@ -//********************************************************* -// -// 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 "DeviceResources.h" - -using namespace D2D1; -using namespace winrt::Windows::Graphics::DirectX::Direct3D11; -using namespace winrt::Windows::Graphics::Display; -using namespace winrt::Windows::Graphics::Holographic; - -namespace DXHelper -{ -#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 Runtime 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 - - // Constructor for DeviceResources. - DeviceResources::DeviceResources() - { - CreateDeviceIndependentResources(); - } - - DeviceResources::~DeviceResources() - { - UnregisterHolographicEventHandlers(); - } - - // Configures resources that don't depend on the Direct3D device. - void 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. - m_d2dFactory = nullptr; - winrt::check_hresult( - D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory2), &options, m_d2dFactory.put_void())); - - // Initialize the DirectWrite Factory. - m_dwriteFactory = nullptr; - winrt::check_hresult(DWriteCreateFactory( - DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), reinterpret_cast(m_dwriteFactory.put_void()))); - - // Initialize the Windows Imaging Component (WIC) Factory. - m_wicFactory = nullptr; - winrt::check_hresult(CoCreateInstance(CLSID_WICImagingFactory2, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(m_wicFactory.put()))); - } - - void DeviceResources::SetWindow(const winrt::Windows::UI::Core::CoreWindow& window) - { - UnregisterHolographicEventHandlers(); - - m_holographicSpace = HolographicSpace::CreateForCoreWindow(window); - - InitializeUsingHolographicSpace(); - - m_cameraAddedToken = m_holographicSpace.CameraAdded({this, &DeviceResources::OnCameraAdded}); - m_cameraRemovedToken = m_holographicSpace.CameraRemoved({this, &DeviceResources::OnCameraRemoved}); - } - - void 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 (SdkLayersAvailable()) - { - createFlags |= DXGI_CREATE_FACTORY_DEBUG; - } -#endif - // Create the DXGI factory. - winrt::com_ptr dxgiFactory; - winrt::check_hresult(CreateDXGIFactory2(createFlags, IID_PPV_ARGS(dxgiFactory.put()))); - winrt::com_ptr dxgiFactory4; - dxgiFactory.as(dxgiFactory4); - - // Retrieve the adapter specified by the holographic space. - m_dxgiAdapter = nullptr; - winrt::check_hresult(dxgiFactory4->EnumAdapterByLuid(id, IID_PPV_ARGS(m_dxgiAdapter.put()))); - } - else - { - m_dxgiAdapter = nullptr; - } - - CreateDeviceResources(); - - m_holographicSpace.SetDirect3D11Device(m_d3dInteropDevice); - } - - // Configures the Direct3D device, and stores handles to it and the device context. - void 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 (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. - winrt::com_ptr device; - winrt::com_ptr context; - - const D3D_DRIVER_TYPE driverType = m_dxgiAdapter == nullptr ? D3D_DRIVER_TYPE_HARDWARE : D3D_DRIVER_TYPE_UNKNOWN; - const HRESULT hr = D3D11CreateDevice( - m_dxgiAdapter.get(), // Either nullptr, or the primary adapter determined by Windows Holographic. - driverType, // 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 Runtime apps. - device.put(), // Returns the Direct3D device created. - &m_d3dFeatureLevel, // Returns feature level of device created. - context.put() // 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 - winrt::check_hresult(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.put(), - &m_d3dFeatureLevel, - context.put())); - } - - // Store pointers to the Direct3D device and immediate context. - device.as(m_d3dDevice); - context.as(m_d3dContext); - - - // Enable multithread protection for video decoding. - winrt::com_ptr multithread; - device.as(multithread); - multithread->SetMultithreadProtected(true); - - // Acquire the DXGI interface for the Direct3D device. - winrt::com_ptr dxgiDevice; - m_d3dDevice.as(dxgiDevice); - - // Wrap the native device using a WinRT interop object. - winrt::com_ptr<::IInspectable> object; - winrt::check_hresult( - CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.get(), reinterpret_cast(winrt::put_abi(object)))); - m_d3dInteropDevice = object.as(); - - // Cache the DXGI adapter. - // This is for the case of no preferred DXGI adapter, or fallback to WARP. - winrt::com_ptr dxgiAdapter; - winrt::check_hresult(dxgiDevice->GetAdapter(dxgiAdapter.put())); - 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; - } - } - - void DeviceResources::OnCameraAdded( - winrt::Windows::Graphics::Holographic::HolographicSpace const& sender, - winrt::Windows::Graphics::Holographic::HolographicSpaceCameraAddedEventArgs const& args) - { - UseHolographicCameraResources( - [this, camera = args.Camera()](std::map>& cameraResourceMap) { - cameraResourceMap[camera.Id()] = std::make_unique(camera); - }); - } - - void DeviceResources::OnCameraRemoved( - winrt::Windows::Graphics::Holographic::HolographicSpace const& sender, - winrt::Windows::Graphics::Holographic::HolographicSpaceCameraRemovedEventArgs const& args) - { - UseHolographicCameraResources( - [this, camera = args.Camera()](std::map>& cameraResourceMap) { - CameraResources* pCameraResources = cameraResourceMap[camera.Id()].get(); - - if (pCameraResources != nullptr) - { - pCameraResources->ReleaseResourcesForBackBuffer(this); - cameraResourceMap.erase(camera.Id()); - } - }); - } - - void DeviceResources::UnregisterHolographicEventHandlers() - { - if (m_holographicSpace != nullptr) - { - // Clear previous event registrations. - m_holographicSpace.CameraAdded(m_cameraAddedToken); - m_cameraAddedToken = {}; - m_holographicSpace.CameraRemoved(m_cameraRemovedToken); - m_cameraRemovedToken = {}; - } - } - - // 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 DeviceResources::EnsureCameraResources(HolographicFrame frame, HolographicFramePrediction prediction) - { - UseHolographicCameraResources([this, frame, prediction](std::map>& cameraResourceMap) { - for (HolographicCameraPose const& cameraPose : prediction.CameraPoses()) - { - HolographicCameraRenderingParameters renderingParameters = frame.GetRenderingParameters(cameraPose); - CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get(); - - pCameraResources->CreateResourcesForBackBuffer(this, renderingParameters); - } - }); - } - - // Recreate all device resources and set them back to the current state. - // Locks the set of holographic camera resources until the function exits. - void DeviceResources::HandleDeviceLost() - { - if (m_deviceNotify != nullptr) - { - m_deviceNotify->OnDeviceLost(); - } - - UseHolographicCameraResources([this](std::map>& 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 DeviceResources::RegisterDeviceNotify(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 DeviceResources::Trim() - { - if (m_d3dContext) - { - m_d3dContext->ClearState(); - } - - if (m_d3dDevice) - { - winrt::com_ptr dxgiDevice; - 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 DeviceResources::Present(HolographicFrame frame) - { - HolographicFramePresentResult presentResult = - frame.PresentUsingCurrentPrediction(HolographicFramePresentWaitBehavior::DoNotWaitForFrameToFinish); - - // Note, by not waiting on PresentUsingCurrentPrediction and instead using WaitForNextFrameReadyWithHeadStart we avoid going into - // pipelined mode. - try - { - // WaitForNextFrameReadyWithHeadStart has been added in 10.0.17763.0. - if (!m_useLegacyWaitBehavior) - { - m_holographicSpace.WaitForNextFrameReadyWithHeadStart(winrt::Windows::Foundation::TimeSpan(0)); - } - else - { - frame.WaitForFrameToFinish(); - } - } - catch (winrt::hresult_error& err) - { - switch (err.code()) - { - case DXGI_ERROR_DEVICE_HUNG: - case DXGI_ERROR_DEVICE_REMOVED: - case DXGI_ERROR_DEVICE_RESET: - presentResult = HolographicFramePresentResult::DeviceRemoved; - break; - - default: - try - { - m_useLegacyWaitBehavior = true; - frame.WaitForFrameToFinish(); - } - catch (winrt::hresult_error& err2) - { - switch (err2.code()) - { - case DXGI_ERROR_DEVICE_HUNG: - case DXGI_ERROR_DEVICE_REMOVED: - case DXGI_ERROR_DEVICE_RESET: - presentResult = HolographicFramePresentResult::DeviceRemoved; - break; - - default: - throw err2; - } - } - break; - } - - // 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(); - } - } - } -} // namespace DXHelper diff --git a/player/common/DeviceResources.h b/player/common/DeviceResources.h deleted file mode 100644 index 540d50d..0000000 --- a/player/common/DeviceResources.h +++ /dev/null @@ -1,182 +0,0 @@ -//********************************************************* -// -// 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 "CameraResources.h" -#include - -namespace DXHelper -{ - // 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(); - ~DeviceResources(); - - // Public methods related to Direct3D devices. - void HandleDeviceLost(); - void RegisterDeviceNotify(IDeviceNotify* deviceNotify); - void Trim(); - void Present(winrt::Windows::Graphics::Holographic::HolographicFrame frame); - - void SetWindow(const winrt::Windows::UI::Core::CoreWindow& window); - - void EnsureCameraResources( - winrt::Windows::Graphics::Holographic::HolographicFrame frame, - winrt::Windows::Graphics::Holographic::HolographicFramePrediction prediction); - - // Holographic accessors. - template - void UseHolographicCameraResources(LCallback const& callback); - - winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice GetD3DInteropDevice() const - { - return m_d3dInteropDevice; - } - - // D3D accessors. - ID3D11Device4* GetD3DDevice() const - { - return m_d3dDevice.get(); - } - template - auto UseD3DDeviceContext(F func) const - { - std::scoped_lock lock(m_d3dContextMutex); - return func(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(); - } - - // Holographic accessors. - winrt::Windows::Graphics::Holographic::HolographicSpace GetHolographicSpace() - { - return m_holographicSpace; - } - - private: - // Private methods related to the Direct3D device, and resources based on that device. - void CreateDeviceIndependentResources(); - void InitializeUsingHolographicSpace(); - void CreateDeviceResources(); - - void OnCameraAdded( - winrt::Windows::Graphics::Holographic::HolographicSpace const& sender, - winrt::Windows::Graphics::Holographic::HolographicSpaceCameraAddedEventArgs const& args); - - void OnCameraRemoved( - winrt::Windows::Graphics::Holographic::HolographicSpace const& sender, - winrt::Windows::Graphics::Holographic::HolographicSpaceCameraRemovedEventArgs const& args); - - void UnregisterHolographicEventHandlers(); - - // Direct3D objects. - winrt::com_ptr m_d3dDevice; - mutable std::recursive_mutex m_d3dContextMutex; - winrt::com_ptr m_d3dContext; - winrt::com_ptr m_dxgiAdapter; - - // Direct3D interop objects. - winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_d3dInteropDevice; - - // Direct2D factories. - winrt::com_ptr m_d2dFactory; - winrt::com_ptr m_dwriteFactory; - winrt::com_ptr m_wicFactory; - - // The holographic space provides a preferred DXGI adapter ID. - winrt::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; - - bool m_useLegacyWaitBehavior = false; - - // Back buffer resources, etc. for attached holographic cameras. - std::map> m_cameraResources; - std::mutex m_cameraResourcesLock; - - winrt::event_token m_cameraAddedToken; - winrt::event_token m_cameraRemovedToken; - }; -} // namespace DXHelper - -// 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>& -// through which the list of cameras will be accessed. -template -void DXHelper::DeviceResources::UseHolographicCameraResources(LCallback const& callback) -{ - try - { - std::lock_guard guard(m_cameraResourcesLock); - callback(m_cameraResources); - } - catch (const winrt::hresult_error& err) - { - switch (err.code()) - { - case DXGI_ERROR_DEVICE_HUNG: - case DXGI_ERROR_DEVICE_REMOVED: - case DXGI_ERROR_DEVICE_RESET: - HandleDeviceLost(); - break; - - default: - throw err; - } - } -} diff --git a/player/common/DeviceResourcesCommon.cpp b/player/common/DeviceResourcesCommon.cpp new file mode 100644 index 0000000..3d52b69 --- /dev/null +++ b/player/common/DeviceResourcesCommon.cpp @@ -0,0 +1,210 @@ +//********************************************************* +// +// 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 "DeviceResourcesCommon.h" + +#include +#include +#include +#include +#include + +namespace DXHelper +{ +#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 Runtime 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 + + // Constructor for DeviceResources. + DeviceResourcesCommon::DeviceResourcesCommon() + { + CreateDeviceIndependentResources(); + } + + DeviceResourcesCommon::~DeviceResourcesCommon() + { + } + + // Configures resources that don't depend on the Direct3D device. + void DeviceResourcesCommon::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. + m_d2dFactory = nullptr; + winrt::check_hresult( + D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory2), &options, m_d2dFactory.put_void())); + + // Initialize the DirectWrite Factory. + m_dwriteFactory = nullptr; + winrt::check_hresult(DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), reinterpret_cast(m_dwriteFactory.put_void()))); + + // Initialize the Windows Imaging Component (WIC) Factory. + m_wicFactory = nullptr; + winrt::check_hresult(CoCreateInstance(CLSID_WICImagingFactory2, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(m_wicFactory.put()))); + } + + // Configures the Direct3D device, and stores handles to it and the device context. + void DeviceResourcesCommon::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 (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. + winrt::com_ptr device; + winrt::com_ptr context; + + const D3D_DRIVER_TYPE driverType = m_dxgiAdapter == nullptr ? D3D_DRIVER_TYPE_HARDWARE : D3D_DRIVER_TYPE_UNKNOWN; + const HRESULT hr = D3D11CreateDevice( + m_dxgiAdapter.get(), // Either nullptr, or the primary adapter determined by Windows Holographic. + driverType, // 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 Runtime apps. + device.put(), // Returns the Direct3D device created. + &m_d3dFeatureLevel, // Returns feature level of device created. + context.put() // 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 + winrt::check_hresult(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.put(), + &m_d3dFeatureLevel, + context.put())); + } + + // Store pointers to the Direct3D device and immediate context. + device.as(m_d3dDevice); + context.as(m_d3dContext); + + // Enable multithread protection for video decoding. + winrt::com_ptr multithread; + device.as(multithread); + multithread->SetMultithreadProtected(true); + + // Acquire the DXGI interface for the Direct3D device. + winrt::com_ptr dxgiDevice; + m_d3dDevice.as(dxgiDevice); + + // Cache the DXGI adapter. + // This is for the case of no preferred DXGI adapter, or fallback to WARP. + winrt::com_ptr dxgiAdapter; + winrt::check_hresult(dxgiDevice->GetAdapter(dxgiAdapter.put())); + 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; + } + } + + void DeviceResourcesCommon::NotifyDeviceLost() + { + if (m_deviceNotify != nullptr) + { + m_deviceNotify->OnDeviceLost(); + } + } + + void DeviceResourcesCommon::NotifyDeviceRestored() + { + if (m_deviceNotify != nullptr) + { + m_deviceNotify->OnDeviceRestored(); + } + } + + // Register our DeviceNotify to be informed on device lost and creation. + void DeviceResourcesCommon::RegisterDeviceNotify(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 DeviceResourcesCommon::Trim() + { + if (m_d3dContext) + { + m_d3dContext->ClearState(); + } + + if (m_d3dDevice) + { + winrt::com_ptr dxgiDevice; + m_d3dDevice.as(dxgiDevice); + dxgiDevice->Trim(); + } + } +} // namespace DXHelper diff --git a/player/common/DeviceResourcesCommon.h b/player/common/DeviceResourcesCommon.h new file mode 100644 index 0000000..f21fcdd --- /dev/null +++ b/player/common/DeviceResourcesCommon.h @@ -0,0 +1,169 @@ +//********************************************************* +// +// 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 + +#include + +#define ARRAY_SIZE(a) (std::extent::value) + +struct ID3D11Device4; +struct IDXGIAdapter3; +struct ID2D1Factory2; +struct IDWriteFactory2; +struct IWICImagingFactory2; +struct ID3D11DeviceContext3; + +namespace DXHelper +{ + // Provides an interface for an application that owns DeviceResources to be notified of the device being lost or created. + struct 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 DeviceResourcesCommon + { + public: + DeviceResourcesCommon(); + virtual ~DeviceResourcesCommon(); + + // Public methods related to Direct3D devices. + void RegisterDeviceNotify(IDeviceNotify* deviceNotify); + void Trim(); + + // D3D accessors. + ID3D11Device4* GetD3DDevice() const + { + return m_d3dDevice.get(); + } + template + auto UseD3DDeviceContext(F func) const + { + std::scoped_lock lock(m_d3dContextMutex); + return func(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(); + } + + protected: + // Private methods related to the Direct3D device, and resources based on that device. + void CreateDeviceIndependentResources(); + virtual void CreateDeviceResources(); + + void NotifyDeviceLost(); + void NotifyDeviceRestored(); + + // Direct3D objects. + winrt::com_ptr m_d3dDevice; + mutable std::recursive_mutex m_d3dContextMutex; + winrt::com_ptr m_d3dContext; + winrt::com_ptr m_dxgiAdapter; + + // Direct2D factories. + winrt::com_ptr m_d2dFactory; + winrt::com_ptr m_dwriteFactory; + winrt::com_ptr m_wicFactory; + + // 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; + }; + + template + void D3D11StoreAndRestoreState(ID3D11DeviceContext* immediateContext, F customRenderingCode) + { + // Query the d3d11 state before rendering + static_assert( + sizeof(winrt::com_ptr) == sizeof(void*), + "Below code reiles on winrt::com_ptr being exactly one pointer in size"); + + winrt::com_ptr vertexShader; + winrt::com_ptr geometryShader; + winrt::com_ptr pixelShader; + winrt::com_ptr vsConstantBuffers[2], psConstantBuffers[3]; + winrt::com_ptr views[4] = {}; + winrt::com_ptr psSampler; + winrt::com_ptr rasterizerState; + winrt::com_ptr depthStencilState; + winrt::com_ptr blendState; + winrt::com_ptr inputLayout; + FLOAT blendFactor[4] = {}; + UINT sampleMask = 0; + D3D11_PRIMITIVE_TOPOLOGY primitiveTopoloy = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + UINT stencilRef = 0; + + immediateContext->VSGetShader(vertexShader.put(), nullptr, nullptr); + immediateContext->VSGetConstantBuffers(0, ARRAY_SIZE(vsConstantBuffers), reinterpret_cast(vsConstantBuffers)); + immediateContext->GSGetShader(geometryShader.put(), nullptr, nullptr); + immediateContext->PSGetShader(pixelShader.put(), nullptr, nullptr); + immediateContext->PSGetShaderResources(0, ARRAY_SIZE(views), reinterpret_cast(views)); + immediateContext->PSGetConstantBuffers(0, ARRAY_SIZE(psConstantBuffers), reinterpret_cast(psConstantBuffers)); + immediateContext->PSGetSamplers(0, 1, psSampler.put()); + immediateContext->RSGetState(rasterizerState.put()); + immediateContext->OMGetDepthStencilState(depthStencilState.put(), &stencilRef); + immediateContext->OMGetBlendState(blendState.put(), blendFactor, &sampleMask); + immediateContext->IAGetPrimitiveTopology(&primitiveTopoloy); + immediateContext->IAGetInputLayout(inputLayout.put()); + + customRenderingCode(); + + // Restore the d3d11 state. + immediateContext->VSSetShader(vertexShader.get(), nullptr, 0); + immediateContext->VSSetConstantBuffers(0, ARRAY_SIZE(vsConstantBuffers), reinterpret_cast(vsConstantBuffers)); + immediateContext->GSSetShader(geometryShader.get(), nullptr, 0); + immediateContext->PSSetShader(pixelShader.get(), nullptr, 0); + immediateContext->PSSetShaderResources(0, ARRAY_SIZE(views), reinterpret_cast(views)); + immediateContext->PSSetConstantBuffers(0, ARRAY_SIZE(psConstantBuffers), reinterpret_cast(psConstantBuffers)); + immediateContext->PSSetSamplers(0, 1, reinterpret_cast(&psSampler)); + immediateContext->RSSetState(rasterizerState.get()); + immediateContext->OMSetDepthStencilState(depthStencilState.get(), stencilRef); + immediateContext->OMSetBlendState(blendState.get(), blendFactor, sampleMask); + immediateContext->IASetPrimitiveTopology(primitiveTopoloy); + immediateContext->IASetInputLayout(inputLayout.get()); + } +} // namespace DXHelper diff --git a/player/common/DeviceResourcesUWP.cpp b/player/common/DeviceResourcesUWP.cpp new file mode 100644 index 0000000..1037fee --- /dev/null +++ b/player/common/DeviceResourcesUWP.cpp @@ -0,0 +1,217 @@ +#include + +#include "CameraResources.h" +#include "DeviceResourcesUWP.h" + +using namespace D2D1; +using namespace winrt::Windows::Graphics::DirectX::Direct3D11; +using namespace winrt::Windows::Graphics::Display; +using namespace winrt::Windows::Graphics::Holographic; + +using namespace DXHelper; + +void DeviceResourcesUWP::SetWindow(const winrt::Windows::UI::Core::CoreWindow& window) +{ + UnregisterHolographicEventHandlers(); + + m_holographicSpace = HolographicSpace::CreateForCoreWindow(window); + + InitializeUsingHolographicSpace(); + + m_cameraAddedToken = m_holographicSpace.CameraAdded({this, &DeviceResourcesUWP::OnCameraAdded}); + m_cameraRemovedToken = m_holographicSpace.CameraRemoved({this, &DeviceResourcesUWP::OnCameraRemoved}); +} + +void DeviceResourcesUWP::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 (SdkLayersAvailable()) + { + createFlags |= DXGI_CREATE_FACTORY_DEBUG; + } +#endif + // Create the DXGI factory. + winrt::com_ptr dxgiFactory; + winrt::check_hresult(CreateDXGIFactory2(createFlags, IID_PPV_ARGS(dxgiFactory.put()))); + winrt::com_ptr dxgiFactory4; + dxgiFactory.as(dxgiFactory4); + + // Retrieve the adapter specified by the holographic space. + m_dxgiAdapter = nullptr; + winrt::check_hresult(dxgiFactory4->EnumAdapterByLuid(id, IID_PPV_ARGS(m_dxgiAdapter.put()))); + } + else + { + m_dxgiAdapter = nullptr; + } + + CreateDeviceResources(); + + m_holographicSpace.SetDirect3D11Device(m_d3dInteropDevice); +} + +void DeviceResourcesUWP::OnCameraAdded( + winrt::Windows::Graphics::Holographic::HolographicSpace const& sender, + winrt::Windows::Graphics::Holographic::HolographicSpaceCameraAddedEventArgs const& args) +{ + UseHolographicCameraResources([this, camera = args.Camera()](std::map>& cameraResourceMap) { + cameraResourceMap[camera.Id()] = std::make_unique(camera); + }); +} + +void DeviceResourcesUWP::OnCameraRemoved( + winrt::Windows::Graphics::Holographic::HolographicSpace const& sender, + winrt::Windows::Graphics::Holographic::HolographicSpaceCameraRemovedEventArgs const& args) +{ + UseHolographicCameraResources([this, camera = args.Camera()](std::map>& cameraResourceMap) { + CameraResources* pCameraResources = cameraResourceMap[camera.Id()].get(); + + if (pCameraResources != nullptr) + { + pCameraResources->ReleaseResourcesForBackBuffer(this); + cameraResourceMap.erase(camera.Id()); + } + }); +} + +void DeviceResourcesUWP::UnregisterHolographicEventHandlers() +{ + if (m_holographicSpace != nullptr) + { + // Clear previous event registrations. + m_holographicSpace.CameraAdded(m_cameraAddedToken); + m_cameraAddedToken = {}; + m_holographicSpace.CameraRemoved(m_cameraRemovedToken); + m_cameraRemovedToken = {}; + } +} + +// 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 DeviceResourcesUWP::EnsureCameraResources(HolographicFrame frame, HolographicFramePrediction prediction) +{ + UseHolographicCameraResources([this, frame, prediction](std::map>& cameraResourceMap) { + for (HolographicCameraPose const& cameraPose : prediction.CameraPoses()) + { + HolographicCameraRenderingParameters renderingParameters = frame.GetRenderingParameters(cameraPose); + CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get(); + + pCameraResources->CreateResourcesForBackBuffer(this, renderingParameters); + } + }); +} + +DeviceResourcesUWP::~DeviceResourcesUWP() +{ + UnregisterHolographicEventHandlers(); +} + +// Recreate all device resources and set them back to the current state. +// Locks the set of holographic camera resources until the function exits. +void DeviceResourcesUWP::HandleDeviceLost() +{ + NotifyDeviceLost(); + + UseHolographicCameraResources([this](std::map>& cameraResourceMap) { + for (auto& pair : cameraResourceMap) + { + CameraResources* pCameraResources = pair.second.get(); + pCameraResources->ReleaseResourcesForBackBuffer(this); + } + }); + + InitializeUsingHolographicSpace(); + + NotifyDeviceRestored(); +} + +void DeviceResourcesUWP::CreateDeviceResources() +{ + DeviceResourcesCommon::CreateDeviceResources(); + + // Acquire the DXGI interface for the Direct3D device. + winrt::com_ptr dxgiDevice; + m_d3dDevice.as(dxgiDevice); + + // Wrap the native device using a WinRT interop object. + winrt::com_ptr<::IInspectable> object; + winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.get(), reinterpret_cast(winrt::put_abi(object)))); + m_d3dInteropDevice = object.as(); +} + +// Present the contents of the swap chain to the screen. +// Locks the set of holographic camera resources until the function exits. +void DeviceResourcesUWP::Present(HolographicFrame frame) +{ + HolographicFramePresentResult presentResult = + frame.PresentUsingCurrentPrediction(HolographicFramePresentWaitBehavior::DoNotWaitForFrameToFinish); + + // Note, by not waiting on PresentUsingCurrentPrediction and instead using WaitForNextFrameReadyWithHeadStart we avoid going into + // pipelined mode. + try + { + // WaitForNextFrameReadyWithHeadStart has been added in 10.0.17763.0. + if (!m_useLegacyWaitBehavior) + { + m_holographicSpace.WaitForNextFrameReadyWithHeadStart(winrt::Windows::Foundation::TimeSpan(0)); + } + else + { + frame.WaitForFrameToFinish(); + } + } + catch (winrt::hresult_error& err) + { + switch (err.code()) + { + case DXGI_ERROR_DEVICE_HUNG: + case DXGI_ERROR_DEVICE_REMOVED: + case DXGI_ERROR_DEVICE_RESET: + presentResult = HolographicFramePresentResult::DeviceRemoved; + break; + + default: + try + { + m_useLegacyWaitBehavior = true; + frame.WaitForFrameToFinish(); + } + catch (winrt::hresult_error& err2) + { + switch (err2.code()) + { + case DXGI_ERROR_DEVICE_HUNG: + case DXGI_ERROR_DEVICE_REMOVED: + case DXGI_ERROR_DEVICE_RESET: + presentResult = HolographicFramePresentResult::DeviceRemoved; + break; + + default: + throw err2; + } + } + break; + } + + // 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(); + } + } +} diff --git a/player/common/DeviceResourcesUWP.h b/player/common/DeviceResourcesUWP.h new file mode 100644 index 0000000..5e9b7ec --- /dev/null +++ b/player/common/DeviceResourcesUWP.h @@ -0,0 +1,100 @@ +#pragma once + +#include "DeviceResourcesCommon.h" + +#include + +namespace DXHelper +{ + class CameraResources; + + class DeviceResourcesUWP : public DeviceResourcesCommon + { + public: + ~DeviceResourcesUWP(); + + void HandleDeviceLost(); + void Present(winrt::Windows::Graphics::Holographic::HolographicFrame frame); + + void SetWindow(const winrt::Windows::UI::Core::CoreWindow& window); + + void EnsureCameraResources( + winrt::Windows::Graphics::Holographic::HolographicFrame frame, + winrt::Windows::Graphics::Holographic::HolographicFramePrediction prediction); + + // Holographic accessors. + template + void UseHolographicCameraResources(LCallback const& callback); + + // Holographic accessors. + winrt::Windows::Graphics::Holographic::HolographicSpace GetHolographicSpace() + { + return m_holographicSpace; + } + + winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice GetD3DInteropDevice() const + { + return m_d3dInteropDevice; + } + + protected: + virtual void CreateDeviceResources() override; + + private: + void InitializeUsingHolographicSpace(); + void OnCameraAdded( + winrt::Windows::Graphics::Holographic::HolographicSpace const& sender, + winrt::Windows::Graphics::Holographic::HolographicSpaceCameraAddedEventArgs const& args); + + void OnCameraRemoved( + winrt::Windows::Graphics::Holographic::HolographicSpace const& sender, + winrt::Windows::Graphics::Holographic::HolographicSpaceCameraRemovedEventArgs const& args); + + void UnregisterHolographicEventHandlers(); + + // Direct3D interop objects. + winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_d3dInteropDevice; + + // The holographic space provides a preferred DXGI adapter ID. + winrt::Windows::Graphics::Holographic::HolographicSpace m_holographicSpace = nullptr; + + bool m_useLegacyWaitBehavior = false; + + // Back buffer resources, etc. for attached holographic cameras. + std::map> m_cameraResources; + std::mutex m_cameraResourcesLock; + + winrt::event_token m_cameraAddedToken; + winrt::event_token m_cameraRemovedToken; + }; +} // namespace DXHelper + +// 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>& +// through which the list of cameras will be accessed. +template +void DXHelper::DeviceResourcesUWP::UseHolographicCameraResources(LCallback const& callback) +{ + try + { + std::lock_guard guard(m_cameraResourcesLock); + callback(m_cameraResources); + } + catch (const winrt::hresult_error& err) + { + switch (err.code()) + { + case DXGI_ERROR_DEVICE_HUNG: + case DXGI_ERROR_DEVICE_REMOVED: + case DXGI_ERROR_DEVICE_RESET: + HandleDeviceLost(); + break; + + default: + throw err; + } + } +} diff --git a/player/common/IpAddressUpdater.cpp b/player/common/IpAddressUpdater.cpp index faede96..259bd37 100644 --- a/player/common/IpAddressUpdater.cpp +++ b/player/common/IpAddressUpdater.cpp @@ -13,6 +13,8 @@ #include "IpAddressUpdater.h" +using namespace winrt::Windows::Networking; +using namespace winrt::Windows::Networking::Connectivity; IpAddressUpdater::IpAddressUpdater() { @@ -24,27 +26,50 @@ IpAddressUpdater::IpAddressUpdater() IpAddressUpdater::~IpAddressUpdater() = default; -winrt::hstring IpAddressUpdater::GetIpAddress() +winrt::hstring IpAddressUpdater::GetIpAddress(bool ipv6) { std::lock_guard lockGuard(m_lock); - return m_ipAddress; + return ipv6 ? m_ipAddressIpv6 : m_ipAddressIpv4; } void IpAddressUpdater::UpdateIpAddress(winrt::Windows::Foundation::IInspectable sender) { - winrt::hstring ipAddress = L"(No Network Connection)"; - winrt::Windows::Foundation::Collections::IVectorView hostnames = - winrt::Windows::Networking::Connectivity::NetworkInformation::GetHostNames(); + winrt::hstring ipAddressIpv4 = L""; + winrt::hstring ipAddressIpv6 = L""; + winrt::Windows::Foundation::Collections::IVectorView hostnames = NetworkInformation::GetHostNames(); for (winrt::Windows::Networking::HostName hostname : hostnames) { - if (hostname.IPInformation() && hostname.IPInformation().NetworkAdapter() && hostname.CanonicalName().size() <= 15) // IPV4 only + auto hostNameType = hostname.Type(); + if (hostNameType != HostNameType::Ipv4 && hostNameType != HostNameType::Ipv6) { - ipAddress = hostname.CanonicalName(); - break; + continue; + } + + if (hostname.IPInformation() && hostname.IPInformation().NetworkAdapter()) + { + if (hostNameType == HostNameType::Ipv6 && ipAddressIpv6.empty()) + { + ipAddressIpv6 = hostname.CanonicalName(); + } + else if (hostNameType == HostNameType::Ipv4 && ipAddressIpv4.empty()) + { + ipAddressIpv4 = hostname.CanonicalName(); + } } } + if (ipAddressIpv6.empty()) + { + ipAddressIpv6 = L"(No Network Connection)"; + } + + if (ipAddressIpv4.empty()) + { + ipAddressIpv4 = L"(No Network Connection)"; + } + std::lock_guard lockGuard(m_lock); - m_ipAddress = ipAddress; + m_ipAddressIpv6 = ipAddressIpv6; + m_ipAddressIpv4 = ipAddressIpv4; }; diff --git a/player/common/IpAddressUpdater.h b/player/common/IpAddressUpdater.h index 3883c21..8383c4a 100644 --- a/player/common/IpAddressUpdater.h +++ b/player/common/IpAddressUpdater.h @@ -13,21 +13,21 @@ #include - class IpAddressUpdater { public: IpAddressUpdater(); ~IpAddressUpdater(); - winrt::hstring GetIpAddress(); + winrt::hstring GetIpAddress(bool ipv6); private: void UpdateIpAddress(winrt::Windows::Foundation::IInspectable sender); private: std::mutex m_lock; - winrt::hstring m_ipAddress; + winrt::hstring m_ipAddressIpv6; + winrt::hstring m_ipAddressIpv4; winrt::Windows::Networking::Connectivity::NetworkInformation::NetworkStatusChanged_revoker m_networkStatusChangedRevoker; }; diff --git a/player/common/PlayerFrameStatisticsHelper.cpp b/player/common/PlayerFrameStatisticsHelper.cpp index 1db7a8b..34a4a63 100644 --- a/player/common/PlayerFrameStatisticsHelper.cpp +++ b/player/common/PlayerFrameStatisticsHelper.cpp @@ -15,10 +15,8 @@ #include - using namespace winrt::Microsoft::Holographic::AppRemoting; - std::wstring PlayerFrameStatisticsHelper::GetStatisticsString() const { float timeSinceLastPresentAvg = 0.0f; @@ -31,7 +29,6 @@ std::wstring PlayerFrameStatisticsHelper::GetStatisticsString() const float latencyAvg = 0.0f; uint32_t videoFramesDiscarded = 0; - for (const PlayerFrameStatistics& frameStatistics : m_lastWindowFrameStats) { timeSinceLastPresentAvg += frameStatistics.TimeSinceLastPresent; @@ -69,14 +66,14 @@ std::wstring PlayerFrameStatisticsHelper::GetStatisticsString() const std::wstringstream statisticsStringStream; statisticsStringStream.precision(3); statisticsStringStream << L"Render: " << frameStatsCount << L" fps - " << timeSinceLastPresentAvg * 1000 << L" / " - << timeSinceLastPresentMax * 1000 << L" ms (avg / max)" << std::endl + << timeSinceLastPresentMax * 1000 << L" ms (avg/max)" << std::endl << L"Video frames: " << videoFramesSkipped << L" / " << videoFramesReused << L" / " << videoFramesReceived - << L" skipped / reused / received" << std::endl + << L" skipped/reused/received" << std::endl << L"Video frames delta: " << videoFrameMinDelta * 1000 << L" / " << videoFrameMaxDelta * 1000 - << L" ms (min / max)" << std::endl + << L" ms (min/max)" << std::endl << L"Latency: " << latencyAvg * 1000 << L" ms (avg)" << std::endl << L"Video frames discarded: " << videoFramesDiscarded << L" / " << m_videoFramesDiscardedTotal - << L" frames (last sec / total)" << std::endl; + << L" frames (last sec/total)" << std::endl; return statisticsStringStream.str(); } diff --git a/player/common/PlayerFrameStatisticsHelper.h b/player/common/PlayerFrameStatisticsHelper.h index f09f7be..50cd47c 100644 --- a/player/common/PlayerFrameStatisticsHelper.h +++ b/player/common/PlayerFrameStatisticsHelper.h @@ -9,7 +9,6 @@ // //********************************************************* - #pragma once #include diff --git a/player/common/PlayerUtil.cpp b/player/common/PlayerUtil.cpp new file mode 100644 index 0000000..34e785c --- /dev/null +++ b/player/common/PlayerUtil.cpp @@ -0,0 +1,37 @@ +//********************************************************* +// +// 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 "PlayerUtil.h" + +#include +#include + +std::wstring PlayerUtil::SplitHostnameAndPortString(const std::wstring& address, uint16_t& port) +{ + static std::basic_regex addressMatcher(L"(?:(\\[.*\\])|([^:]*))(?:[:](\\d+))?"); + std::match_results results; + if (std::regex_match(address, results, addressMatcher)) + { + if (results[3].matched) + { + std::wstring portStr = results[3].str(); + port = static_cast(std::wcstol(portStr.c_str(), nullptr, 10)); + } + + return (results[1].matched) ? results[1].str() : results[2].str(); + } + else + { + return address; + } +} diff --git a/player/common/PlayerUtil.h b/player/common/PlayerUtil.h new file mode 100644 index 0000000..cae5369 --- /dev/null +++ b/player/common/PlayerUtil.h @@ -0,0 +1,17 @@ +//********************************************************* +// +// 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 + +struct PlayerUtil +{ + static std::wstring SplitHostnameAndPortString(const std::wstring& address, uint16_t& port); +}; diff --git a/player/common/Shaders/PixelShader.hlsl b/player/common/Shaders/PixelShader.hlsl index 0fb3c8a..ef83541 100644 --- a/player/common/Shaders/PixelShader.hlsl +++ b/player/common/Shaders/PixelShader.hlsl @@ -12,14 +12,24 @@ // Per-pixel color data passed through the pixel shader. struct PixelShaderInput { - min16float4 pos : SV_POSITION; - float2 uv : TEXCOORD0; //Note: we use full precission floats for texture coordinates to avoid artifacts with large textures + min16float4 pos : SV_POSITION; + float2 uv : TEXCOORD0; // Note: we use full precission floats for texture coordinates to avoid artifacts with large textures }; -Texture2D tex : t0; -SamplerState samp : s0; +Texture2D tex : t0; +SamplerState samp : s0; -min16float4 main(PixelShaderInput input) : SV_TARGET +float4 main(PixelShaderInput input) : SV_TARGET { - return (min16float4)tex.Sample(samp, input.uv); + float2 offsets[4] = {float2(-0.125, -0.375), float2(0.375, -0.125), float2(-0.375, 0.125), float2(0.125f, 0.375f)}; + float4 color = float4(0, 0, 0, 0); + float2 dtdx = ddx(input.uv); + float2 dtdy = ddy(input.uv); + + [unroll] + for (int i = 0; i < 4; ++i) + { + color += 0.25 * tex.Sample(samp, input.uv + offsets[i].x * dtdx + offsets[i].y * dtdy); + } + return color; } diff --git a/player/sample/LICENSE b/player/sample/LICENSE new file mode 100644 index 0000000..12283d0 --- /dev/null +++ b/player/sample/LICENSE @@ -0,0 +1,20 @@ + The MIT License (MIT) + +Copyright (c) 2012-2019 Microsoft Corp + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be included in all copies +or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/player/sample/Package.appxmanifest b/player/sample/Package.appxmanifest index fac5635..1337650 100644 --- a/player/sample/Package.appxmanifest +++ b/player/sample/Package.appxmanifest @@ -1,6 +1,6 @@ - + - + Sample Holographic AppRemoting Player diff --git a/player/sample/SamplePlayer.sln b/player/sample/SamplePlayer.sln index f74d0f6..cf33542 100644 --- a/player/sample/SamplePlayer.sln +++ b/player/sample/SamplePlayer.sln @@ -1,26 +1,26 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.645 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29806.167 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SamplePlayer", "SamplePlayer.vcxproj", "{B26EEC5F-BBFF-3973-A459-AD3E5A33EF70}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SamplePlayer", "SamplePlayer.vcxproj", "{B848F924-651A-3EC7-8166-E5565290E1FB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|ARM = Debug|ARM - Release|ARM = Release|ARM - RelWithDebInfo|ARM = RelWithDebInfo|ARM + Debug|ARM64 = Debug|ARM64 + Release|ARM64 = Release|ARM64 + RelWithDebInfo|ARM64 = RelWithDebInfo|ARM64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B26EEC5F-BBFF-3973-A459-AD3E5A33EF70}.Debug|ARM.ActiveCfg = Debug|ARM - {B26EEC5F-BBFF-3973-A459-AD3E5A33EF70}.Debug|ARM.Build.0 = Debug|ARM - {B26EEC5F-BBFF-3973-A459-AD3E5A33EF70}.Debug|ARM.Deploy.0 = Debug|ARM - {B26EEC5F-BBFF-3973-A459-AD3E5A33EF70}.Release|ARM.ActiveCfg = Release|ARM - {B26EEC5F-BBFF-3973-A459-AD3E5A33EF70}.Release|ARM.Build.0 = Release|ARM - {B26EEC5F-BBFF-3973-A459-AD3E5A33EF70}.Release|ARM.Deploy.0 = Release|ARM - {B26EEC5F-BBFF-3973-A459-AD3E5A33EF70}.RelWithDebInfo|ARM.ActiveCfg = RelWithDebInfo|ARM - {B26EEC5F-BBFF-3973-A459-AD3E5A33EF70}.RelWithDebInfo|ARM.Build.0 = RelWithDebInfo|ARM - {B26EEC5F-BBFF-3973-A459-AD3E5A33EF70}.RelWithDebInfo|ARM.Deploy.0 = RelWithDebInfo|ARM + {B848F924-651A-3EC7-8166-E5565290E1FB}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {B848F924-651A-3EC7-8166-E5565290E1FB}.Debug|ARM64.Build.0 = Debug|ARM64 + {B848F924-651A-3EC7-8166-E5565290E1FB}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {B848F924-651A-3EC7-8166-E5565290E1FB}.Release|ARM64.ActiveCfg = Release|ARM64 + {B848F924-651A-3EC7-8166-E5565290E1FB}.Release|ARM64.Build.0 = Release|ARM64 + {B848F924-651A-3EC7-8166-E5565290E1FB}.Release|ARM64.Deploy.0 = Release|ARM64 + {B848F924-651A-3EC7-8166-E5565290E1FB}.RelWithDebInfo|ARM64.ActiveCfg = RelWithDebInfo|ARM64 + {B848F924-651A-3EC7-8166-E5565290E1FB}.RelWithDebInfo|ARM64.Build.0 = RelWithDebInfo|ARM64 + {B848F924-651A-3EC7-8166-E5565290E1FB}.RelWithDebInfo|ARM64.Deploy.0 = RelWithDebInfo|ARM64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/player/sample/SamplePlayer.vcxproj b/player/sample/SamplePlayer.vcxproj index 321bc9f..55c1f7f 100644 --- a/player/sample/SamplePlayer.vcxproj +++ b/player/sample/SamplePlayer.vcxproj @@ -1,21 +1,25 @@  - + + + + x64 + - + Debug - ARM + ARM64 - + Release - ARM + ARM64 - + RelWithDebInfo - ARM + ARM64 - {B26EEC5F-BBFF-3973-A459-AD3E5A33EF70} + {B848F924-651A-3EC7-8166-E5565290E1FB} Windows Store en-US 10.0 @@ -24,67 +28,66 @@ 10.0.18362.0 10.0.17134.0 Win32Proj - ARM + ARM64 SamplePlayer NoUpgrade - + Application Unicode - v141 + v142 - + Application Unicode - v141 + v142 - + Application Unicode - v141 + v142 - <_ProjectFileVersion>10.0.20506.1 - .\bin\Debug\ - SamplePlayer.dir\Debug\ - SamplePlayer - .exe - true - true - .\bin\Release\ - SamplePlayer.dir\Release\ - SamplePlayer - .exe - false - true - .\bin\RelWithDebInfo\ - SamplePlayer.dir\RelWithDebInfo\ - SamplePlayer - .exe - true - true + .\bin\Debug\ + SamplePlayer.dir\Debug\ + SamplePlayer + .exe + true + true + .\bin\Release\ + SamplePlayer.dir\Release\ + SamplePlayer + .exe + false + true + .\bin\RelWithDebInfo\ + SamplePlayer.dir\RelWithDebInfo\ + SamplePlayer + .exe + true + true - + .;%(AdditionalIncludeDirectories) %(AdditionalOptions) /await $(VCIDEInstallDir)vcpackages;$(UniversalCRTSdkDir)UnionMetadata - Debug/ + $(IntDir) CompileAsCpp false ProgramDatabase - 4503;4311;4456;4458;4459;4499 + 4503 Sync ;%(ForcedUsingFiles) true @@ -98,11 +101,11 @@ true false Level3 - WIN32;_WINDOWS;UNICODE;_UNICODE;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_ARM;RDBUILD_ARCH_ARM_ARM32;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="Debug";%(PreprocessorDefinitions) + WIN32;_WINDOWS;UNICODE;_UNICODE;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_ARM;RDBUILD_ARCH_ARM_ARM64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="Debug";%(PreprocessorDefinitions) $(IntDir) - WIN32;_DEBUG;_WINDOWS;UNICODE;_UNICODE;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_ARM;RDBUILD_ARCH_ARM_ARM32;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"Debug\";%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;UNICODE;_UNICODE;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_ARM;RDBUILD_ARCH_ARM_ARM64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"Debug\";%(PreprocessorDefinitions) .;%(AdditionalIncludeDirectories) @@ -116,7 +119,7 @@ %(AdditionalDependencies) %(AdditionalLibraryDirectories) - %(AdditionalOptions) /machine:ARM + %(AdditionalOptions) /machine:ARM64 false true false @@ -130,17 +133,17 @@ false - + .;%(AdditionalIncludeDirectories) %(AdditionalOptions) /await $(VCIDEInstallDir)vcpackages;$(UniversalCRTSdkDir)UnionMetadata - Release/ + $(IntDir) CompileAsCpp false Guard ProgramDatabase - 4503;4311;4456;4458;4459;4499 + 4503 Sync ;%(ForcedUsingFiles) true @@ -154,11 +157,11 @@ true false Level3 - WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_ARM;RDBUILD_ARCH_ARM_ARM32;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="Release";%(PreprocessorDefinitions) + WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_ARM;RDBUILD_ARCH_ARM_ARM64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="Release";%(PreprocessorDefinitions) $(IntDir) - WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_ARM;RDBUILD_ARCH_ARM_ARM32;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"Release\";%(PreprocessorDefinitions) + WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_ARM;RDBUILD_ARCH_ARM_ARM64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"Release\";%(PreprocessorDefinitions) .;%(AdditionalIncludeDirectories) @@ -172,7 +175,7 @@ %(AdditionalDependencies) %(AdditionalLibraryDirectories) - %(AdditionalOptions) /machine:ARM + %(AdditionalOptions) /machine:ARM64 DebugFull false %(IgnoreSpecificDefaultLibraries) @@ -184,16 +187,16 @@ false - + .;%(AdditionalIncludeDirectories) %(AdditionalOptions) /await $(VCIDEInstallDir)vcpackages;$(UniversalCRTSdkDir)UnionMetadata - RelWithDebInfo/ + $(IntDir) CompileAsCpp false ProgramDatabase - 4503;4311;4456;4458;4459;4499 + 4503 Sync ;%(ForcedUsingFiles) true @@ -207,11 +210,11 @@ true false Level3 - WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_ARM;RDBUILD_ARCH_ARM_ARM32;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="RelWithDebInfo";%(PreprocessorDefinitions) + WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_ARM;RDBUILD_ARCH_ARM_ARM64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="RelWithDebInfo";%(PreprocessorDefinitions) $(IntDir) - WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_ARM;RDBUILD_ARCH_ARM_ARM32;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"RelWithDebInfo\";%(PreprocessorDefinitions) + WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_ARM;RDBUILD_ARCH_ARM_ARM64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"RelWithDebInfo\";%(PreprocessorDefinitions) .;%(AdditionalIncludeDirectories) @@ -225,7 +228,7 @@ %(AdditionalDependencies) %(AdditionalLibraryDirectories) - %(AdditionalOptions) /machine:ARM + %(AdditionalOptions) /machine:ARM64 false true false @@ -246,12 +249,16 @@ - - + + + + + + @@ -261,97 +268,101 @@ .\%(FileName)%(Extension) - true - true - true + true + true + true Assets\%(FileName)%(Extension) - true - true - true + true + true + true Assets\%(FileName)%(Extension) - true - true - true + true + true + true Assets\%(FileName)%(Extension) - true - true - true + true + true + true Assets\%(FileName)%(Extension) - true - true - true + true + true + true Assets\%(FileName)%(Extension) - true - true - true + true + true + true Assets\%(FileName)%(Extension) - true - true - true + true + true + true Assets\%(FileName)%(Extension) - true - true - true + true + true + true Vertex main 5.0 - .\shaders\%(Filename).h - .\shaders\%(Filename).h - .\shaders\%(Filename).h - %(Filename) - %(Filename) - %(Filename) + .\shaders\%(Filename).h + .\shaders\%(Filename).h + .\shaders\%(Filename).h + %(Filename) + %(Filename) + %(Filename) Vertex main 5.0 - .\shaders\%(Filename).h - .\shaders\%(Filename).h - .\shaders\%(Filename).h - %(Filename) - %(Filename) - %(Filename) + .\shaders\%(Filename).h + .\shaders\%(Filename).h + .\shaders\%(Filename).h + %(Filename) + %(Filename) + %(Filename) Pixel main 5.0 - .\shaders\%(Filename).h - .\shaders\%(Filename).h - .\shaders\%(Filename).h - %(Filename) - %(Filename) - %(Filename) + .\shaders\%(Filename).h + .\shaders\%(Filename).h + .\shaders\%(Filename).h + %(Filename) + %(Filename) + %(Filename) Geometry main 5.0 - .\shaders\%(Filename).h - .\shaders\%(Filename).h - .\shaders\%(Filename).h - %(Filename) - %(Filename) - %(Filename) + .\shaders\%(Filename).h + .\shaders\%(Filename).h + .\shaders\%(Filename).h + %(Filename) + %(Filename) + %(Filename) + + + + \ No newline at end of file diff --git a/player/sample/SamplePlayerMain.cpp b/player/sample/SamplePlayerMain.cpp index aedeb6b..a42d941 100644 --- a/player/sample/SamplePlayerMain.cpp +++ b/player/sample/SamplePlayerMain.cpp @@ -13,10 +13,14 @@ #include "SamplePlayerMain.h" +#include "../common/CameraResources.h" #include "../common/Content/DDSTextureLoader.h" +#include "../common/PlayerUtil.h" #include +#include + using namespace std::chrono_literals; using namespace winrt::Microsoft::Holographic::AppRemoting; @@ -30,7 +34,11 @@ using namespace winrt::Windows::Perception::Spatial; using namespace winrt::Windows::UI::Core; using namespace winrt::Windows::UI::Input::Spatial; - +SamplePlayerMain::SamplePlayerMain() +{ + m_canCommitDirect3D11DepthBuffer = winrt::Windows::Foundation::Metadata::ApiInformation::IsMethodPresent( + L"Windows.Graphics.Holographic.HolographicCameraRenderingParameters", L"CommitDirect3D11DepthBuffer"); +} SamplePlayerMain::~SamplePlayerMain() { Uninitialize(); @@ -127,8 +135,8 @@ HolographicFrame SamplePlayerMain::Update(float deltaTimeInSeconds) HolographicCameraRenderingParameters renderingParameters = holographicFrame.GetRenderingParameters(cameraPose); // Set the focus point for image stabilization to the center of the status display. - // NOTE: By doing this before the call to PlayerContext::BlitRemoteFrame (in the Render() method), - // the focus point can be overriden by the remote side. + // NOTE: The focus point set here will be overwritten with the focus point from the remote side by BlitRemoteFrame or + // ignored if a depth buffer is commited (see HolographicRemotingPlayerMain::Render for details). renderingParameters.SetFocusPoint(coordinateSystem, m_statusDisplay->GetPosition()); } } @@ -147,7 +155,7 @@ HolographicFrame SamplePlayerMain::Update(float deltaTimeInSeconds) } else { - StatusDisplay::Line line = {std::move(statisticsString), StatusDisplay::Small, StatusDisplay::Yellow, 1.0f, true}; + StatusDisplay::Line line = {std::move(statisticsString), StatusDisplay::Medium, StatusDisplay::Yellow, 1.0f, true}; m_statusDisplay->AddLine(line); } } @@ -156,7 +164,7 @@ HolographicFrame SamplePlayerMain::Update(float deltaTimeInSeconds) { if (m_playerOptions.m_listen) { - auto deviceIpNew = m_ipAddressUpdater.GetIpAddress(); + auto deviceIpNew = m_ipAddressUpdater.GetIpAddress(m_playerOptions.m_ipv6); if (m_deviceIp != deviceIpNew) { m_deviceIp = deviceIpNew; @@ -209,12 +217,30 @@ void SamplePlayerMain::Render(const HolographicFrame& holographicFrame) deviceContext->ClearRenderTargetView(targets[0], DirectX::Colors::Transparent); deviceContext->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); - // 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. if (coordinateSystem) { + // 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, coordinateSystem); + + const bool connected = (m_playerContext.ConnectionState() == ConnectionState::Connected); + + // Reduce the fov of the statistics view. + float quadFov = m_statusDisplay->GetDefaultQuadFov(); + float quadRatio = 1.0f; + if (m_playerOptions.m_showStatistics && connected && !m_trackingLost) + { + quadFov = m_statusDisplay->GetStatisticsFov(); + quadRatio = m_statusDisplay->GetStatisticsHeightRatio(); + } + // Pass data from the camera resources to the status display. + m_statusDisplay->UpdateTextScale( + pCameraResources->GetProjectionTransform(), + pCameraResources->GetRenderTargetSize().Width, + pCameraResources->GetRenderTargetSize().Height, + quadFov, + quadRatio); } // Attach the view/projection constant buffer for this camera to the graphics pipeline. @@ -223,6 +249,8 @@ void SamplePlayerMain::Render(const HolographicFrame& holographicFrame) // Only render world-locked content when positional tracking is active. if (cameraActive) { + bool depthAvailable = false; + try { if (m_playerContext.ConnectionState() == ConnectionState::Connected) @@ -230,7 +258,11 @@ void SamplePlayerMain::Render(const HolographicFrame& holographicFrame) // Blit the remote frame into the backbuffer for the HolographicFrame. // NOTE: This overwrites the focus point for the current frame, if the remote application // has specified a focus point during the rendering of the remote frame. - m_playerContext.BlitRemoteFrame(); + if (m_playerContext.BlitRemoteFrame() == BlitResult::Success_Color_Depth) + { + // In case of Success_Color_Depth a depth buffer has been committed by the remote application. + depthAvailable = true; + } } } catch (winrt::hresult_error err) @@ -240,8 +272,23 @@ void SamplePlayerMain::Render(const HolographicFrame& holographicFrame) UpdateStatusDisplay(); } - // Draw connection status and/or statistics. - m_statusDisplay->Render(); + // Render local content. + { + // NOTE: Any local custom content would be rendered here. + + // Draw connection status and/or statistics. + m_statusDisplay->Render(); + } + + // Commit depth buffer if available. + // NOTE: CommitDirect3D11DepthBuffer should be the last thing before the frame is presented. By doing so the depth + // buffer submitted include remote content and local content. + if (m_canCommitDirect3D11DepthBuffer && depthAvailable) + { + auto interopSurface = pCameraResources->GetDepthStencilTextureInteropObject(); + HolographicCameraRenderingParameters renderingParameters = holographicFrame.GetRenderingParameters(cameraPose); + renderingParameters.CommitDirect3D11DepthBuffer(interopSurface); + } } atLeastOneCameraRendered = true; @@ -274,7 +321,7 @@ void SamplePlayerMain::Initialize(const CoreApplicationView& applicationView) m_suspendingEventRevoker = CoreApplication::Suspending(winrt::auto_revoke, {this, &SamplePlayerMain::OnSuspending}); m_resumingEventRevoker = CoreApplication::Resuming(winrt::auto_revoke, {this, &SamplePlayerMain::OnResuming}); - m_deviceResources = std::make_shared(); + m_deviceResources = std::make_shared(); m_deviceResources->RegisterDeviceNotify(this); m_spatialLocator = SpatialLocator::GetDefault(); @@ -295,6 +342,9 @@ void SamplePlayerMain::Initialize(const CoreApplicationView& applicationView) // Set the BlitRemoteFrame timeout to 0.5s m_playerContext.BlitRemoteFrameTimeout(500ms); + + // Projection transform always reflects what has been configured on the remote side. + m_playerContext.ProjectionTransformConfig(ProjectionTransformMode::Remote); } void SamplePlayerMain::SetWindow(const CoreWindow& window) @@ -315,7 +365,7 @@ void SamplePlayerMain::SetWindow(const CoreWindow& window) { m_playerContext.OnDataChannelCreated([this](const IDataChannel& dataChannel, uint8_t channelId) { std::lock_guard lock(m_customDataChannelLock); - m_customDataChannel = dataChannel; + m_customDataChannel = dataChannel.as(); m_customChannelDataReceivedEventRevoker = m_customDataChannel.OnDataReceived( winrt::auto_revoke, [this](winrt::array_view dataView) { OnCustomDataChannelDataReceived(); }); @@ -436,7 +486,7 @@ void SamplePlayerMain::LoadLogoImage() SamplePlayerMain::PlayerOptions SamplePlayerMain::ParseActivationArgs(const IActivatedEventArgs& activationArgs) { std::wstring host = L""; - int32_t port = 0; + uint16_t port = 0; bool listen = false; bool showStatistics = false; @@ -479,19 +529,7 @@ SamplePlayerMain::PlayerOptions SamplePlayerMain::ParseActivationArgs(const IAct continue; } - size_t colonPos = arg.find(L':'); - if (colonPos != std::wstring::npos) - { - std::wstring portStr = arg.substr(colonPos + 1); - - host = arg.substr(0, colonPos); - port = std::wcstol(portStr.c_str(), nullptr, 10); - } - else - { - host = arg.c_str(); - port = 0; - } + host = PlayerUtil::SplitHostnameAndPortString(arg, port); } break; } @@ -558,6 +596,7 @@ SamplePlayerMain::PlayerOptions SamplePlayerMain::ParseActivationArgs(const IAct playerOptions.m_port = port; playerOptions.m_listen = listen; playerOptions.m_showStatistics = showStatistics; + playerOptions.m_ipv6 = hostname.front() == L'['; return playerOptions; } @@ -568,12 +607,10 @@ void SamplePlayerMain::UpdateStatusDisplay() if (m_trackingLost) { - StatusDisplay::Line lines[] = {StatusDisplay::Line{L"Device Tracking Lost", StatusDisplay::LargeBold, StatusDisplay::White, 1.2f}, - StatusDisplay::Line{L"Ensure your environment is properly lit\r\n" - L"and the device's sensors are not covered.", - StatusDisplay::Small, - StatusDisplay::White, - 6.0f}}; + StatusDisplay::Line lines[] = { + StatusDisplay::Line{L"Device Tracking Lost", StatusDisplay::LargeBold, StatusDisplay::White, 1.0f}, + StatusDisplay::Line{L"Ensure your environment is properly lit", StatusDisplay::Small, StatusDisplay::White, 1.0f}, + StatusDisplay::Line{L"and the device's sensors are not covered.", StatusDisplay::Small, StatusDisplay::White, 12.0f}}; m_statusDisplay->SetLines(lines); } else @@ -581,15 +618,14 @@ void SamplePlayerMain::UpdateStatusDisplay() if (m_playerContext.ConnectionState() != ConnectionState::Connected) { StatusDisplay::Line lines[] = { - StatusDisplay::Line{L"Sample Holographic Remoting Player", StatusDisplay::LargeBold, StatusDisplay::White, 1.2f}, - StatusDisplay::Line{L"This app is a sample companion for Holographic Remoting apps.\r\n" - L"Connect from a compatible app to begin.", - StatusDisplay::Small, - StatusDisplay::White, - 6.0f}, - StatusDisplay::Line{m_playerOptions.m_listen ? L"Waiting for connection on" : L"Connecting to", - StatusDisplay::Large, - StatusDisplay::White}}; + StatusDisplay::Line{L"Holographic Remoting Player", StatusDisplay::LargeBold, StatusDisplay::White, 1.0f}, + StatusDisplay::Line{ + L"This app is a companion for Holographic Remoting apps.", StatusDisplay::Small, StatusDisplay::White, 1.0f}, + StatusDisplay::Line{L"Connect from a compatible app to begin.", StatusDisplay::Small, StatusDisplay::White, 8.0f}, + StatusDisplay::Line{ + m_playerOptions.m_listen ? L"Waiting for connection on" : L"Connecting to", + StatusDisplay::Large, + StatusDisplay::White}}; m_statusDisplay->SetLines(lines); std::wostringstream addressLine; @@ -598,13 +634,15 @@ void SamplePlayerMain::UpdateStatusDisplay() { addressLine << L":" << m_playerOptions.m_port; } - m_statusDisplay->AddLine(StatusDisplay::Line{addressLine.str(), StatusDisplay::LargeBold, StatusDisplay::White}); - } - } + m_statusDisplay->AddLine(StatusDisplay::Line{addressLine.str(), StatusDisplay::Large, StatusDisplay::White}); + m_statusDisplay->AddLine( + StatusDisplay::Line{L"Get help at: https://aka.ms/holographicremotinghelp", StatusDisplay::Small, StatusDisplay::White}); - if (m_playerOptions.m_showStatistics) - { - m_statusDisplay->AddLine(StatusDisplay::Line{L"Diagnostics Enabled", StatusDisplay::Small, StatusDisplay::Yellow}); + if (m_playerOptions.m_showStatistics) + { + m_statusDisplay->AddLine(StatusDisplay::Line{L"Diagnostics Enabled", StatusDisplay::Small, StatusDisplay::Yellow}); + } + } } m_errorHelper.Apply(m_statusDisplay); @@ -619,8 +657,25 @@ void SamplePlayerMain::OnCustomDataChannelDataReceived() std::lock_guard customDataChannelLockGuard(m_customDataChannelLock); if (m_customDataChannel) { - uint8_t data[] = {1}; - m_customDataChannel.SendData(data, true); + // Get send queue size. The send queue size returns the size of data, that has not been send yet, in bytes. A big number can + // indicate that more data is being queued for sending than is actually getting sent. If possible skip sending data in this + // case, to help the queue getting smaller again. + uint32_t sendQueueSize = m_customDataChannel.SendQueueSize(); + + // Only send the packet if the send queue is smaller than 1MiB + if (sendQueueSize < 1 * 1024 * 1024) + { + uint8_t data[] = {1}; + + try + { + m_customDataChannel.SendData(data, true); + } + catch (...) + { + // SendData might throw if channel is closed, but we did not get or process the async closed event yet. + } + } } } @@ -751,6 +806,7 @@ void SamplePlayerMain::OnWindowClosed(const CoreWindow& sender, const CoreWindow int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) { winrt::init_apartment(); - CoreApplication::Run(SamplePlayerMain()); + winrt::com_ptr main = winrt::make_self(); + CoreApplication::Run(*main); return 0; } diff --git a/player/sample/SamplePlayerMain.h b/player/sample/SamplePlayerMain.h index 9003560..e8f93e4 100644 --- a/player/sample/SamplePlayerMain.h +++ b/player/sample/SamplePlayerMain.h @@ -15,14 +15,12 @@ #include "../common/Content/ErrorHelper.h" #include "../common/Content/StatusDisplay.h" -#include "../common/DeviceResources.h" +#include "../common/DeviceResourcesUWP.h" #include "../common/IpAddressUpdater.h" #include "../common/PlayerFrameStatisticsHelper.h" #include - - class SamplePlayerMain : public winrt::implements< SamplePlayerMain, winrt::Windows::ApplicationModel::Core::IFrameworkViewSource, @@ -30,6 +28,7 @@ class SamplePlayerMain : public winrt::implements< public DXHelper::IDeviceNotify { public: + SamplePlayerMain(); ~SamplePlayerMain(); // Try to (re-)connect to or listen on the hostname/port, that was set during activation of the app. @@ -67,6 +66,7 @@ private: uint16_t m_port = 0; bool m_listen = true; bool m_showStatistics = false; + bool m_ipv6 = false; }; private: @@ -107,7 +107,7 @@ private: private: // Cached pointer to device resources. - std::shared_ptr m_deviceResources; + std::shared_ptr m_deviceResources; // SpatialLocator that is attached to the default HolographicDisplay. winrt::Windows::Perception::Spatial::SpatialLocator m_spatialLocator = nullptr; @@ -139,9 +139,9 @@ private: #ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE std::mutex m_customDataChannelLock; - winrt::Microsoft::Holographic::AppRemoting::IDataChannel m_customDataChannel = nullptr; - winrt::Microsoft::Holographic::AppRemoting::IDataChannel::OnDataReceived_revoker m_customChannelDataReceivedEventRevoker; - winrt::Microsoft::Holographic::AppRemoting::IDataChannel::OnClosed_revoker m_customChannelClosedEventRevoker; + winrt::Microsoft::Holographic::AppRemoting::IDataChannel2 m_customDataChannel = nullptr; + winrt::Microsoft::Holographic::AppRemoting::IDataChannel2::OnDataReceived_revoker m_customChannelDataReceivedEventRevoker; + winrt::Microsoft::Holographic::AppRemoting::IDataChannel2::OnClosed_revoker m_customChannelClosedEventRevoker; #endif // Indicates that tracking has been lost @@ -151,6 +151,8 @@ private: bool m_windowClosed = false; bool m_windowVisible = true; + bool m_canCommitDirect3D11DepthBuffer = false; + // Event registration revokers winrt::Windows::Perception::Spatial::SpatialLocator::LocatabilityChanged_revoker m_locatabilityChangedRevoker; winrt::Windows::ApplicationModel::Core::CoreApplication::Suspending_revoker m_suspendingEventRevoker; diff --git a/player/sample/packages.config b/player/sample/packages.config index 7e842e8..fe7c81c 100644 --- a/player/sample/packages.config +++ b/player/sample/packages.config @@ -1,4 +1,5 @@  - + + diff --git a/remote/desktop/Common/CameraResources.cpp b/remote/desktop/Common/CameraResources.cpp new file mode 100644 index 0000000..ed64cbe --- /dev/null +++ b/remote/desktop/Common/CameraResources.cpp @@ -0,0 +1,269 @@ +//********************************************************* +// +// 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 "CameraResources.h" +#include "DeviceResources.h" +#include "DirectXHelper.h" + +#include + +using namespace DirectX; +using namespace winrt::Windows::Graphics::Holographic; +using namespace winrt::Windows::Perception::Spatial; + +namespace DXHelper +{ + CameraResources::CameraResources(const 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 CameraResources::CreateResourcesForBackBuffer( + DeviceResources* pDeviceResources, const HolographicCameraRenderingParameters& cameraParameters) + { + const auto device = pDeviceResources->GetD3DDevice(); + + // 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. + winrt::com_ptr resource; + { + winrt::com_ptr<::IInspectable> inspectable = cameraParameters.Direct3D11BackBuffer().as<::IInspectable>(); + winrt::com_ptr dxgiInterfaceAccess; + + HRESULT hr = inspectable->QueryInterface(__uuidof(dxgiInterfaceAccess), dxgiInterfaceAccess.put_void()); + if (FAILED(hr)) + { + winrt::throw_hresult(hr); + } + + hr = dxgiInterfaceAccess->GetInterface(__uuidof(resource), resource.put_void()); + if (FAILED(hr)) + { + winrt::throw_hresult(hr); + } + } + + // Get a Direct3D interface for the holographic camera's back buffer. + winrt::com_ptr cameraBackBuffer; + 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 != cameraBackBuffer) + { + // 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; + + // 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; + + D3D11_RENDER_TARGET_VIEW_DESC viewDesc = {}; + viewDesc.ViewDimension = backBufferDesc.ArraySize > 1 ? D3D11_RTV_DIMENSION_TEXTURE2DARRAY : D3D11_RTV_DIMENSION_TEXTURE2D; + viewDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + if (backBufferDesc.ArraySize > 1) + { + viewDesc.Texture2DArray.ArraySize = backBufferDesc.ArraySize; + } + + // 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. + m_d3dRenderTargetView = nullptr; + winrt::check_hresult(device->CreateRenderTargetView(m_d3dBackBuffer.get(), &viewDesc, m_d3dRenderTargetView.put())); + + // Check for render target size changes. + winrt::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 = nullptr; + } + } + + // 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_R16_TYPELESS, + static_cast(m_d3dRenderTargetSize.Width), + static_cast(m_d3dRenderTargetSize.Height), + m_isStereo ? 2 : 1, // Create two textures when rendering in stereo. + 1, // Use a single mipmap level. + D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE); + + winrt::check_hresult(device->CreateTexture2D(&depthStencilDesc, nullptr, m_d3dDepthStencil.put())); + + CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc( + m_isStereo ? D3D11_DSV_DIMENSION_TEXTURE2DARRAY : D3D11_DSV_DIMENSION_TEXTURE2D); + depthStencilViewDesc.Format = DXGI_FORMAT_D16_UNORM; + + winrt::check_hresult( + device->CreateDepthStencilView(m_d3dDepthStencil.get(), &depthStencilViewDesc, m_d3dDepthStencilView.put())); + } + + // 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); + winrt::check_hresult(device->CreateBuffer(&constantBufferDesc, nullptr, m_viewProjectionConstantBuffer.put())); + } + } + + // Releases resources associated with a back buffer. + void CameraResources::ReleaseResourcesForBackBuffer(DeviceResources* pDeviceResources) + { + // Release camera-specific resources. + m_d3dBackBuffer = nullptr; + m_d3dDepthStencil = nullptr; + m_d3dRenderTargetView = nullptr; + m_d3dDepthStencilView = nullptr; + m_viewProjectionConstantBuffer = nullptr; + + // 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. + pDeviceResources->UseD3DDeviceContext([](auto 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 CameraResources::UpdateViewProjectionBuffer( + std::shared_ptr deviceResources, + const HolographicCameraPose& cameraPose, + const SpatialCoordinateSystem& coordinateSystem) + { + // The system changes the viewport on a per-frame basis for system optimizations. + m_d3dViewport = + CD3D11_VIEWPORT(cameraPose.Viewport().X, cameraPose.Viewport().Y, cameraPose.Viewport().Width, cameraPose.Viewport().Height); + + // The projection transform for each frame is provided by the HolographicCameraPose. + auto cameraProjectionTransform = cameraPose.ProjectionTransform(); + + // Get a container object with the view and projection matrices for the given + // pose in the given coordinate system. + auto 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. + ViewProjectionConstantBuffer viewProjectionConstantBufferData = {}; + bool viewTransformAcquired = viewTransformContainer != nullptr; + if (viewTransformAcquired) + { + // Otherwise, the set of view transforms can be retrieved. + auto 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. + deviceResources->UseD3DDeviceContext([&](auto context) { + // 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 CameraResources::AttachViewProjectionBuffer(std::shared_ptr deviceResources) + { + // This method uses Direct3D device-based resources. + return deviceResources->UseD3DDeviceContext([&](auto context) { + // 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. + ID3D11Buffer* pBuffer = m_viewProjectionConstantBuffer.get(); + context->VSSetConstantBuffers(1, 1, &pBuffer); + + // 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; + }); + } + + winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface CameraResources::GetDepthStencilTextureInteropObject() + { + // Direct3D interop APIs are used to provide the buffer to the WinRT API. + winrt::com_ptr depthStencilResource; + winrt::check_bool(m_d3dDepthStencil.try_as(depthStencilResource)); + winrt::com_ptr depthDxgiSurface; + winrt::check_hresult(depthStencilResource->CreateSubresourceSurface(0, depthDxgiSurface.put())); + winrt::com_ptr<::IInspectable> inspectableSurface; + winrt::check_hresult(CreateDirect3D11SurfaceFromDXGISurface( + depthDxgiSurface.get(), reinterpret_cast(winrt::put_abi(inspectableSurface)))); + return inspectableSurface.as(); + } +} // namespace DXHelper diff --git a/hostsampleapp/desktop/Common/CameraResources.h b/remote/desktop/Common/CameraResources.h similarity index 89% rename from hostsampleapp/desktop/Common/CameraResources.h rename to remote/desktop/Common/CameraResources.h index a1b560b..e277802 100644 --- a/hostsampleapp/desktop/Common/CameraResources.h +++ b/remote/desktop/Common/CameraResources.h @@ -1,115 +1,122 @@ -//********************************************************* -// -// 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 - -#include - -using namespace winrt::Windows::Graphics::Holographic; -using namespace winrt::Windows::Perception::Spatial; - -namespace DXHelper -{ - 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(const HolographicCamera& holographicCamera); - - void CreateResourcesForBackBuffer( - DXHelper::DeviceResources* pDeviceResources, const HolographicCameraRenderingParameters& cameraParameters); - void ReleaseResourcesForBackBuffer(DXHelper::DeviceResources* pDeviceResources); - - void UpdateViewProjectionBuffer( - std::shared_ptr deviceResources, - const HolographicCameraPose& cameraPose, - const SpatialCoordinateSystem& coordinateSystem); - - bool AttachViewProjectionBuffer(std::shared_ptr 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. - winrt::Windows::Foundation::Size GetRenderTargetSize() const - { - return m_d3dRenderTargetSize; - } - bool IsRenderingStereoscopic() const - { - return m_isStereo; - } - - // The holographic camera these resources are for. - const HolographicCamera& GetHolographicCamera() const - { - return m_holographicCamera; - } - - private: - // Direct3D rendering objects. Required for 3D. - winrt::com_ptr m_d3dRenderTargetView; - winrt::com_ptr m_d3dDepthStencilView; - winrt::com_ptr m_d3dBackBuffer; - - // Device resource to store view and projection matrices. - winrt::com_ptr m_viewProjectionConstantBuffer; - - // Direct3D rendering properties. - DXGI_FORMAT m_dxgiFormat; - winrt::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. - HolographicCamera m_holographicCamera = nullptr; - }; -} // namespace DXHelper +//********************************************************* +// +// 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 + +#include + +using namespace winrt::Windows::Graphics::Holographic; +using namespace winrt::Windows::Perception::Spatial; + +namespace DXHelper +{ + 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(const HolographicCamera& holographicCamera); + + void CreateResourcesForBackBuffer( + DXHelper::DeviceResources* pDeviceResources, const HolographicCameraRenderingParameters& cameraParameters); + void ReleaseResourcesForBackBuffer(DXHelper::DeviceResources* pDeviceResources); + + void UpdateViewProjectionBuffer( + std::shared_ptr deviceResources, + const HolographicCameraPose& cameraPose, + const SpatialCoordinateSystem& coordinateSystem); + + bool AttachViewProjectionBuffer(std::shared_ptr 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(); + } + ID3D11Texture2D* GetDepthStencilTexture2D() const + { + return m_d3dDepthStencil.get(); + } + D3D11_VIEWPORT GetViewport() const + { + return m_d3dViewport; + } + DXGI_FORMAT GetBackBufferDXGIFormat() const + { + return m_dxgiFormat; + } + + // Render target properties. + winrt::Windows::Foundation::Size GetRenderTargetSize() const + { + return m_d3dRenderTargetSize; + } + bool IsRenderingStereoscopic() const + { + return m_isStereo; + } + + // The holographic camera these resources are for. + const HolographicCamera& GetHolographicCamera() const + { + return m_holographicCamera; + } + + winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface GetDepthStencilTextureInteropObject(); + + private: + // Direct3D rendering objects. Required for 3D. + winrt::com_ptr m_d3dRenderTargetView; + winrt::com_ptr m_d3dDepthStencilView; + winrt::com_ptr m_d3dBackBuffer; + winrt::com_ptr m_d3dDepthStencil; + + // Device resource to store view and projection matrices. + winrt::com_ptr m_viewProjectionConstantBuffer; + + // Direct3D rendering properties. + DXGI_FORMAT m_dxgiFormat = DXGI_FORMAT_UNKNOWN; + winrt::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. + HolographicCamera m_holographicCamera = nullptr; + }; +} // namespace DXHelper diff --git a/hostsampleapp/uwp/Common/DbgLog.h b/remote/desktop/Common/DbgLog.h similarity index 96% rename from hostsampleapp/uwp/Common/DbgLog.h rename to remote/desktop/Common/DbgLog.h index d229cb8..f6648b1 100644 --- a/hostsampleapp/uwp/Common/DbgLog.h +++ b/remote/desktop/Common/DbgLog.h @@ -1,37 +1,37 @@ -//********************************************************* -// -// 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 - -static void DebugLog(_In_z_ LPCWSTR format, ...) -{ - wchar_t buffer[1024]; - LPWSTR bufEnd = nullptr; - - va_list args; - va_start(args, format); - HRESULT hr = - StringCchVPrintfExW(buffer, _countof(buffer), &bufEnd, nullptr, STRSAFE_FILL_BEHIND_NULL | STRSAFE_FILL_ON_FAILURE, format, args); - - if (SUCCEEDED(hr)) - { - if (*bufEnd != L'\n') - { - StringCchCatW(buffer, _countof(buffer), L"\r\n"); - } - - OutputDebugStringW(buffer); - } - - va_end(args); -} +//********************************************************* +// +// 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 + +static void DebugLog(_In_z_ LPCWSTR format, ...) +{ + wchar_t buffer[1024]; + LPWSTR bufEnd = nullptr; + + va_list args; + va_start(args, format); + HRESULT hr = + StringCchVPrintfExW(buffer, _countof(buffer), &bufEnd, nullptr, STRSAFE_FILL_BEHIND_NULL | STRSAFE_FILL_ON_FAILURE, format, args); + + if (SUCCEEDED(hr)) + { + if (*bufEnd != L'\n') + { + StringCchCatW(buffer, _countof(buffer), L"\r\n"); + } + + OutputDebugStringW(buffer); + } + + va_end(args); +} diff --git a/hostsampleapp/uwp/Common/DeviceResources.cpp b/remote/desktop/Common/DeviceResources.cpp similarity index 93% rename from hostsampleapp/uwp/Common/DeviceResources.cpp rename to remote/desktop/Common/DeviceResources.cpp index 8165604..bb2162e 100644 --- a/hostsampleapp/uwp/Common/DeviceResources.cpp +++ b/remote/desktop/Common/DeviceResources.cpp @@ -1,304 +1,305 @@ -//********************************************************* -// -// 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 "DeviceResources.h" -#include "DirectXHelper.h" - -#include - -using namespace D2D1; -using namespace Microsoft::WRL; -using namespace winrt::Windows::Graphics::DirectX::Direct3D11; -using namespace winrt::Windows::Graphics::Display; -using namespace winrt::Windows::Graphics::Holographic; - -// Constructor for DeviceResources. -DXHelper::DeviceResources::DeviceResources() -{ - CreateDeviceIndependentResources(); -} - -DXHelper::DeviceResources::~DeviceResources() -{ - if (m_d3dContext) - { - m_d3dContext->Flush(); - m_d3dContext->ClearState(); - } -} - -// Configures resources that don't depend on the Direct3D device. -void DXHelper::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. - winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory2), &options, m_d2dFactory.put_void())); - - // Initialize the DirectWrite Factory. - winrt::check_hresult( - DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), (::IUnknown**)m_dwriteFactory.put_void())); - - // Initialize the Windows Imaging Component (WIC) Factory. - winrt::check_hresult( - CoCreateInstance(CLSID_WICImagingFactory2, nullptr, CLSCTX_INPROC_SERVER, __uuidof(m_wicFactory), m_wicFactory.put_void())); -} - -void DXHelper::DeviceResources::SetHolographicSpace(HolographicSpace holographicSpace) -{ - // Cache the holographic space. Used to re-initalize during device-lost scenarios. - m_holographicSpace = holographicSpace; - - InitializeUsingHolographicSpace(); -} - -void DXHelper::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 (DXHelper::SdkLayersAvailable()) - { - createFlags |= DXGI_CREATE_FACTORY_DEBUG; - } -#endif - // Create the DXGI factory. - winrt::com_ptr dxgiFactory; - winrt::check_hresult(CreateDXGIFactory2(createFlags, __uuidof(dxgiFactory), dxgiFactory.put_void())); - winrt::com_ptr dxgiFactory4; - dxgiFactory.as(dxgiFactory4); - - // Retrieve the adapter specified by the holographic space. - winrt::check_hresult(dxgiFactory4->EnumAdapterByLuid(id, __uuidof(m_dxgiAdapter), m_dxgiAdapter.put_void())); - } - else - { - m_dxgiAdapter = nullptr; - } - - CreateDeviceResources(); - - m_holographicSpace.SetDirect3D11Device(m_d3dInteropDevice); -} - -// Configures the Direct3D device, and stores handles to it and the device context. -void DXHelper::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 (DXHelper::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. - winrt::com_ptr device; - winrt::com_ptr context; - - const D3D_DRIVER_TYPE driverType = m_dxgiAdapter == nullptr ? D3D_DRIVER_TYPE_HARDWARE : D3D_DRIVER_TYPE_UNKNOWN; - const HRESULT hr = D3D11CreateDevice( - m_dxgiAdapter.get(), // Either nullptr, or the primary adapter determined by Windows Holographic. - driverType, // 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 Runtime apps. - device.put(), // Returns the Direct3D device created. - &m_d3dFeatureLevel, // Returns feature level of device created. - context.put() // 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 - winrt::check_hresult(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.put(), - &m_d3dFeatureLevel, - context.put())); - } - - // Store pointers to the Direct3D device and immediate context. - device.as(m_d3dDevice); - context.as(m_d3dContext); - - // Acquire the DXGI interface for the Direct3D device. - winrt::com_ptr dxgiDevice; - m_d3dDevice.as(dxgiDevice); - - // Wrap the native device using a WinRT interop object. - winrt::com_ptr<::IInspectable> object; - winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.get(), reinterpret_cast(winrt::put_abi(object)))); - m_d3dInteropDevice = object.as(); - - // Cache the DXGI adapter. - // This is for the case of no preferred DXGI adapter, or fallback to WARP. - winrt::com_ptr dxgiAdapter; - dxgiDevice->GetAdapter(dxgiAdapter.put()); - 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 DXHelper::DeviceResources::EnsureCameraResources(HolographicFrame frame, HolographicFramePrediction prediction) -{ - UseHolographicCameraResources([this, frame, prediction](std::map>& cameraResourceMap) { - for (HolographicCameraPose const& cameraPose : prediction.CameraPoses()) - { - try - { - HolographicCameraRenderingParameters renderingParameters = frame.GetRenderingParameters(cameraPose); - CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get(); - pCameraResources->CreateResourcesForBackBuffer(this, renderingParameters); - } - catch (const winrt::hresult_error&) - { - } - } - }); -} - -// Prepares to allocate resources and adds resource views for a camera. -// Locks the set of holographic camera resources until the function exits. -void DXHelper::DeviceResources::AddHolographicCamera(HolographicCamera camera) -{ - UseHolographicCameraResources([this, camera](std::map>& cameraResourceMap) { - cameraResourceMap[camera.Id()] = std::make_unique(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 DXHelper::DeviceResources::RemoveHolographicCamera(HolographicCamera camera) -{ - UseHolographicCameraResources([this, camera](std::map>& 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 DXHelper::DeviceResources::HandleDeviceLost() -{ - if (m_deviceNotify != nullptr) - { - m_deviceNotify->OnDeviceLost(); - } - - UseHolographicCameraResources([this](std::map>& 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 DXHelper::DeviceResources::RegisterDeviceNotify(DXHelper::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 DXHelper::DeviceResources::Trim() -{ - m_d3dContext->ClearState(); - - winrt::com_ptr dxgiDevice; - 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 DXHelper::DeviceResources::Present(HolographicFrame frame) -{ - // By default, this API waits for the frame to finish before it returns. - // For Holographic Remoting we do not wait but instead wait in SampleHostMain::Update to ensure that CreateNextFrame is called exactly - // with a delta of 16.6ms (in case of 60Hz). - HolographicFramePresentResult presentResult = - frame.PresentUsingCurrentPrediction(HolographicFramePresentWaitBehavior::DoNotWaitForFrameToFinish); - - // 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(); - } -} +//********************************************************* +// +// 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 "DeviceResources.h" +#include "DirectXHelper.h" + +#include + +using namespace D2D1; +using namespace Microsoft::WRL; +using namespace winrt::Windows::Graphics::DirectX::Direct3D11; +using namespace winrt::Windows::Graphics::Display; +using namespace winrt::Windows::Graphics::Holographic; + +// Constructor for DeviceResources. +DXHelper::DeviceResources::DeviceResources() +{ + CreateDeviceIndependentResources(); +} + +DXHelper::DeviceResources::~DeviceResources() +{ + if (m_d3dContext) + { + m_d3dContext->Flush(); + m_d3dContext->ClearState(); + } +} + +// Configures resources that don't depend on the Direct3D device. +void DXHelper::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. + winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory2), &options, m_d2dFactory.put_void())); + + // Initialize the DirectWrite Factory. + winrt::check_hresult( + DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), (::IUnknown**)m_dwriteFactory.put_void())); + + // Initialize the Windows Imaging Component (WIC) Factory. + winrt::check_hresult( + CoCreateInstance(CLSID_WICImagingFactory2, nullptr, CLSCTX_INPROC_SERVER, __uuidof(m_wicFactory), m_wicFactory.put_void())); +} + +void DXHelper::DeviceResources::SetHolographicSpace(HolographicSpace holographicSpace) +{ + // Cache the holographic space. Used to re-initalize during device-lost scenarios. + m_holographicSpace = holographicSpace; + + InitializeUsingHolographicSpace(); +} + +void DXHelper::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 (DXHelper::SdkLayersAvailable()) + { + createFlags |= DXGI_CREATE_FACTORY_DEBUG; + } +#endif + // Create the DXGI factory. + winrt::com_ptr dxgiFactory; + winrt::check_hresult(CreateDXGIFactory2(createFlags, __uuidof(dxgiFactory), dxgiFactory.put_void())); + winrt::com_ptr dxgiFactory4; + dxgiFactory.as(dxgiFactory4); + + // Retrieve the adapter specified by the holographic space. + winrt::check_hresult(dxgiFactory4->EnumAdapterByLuid(id, __uuidof(m_dxgiAdapter), m_dxgiAdapter.put_void())); + } + else + { + m_dxgiAdapter = nullptr; + } + + CreateDeviceResources(); + + m_holographicSpace.SetDirect3D11Device(m_d3dInteropDevice); +} + +// Configures the Direct3D device, and stores handles to it and the device context. +void DXHelper::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 (DXHelper::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. + winrt::com_ptr device; + winrt::com_ptr context; + + const D3D_DRIVER_TYPE driverType = m_dxgiAdapter == nullptr ? D3D_DRIVER_TYPE_HARDWARE : D3D_DRIVER_TYPE_UNKNOWN; + const HRESULT hr = D3D11CreateDevice( + m_dxgiAdapter.get(), // Either nullptr, or the primary adapter determined by Windows Holographic. + driverType, // 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 Runtime apps. + device.put(), // Returns the Direct3D device created. + &m_d3dFeatureLevel, // Returns feature level of device created. + context.put() // 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 + winrt::check_hresult(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.put(), + &m_d3dFeatureLevel, + context.put())); + } + + // Store pointers to the Direct3D device and immediate context. + device.as(m_d3dDevice); + context.as(m_d3dContext); + + // Acquire the DXGI interface for the Direct3D device. + winrt::com_ptr dxgiDevice; + m_d3dDevice.as(dxgiDevice); + + // Wrap the native device using a WinRT interop object. + winrt::com_ptr<::IInspectable> object; + winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.get(), reinterpret_cast(winrt::put_abi(object)))); + m_d3dInteropDevice = object.as(); + + // Cache the DXGI adapter. + // This is for the case of no preferred DXGI adapter, or fallback to WARP. + winrt::com_ptr dxgiAdapter; + dxgiDevice->GetAdapter(dxgiAdapter.put()); + 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 DXHelper::DeviceResources::EnsureCameraResources(HolographicFrame frame, HolographicFramePrediction prediction) +{ + UseHolographicCameraResources([this, frame, prediction](std::map>& cameraResourceMap) { + for (HolographicCameraPose const& cameraPose : prediction.CameraPoses()) + { + try + { + HolographicCameraRenderingParameters renderingParameters = frame.GetRenderingParameters(cameraPose); + CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get(); + pCameraResources->CreateResourcesForBackBuffer(this, renderingParameters); + } + catch (const winrt::hresult_error&) + { + } + } + }); +} + +// Prepares to allocate resources and adds resource views for a camera. +// Locks the set of holographic camera resources until the function exits. +void DXHelper::DeviceResources::AddHolographicCamera(HolographicCamera camera) +{ + UseHolographicCameraResources([this, camera](std::map>& cameraResourceMap) { + cameraResourceMap[camera.Id()] = std::make_unique(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 DXHelper::DeviceResources::RemoveHolographicCamera(HolographicCamera camera) +{ + UseHolographicCameraResources([this, camera](std::map>& 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 DXHelper::DeviceResources::HandleDeviceLost() +{ + if (m_deviceNotify != nullptr) + { + m_deviceNotify->OnDeviceLost(); + } + + UseHolographicCameraResources([this](std::map>& 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 DXHelper::DeviceResources::RegisterDeviceNotify(DXHelper::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 DXHelper::DeviceResources::Trim() +{ + m_d3dContext->ClearState(); + + winrt::com_ptr dxgiDevice; + 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 DXHelper::DeviceResources::Present(HolographicFrame frame) +{ + // By default, this API waits for the frame to finish before it returns. + // For Holographic Remoting we do not wait but instead wait in SampleRemoteMain::Update to ensure that CreateNextFrame is called exactly + // with a delta of 16.6ms (in case of 60Hz). + HolographicFramePresentResult presentResult = + frame.PresentUsingCurrentPrediction(HolographicFramePresentWaitBehavior::DoNotWaitForFrameToFinish); + + // 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(); + } +} diff --git a/hostsampleapp/desktop/Common/DeviceResources.h b/remote/desktop/Common/DeviceResources.h similarity index 97% rename from hostsampleapp/desktop/Common/DeviceResources.h rename to remote/desktop/Common/DeviceResources.h index a4feb62..3071fb6 100644 --- a/hostsampleapp/desktop/Common/DeviceResources.h +++ b/remote/desktop/Common/DeviceResources.h @@ -1,156 +1,157 @@ -//********************************************************* -// -// 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 "CameraResources.h" - -#include -#include -#include -#include -#include - -namespace DXHelper -{ - // 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(); - ~DeviceResources(); - - // Public methods related to Direct3D devices. - void HandleDeviceLost(); - void RegisterDeviceNotify(IDeviceNotify* deviceNotify); - void Trim(); - void Present(winrt::Windows::Graphics::Holographic::HolographicFrame frame); - - // Public methods related to holographic devices. - void SetHolographicSpace(winrt::Windows::Graphics::Holographic::HolographicSpace space); - void EnsureCameraResources( - winrt::Windows::Graphics::Holographic::HolographicFrame frame, - winrt::Windows::Graphics::Holographic::HolographicFramePrediction prediction); - - void AddHolographicCamera(winrt::Windows::Graphics::Holographic::HolographicCamera camera); - void RemoveHolographicCamera(winrt::Windows::Graphics::Holographic::HolographicCamera camera); - - // Holographic accessors. - template - void UseHolographicCameraResources(LCallback const& callback); - - winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice GetD3DInteropDevice() const - { - return m_d3dInteropDevice; - } - - // D3D accessors. - ID3D11Device4* GetD3DDevice() const - { - return m_d3dDevice.get(); - } - template - auto UseD3DDeviceContext(F func) const - { - std::scoped_lock lock(m_d3dContextMutex); - return func(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(); - } - - protected: - void CreateDeviceResources(); - - private: - // Private methods related to the Direct3D device, and resources based on that device. - void CreateDeviceIndependentResources(); - void InitializeUsingHolographicSpace(); - - protected: - // Direct3D objects. - winrt::com_ptr m_d3dDevice; - mutable std::recursive_mutex m_d3dContextMutex; - winrt::com_ptr m_d3dContext; - winrt::com_ptr m_dxgiAdapter; - - // Direct3D interop objects. - winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_d3dInteropDevice; - - // Direct2D factories. - winrt::com_ptr m_d2dFactory; - winrt::com_ptr m_dwriteFactory; - winrt::com_ptr m_wicFactory; - - // 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; - - private: - // The holographic space provides a preferred DXGI adapter ID. - winrt::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; - - // Back buffer resources, etc. for attached holographic cameras. - std::map> m_cameraResources; - std::mutex m_cameraResourcesLock; - }; -} // namespace DXHelper - -// 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>& -// through which the list of cameras will be accessed. -template -void DXHelper::DeviceResources::UseHolographicCameraResources(LCallback const& callback) -{ - std::lock_guard guard(m_cameraResourcesLock); - callback(m_cameraResources); -} +//********************************************************* +// +// 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 "CameraResources.h" + +#include +#include +#include +#include +#include +#include + +namespace DXHelper +{ + // 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(); + ~DeviceResources(); + + // Public methods related to Direct3D devices. + void HandleDeviceLost(); + void RegisterDeviceNotify(IDeviceNotify* deviceNotify); + void Trim(); + void Present(winrt::Windows::Graphics::Holographic::HolographicFrame frame); + + // Public methods related to holographic devices. + void SetHolographicSpace(winrt::Windows::Graphics::Holographic::HolographicSpace space); + void EnsureCameraResources( + winrt::Windows::Graphics::Holographic::HolographicFrame frame, + winrt::Windows::Graphics::Holographic::HolographicFramePrediction prediction); + + void AddHolographicCamera(winrt::Windows::Graphics::Holographic::HolographicCamera camera); + void RemoveHolographicCamera(winrt::Windows::Graphics::Holographic::HolographicCamera camera); + + // Holographic accessors. + template + void UseHolographicCameraResources(LCallback const& callback); + + winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice GetD3DInteropDevice() const + { + return m_d3dInteropDevice; + } + + // D3D accessors. + ID3D11Device4* GetD3DDevice() const + { + return m_d3dDevice.get(); + } + template + auto UseD3DDeviceContext(F func) const + { + std::scoped_lock lock(m_d3dContextMutex); + return func(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(); + } + + protected: + void CreateDeviceResources(); + + private: + // Private methods related to the Direct3D device, and resources based on that device. + void CreateDeviceIndependentResources(); + void InitializeUsingHolographicSpace(); + + protected: + // Direct3D objects. + winrt::com_ptr m_d3dDevice; + mutable std::recursive_mutex m_d3dContextMutex; + winrt::com_ptr m_d3dContext; + winrt::com_ptr m_dxgiAdapter; + + // Direct3D interop objects. + winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_d3dInteropDevice; + + // Direct2D factories. + winrt::com_ptr m_d2dFactory; + winrt::com_ptr m_dwriteFactory; + winrt::com_ptr m_wicFactory; + + // 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; + + private: + // The holographic space provides a preferred DXGI adapter ID. + winrt::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; + + // Back buffer resources, etc. for attached holographic cameras. + std::map> m_cameraResources; + std::mutex m_cameraResourcesLock; + }; +} // namespace DXHelper + +// 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>& +// through which the list of cameras will be accessed. +template +void DXHelper::DeviceResources::UseHolographicCameraResources(LCallback const& callback) +{ + std::lock_guard guard(m_cameraResourcesLock); + callback(m_cameraResources); +} diff --git a/hostsampleapp/uwp/Common/DirectXHelper.h b/remote/desktop/Common/DirectXHelper.h similarity index 97% rename from hostsampleapp/uwp/Common/DirectXHelper.h rename to remote/desktop/Common/DirectXHelper.h index 99f04c1..2955f5e 100644 --- a/hostsampleapp/uwp/Common/DirectXHelper.h +++ b/remote/desktop/Common/DirectXHelper.h @@ -1,87 +1,89 @@ -//********************************************************* -// -// 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 - -#include - -#include -#include - -#include - -#include - -#include -#include - -#include - -namespace DXHelper -{ - // Function that reads from a binary file asynchronously. - inline std::future> ReadDataAsync(const std::wstring_view& filename) - { - using namespace winrt::Windows::Storage; - using namespace winrt::Windows::Storage::Streams; - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - - wchar_t moduleFullyQualifiedFilename[MAX_PATH] = {}; - uint32_t moduleFileNameLength = GetModuleFileNameW(NULL, moduleFullyQualifiedFilename, _countof(moduleFullyQualifiedFilename)); - moduleFullyQualifiedFilename[moduleFileNameLength] = L'\0'; - - std::filesystem::path modulePath = moduleFullyQualifiedFilename; - // winrt::hstring moduleFilename = modulePath.filename().c_str(); - modulePath.replace_filename(filename); - winrt::hstring absoluteFilename = modulePath.c_str(); - - IBuffer fileBuffer = co_await PathIO::ReadBufferAsync(absoluteFilename); -#else - IBuffer fileBuffer = co_await PathIO::ReadBufferAsync(filename); -#endif - - std::vector returnBuffer; - returnBuffer.resize(fileBuffer.Length()); - DataReader::FromBuffer(fileBuffer).ReadBytes(winrt::array_view(returnBuffer)); - return returnBuffer; - } - - // Converts a length in device-independent pixels (DIPs) to a length in physical pixels. - inline float ConvertDipsToPixels(float dips, float dpi) - { - static const 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 Runtime 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 -} // namespace DXHelper +//********************************************************* +// +// 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 + +#include + +#include +#include + +#include + +#include + +#include + +#include +#include + +#include + +namespace DXHelper +{ + // Function that reads from a binary file asynchronously. + inline std::future> ReadDataAsync(const std::wstring_view& filename) + { + using namespace winrt::Windows::Storage; + using namespace winrt::Windows::Storage::Streams; + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + + wchar_t moduleFullyQualifiedFilename[MAX_PATH] = {}; + uint32_t moduleFileNameLength = GetModuleFileNameW(NULL, moduleFullyQualifiedFilename, _countof(moduleFullyQualifiedFilename) - 1); + moduleFullyQualifiedFilename[moduleFileNameLength] = L'\0'; + + std::filesystem::path modulePath = moduleFullyQualifiedFilename; + // winrt::hstring moduleFilename = modulePath.filename().c_str(); + modulePath.replace_filename(filename); + winrt::hstring absoluteFilename = modulePath.c_str(); + + IBuffer fileBuffer = co_await PathIO::ReadBufferAsync(absoluteFilename); +#else + IBuffer fileBuffer = co_await PathIO::ReadBufferAsync(filename); +#endif + + std::vector returnBuffer; + returnBuffer.resize(fileBuffer.Length()); + DataReader::FromBuffer(fileBuffer).ReadBytes(winrt::array_view(returnBuffer)); + return returnBuffer; + } + + // Converts a length in device-independent pixels (DIPs) to a length in physical pixels. + inline float ConvertDipsToPixels(float dips, float dpi) + { + static const 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 Runtime 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 +} // namespace DXHelper diff --git a/hostsampleapp/desktop/Common/PerceptionTypes.cpp b/remote/desktop/Common/PerceptionTypes.cpp similarity index 97% rename from hostsampleapp/desktop/Common/PerceptionTypes.cpp rename to remote/desktop/Common/PerceptionTypes.cpp index 72c1b74..fc8c9b0 100644 --- a/hostsampleapp/desktop/Common/PerceptionTypes.cpp +++ b/remote/desktop/Common/PerceptionTypes.cpp @@ -1,18 +1,18 @@ -//********************************************************* -// -// 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" - -// -- important: preserve order of these two includes (initguid before PerceptionTypes)! -#include - -#include "PerceptionTypes.h" -// -- +//********************************************************* +// +// 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" + +// -- important: preserve order of these two includes (initguid before PerceptionTypes)! +#include + +#include "PerceptionTypes.h" +// -- diff --git a/hostsampleapp/desktop/Common/PerceptionTypes.h b/remote/desktop/Common/PerceptionTypes.h similarity index 97% rename from hostsampleapp/desktop/Common/PerceptionTypes.h rename to remote/desktop/Common/PerceptionTypes.h index 2379971..112ac33 100644 --- a/hostsampleapp/desktop/Common/PerceptionTypes.h +++ b/remote/desktop/Common/PerceptionTypes.h @@ -1,33 +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 - -DEFINE_GUID(SPATIALPROP_QRTrackerObjectId, 0xf2e86326, 0xfbd8, 0x4088, 0xb5, 0xfb, 0xac, 0x61, 0xc, 0x3, 0x99, 0x7f); -DEFINE_GUID(SPATIALPROP_QRTracker_TrackingStatus, 0x270f00dc, 0xc0d9, 0x442c, 0x87, 0x25, 0x27, 0xb6, 0xbb, 0xd9, 0x43, 0xd); -DEFINE_GUID(SPATIALPROP_QRTracker_QRCodesList, 0x338b32f8, 0x1ce0, 0x4e75, 0x8d, 0xf4, 0x56, 0xd4, 0x2f, 0x73, 0x96, 0x74); -DEFINE_GUID(SPATIALPROP_QRCode_PhysicalSize, 0xcfb07ae5, 0x456a, 0x4aaf, 0x9d, 0x6a, 0xa2, 0x9d, 0x3, 0x9b, 0xc0, 0x56); -DEFINE_GUID(SPATIALPROP_QRCode_LastSeenTime, 0xb2b08c2d, 0xb531, 0x4f18, 0x87, 0x84, 0x44, 0x84, 0x46, 0x3d, 0x88, 0x53); -DEFINE_GUID(SPATIALPROP_QRCode_StreamInfo, 0x609143ea, 0x4ec5, 0x4b0e, 0xba, 0xef, 0x52, 0xa5, 0x5c, 0xfc, 0x23, 0x58); - - -#pragma pack(push, 1) -typedef struct SPATIAL_GRAPH_QR_CODE_STREAM_INFO -{ - UINT32 Version; - ULONG StreamSize; - - _Field_size_(StreamSize) BYTE StreamData[ANYSIZE_ARRAY]; - -} SPATIAL_GRAPH_QR_CODE_STREAM_INFO, *PSPATIAL_GRAPH_QR_CODE_STREAM_INFO; -#pragma pack(pop) +//********************************************************* +// +// 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 + +DEFINE_GUID(SPATIALPROP_QRTrackerObjectId, 0xf2e86326, 0xfbd8, 0x4088, 0xb5, 0xfb, 0xac, 0x61, 0xc, 0x3, 0x99, 0x7f); +DEFINE_GUID(SPATIALPROP_QRTracker_TrackingStatus, 0x270f00dc, 0xc0d9, 0x442c, 0x87, 0x25, 0x27, 0xb6, 0xbb, 0xd9, 0x43, 0xd); +DEFINE_GUID(SPATIALPROP_QRTracker_QRCodesList, 0x338b32f8, 0x1ce0, 0x4e75, 0x8d, 0xf4, 0x56, 0xd4, 0x2f, 0x73, 0x96, 0x74); +DEFINE_GUID(SPATIALPROP_QRCode_PhysicalSize, 0xcfb07ae5, 0x456a, 0x4aaf, 0x9d, 0x6a, 0xa2, 0x9d, 0x3, 0x9b, 0xc0, 0x56); +DEFINE_GUID(SPATIALPROP_QRCode_LastSeenTime, 0xb2b08c2d, 0xb531, 0x4f18, 0x87, 0x84, 0x44, 0x84, 0x46, 0x3d, 0x88, 0x53); +DEFINE_GUID(SPATIALPROP_QRCode_StreamInfo, 0x609143ea, 0x4ec5, 0x4b0e, 0xba, 0xef, 0x52, 0xa5, 0x5c, 0xfc, 0x23, 0x58); + +#pragma pack(push, 1) +typedef struct SPATIAL_GRAPH_QR_CODE_STREAM_INFO +{ + UINT32 Version; + ULONG StreamSize; + + _Field_size_(StreamSize) BYTE StreamData[ANYSIZE_ARRAY]; + +} SPATIAL_GRAPH_QR_CODE_STREAM_INFO, *PSPATIAL_GRAPH_QR_CODE_STREAM_INFO; +#pragma pack(pop) diff --git a/hostsampleapp/uwp/Common/Speech.cpp b/remote/desktop/Common/Speech.cpp similarity index 83% rename from hostsampleapp/uwp/Common/Speech.cpp rename to remote/desktop/Common/Speech.cpp index 96d0363..53f25c6 100644 --- a/hostsampleapp/uwp/Common/Speech.cpp +++ b/remote/desktop/Common/Speech.cpp @@ -1,70 +1,70 @@ -//********************************************************* -// -// 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 "SampleHostMain.h" -#include "Speech.h" - -#include -#include -#include - -#include - -namespace -{ - winrt::Windows::Foundation::IAsyncOperation LoadGrammarFileAsync() - { - const wchar_t* speechGrammarFile = L"SpeechGrammar.xml"; -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - wchar_t executablePath[MAX_PATH]; - - if (GetModuleFileNameW(NULL, executablePath, ARRAYSIZE(executablePath)) == 0) - { - winrt::throw_last_error(); - } - std::filesystem::path executableFolder(executablePath); - executableFolder.remove_filename(); - auto rootFolder = co_await winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(executableFolder.c_str()); - auto file = co_await rootFolder.GetFileAsync(speechGrammarFile); - co_return file; -#else - auto rootFolder = winrt::Windows::ApplicationModel::Package::Current().InstalledLocation(); - return rootFolder.GetFileAsync(speechGrammarFile); -#endif - } -} // namespace - -winrt::fire_and_forget Speech::InitializeSpeechAsync( - winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech remoteSpeech, - winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker& onRecognizedSpeechRevoker, - std::weak_ptr sampleHostMainWeak) -{ - onRecognizedSpeechRevoker = remoteSpeech.OnRecognizedSpeech( - winrt::auto_revoke, [sampleHostMainWeak](const winrt::Microsoft::Holographic::AppRemoting::RecognizedSpeech& recognizedSpeech) { - if (auto sampleHostMain = sampleHostMainWeak.lock()) - { - sampleHostMain->OnRecognizedSpeech(recognizedSpeech.RecognizedText); - } - }); - - auto grammarFile = co_await LoadGrammarFileAsync(); - - std::vector dictionary; - dictionary.push_back(L"Red"); - dictionary.push_back(L"Blue"); - dictionary.push_back(L"Green"); - dictionary.push_back(L"Default"); - dictionary.push_back(L"Aquamarine"); - - remoteSpeech.ApplyParameters(L"en-US", grammarFile, dictionary); -} +//********************************************************* +// +// 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 "SampleRemoteMain.h" +#include "Speech.h" + +#include +#include +#include + +#include + +namespace +{ + winrt::Windows::Foundation::IAsyncOperation LoadGrammarFileAsync() + { + const wchar_t* speechGrammarFile = L"SpeechGrammar.xml"; +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + wchar_t executablePath[MAX_PATH]; + + if (GetModuleFileNameW(NULL, executablePath, ARRAYSIZE(executablePath)) == 0) + { + winrt::throw_last_error(); + } + std::filesystem::path executableFolder(executablePath); + executableFolder.remove_filename(); + auto rootFolder = co_await winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(executableFolder.c_str()); + auto file = co_await rootFolder.GetFileAsync(speechGrammarFile); + co_return file; +#else + auto rootFolder = winrt::Windows::ApplicationModel::Package::Current().InstalledLocation(); + return rootFolder.GetFileAsync(speechGrammarFile); +#endif + } +} // namespace + +winrt::fire_and_forget Speech::InitializeSpeechAsync( + winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech remoteSpeech, + winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker& onRecognizedSpeechRevoker, + std::weak_ptr sampleRemoteMainWeak) +{ + onRecognizedSpeechRevoker = remoteSpeech.OnRecognizedSpeech( + winrt::auto_revoke, [sampleRemoteMainWeak](const winrt::Microsoft::Holographic::AppRemoting::RecognizedSpeech& recognizedSpeech) { + if (auto sampleRemoteMain = sampleRemoteMainWeak.lock()) + { + sampleRemoteMain->OnRecognizedSpeech(recognizedSpeech.RecognizedText); + } + }); + + auto grammarFile = co_await LoadGrammarFileAsync(); + + std::vector dictionary; + dictionary.push_back(L"Red"); + dictionary.push_back(L"Blue"); + dictionary.push_back(L"Green"); + dictionary.push_back(L"Default"); + dictionary.push_back(L"Aquamarine"); + + remoteSpeech.ApplyParameters(L"en-US", grammarFile, dictionary); +} diff --git a/hostsampleapp/uwp/Common/Speech.h b/remote/desktop/Common/Speech.h similarity index 88% rename from hostsampleapp/uwp/Common/Speech.h rename to remote/desktop/Common/Speech.h index 2aee153..92d44dc 100644 --- a/hostsampleapp/uwp/Common/Speech.h +++ b/remote/desktop/Common/Speech.h @@ -1,28 +1,27 @@ -//********************************************************* -// -// 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 - -#include -#include - - -class SampleHostMain; - -namespace Speech -{ - winrt::fire_and_forget InitializeSpeechAsync( - winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech remoteSpeech, - winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker& onRecognizedSpeechRevoker, - std::weak_ptr sampleHostMainWeak); -} +//********************************************************* +// +// 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 + +#include +#include + +class SampleRemoteMain; + +namespace Speech +{ + winrt::fire_and_forget InitializeSpeechAsync( + winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech remoteSpeech, + winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker& onRecognizedSpeechRevoker, + std::weak_ptr sampleRemoteMainWeak); +} diff --git a/hostsampleapp/uwp/Common/Utils.h b/remote/desktop/Common/Utils.h similarity index 96% rename from hostsampleapp/uwp/Common/Utils.h rename to remote/desktop/Common/Utils.h index 04e9bda..7ca263f 100644 --- a/hostsampleapp/uwp/Common/Utils.h +++ b/remote/desktop/Common/Utils.h @@ -1,31 +1,31 @@ -//********************************************************* -// -// 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 - -// comparison function to allow for GUID as a hash map key -struct GUIDComparer -{ - inline static int compare(const GUID& Left, const GUID& Right) - { - return memcmp(&Left, &Right, sizeof(GUID)); - } - - inline static bool equals(const GUID& Left, const GUID& Right) - { - return memcmp(&Left, &Right, sizeof(GUID)) == 0; - } - - bool operator()(const GUID& Left, const GUID& Right) const - { - return compare(Left, Right) < 0; - } -}; +//********************************************************* +// +// 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 + +// comparison function to allow for GUID as a hash map key +struct GUIDComparer +{ + inline static int compare(const GUID& Left, const GUID& Right) + { + return memcmp(&Left, &Right, sizeof(GUID)); + } + + inline static bool equals(const GUID& Left, const GUID& Right) + { + return memcmp(&Left, &Right, sizeof(GUID)) == 0; + } + + bool operator()(const GUID& Left, const GUID& Right) const + { + return compare(Left, Right) < 0; + } +}; diff --git a/hostsampleapp/uwp/Content/PerceptionDeviceHandler.cpp b/remote/desktop/Content/PerceptionDeviceHandler.cpp similarity index 95% rename from hostsampleapp/uwp/Content/PerceptionDeviceHandler.cpp rename to remote/desktop/Content/PerceptionDeviceHandler.cpp index 13689b9..e3b658d 100644 --- a/hostsampleapp/uwp/Content/PerceptionDeviceHandler.cpp +++ b/remote/desktop/Content/PerceptionDeviceHandler.cpp @@ -1,218 +1,211 @@ -//********************************************************* -// -// 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 "../Common/PerceptionTypes.h" -#include "../Common/Utils.h" -#include "PerceptionDeviceHandler.h" -#include "QRCodeTracker.h" - - -PerceptionRootObject::~PerceptionRootObject() -{ -} - -const GUID& PerceptionRootObject::GetPropertyId() const -{ - return m_typeId; -} - -const GUID& PerceptionRootObject::GetObjectId() const -{ - return m_objectId; -} - -PerceptionRootObject::PerceptionRootObject(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId) - : m_typeId(typeId) - , m_objectId(objectId) -{ - m_device.copy_from(device); -} - - - -PerceptionDeviceHandler::PerceptionDeviceHandler() -{ -} - -PerceptionDeviceHandler::~PerceptionDeviceHandler() -{ - Stop(); -} - -void PerceptionDeviceHandler::Start() -{ - std::lock_guard stateLock(m_stateProtect); - - if (m_running) - { - return; - } - - HRESULT hr = PerceptionDeviceCreateFactory(IID_PPV_ARGS(m_perceptionDeviceFactory.put())); - if (FAILED(hr)) - { - Stop(); - return; - } - - m_rootObjectChangeHandler = winrt::make_self(*this); - - std::array rootObjectIds{QRCodeTracker::GetStaticPropertyId()}; - for (size_t i = 0; i < rootObjectIds.size(); ++i) - { - winrt::com_ptr watcher; - hr = m_perceptionDeviceFactory->CreateRootObjectWatcher(1, &rootObjectIds[i], PerceptionDeviceOptions::None, watcher.put()); - if (FAILED(hr)) - { - Stop(); - return; - } - - hr = watcher->SetAddedHandler(m_rootObjectChangeHandler.get()); - if (FAILED(hr)) - { - Stop(); - return; - } - - hr = watcher->SetRemovedHandler(m_rootObjectChangeHandler.get()); - if (FAILED(hr)) - { - Stop(); - return; - } - - m_rootObjectWatchers.emplace_back(std::move(watcher)); - } - - m_running = true; - - for (auto& watcher : m_rootObjectWatchers) - { - hr = watcher->Start(); - if (FAILED(hr)) - { - Stop(); - return; - } - } -} - -void PerceptionDeviceHandler::Stop() -{ - std::lock_guard stateLock(m_stateProtect); - - m_running = false; - - for (auto& watcher : m_rootObjectWatchers) - { - watcher->Stop(); - } - m_rootObjectWatchers.clear(); - m_rootObjectChangeHandler = nullptr; - m_perceptionDeviceFactory = nullptr; -} - -HRESULT PerceptionDeviceHandler::HandleRootObjectAdded(IPerceptionDeviceRootObjectAddedEventArgs* args) -{ - std::lock_guard stateLock(m_stateProtect); - - if (!m_running) - { - return S_OK; - } - - RootObjectKey key{args->GetPropertyId(), args->GetObjectId()}; - if (m_rootObjects.find(key) != m_rootObjects.end()) - { - return S_FALSE; // Already have that root object; don't add it twice - } - - if (GUIDComparer::equals(key.propertyId, QRCodeTracker::GetStaticPropertyId())) - { - winrt::com_ptr device; - args->GetDevice(device.put()); - m_rootObjects.emplace(key, std::make_shared(device.get(), key.propertyId, key.objectId)); - } - - return S_OK; -} - -HRESULT PerceptionDeviceHandler::HandleRootObjectRemoved(IPerceptionDeviceRootObjectRemovedEventArgs* args) -{ - std::lock_guard stateLock(m_stateProtect); - - if (!m_running) - { - return S_OK; - } - - RootObjectKey key{args->GetPropertyId(), args->GetObjectId()}; - auto it = m_rootObjects.find(key); - if (it != m_rootObjects.end()) - { - m_rootObjects.erase(key); - } - - return S_OK; -} - - - -PerceptionDeviceHandler::RootObjectChangeHandler::RootObjectChangeHandler(PerceptionDeviceHandler& owner) - : m_weakOwner(owner.weak_from_this()) -{ -} - -STDMETHODIMP PerceptionDeviceHandler::RootObjectChangeHandler::Invoke( - _In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectAddedEventArgs* args) -{ - auto owner{m_weakOwner.lock()}; - if (owner) - { - return owner->HandleRootObjectAdded(args); - } - - return S_OK; -} - -STDMETHODIMP PerceptionDeviceHandler::RootObjectChangeHandler::Invoke( - _In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectRemovedEventArgs* args) -{ - auto owner{m_weakOwner.lock()}; - if (owner) - { - return owner->HandleRootObjectRemoved(args); - } - - return S_OK; -} - - - -bool PerceptionDeviceHandler::RootObjectKey::operator<(const RootObjectKey& other) const -{ - const auto typeIdRes = GUIDComparer::compare(propertyId, other.propertyId); - if (typeIdRes < 0) - { - return true; - } - else if (typeIdRes > 0) - { - return false; - } - else - { - return GUIDComparer::compare(objectId, other.objectId) < 0; - } -} +//********************************************************* +// +// 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 "../Common/PerceptionTypes.h" +#include "../Common/Utils.h" +#include "PerceptionDeviceHandler.h" +#include "QRCodeTracker.h" + +PerceptionRootObject::~PerceptionRootObject() +{ +} + +const GUID& PerceptionRootObject::GetPropertyId() const +{ + return m_typeId; +} + +const GUID& PerceptionRootObject::GetObjectId() const +{ + return m_objectId; +} + +PerceptionRootObject::PerceptionRootObject(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId) + : m_typeId(typeId) + , m_objectId(objectId) +{ + m_device.copy_from(device); +} + +PerceptionDeviceHandler::PerceptionDeviceHandler() +{ +} + +PerceptionDeviceHandler::~PerceptionDeviceHandler() +{ + Stop(); +} + +void PerceptionDeviceHandler::Start() +{ + std::lock_guard stateLock(m_stateProtect); + + if (m_running) + { + return; + } + + HRESULT hr = PerceptionDeviceCreateFactory(IID_PPV_ARGS(m_perceptionDeviceFactory.put())); + if (FAILED(hr)) + { + Stop(); + return; + } + + m_rootObjectChangeHandler = winrt::make_self(*this); + + std::array rootObjectIds{QRCodeTracker::GetStaticPropertyId()}; + for (size_t i = 0; i < rootObjectIds.size(); ++i) + { + winrt::com_ptr watcher; + hr = m_perceptionDeviceFactory->CreateRootObjectWatcher(1, &rootObjectIds[i], PerceptionDeviceOptions::None, watcher.put()); + if (FAILED(hr)) + { + Stop(); + return; + } + + hr = watcher->SetAddedHandler(m_rootObjectChangeHandler.get()); + if (FAILED(hr)) + { + Stop(); + return; + } + + hr = watcher->SetRemovedHandler(m_rootObjectChangeHandler.get()); + if (FAILED(hr)) + { + Stop(); + return; + } + + m_rootObjectWatchers.emplace_back(std::move(watcher)); + } + + m_running = true; + + for (auto& watcher : m_rootObjectWatchers) + { + hr = watcher->Start(); + if (FAILED(hr)) + { + Stop(); + return; + } + } +} + +void PerceptionDeviceHandler::Stop() +{ + std::lock_guard stateLock(m_stateProtect); + + m_running = false; + + for (auto& watcher : m_rootObjectWatchers) + { + watcher->Stop(); + } + m_rootObjectWatchers.clear(); + m_rootObjectChangeHandler = nullptr; + m_perceptionDeviceFactory = nullptr; +} + +HRESULT PerceptionDeviceHandler::HandleRootObjectAdded(IPerceptionDeviceRootObjectAddedEventArgs* args) +{ + std::lock_guard stateLock(m_stateProtect); + + if (!m_running) + { + return S_OK; + } + + RootObjectKey key{args->GetPropertyId(), args->GetObjectId()}; + if (m_rootObjects.find(key) != m_rootObjects.end()) + { + return S_FALSE; // Already have that root object; don't add it twice + } + + if (GUIDComparer::equals(key.propertyId, QRCodeTracker::GetStaticPropertyId())) + { + winrt::com_ptr device; + args->GetDevice(device.put()); + m_rootObjects.emplace(key, std::make_shared(device.get(), key.propertyId, key.objectId)); + } + + return S_OK; +} + +HRESULT PerceptionDeviceHandler::HandleRootObjectRemoved(IPerceptionDeviceRootObjectRemovedEventArgs* args) +{ + std::lock_guard stateLock(m_stateProtect); + + if (!m_running) + { + return S_OK; + } + + RootObjectKey key{args->GetPropertyId(), args->GetObjectId()}; + auto it = m_rootObjects.find(key); + if (it != m_rootObjects.end()) + { + m_rootObjects.erase(key); + } + + return S_OK; +} + +PerceptionDeviceHandler::RootObjectChangeHandler::RootObjectChangeHandler(PerceptionDeviceHandler& owner) + : m_weakOwner(owner.weak_from_this()) +{ +} + +STDMETHODIMP PerceptionDeviceHandler::RootObjectChangeHandler::Invoke( + _In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectAddedEventArgs* args) +{ + auto owner{m_weakOwner.lock()}; + if (owner) + { + return owner->HandleRootObjectAdded(args); + } + + return S_OK; +} + +STDMETHODIMP PerceptionDeviceHandler::RootObjectChangeHandler::Invoke( + _In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectRemovedEventArgs* args) +{ + auto owner{m_weakOwner.lock()}; + if (owner) + { + return owner->HandleRootObjectRemoved(args); + } + + return S_OK; +} + +bool PerceptionDeviceHandler::RootObjectKey::operator<(const RootObjectKey& other) const +{ + const auto typeIdRes = GUIDComparer::compare(propertyId, other.propertyId); + if (typeIdRes < 0) + { + return true; + } + else if (typeIdRes > 0) + { + return false; + } + else + { + return GUIDComparer::compare(objectId, other.objectId) < 0; + } +} diff --git a/hostsampleapp/desktop/Content/PerceptionDeviceHandler.h b/remote/desktop/Content/PerceptionDeviceHandler.h similarity index 96% rename from hostsampleapp/desktop/Content/PerceptionDeviceHandler.h rename to remote/desktop/Content/PerceptionDeviceHandler.h index 5d7d9f1..02474c3 100644 --- a/hostsampleapp/desktop/Content/PerceptionDeviceHandler.h +++ b/remote/desktop/Content/PerceptionDeviceHandler.h @@ -1,121 +1,119 @@ -//********************************************************* -// -// 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 - -#include - -#include - - -// Base class for perception root objects managed by the PerceptionDeviceHandler -class PerceptionRootObject -{ -public: - virtual ~PerceptionRootObject(); - - const GUID& GetPropertyId() const; - const GUID& GetObjectId() const; - -protected: - PerceptionRootObject(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId); - -protected: - winrt::com_ptr m_device; - GUID m_typeId; - GUID m_objectId; -}; - -// Sample perception device handler. Listens to the availability of perception devices (more accurately: -// perception root objects of known types), and retrieves data from these root objects. -class PerceptionDeviceHandler : public std::enable_shared_from_this -{ -public: - PerceptionDeviceHandler(); - ~PerceptionDeviceHandler(); - - // Starts monitoring for perception root object changes - void Start(); - - // Stops monitoring perception root object changes - void Stop(); - - // Iterates over all perception root objects currently known - template - void ForEachRootObject(Func& func) - { - std::lock_guard stateLock(m_stateProtect); - for (auto& rootObjectEntry : m_rootObjects) - { - func(*rootObjectEntry.second.get()); - } - } - - // Iterates over all root objects of a certain type - template - void ForEachRootObjectOfType(Func& func) - { - std::lock_guard stateLock(m_stateProtect); - for (auto& rootObjectEntry : m_rootObjects) - { - PerceptionRootObject& rootObject = *rootObjectEntry.second.get(); - if (GUIDComparer::equals(rootObject.GetPropertyId(), RootObjectType::GetStaticPropertyId())) - { - func(static_cast(rootObject)); - } - } - } - - -private: - struct RootObjectChangeHandler - : winrt::implements - { - RootObjectChangeHandler(PerceptionDeviceHandler& owner); - - IFACEMETHOD(Invoke) - (_In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectAddedEventArgs* args) override; - IFACEMETHOD(Invoke) - (_In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectRemovedEventArgs* args) override; - - private: - std::weak_ptr m_weakOwner; - }; - friend RootObjectChangeHandler; - - struct RootObjectKey - { - GUID propertyId; - GUID objectId; - - bool operator<(const RootObjectKey& other) const; - }; - - using RootObjectMap = std::map>; - - -private: - HRESULT HandleRootObjectAdded(IPerceptionDeviceRootObjectAddedEventArgs* args); - HRESULT HandleRootObjectRemoved(IPerceptionDeviceRootObjectRemovedEventArgs* args); - -private: - std::recursive_mutex m_stateProtect; - - bool m_running{false}; - - winrt::com_ptr m_perceptionDeviceFactory; - std::vector> m_rootObjectWatchers; - winrt::com_ptr m_rootObjectChangeHandler; - - RootObjectMap m_rootObjects; -}; +//********************************************************* +// +// 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 +#include + +#include + +#include + +// Base class for perception root objects managed by the PerceptionDeviceHandler +class PerceptionRootObject +{ +public: + virtual ~PerceptionRootObject(); + + const GUID& GetPropertyId() const; + const GUID& GetObjectId() const; + +protected: + PerceptionRootObject(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId); + +protected: + winrt::com_ptr m_device; + GUID m_typeId; + GUID m_objectId; +}; + +// Sample perception device handler. Listens to the availability of perception devices (more accurately: +// perception root objects of known types), and retrieves data from these root objects. +class PerceptionDeviceHandler : public std::enable_shared_from_this +{ +public: + PerceptionDeviceHandler(); + ~PerceptionDeviceHandler(); + + // Starts monitoring for perception root object changes + void Start(); + + // Stops monitoring perception root object changes + void Stop(); + + // Iterates over all perception root objects currently known + template + void ForEachRootObject(Func& func) + { + std::lock_guard stateLock(m_stateProtect); + for (auto& rootObjectEntry : m_rootObjects) + { + func(*rootObjectEntry.second.get()); + } + } + + // Iterates over all root objects of a certain type + template + void ForEachRootObjectOfType(Func& func) + { + std::lock_guard stateLock(m_stateProtect); + for (auto& rootObjectEntry : m_rootObjects) + { + PerceptionRootObject& rootObject = *rootObjectEntry.second.get(); + if (GUIDComparer::equals(rootObject.GetPropertyId(), RootObjectType::GetStaticPropertyId())) + { + func(static_cast(rootObject)); + } + } + } + +private: + struct RootObjectChangeHandler + : winrt::implements + { + RootObjectChangeHandler(PerceptionDeviceHandler& owner); + + IFACEMETHOD(Invoke) + (_In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectAddedEventArgs* args) override; + IFACEMETHOD(Invoke) + (_In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectRemovedEventArgs* args) override; + + private: + std::weak_ptr m_weakOwner; + }; + friend RootObjectChangeHandler; + + struct RootObjectKey + { + GUID propertyId; + GUID objectId; + + bool operator<(const RootObjectKey& other) const; + }; + + using RootObjectMap = std::map>; + +private: + HRESULT HandleRootObjectAdded(IPerceptionDeviceRootObjectAddedEventArgs* args); + HRESULT HandleRootObjectRemoved(IPerceptionDeviceRootObjectRemovedEventArgs* args); + +private: + std::recursive_mutex m_stateProtect; + + bool m_running{false}; + + winrt::com_ptr m_perceptionDeviceFactory; + std::vector> m_rootObjectWatchers; + winrt::com_ptr m_rootObjectChangeHandler; + + RootObjectMap m_rootObjects; +}; diff --git a/hostsampleapp/desktop/Content/QRCodeRenderer.cpp b/remote/desktop/Content/QRCodeRenderer.cpp similarity index 97% rename from hostsampleapp/desktop/Content/QRCodeRenderer.cpp rename to remote/desktop/Content/QRCodeRenderer.cpp index 8f3944c..531d7fd 100644 --- a/hostsampleapp/desktop/Content/QRCodeRenderer.cpp +++ b/remote/desktop/Content/QRCodeRenderer.cpp @@ -1,107 +1,108 @@ -//********************************************************* -// -// 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 "../Common/DirectXHelper.h" -#include "../Common/PerceptionTypes.h" -#include "PerceptionDeviceHandler.h" -#include "QRCodeRenderer.h" -#include "QRCodeTracker.h" - -namespace -{ - using namespace DirectX; - - void AppendColoredTriangle( - winrt::Windows::Foundation::Numerics::float3 p0, - winrt::Windows::Foundation::Numerics::float3 p1, - winrt::Windows::Foundation::Numerics::float3 p2, - winrt::Windows::Foundation::Numerics::float3 color, - std::vector& vertices) - { - VertexPositionNormalColor vertex; - vertex.color = XMFLOAT3(&color.x); - vertex.normal = XMFLOAT3(0.0f, 0.0f, 0.0f); - - vertex.pos = XMFLOAT3(&p0.x); - vertices.push_back(vertex); - vertex.pos = XMFLOAT3(&p1.x); - vertices.push_back(vertex); - vertex.pos = XMFLOAT3(&p2.x); - vertices.push_back(vertex); - } -} // namespace - - -QRCodeRenderer::QRCodeRenderer(const std::shared_ptr& deviceResources) - : RenderableObject(deviceResources) -{ -} - -void QRCodeRenderer::Update( - PerceptionDeviceHandler& perceptionDeviceHandler, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) -{ - auto processQRCode = [this, renderingCoordinateSystem](QRCode& code) { - auto codeCS = code.GetCoordinateSystem(); - float size = code.GetPhysicalSize(); - auto codeToRendering = codeCS.TryGetTransformTo(renderingCoordinateSystem); - if (!codeToRendering) - { - return; - } - - auto codeToRenderingV = codeToRendering.Value(); - winrt::Windows::Foundation::Numerics::float3 positions[4] = { - {0.0f, 0.0f, 0.0f}, {0.0f, size, 0.0f}, {size, size, 0.0f}, {size, 0.0f, 0.0f}}; - for (int i = 0; i < 4; ++i) - { - positions[i] = winrt::Windows::Foundation::Numerics::transform(positions[i], codeToRenderingV); - } - - winrt::Windows::Foundation::Numerics::float3 col{1.0f, 1.0f, 0.0f}; - AppendColoredTriangle(positions[0], positions[2], positions[1], col, m_vertices); - AppendColoredTriangle(positions[0], positions[3], positions[2], col, m_vertices); - }; - - auto processQRCodeTracker = [this, processQRCode](QRCodeTracker& tracker) { tracker.ForEachQRCode(processQRCode); }; - - m_vertices.clear(); - perceptionDeviceHandler.ForEachRootObjectOfType(processQRCodeTracker); - - auto modelTransform = winrt::Windows::Foundation::Numerics::float4x4::identity(); - UpdateModelConstantBuffer(modelTransform); -} - -void QRCodeRenderer::Draw(unsigned int numInstances) -{ - if (m_vertices.empty()) - { - return; - } - - const UINT stride = sizeof(m_vertices[0]); - const UINT offset = 0; - D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; - vertexBufferData.pSysMem = m_vertices.data(); - const CD3D11_BUFFER_DESC vertexBufferDesc(static_cast(m_vertices.size() * stride), D3D11_BIND_VERTEX_BUFFER); - winrt::com_ptr vertexBuffer; - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, vertexBuffer.put())); - - m_deviceResources->UseD3DDeviceContext([&](auto context) { - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - ID3D11Buffer* pBuffer = vertexBuffer.get(); - context->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset); - context->DrawInstanced(static_cast(m_vertices.size()), numInstances, offset, 0); - }); -} +//********************************************************* +// +// 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 "../Common/DirectXHelper.h" +#include "../Common/PerceptionTypes.h" +#include "PerceptionDeviceHandler.h" +#include "QRCodeRenderer.h" +#include "QRCodeTracker.h" + +#include + +namespace +{ + using namespace DirectX; + + void AppendColoredTriangle( + winrt::Windows::Foundation::Numerics::float3 p0, + winrt::Windows::Foundation::Numerics::float3 p1, + winrt::Windows::Foundation::Numerics::float3 p2, + winrt::Windows::Foundation::Numerics::float3 color, + std::vector& vertices) + { + VertexPositionNormalColor vertex; + vertex.color = XMFLOAT3(&color.x); + vertex.normal = XMFLOAT3(0.0f, 0.0f, 0.0f); + + vertex.pos = XMFLOAT3(&p0.x); + vertices.push_back(vertex); + vertex.pos = XMFLOAT3(&p1.x); + vertices.push_back(vertex); + vertex.pos = XMFLOAT3(&p2.x); + vertices.push_back(vertex); + } +} // namespace + +QRCodeRenderer::QRCodeRenderer(const std::shared_ptr& deviceResources) + : RenderableObject(deviceResources) +{ +} + +void QRCodeRenderer::Update( + PerceptionDeviceHandler& perceptionDeviceHandler, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) +{ + auto processQRCode = [this, renderingCoordinateSystem](QRCode& code) { + auto codeCS = code.GetCoordinateSystem(); + float size = code.GetPhysicalSize(); + auto codeToRendering = codeCS.TryGetTransformTo(renderingCoordinateSystem); + if (!codeToRendering) + { + return; + } + + auto codeToRenderingV = codeToRendering.Value(); + winrt::Windows::Foundation::Numerics::float3 positions[4] = { + {0.0f, 0.0f, 0.0f}, {0.0f, size, 0.0f}, {size, size, 0.0f}, {size, 0.0f, 0.0f}}; + for (int i = 0; i < 4; ++i) + { + positions[i] = winrt::Windows::Foundation::Numerics::transform(positions[i], codeToRenderingV); + } + + winrt::Windows::Foundation::Numerics::float3 col{1.0f, 1.0f, 0.0f}; + AppendColoredTriangle(positions[0], positions[2], positions[1], col, m_vertices); + AppendColoredTriangle(positions[0], positions[3], positions[2], col, m_vertices); + }; + + auto processQRCodeTracker = [this, processQRCode](QRCodeTracker& tracker) { tracker.ForEachQRCode(processQRCode); }; + + m_vertices.clear(); + perceptionDeviceHandler.ForEachRootObjectOfType(processQRCodeTracker); + + auto modelTransform = winrt::Windows::Foundation::Numerics::float4x4::identity(); + UpdateModelConstantBuffer(modelTransform); +} + +void QRCodeRenderer::Draw(unsigned int numInstances) +{ + if (m_vertices.empty()) + { + return; + } + + const UINT stride = sizeof(m_vertices[0]); + const UINT offset = 0; + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = m_vertices.data(); + const CD3D11_BUFFER_DESC vertexBufferDesc(static_cast(m_vertices.size() * stride), D3D11_BIND_VERTEX_BUFFER); + winrt::com_ptr vertexBuffer; + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, vertexBuffer.put())); + + m_deviceResources->UseD3DDeviceContext([&](auto context) { + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + ID3D11Buffer* pBuffer = vertexBuffer.get(); + context->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset); + context->DrawInstanced(static_cast(m_vertices.size()), numInstances, offset, 0); + }); +} diff --git a/hostsampleapp/desktop/Content/QRCodeRenderer.h b/remote/desktop/Content/QRCodeRenderer.h similarity index 96% rename from hostsampleapp/desktop/Content/QRCodeRenderer.h rename to remote/desktop/Content/QRCodeRenderer.h index 8592b9a..26cbaa8 100644 --- a/hostsampleapp/desktop/Content/QRCodeRenderer.h +++ b/remote/desktop/Content/QRCodeRenderer.h @@ -1,35 +1,35 @@ -//********************************************************* -// -// 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 "RenderableObject.h" -#include - -#include - -class PerceptionDeviceHandler; - -class QRCodeRenderer : public RenderableObject -{ -public: - QRCodeRenderer(const std::shared_ptr& deviceResources); - - void Update( - PerceptionDeviceHandler& perceptionDeviceHandler, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); - -private: - void Draw(unsigned int numInstances) override; - -private: - std::vector m_vertices; -}; +//********************************************************* +// +// 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 "RenderableObject.h" +#include + +#include + +class PerceptionDeviceHandler; + +class QRCodeRenderer : public RenderableObject +{ +public: + QRCodeRenderer(const std::shared_ptr& deviceResources); + + void Update( + PerceptionDeviceHandler& perceptionDeviceHandler, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); + +private: + void Draw(unsigned int numInstances) override; + +private: + std::vector m_vertices; +}; diff --git a/hostsampleapp/uwp/Content/QRCodeTracker.cpp b/remote/desktop/Content/QRCodeTracker.cpp similarity index 96% rename from hostsampleapp/uwp/Content/QRCodeTracker.cpp rename to remote/desktop/Content/QRCodeTracker.cpp index 79c2967..5e5dd22 100644 --- a/hostsampleapp/uwp/Content/QRCodeTracker.cpp +++ b/remote/desktop/Content/QRCodeTracker.cpp @@ -1,337 +1,332 @@ -//********************************************************* -// -// 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 - -#include "QRCodeTracker.h" - -#include - - -QRCode::QRCode( - const GUID& id, - PSPATIAL_GRAPH_QR_CODE_STREAM_INFO streamInfo, - const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& coordinateSystem) - : m_id(id) - , m_streamInfo(streamInfo) - , m_coordinateSystem(coordinateSystem) -{ -} - -QRCode::~QRCode() -{ - if (m_streamInfo) - { - CoTaskMemFree(m_streamInfo); - } -} - -const GUID& QRCode::GetId() const -{ - return m_id; -} - -float QRCode::GetPhysicalSize() const -{ - return m_physicalSizeInMeters; -} - -winrt::Windows::Perception::Spatial::SpatialCoordinateSystem QRCode::GetCoordinateSystem() const -{ - return m_coordinateSystem; -} - - - -QRCodeTracker::QRCodeTracker(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId) - : PerceptionRootObject(device, typeId, objectId) -{ - Start(); -} - -QRCodeTracker::~QRCodeTracker() -{ - Stop(); -} - -const GUID& QRCodeTracker::GetStaticPropertyId() -{ - return SPATIALPROP_QRTrackerObjectId; -} - -void QRCodeTracker::Start() -{ - std::lock_guard stateLock(m_stateProtect); - - if (m_running) - { - return; - } - - HRESULT hr = m_device->CreateObjectSubscription(m_objectId, UINT(1), m_qrTrackerSubscription.put()); - if (FAILED(hr)) - { - Stop(); - return; - } - - hr = m_device->CreatePropertyListener(GetObjectId(), SPATIALPROP_QRTracker_QRCodesList, m_qrListChangeListener.put()); - if (FAILED(hr)) - { - Stop(); - return; - } - - m_propertyChangeHandler = winrt::make_self(*this); - hr = m_qrListChangeListener->SetPropertyChangedHandler(m_propertyChangeHandler.get()); - if (FAILED(hr)) - { - Stop(); - return; - } - - hr = m_qrListChangeListener->Start(); - if (FAILED(hr)) - { - Stop(); - return; - } - - m_running = true; -} - -void QRCodeTracker::Stop() -{ - std::lock_guard stateLock(m_stateProtect); - - m_running = false; - - if (m_qrListChangeListener) - { - m_qrListChangeListener->Stop(); - } - - for (auto& qrByPointer : m_qrCodesByPointer) - { - QRCode* qrCode = qrByPointer.second.get(); - if (qrCode->m_propertyChangedListener) - { - qrCode->m_propertyChangedListener->Stop(); - qrCode->m_propertyChangedListener = nullptr; - } - } - - if (m_propertyChangeHandler) - { - m_propertyChangeHandler->Dispose(); - m_propertyChangeHandler = nullptr; - } -} - -HRESULT QRCodeTracker::HandlePropertyChange(IPerceptionDevicePropertyListener* sender, IPerceptionDevicePropertyChangedEventArgs* args) -{ - // Change event for QR code list? - if (sender == m_qrListChangeListener.get()) - { - const GUID* guids = static_cast(args->GetValue()); - UINT numGuids = args->GetValueSize() / sizeof(GUID); - return HandleQRCodeListChange(guids, numGuids); - } - - // Change event for single QR code? - { - std::lock_guard stateLock(m_stateProtect); - auto byListenerPos = m_qrCodesByListener.find(sender); - if (byListenerPos != m_qrCodesByListener.end()) - { - QRCode* qrCode = byListenerPos->second; - return UpdateQRCode(*qrCode); - } - } - - return S_OK; -} - -HRESULT QRCodeTracker::HandleQRCodeListChange(const GUID* guids, UINT numGuids) -{ - std::lock_guard stateLock(m_stateProtect); - - if (!m_running) - { - return S_FALSE; - } - - // Duplicate the list of known QR code IDs. We'll remove all entries from it that we see in - // the incoming list, and thus will end up with a list of the IDs of all removed QR codes. - std::set codesNotInList; - for (auto& kv : m_qrCodesByGUID) - { - codesNotInList.insert(kv.first); - } - - // Check each QR code on the incoming list, and update the local cache - // with new codes. - for (size_t qrIndex = 0; qrIndex < numGuids; ++qrIndex) - { - const GUID& qrCodeId = guids[qrIndex]; - auto it = m_qrCodesByGUID.find(qrCodeId); - if (it != m_qrCodesByGUID.end()) - { - // Code is already known. - codesNotInList.erase(qrCodeId); - continue; - } - - // Code is new. Read initial state, and add to collections. - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem coordinateSystem{nullptr}; - try - { - coordinateSystem = - winrt::Windows::Perception::Spatial::Preview::SpatialGraphInteropPreview::CreateCoordinateSystemForNode(qrCodeId); - } - catch (winrt::hresult_error const& ex) - { - return ex.to_abi(); - } - - if (coordinateSystem == nullptr) - { - return E_FAIL; - } - - void* streamData{nullptr}; - UINT streamDataSize{0}; - HRESULT hr = m_device->ReadVariableSizeProperty(qrCodeId, SPATIALPROP_QRCode_StreamInfo, &streamDataSize, &streamData, nullptr); - if (FAILED(hr)) - { - return hr; - } - - if (streamDataSize == 0) - { - CoTaskMemFree(streamData); - return E_FAIL; - } - - auto newCode = - std::make_unique(qrCodeId, reinterpret_cast(streamData), coordinateSystem); - QRCode* qrCode = newCode.get(); - - m_qrCodesByPointer.emplace(qrCode, std::move(newCode)); - m_qrCodesByGUID.emplace(qrCodeId, qrCode); - - hr = UpdateQRCode(*qrCode); - if (FAILED(hr)) - { - return hr; - } - - hr = m_device->CreatePropertyListener(qrCodeId, SPATIALPROP_QRCode_LastSeenTime, qrCode->m_propertyChangedListener.put()); - if (FAILED(hr)) - { - return hr; - } - - if (!m_propertyChangeHandler) - { - return E_UNEXPECTED; - } - - hr = qrCode->m_propertyChangedListener->SetPropertyChangedHandler( - m_propertyChangeHandler.as().get()); - if (FAILED(hr)) - { - return hr; - } - - hr = qrCode->m_propertyChangedListener->Start(); - if (FAILED(hr)) - { - return hr; - } - - m_qrCodesByListener.emplace(qrCode->m_propertyChangedListener.get(), qrCode); - } - - // Remove all QR codes that have not been seen in this update - for (auto& qrCodeId : codesNotInList) - { - auto byCodeIdPos = m_qrCodesByGUID.find(qrCodeId); - if (byCodeIdPos == m_qrCodesByGUID.end()) - { - // Not found (this should not ever happen) - continue; - } - - QRCode* qrCode = byCodeIdPos->second; - m_qrCodesByGUID.erase(byCodeIdPos); - - if (qrCode->m_propertyChangedListener) - { - qrCode->m_propertyChangedListener->Stop(); - qrCode->m_propertyChangedListener = nullptr; - - m_qrCodesByListener.erase(qrCode->m_propertyChangedListener.get()); - } - - m_qrCodesByPointer.erase(qrCode); - } - - return S_OK; -} - -HRESULT QRCodeTracker::UpdateQRCode(QRCode& qrCode) -{ - float physicalSizeInMeters{0}; - HRESULT hr = - m_device->ReadProperty(qrCode.m_id, SPATIALPROP_QRCode_PhysicalSize, sizeof(physicalSizeInMeters), &physicalSizeInMeters, nullptr); - if (FAILED(hr)) - { - return hr; - } - qrCode.m_physicalSizeInMeters = physicalSizeInMeters; - - LONGLONG lastSeenTime{0}; - hr = m_device->ReadProperty(qrCode.m_id, SPATIALPROP_QRCode_LastSeenTime, sizeof(lastSeenTime), &lastSeenTime, nullptr); - if (FAILED(hr)) - { - return hr; - } - qrCode.m_lastSeenTime = lastSeenTime; - - return S_OK; -} - - - -QRCodeTracker::PropertyChangeHandler::PropertyChangeHandler(QRCodeTracker& owner) - : m_owner(&owner) -{ -} - -void QRCodeTracker::PropertyChangeHandler::Dispose() -{ - m_owner = nullptr; -} - -STDMETHODIMP QRCodeTracker::PropertyChangeHandler::Invoke( - _In_ IPerceptionDevicePropertyListener* sender, _In_ IPerceptionDevicePropertyChangedEventArgs* eventArgs) -{ - auto owner = m_owner; - if (owner) - { - return owner->HandlePropertyChange(sender, eventArgs); - } - - return S_OK; -} +//********************************************************* +// +// 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 + +#include "QRCodeTracker.h" + +#include + +QRCode::QRCode( + const GUID& id, + PSPATIAL_GRAPH_QR_CODE_STREAM_INFO streamInfo, + const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& coordinateSystem) + : m_id(id) + , m_streamInfo(streamInfo) + , m_coordinateSystem(coordinateSystem) +{ +} + +QRCode::~QRCode() +{ + if (m_streamInfo) + { + CoTaskMemFree(m_streamInfo); + } +} + +const GUID& QRCode::GetId() const +{ + return m_id; +} + +float QRCode::GetPhysicalSize() const +{ + return m_physicalSizeInMeters; +} + +winrt::Windows::Perception::Spatial::SpatialCoordinateSystem QRCode::GetCoordinateSystem() const +{ + return m_coordinateSystem; +} + +QRCodeTracker::QRCodeTracker(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId) + : PerceptionRootObject(device, typeId, objectId) +{ + Start(); +} + +QRCodeTracker::~QRCodeTracker() +{ + Stop(); +} + +const GUID& QRCodeTracker::GetStaticPropertyId() +{ + return SPATIALPROP_QRTrackerObjectId; +} + +void QRCodeTracker::Start() +{ + std::lock_guard stateLock(m_stateProtect); + + if (m_running) + { + return; + } + + HRESULT hr = m_device->CreateObjectSubscription(m_objectId, UINT(1), m_qrTrackerSubscription.put()); + if (FAILED(hr)) + { + Stop(); + return; + } + + hr = m_device->CreatePropertyListener(GetObjectId(), SPATIALPROP_QRTracker_QRCodesList, m_qrListChangeListener.put()); + if (FAILED(hr)) + { + Stop(); + return; + } + + m_propertyChangeHandler = winrt::make_self(*this); + hr = m_qrListChangeListener->SetPropertyChangedHandler(m_propertyChangeHandler.get()); + if (FAILED(hr)) + { + Stop(); + return; + } + + hr = m_qrListChangeListener->Start(); + if (FAILED(hr)) + { + Stop(); + return; + } + + m_running = true; +} + +void QRCodeTracker::Stop() +{ + std::lock_guard stateLock(m_stateProtect); + + m_running = false; + + if (m_qrListChangeListener) + { + m_qrListChangeListener->Stop(); + } + + for (auto& qrByPointer : m_qrCodesByPointer) + { + QRCode* qrCode = qrByPointer.second.get(); + if (qrCode->m_propertyChangedListener) + { + qrCode->m_propertyChangedListener->Stop(); + qrCode->m_propertyChangedListener = nullptr; + } + } + + if (m_propertyChangeHandler) + { + m_propertyChangeHandler->Dispose(); + m_propertyChangeHandler = nullptr; + } +} + +HRESULT QRCodeTracker::HandlePropertyChange(IPerceptionDevicePropertyListener* sender, IPerceptionDevicePropertyChangedEventArgs* args) +{ + // Change event for QR code list? + if (sender == m_qrListChangeListener.get()) + { + const GUID* guids = static_cast(args->GetValue()); + UINT numGuids = args->GetValueSize() / sizeof(GUID); + return HandleQRCodeListChange(guids, numGuids); + } + + // Change event for single QR code? + { + std::lock_guard stateLock(m_stateProtect); + auto byListenerPos = m_qrCodesByListener.find(sender); + if (byListenerPos != m_qrCodesByListener.end()) + { + QRCode* qrCode = byListenerPos->second; + return UpdateQRCode(*qrCode); + } + } + + return S_OK; +} + +HRESULT QRCodeTracker::HandleQRCodeListChange(const GUID* guids, UINT numGuids) +{ + std::lock_guard stateLock(m_stateProtect); + + if (!m_running) + { + return S_FALSE; + } + + // Duplicate the list of known QR code IDs. We'll remove all entries from it that we see in + // the incoming list, and thus will end up with a list of the IDs of all removed QR codes. + std::set codesNotInList; + for (auto& kv : m_qrCodesByGUID) + { + codesNotInList.insert(kv.first); + } + + // Check each QR code on the incoming list, and update the local cache + // with new codes. + for (size_t qrIndex = 0; qrIndex < numGuids; ++qrIndex) + { + const GUID& qrCodeId = guids[qrIndex]; + auto it = m_qrCodesByGUID.find(qrCodeId); + if (it != m_qrCodesByGUID.end()) + { + // Code is already known. + codesNotInList.erase(qrCodeId); + continue; + } + + // Code is new. Read initial state, and add to collections. + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem coordinateSystem{nullptr}; + try + { + coordinateSystem = + winrt::Windows::Perception::Spatial::Preview::SpatialGraphInteropPreview::CreateCoordinateSystemForNode(qrCodeId); + } + catch (winrt::hresult_error const& ex) + { + return ex.to_abi(); + } + + if (coordinateSystem == nullptr) + { + return E_FAIL; + } + + void* streamData{nullptr}; + UINT streamDataSize{0}; + HRESULT hr = m_device->ReadVariableSizeProperty(qrCodeId, SPATIALPROP_QRCode_StreamInfo, &streamDataSize, &streamData, nullptr); + if (FAILED(hr)) + { + return hr; + } + + if (streamDataSize == 0) + { + CoTaskMemFree(streamData); + return E_FAIL; + } + + auto newCode = + std::make_unique(qrCodeId, reinterpret_cast(streamData), coordinateSystem); + QRCode* qrCode = newCode.get(); + + m_qrCodesByPointer.emplace(qrCode, std::move(newCode)); + m_qrCodesByGUID.emplace(qrCodeId, qrCode); + + hr = UpdateQRCode(*qrCode); + if (FAILED(hr)) + { + return hr; + } + + hr = m_device->CreatePropertyListener(qrCodeId, SPATIALPROP_QRCode_LastSeenTime, qrCode->m_propertyChangedListener.put()); + if (FAILED(hr)) + { + return hr; + } + + if (!m_propertyChangeHandler) + { + return E_UNEXPECTED; + } + + hr = qrCode->m_propertyChangedListener->SetPropertyChangedHandler( + m_propertyChangeHandler.as().get()); + if (FAILED(hr)) + { + return hr; + } + + hr = qrCode->m_propertyChangedListener->Start(); + if (FAILED(hr)) + { + return hr; + } + + m_qrCodesByListener.emplace(qrCode->m_propertyChangedListener.get(), qrCode); + } + + // Remove all QR codes that have not been seen in this update + for (auto& qrCodeId : codesNotInList) + { + auto byCodeIdPos = m_qrCodesByGUID.find(qrCodeId); + if (byCodeIdPos == m_qrCodesByGUID.end()) + { + // Not found (this should not ever happen) + continue; + } + + QRCode* qrCode = byCodeIdPos->second; + m_qrCodesByGUID.erase(byCodeIdPos); + + if (qrCode->m_propertyChangedListener) + { + qrCode->m_propertyChangedListener->Stop(); + qrCode->m_propertyChangedListener = nullptr; + + m_qrCodesByListener.erase(qrCode->m_propertyChangedListener.get()); + } + + m_qrCodesByPointer.erase(qrCode); + } + + return S_OK; +} + +HRESULT QRCodeTracker::UpdateQRCode(QRCode& qrCode) +{ + float physicalSizeInMeters{0}; + HRESULT hr = + m_device->ReadProperty(qrCode.m_id, SPATIALPROP_QRCode_PhysicalSize, sizeof(physicalSizeInMeters), &physicalSizeInMeters, nullptr); + if (FAILED(hr)) + { + return hr; + } + qrCode.m_physicalSizeInMeters = physicalSizeInMeters; + + LONGLONG lastSeenTime{0}; + hr = m_device->ReadProperty(qrCode.m_id, SPATIALPROP_QRCode_LastSeenTime, sizeof(lastSeenTime), &lastSeenTime, nullptr); + if (FAILED(hr)) + { + return hr; + } + qrCode.m_lastSeenTime = lastSeenTime; + + return S_OK; +} + +QRCodeTracker::PropertyChangeHandler::PropertyChangeHandler(QRCodeTracker& owner) + : m_owner(&owner) +{ +} + +void QRCodeTracker::PropertyChangeHandler::Dispose() +{ + m_owner = nullptr; +} + +STDMETHODIMP QRCodeTracker::PropertyChangeHandler::Invoke( + _In_ IPerceptionDevicePropertyListener* sender, _In_ IPerceptionDevicePropertyChangedEventArgs* eventArgs) +{ + auto owner = m_owner; + if (owner) + { + return owner->HandlePropertyChange(sender, eventArgs); + } + + return S_OK; +} diff --git a/hostsampleapp/uwp/Content/QRCodeTracker.h b/remote/desktop/Content/QRCodeTracker.h similarity index 97% rename from hostsampleapp/uwp/Content/QRCodeTracker.h rename to remote/desktop/Content/QRCodeTracker.h index 4628a29..97519db 100644 --- a/hostsampleapp/uwp/Content/QRCodeTracker.h +++ b/remote/desktop/Content/QRCodeTracker.h @@ -1,108 +1,108 @@ -//********************************************************* -// -// 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 "../Common/PerceptionTypes.h" -#include "../Common/Utils.h" -#include "PerceptionDeviceHandler.h" - -// Represents a single tracked QR code with position, size and last seen time. -class QRCode -{ -public: - QRCode( - const GUID& id, - PSPATIAL_GRAPH_QR_CODE_STREAM_INFO streamInfo, - const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& coordinateSystem); - ~QRCode(); - - const GUID& GetId() const; - float GetPhysicalSize() const; - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem GetCoordinateSystem() const; - -private: - friend class QRCodeTracker; - -private: - GUID m_id; - PSPATIAL_GRAPH_QR_CODE_STREAM_INFO m_streamInfo; - - __int64 m_lastSeenTime{0}; - float m_physicalSizeInMeters{0}; - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem m_coordinateSystem{nullptr}; - winrt::com_ptr m_propertyChangedListener; -}; - -// Manages all active QR codes. -// Listens for events from the perception device to add, remove or update QR codes. -class QRCodeTracker : public PerceptionRootObject -{ -public: - QRCodeTracker(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId); - ~QRCodeTracker(); - - // Helper function to iterate all QR codes in a thread safe manner. - template - void ForEachQRCode(Func& func) - { - std::lock_guard stateLock(m_stateProtect); - for (auto& qrCodeEntry : m_qrCodesByPointer) - { - func(*qrCodeEntry.second.get()); - } - } - -public: - static const GUID& GetStaticPropertyId(); - -private: - // Implementation of the IPerceptionDevicePropertyChangedHandler interface. - // Events from the perception device are propagated through an instance of this class. - struct PropertyChangeHandler : winrt::implements - { - PropertyChangeHandler(QRCodeTracker& owner); - - void Dispose(); - - STDMETHOD(Invoke) - (_In_ IPerceptionDevicePropertyListener* sender, _In_ IPerceptionDevicePropertyChangedEventArgs* eventArgs) override; - - private: - QRCodeTracker* m_owner; - }; - friend PropertyChangeHandler; - - using QRCodesByPointerMap = std::map>; - using QRCodesByGUIDMap = std::map; - using QRCodesByListenerMap = std::map; - -private: - void Start(); - void Stop(); - - HRESULT HandlePropertyChange(IPerceptionDevicePropertyListener* sender, IPerceptionDevicePropertyChangedEventArgs* args); - HRESULT HandleQRCodeListChange(const GUID* guids, UINT numGuids); - HRESULT UpdateQRCode(QRCode& qrCode); - -private: - std::recursive_mutex m_stateProtect; - - bool m_running{false}; - - winrt::com_ptr m_qrTrackerSubscription; - winrt::com_ptr m_qrListChangeListener; - winrt::com_ptr m_propertyChangeHandler; - - QRCodesByPointerMap m_qrCodesByPointer; - QRCodesByGUIDMap m_qrCodesByGUID; - QRCodesByListenerMap m_qrCodesByListener; -}; +//********************************************************* +// +// 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 "../Common/PerceptionTypes.h" +#include "../Common/Utils.h" +#include "PerceptionDeviceHandler.h" + +// Represents a single tracked QR code with position, size and last seen time. +class QRCode +{ +public: + QRCode( + const GUID& id, + PSPATIAL_GRAPH_QR_CODE_STREAM_INFO streamInfo, + const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& coordinateSystem); + ~QRCode(); + + const GUID& GetId() const; + float GetPhysicalSize() const; + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem GetCoordinateSystem() const; + +private: + friend class QRCodeTracker; + +private: + GUID m_id; + PSPATIAL_GRAPH_QR_CODE_STREAM_INFO m_streamInfo; + + __int64 m_lastSeenTime{0}; + float m_physicalSizeInMeters{0}; + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem m_coordinateSystem{nullptr}; + winrt::com_ptr m_propertyChangedListener; +}; + +// Manages all active QR codes. +// Listens for events from the perception device to add, remove or update QR codes. +class QRCodeTracker : public PerceptionRootObject +{ +public: + QRCodeTracker(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId); + ~QRCodeTracker(); + + // Helper function to iterate all QR codes in a thread safe manner. + template + void ForEachQRCode(Func& func) + { + std::lock_guard stateLock(m_stateProtect); + for (auto& qrCodeEntry : m_qrCodesByPointer) + { + func(*qrCodeEntry.second.get()); + } + } + +public: + static const GUID& GetStaticPropertyId(); + +private: + // Implementation of the IPerceptionDevicePropertyChangedHandler interface. + // Events from the perception device are propagated through an instance of this class. + struct PropertyChangeHandler : winrt::implements + { + PropertyChangeHandler(QRCodeTracker& owner); + + void Dispose(); + + STDMETHOD(Invoke) + (_In_ IPerceptionDevicePropertyListener* sender, _In_ IPerceptionDevicePropertyChangedEventArgs* eventArgs) override; + + private: + QRCodeTracker* m_owner; + }; + friend PropertyChangeHandler; + + using QRCodesByPointerMap = std::map>; + using QRCodesByGUIDMap = std::map; + using QRCodesByListenerMap = std::map; + +private: + void Start(); + void Stop(); + + HRESULT HandlePropertyChange(IPerceptionDevicePropertyListener* sender, IPerceptionDevicePropertyChangedEventArgs* args); + HRESULT HandleQRCodeListChange(const GUID* guids, UINT numGuids); + HRESULT UpdateQRCode(QRCode& qrCode); + +private: + std::recursive_mutex m_stateProtect; + + bool m_running{false}; + + winrt::com_ptr m_qrTrackerSubscription; + winrt::com_ptr m_qrListChangeListener; + winrt::com_ptr m_propertyChangeHandler; + + QRCodesByPointerMap m_qrCodesByPointer; + QRCodesByGUIDMap m_qrCodesByGUID; + QRCodesByListenerMap m_qrCodesByListener; +}; diff --git a/hostsampleapp/desktop/Content/RenderableObject.cpp b/remote/desktop/Content/RenderableObject.cpp similarity index 97% rename from hostsampleapp/desktop/Content/RenderableObject.cpp rename to remote/desktop/Content/RenderableObject.cpp index 9934228..341c3b3 100644 --- a/hostsampleapp/desktop/Content/RenderableObject.cpp +++ b/remote/desktop/Content/RenderableObject.cpp @@ -1,148 +1,147 @@ -//********************************************************* -// -// 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 "RenderableObject.h" - -#include "../Common/DirectXHelper.h" - - -RenderableObject::RenderableObject(const std::shared_ptr& deviceResources) - : m_deviceResources(deviceResources) -{ - CreateDeviceDependentResources(); -} - -void RenderableObject::UpdateModelConstantBuffer(const winrt::Windows::Foundation::Numerics::float4x4& modelTransform) -{ - winrt::Windows::Foundation::Numerics::float4x4 normalTransform = modelTransform; - normalTransform.m41 = normalTransform.m42 = normalTransform.m43 = 0; - UpdateModelConstantBuffer(modelTransform, normalTransform); -} - -void RenderableObject::UpdateModelConstantBuffer( - const winrt::Windows::Foundation::Numerics::float4x4& modelTransform, - const winrt::Windows::Foundation::Numerics::float4x4& normalTransform) -{ - if (m_loadingComplete) - { - m_modelConstantBufferData.model = reinterpret_cast(transpose(modelTransform)); - m_modelConstantBufferData.normal = reinterpret_cast(transpose(normalTransform)); - - // Update the model transform buffer for the hologram. - m_deviceResources->UseD3DDeviceContext( - [&](auto context) { context->UpdateSubresource(m_modelConstantBuffer.get(), 0, nullptr, &m_modelConstantBufferData, 0, 0); }); - } -} - -void RenderableObject::Render(bool isStereo) -{ - if (!m_loadingComplete) - { - return; - } - - // Use the D3D device context to update Direct3D device-based resources. - m_deviceResources->UseD3DDeviceContext([&](auto context) { - context->IASetInputLayout(m_inputLayout.get()); - context->PSSetShader(m_pixelShader.get(), nullptr, 0); - - // Attach the vertex shader. - context->VSSetShader(m_vertexShader.get(), nullptr, 0); - - // Apply the model constant buffer to the vertex shader. - ID3D11Buffer* pBuffer = m_modelConstantBuffer.get(); - context->VSSetConstantBuffers(0, 1, &pBuffer); - - 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); - } - - Draw(isStereo ? 2 : 1); - }); -} - -std::future RenderableObject::CreateDeviceDependentResources() -{ -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - std::wstring fileNamePrefix = L""; -#else - std::wstring fileNamePrefix = L"ms-appx:///"; -#endif - - 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"hsa_VprtVertexShader.cso" : L"hsa_VertexShader.cso"; - - // Load shaders asynchronously. - std::vector vertexShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + vertexShaderFileName); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateVertexShader( - vertexShaderFileData.data(), vertexShaderFileData.size(), nullptr, m_vertexShader.put())); - - constexpr std::array vertexDesc = {{ - {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, - }}; - - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateInputLayout( - vertexDesc.data(), - static_cast(vertexDesc.size()), - vertexShaderFileData.data(), - static_cast(vertexShaderFileData.size()), - m_inputLayout.put())); - - std::vector pixelShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_PixelShader.cso"); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreatePixelShader( - pixelShaderFileData.data(), pixelShaderFileData.size(), nullptr, m_pixelShader.put())); - - const ModelConstantBuffer constantBuffer{ - reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), - reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), - }; - - const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, m_modelConstantBuffer.put())); - - if (!m_usingVprtShaders) - { - // Load the pass-through geometry shader. - std::vector geometryShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_GeometryShader.cso"); - - // After the pass-through geometry shader file is loaded, create the shader. - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateGeometryShader( - geometryShaderFileData.data(), geometryShaderFileData.size(), nullptr, m_geometryShader.put())); - } - - m_loadingComplete = true; -} - -void RenderableObject::ReleaseDeviceDependentResources() -{ - m_loadingComplete = false; - m_usingVprtShaders = false; - m_vertexShader = nullptr; - m_inputLayout = nullptr; - m_pixelShader = nullptr; - m_geometryShader = nullptr; - m_modelConstantBuffer = nullptr; -} +//********************************************************* +// +// 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 "RenderableObject.h" + +#include "../Common/DirectXHelper.h" + +RenderableObject::RenderableObject(const std::shared_ptr& deviceResources) + : m_deviceResources(deviceResources) +{ + CreateDeviceDependentResources(); +} + +void RenderableObject::UpdateModelConstantBuffer(const winrt::Windows::Foundation::Numerics::float4x4& modelTransform) +{ + winrt::Windows::Foundation::Numerics::float4x4 normalTransform = modelTransform; + normalTransform.m41 = normalTransform.m42 = normalTransform.m43 = 0; + UpdateModelConstantBuffer(modelTransform, normalTransform); +} + +void RenderableObject::UpdateModelConstantBuffer( + const winrt::Windows::Foundation::Numerics::float4x4& modelTransform, + const winrt::Windows::Foundation::Numerics::float4x4& normalTransform) +{ + if (m_loadingComplete) + { + m_modelConstantBufferData.model = reinterpret_cast(transpose(modelTransform)); + m_modelConstantBufferData.normal = reinterpret_cast(transpose(normalTransform)); + + // Update the model transform buffer for the hologram. + m_deviceResources->UseD3DDeviceContext( + [&](auto context) { context->UpdateSubresource(m_modelConstantBuffer.get(), 0, nullptr, &m_modelConstantBufferData, 0, 0); }); + } +} + +void RenderableObject::Render(bool isStereo) +{ + if (!m_loadingComplete) + { + return; + } + + // Use the D3D device context to update Direct3D device-based resources. + m_deviceResources->UseD3DDeviceContext([&](auto context) { + context->IASetInputLayout(m_inputLayout.get()); + context->PSSetShader(m_pixelShader.get(), nullptr, 0); + + // Attach the vertex shader. + context->VSSetShader(m_vertexShader.get(), nullptr, 0); + + // Apply the model constant buffer to the vertex shader. + ID3D11Buffer* pBuffer = m_modelConstantBuffer.get(); + context->VSSetConstantBuffers(0, 1, &pBuffer); + + 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); + } + + Draw(isStereo ? 2 : 1); + }); +} + +std::future RenderableObject::CreateDeviceDependentResources() +{ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + std::wstring fileNamePrefix = L""; +#else + std::wstring fileNamePrefix = L"ms-appx:///"; +#endif + + 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"hsa_VprtVertexShader.cso" : L"hsa_VertexShader.cso"; + + // Load shaders asynchronously. + std::vector vertexShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + vertexShaderFileName); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateVertexShader( + vertexShaderFileData.data(), vertexShaderFileData.size(), nullptr, m_vertexShader.put())); + + constexpr std::array vertexDesc = {{ + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }}; + + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateInputLayout( + vertexDesc.data(), + static_cast(vertexDesc.size()), + vertexShaderFileData.data(), + static_cast(vertexShaderFileData.size()), + m_inputLayout.put())); + + std::vector pixelShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_PixelShader.cso"); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreatePixelShader( + pixelShaderFileData.data(), pixelShaderFileData.size(), nullptr, m_pixelShader.put())); + + const ModelConstantBuffer constantBuffer{ + reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), + reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), + }; + + const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, m_modelConstantBuffer.put())); + + if (!m_usingVprtShaders) + { + // Load the pass-through geometry shader. + std::vector geometryShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_GeometryShader.cso"); + + // After the pass-through geometry shader file is loaded, create the shader. + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateGeometryShader( + geometryShaderFileData.data(), geometryShaderFileData.size(), nullptr, m_geometryShader.put())); + } + + m_loadingComplete = true; +} + +void RenderableObject::ReleaseDeviceDependentResources() +{ + m_loadingComplete = false; + m_usingVprtShaders = false; + m_vertexShader = nullptr; + m_inputLayout = nullptr; + m_pixelShader = nullptr; + m_geometryShader = nullptr; + m_modelConstantBuffer = nullptr; +} diff --git a/hostsampleapp/uwp/Content/RenderableObject.h b/remote/desktop/Content/RenderableObject.h similarity index 97% rename from hostsampleapp/uwp/Content/RenderableObject.h rename to remote/desktop/Content/RenderableObject.h index 8f28484..0422d6e 100644 --- a/hostsampleapp/uwp/Content/RenderableObject.h +++ b/remote/desktop/Content/RenderableObject.h @@ -1,61 +1,61 @@ -//********************************************************* -// -// 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 "..\Common\DeviceResources.h" -#include "ShaderStructures.h" - -#include - -class RenderableObject -{ -public: - RenderableObject(const std::shared_ptr& deviceResources); - virtual ~RenderableObject() - { - } - - virtual std::future CreateDeviceDependentResources(); - virtual void ReleaseDeviceDependentResources(); - - void Render(bool isStereo); - -protected: - void UpdateModelConstantBuffer(const winrt::Windows::Foundation::Numerics::float4x4& modelTransform); - void UpdateModelConstantBuffer( - const winrt::Windows::Foundation::Numerics::float4x4& modelTransform, - const winrt::Windows::Foundation::Numerics::float4x4& normalTransform); - - virtual void Draw(unsigned int numInstances) = 0; - - // Cached pointer to device resources. - std::shared_ptr m_deviceResources; - -private: - // Direct3D resources for geometry. - winrt::com_ptr m_inputLayout; - winrt::com_ptr m_vertexShader; - winrt::com_ptr m_geometryShader; - winrt::com_ptr m_pixelShader; - winrt::com_ptr m_modelConstantBuffer; - - // System resources for geometry. - ModelConstantBuffer m_modelConstantBufferData; - uint32_t m_indexCount = 0; - - // Variables used with the rendering loop. - bool m_loadingComplete = false; - - // 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; -}; +//********************************************************* +// +// 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 "..\Common\DeviceResources.h" +#include "ShaderStructures.h" + +#include + +class RenderableObject +{ +public: + RenderableObject(const std::shared_ptr& deviceResources); + virtual ~RenderableObject() + { + } + + virtual std::future CreateDeviceDependentResources(); + virtual void ReleaseDeviceDependentResources(); + + void Render(bool isStereo); + +protected: + void UpdateModelConstantBuffer(const winrt::Windows::Foundation::Numerics::float4x4& modelTransform); + void UpdateModelConstantBuffer( + const winrt::Windows::Foundation::Numerics::float4x4& modelTransform, + const winrt::Windows::Foundation::Numerics::float4x4& normalTransform); + + virtual void Draw(unsigned int numInstances) = 0; + + // Cached pointer to device resources. + std::shared_ptr m_deviceResources; + +private: + // Direct3D resources for geometry. + winrt::com_ptr m_inputLayout; + winrt::com_ptr m_vertexShader; + winrt::com_ptr m_geometryShader; + winrt::com_ptr m_pixelShader; + winrt::com_ptr m_modelConstantBuffer; + + // System resources for geometry. + ModelConstantBuffer m_modelConstantBufferData; + uint32_t m_indexCount = 0; + + // Variables used with the rendering loop. + bool m_loadingComplete = false; + + // 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; +}; diff --git a/hostsampleapp/desktop/Content/SceneUnderstandingRenderer.cpp b/remote/desktop/Content/SceneUnderstandingRenderer.cpp similarity index 97% rename from hostsampleapp/desktop/Content/SceneUnderstandingRenderer.cpp rename to remote/desktop/Content/SceneUnderstandingRenderer.cpp index 06b3792..4c8c5e8 100644 --- a/hostsampleapp/desktop/Content/SceneUnderstandingRenderer.cpp +++ b/remote/desktop/Content/SceneUnderstandingRenderer.cpp @@ -1,576 +1,575 @@ -//********************************************************* -// -// 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 "../Common/DbgLog.h" -#include "../Common/DirectXHelper.h" - -#include "SceneUnderstandingRenderer.h" - -#include - -using namespace RemotingHostSample; - -namespace -{ - using namespace DirectX; - - void AppendColoredTriangle( - winrt::Windows::Foundation::Numerics::float3 p0, - winrt::Windows::Foundation::Numerics::float3 p1, - winrt::Windows::Foundation::Numerics::float3 p2, - winrt::Windows::Foundation::Numerics::float3 color, - std::vector& vertices) - { - VertexPositionNormalColor vertex; - vertex.color = XMFLOAT3(&color.x); - vertex.normal = XMFLOAT3(0.0f, 0.0f, 0.0f); - - vertex.pos = XMFLOAT3(&p0.x); - vertices.push_back(vertex); - vertex.pos = XMFLOAT3(&p1.x); - vertices.push_back(vertex); - vertex.pos = XMFLOAT3(&p2.x); - vertices.push_back(vertex); - } -} // namespace - - -// Struct to hold one entity label type entry -struct Label -{ - const wchar_t* const Name; - uint32_t Index; - uint8_t RGB[3]; -}; - -// Entity label types -static const Label LabelStorage[] = { - {L"Background", 0, {243, 121, 223}}, - {L"Ignore", 255, {255, 255, 255}}, - {L"Wall", 1, {243, 126, 121}}, - {L"Floor", 2, {187, 243, 121}}, - {L"Ceiling", 3, {121, 152, 243}}, - {L"Table", 4, {121, 243, 227}}, - {L"Chair", 5, {243, 191, 121}}, - {L"Window", 6, {121, 243, 146}}, - {L"Door", 7, {156, 121, 243}}, - {L"Monitor", 8, {2, 159, 253}}, - {L"Pillar", 10, {253, 106, 2}}, - {L"Couch", 11, {72, 197, 126}}, - {L"Whiteboard", 12, {137, 159, 2}}, - {L"Beanbag", 13, {206, 112, 74}}, - {L"Cabinet", 14, {36, 43, 138}}, - {L"Nightstands", 15, {78, 231, 210}}, - {L"TVStands", 16, {26, 71, 66}}, - {L"Countertops", 17, {13, 60, 55}}, - {L"Dressers", 18, {29, 58, 55}}, - {L"Bench", 19, {105, 54, 136}}, - {L"Ottoman", 20, {99, 9, 44}}, - {L"Stool", 21, {255, 204, 153}}, - {L"GTEquipment", 22, {206, 199, 74}}, - {L"Telephone", 23, {243, 217, 121}}, - {L"Bookshelf", 24, {37, 117, 164}}, - {L"Laptop", 25, {96, 147, 234}}, - {L"Stanchion", 26, {29, 117, 40}}, - {L"Markers", 27, {111, 93, 167}}, - {L"Controller", 28, {230, 254, 251}}, - {L"Stairs", 9, {43, 174, 100}}, - {L"Empty", 254, {0, 0, 0}}, - {L"Appliances-CeilingLight", 30, {250, 24, 180}}, - {L"Appliances-DishWasher", 32, {38, 204, 168}}, - {L"Appliances-FloorLamp", 34, {106, 134, 187}}, - {L"Appliances-Lighting", 36, {156, 162, 56}}, - {L"Appliances-Microwave", 37, {6, 44, 91}}, - {L"Appliances-NotSpecified", 38, {35, 188, 199}}, - {L"Appliances-Oven", 39, {153, 60, 52}}, - {L"Appliances-SmallAppliances", 40, {255, 83, 112}}, - {L"Appliances-Stove", 41, {76, 175, 147}}, - {L"Appliances-Toaster", 42, {145, 58, 23}}, - {L"Appliances-WashingMachine", 44, {46, 66, 12}}, - {L"Appliances-DeskLamp", 45, {128, 86, 177}}, - {L"Appliances-Dryer", 46, {239, 162, 164}}, - {L"Appliances-Fridge", 47, {87, 243, 139}}, - {L"Appliances-WallLight", 50, {222, 49, 1}}, - {L"Bed-BunkBed", 51, {97, 174, 71}}, - {L"Bed-DoubleBed", 52, {85, 195, 111}}, - {L"Bed-NotSpecified", 53, {212, 26, 75}}, - {L"Bed-SingleBed", 54, {200, 219, 241}}, - {L"Ceiling-Unassigned", 55, {48, 120, 115}}, - {L"Ceiling-NotSpecified", 56, {205, 144, 139}}, - {L"Chair-Beanbag", 57, {136, 175, 192}}, - {L"Chair-Bench", 58, {89, 41, 203}}, - {L"Chair-ArmChair", 59, {192, 1, 27}}, - {L"Chair-ArmOfAChair", 60, {194, 241, 101}}, - {L"Chair-BarStool", 61, {146, 21, 8}}, - {L"Chair-ChaiseLounge", 62, {178, 31, 121}}, - {L"Chair-DiningChair", 63, {76, 10, 219}}, - {L"Chair-LoungeChair", 64, {174, 165, 77}}, - {L"Chair-NotSpecified", 65, {186, 217, 58}}, - {L"Chair-OfficeChair", 66, {177, 29, 181}}, - {L"Chair-Unknown", 67, {155, 128, 196}}, - {L"Chair-Ottoman", 68, {28, 75, 247}}, - {L"Chair-Stool", 69, {60, 243, 241}}, - {L"Door-DoubleDoors", 70, {220, 101, 83}}, - {L"Door-NotSpecified", 71, {219, 20, 187}}, - {L"Door-Revolving", 72, {211, 229, 158}}, - {L"Door-SingleDoor", 73, {10, 100, 12}}, - {L"Door-Sliding", 74, {73, 197, 108}}, - {L"Electronics-Desktop", 75, {181, 22, 191}}, - {L"Electronics-DVDPlayer", 76, {5, 131, 13}}, - {L"Electronics-Headphones", 77, {169, 60, 180}}, - {L"Electronics-Keyboard", 78, {6, 92, 79}}, - {L"Electronics-Laptop", 79, {252, 108, 50}}, - {L"Electronics-Mobile", 80, {35, 73, 64}}, - {L"Electronics-Mouse", 81, {3, 112, 214}}, - {L"Electronics-Mousepad", 82, {106, 70, 62}}, - {L"Electronics-NotSpecified", 83, {63, 100, 209}}, - {L"Electronics-Phone", 84, {64, 32, 142}}, - {L"Electronics-Printer", 85, {70, 188, 0}}, - {L"Electronics-Projector", 86, {72, 100, 38}}, - {L"Electronics-Speakers", 87, {202, 60, 135}}, - {L"Electronics-Tablet", 88, {126, 2, 49}}, - {L"Electronics-TVMonitor", 89, {188, 184, 46}}, - {L"Electronics-Xbox", 90, {6, 218, 26}}, - {L"Electronics-Monitor", 91, {179, 160, 177}}, - {L"Floor-Unassigned", 92, {9, 42, 145}}, - {L"Human-Female", 93, {52, 156, 230}}, - {L"Human-Male", 94, {231, 88, 138}}, - {L"Human-Other", 95, {0, 0, 255}}, - {L"NotSpecified-Ax", 96, {230, 228, 24}}, - {L"NotSpecified-Backpack", 97, {228, 104, 245}}, - {L"NotSpecified-Bag", 98, {215, 41, 202}}, - {L"NotSpecified-Barbell", 99, {100, 125, 112}}, - {L"NotSpecified-BlackBoard", 100, {65, 166, 116}}, - {L"NotSpecified-Bottle", 101, {140, 68, 191}}, - {L"NotSpecified-box", 102, {145, 146, 89}}, - {L"NotSpecified-Cable", 103, {170, 1, 118}}, - {L"NotSpecified-Can", 104, {205, 195, 201}}, - {L"NotSpecified-Cart", 105, {156, 159, 0}}, - {L"NotSpecified-case", 106, {208, 70, 137}}, - {L"NotSpecified-CeilingFan", 107, {9, 227, 245}}, - {L"NotSpecified-Clothes", 108, {181, 123, 192}}, - {L"NotSpecified-Coat", 109, {189, 249, 62}}, - {L"NotSpecified-Coatrack", 110, {136, 15, 19}}, - {L"NotSpecified-CorkBoard", 111, {167, 98, 139}}, - {L"NotSpecified-CounterTop", 112, {6, 14, 93}}, - {L"NotSpecified-Drawers", 113, {216, 156, 242}}, - {L"NotSpecified-Drinkcontainer", 114, {238, 153, 75}}, - {L"NotSpecified-Dumbbell", 115, {183, 111, 41}}, - {L"NotSpecified-ElectricalOutlet", 116, {191, 199, 36}}, - {L"NotSpecified-ElectricalSwitch", 117, {31, 81, 127}}, - {L"NotSpecified-Elliptical", 118, {244, 92, 59}}, - {L"NotSpecified-Food", 119, {221, 210, 211}}, - {L"NotSpecified-Footwear", 120, {163, 245, 159}}, - {L"NotSpecified-Hammer", 121, {118, 176, 85}}, - {L"NotSpecified-LaptopBag", 122, {225, 32, 60}}, - {L"NotSpecified-LIDAR", 123, {26, 105, 172}}, - {L"NotSpecified-Mannequin", 124, {131, 135, 194}}, - {L"NotSpecified-Markers", 125, {124, 23, 155}}, - {L"NotSpecified-Microscope", 126, {128, 143, 248}}, - {L"NotSpecified-NDI", 127, {220, 39, 237}}, - {L"NotSpecified-Pinwheel", 128, {155, 24, 46}}, - {L"NotSpecified-PunchingBag", 129, {152, 215, 122}}, - {L"NotSpecified-Shower", 130, {78, 243, 86}}, - {L"NotSpecified-Sign", 131, {29, 159, 136}}, - {L"NotSpecified-Sink", 132, {209, 19, 236}}, - {L"NotSpecified-Sissors", 133, {31, 229, 162}}, - {L"NotSpecified-Sphere", 134, {151, 86, 155}}, - {L"NotSpecified-StairClimber", 135, {52, 236, 130}}, - {L"NotSpecified-stanchion", 136, {6, 76, 221}}, - {L"NotSpecified-Stand", 137, {2, 12, 172}}, - {L"NotSpecified-StationaryBike", 138, {69, 190, 196}}, - {L"NotSpecified-Tape", 139, {176, 3, 131}}, - {L"NotSpecified-Thermostat", 140, {33, 22, 47}}, - {L"NotSpecified-Toilet", 141, {107, 45, 152}}, - {L"NotSpecified-TrashCan", 142, {128, 72, 143}}, - {L"NotSpecified-Tripod", 143, {225, 31, 162}}, - {L"NotSpecified-Tub", 144, {110, 147, 77}}, - {L"NotSpecified-Vent", 145, {137, 170, 110}}, - {L"NotSpecified-WeightBench", 146, {183, 79, 90}}, - {L"NotSpecified-Wire", 147, {0, 255, 38}}, - {L"NotSpecified-Wrench", 148, {116, 3, 22}}, - {L"NotSpecified-Pillar", 149, {128, 184, 144}}, - {L"NotSpecified-Whiteboard", 150, {94, 240, 206}}, - {L"Plant-Fake", 151, {216, 230, 169}}, - {L"Plant-NotSpecified", 152, {182, 43, 63}}, - {L"Plant-Organic", 153, {197, 86, 148}}, - {L"Props-Book", 154, {247, 3, 157}}, - {L"Props-Cushion", 155, {13, 94, 49}}, - {L"Props-FloorVase", 156, {55, 213, 231}}, - {L"Props-FlowerPot", 157, {239, 172, 43}}, - {L"Props-Magazine", 158, {138, 164, 178}}, - {L"Props-Mirror", 159, {116, 236, 157}}, - {L"Props-NewsPaper", 160, {62, 80, 43}}, - {L"Props-NotSpecified", 161, {9, 106, 45}}, - {L"Props-Paintings", 162, {164, 117, 118}}, - {L"Props-PaperSheet", 163, {85, 190, 229}}, - {L"Props-PhotoFrame", 164, {18, 95, 80}}, - {L"Props-Rug", 165, {192, 82, 167}}, - {L"Props-Sculpture", 166, {130, 15, 64}}, - {L"Props-Toys", 167, {136, 130, 225}}, - {L"Sofa-ChaiseLounge", 168, {241, 154, 12}}, - {L"Sofa-NotSpecified", 169, {113, 197, 139}}, - {L"Sofa-Sectional", 170, {24, 132, 64}}, - {L"Sofa-Straight", 171, {248, 137, 194}}, - {L"Storage-Bookshelf", 172, {4, 69, 174}}, - {L"Storage-ChinaCabinet", 173, {216, 165, 83}}, - {L"Storage-Dresser", 174, {156, 24, 110}}, - {L"Storage-FileCabinet", 175, {78, 78, 12}}, - {L"Storage-MediaCabinet", 176, {168, 234, 45}}, - {L"Storage-NotSpecified", 177, {29, 232, 238}}, - {L"Storage-Rack", 178, {161, 36, 92}}, - {L"Storage-Shelf", 179, {57, 187, 87}}, - {L"Storage-Cabinet", 180, {164, 23, 45}}, - {L"Storage-Stairs", 181, {10, 13, 61}}, - {L"Table-CoffeeTable", 182, {178, 214, 30}}, - {L"Table-ConferenceTable", 183, {25, 153, 182}}, - {L"Table-Desk", 184, {171, 128, 231}}, - {L"Table-DiningTable", 185, {12, 169, 156}}, - {L"Table-Nightstand", 186, {247, 131, 122}}, - {L"Table-NotSpecified", 187, {227, 214, 90}}, - {L"Table-OfficeDesk", 188, {122, 253, 7}}, - {L"Table-OfficeTable", 189, {6, 20, 5}}, - {L"Table-SideTable", 190, {230, 211, 253}}, - {L"Unassigned-Unassigned", 191, {141, 204, 180}}, - {L"Utensils-Bowl", 192, {108, 89, 46}}, - {L"Utensils-Cups", 193, {90, 250, 131}}, - {L"Utensils-Knife", 194, {28, 67, 176}}, - {L"Utensils-Mug", 195, {152, 218, 150}}, - {L"Utensils-NotSpecified", 196, {211, 96, 157}}, - {L"Utensils-Pans", 197, {73, 159, 109}}, - {L"Utensils-Pots", 198, {7, 193, 112}}, - {L"Utensils-Tray", 199, {60, 152, 1}}, - {L"Vehicle-Car", 200, {189, 149, 61}}, - {L"Vehicle-MotorCycle", 201, {2, 164, 102}}, - {L"Vehicle-Segway", 202, {198, 165, 85}}, - {L"Vehicle-Truck", 203, {134, 46, 106}}, - {L"Wall-Blinds", 204, {9, 13, 13}}, - {L"Wall-Curtain", 205, {52, 74, 241}}, - {L"Wall-Unassigned", 206, {83, 158, 59}}, - {L"Wall-Window", 207, {117, 162, 84}}, - {L"Storage-BathroomVanity", 208, {127, 151, 35}}, - {L"NotSpecified-Unassigned", 209, {143, 133, 123}}, - {L"Storage-Nightstand", 210, {181, 112, 177}}, - {L"Storage-Unassigned", 211, {73, 125, 140}}, - {L"Props-Unassigned", 212, {156, 127, 134}}, - {L"Storage-ArmChair", 213, {102, 111, 19}}, - {L"NotSpecified-LaundryBasket", 214, {106, 168, 192}}, - {L"Props-Decorations", 215, {49, 242, 177}}, - {L"NotSpecified-Fireplace", 216, {96, 128, 236}}, - {L"NotSpecified-Drinkware", 217, {6, 247, 22}}, - {L"Sofa-LoungeChair", 218, {167, 92, 66}}, - {L"NotSpecified-NotSpecified", 219, {174, 127, 40}}, - {L"Mouse", 220, {65, 33, 210}}, - {L"Bag", 221, {168, 71, 185}}, - {L"Fridge", 222, {255, 127, 94}}, - {L"Stand", 223, {246, 160, 193}}, - {L"Sign", 224, {143, 221, 54}}, - {L"Sphere", 225, {255, 207, 172}}, - {L"Tripod", 227, {255, 235, 46}}, - {L"PinWheel", 228, {13, 92, 139}}, - {L"Kart", 229, {49, 3, 27}}, - {L"Box", 230, {134, 215, 144}}, - {L"Light", 231, {140, 3, 56}}, - {L"Keyboard ", 232, {7, 66, 58}}, - {L"Scupture", 233, {240, 191, 82}}, - {L"Lamp", 234, {189, 8, 78}}, - {L"Microscope ", 235, {255, 211, 112}}, - {L"Case ", 236, {59, 155, 70}}, - {L"Ax", 237, {157, 117, 29}}, - {L"Manikin_Parts ", 238, {67, 141, 186}}, - {L"Clothing ", 239, {4, 122, 55}}, - {L"CoatRack", 240, {211, 52, 114}}, - {L"DrinkContainer ", 241, {35, 23, 0}}, - {L"MousePad", 242, {68, 28, 0}}, - {L"Tape", 243, {107, 173, 211}}, - {L"Sissors ", 245, {53, 24, 143}}, - {L"Headphones ", 246, {45, 212, 189}}, -}; - -constexpr auto NumLabels = sizeof(LabelStorage) / sizeof(Label); - -// Dictionary to quickly access labels by numeric label ID -using LabelDictionary = std::map; -static LabelDictionary Labels; - -SceneUnderstandingRenderer::SceneUnderstandingRenderer(const std::shared_ptr& deviceResources) - : RenderableObject(deviceResources) -{ - // If the label dictionary is still empty, build it from static data - if (Labels.empty()) - { - for (size_t i = 0; i < NumLabels; ++i) - { - Labels[LabelStorage[i].Index] = &LabelStorage[i]; - } - } -} - -void SceneUnderstandingRenderer::Update( - winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, - winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation) -{ - m_vertices.clear(); - - // Calculate the head position at the time of the last SU update in render space. This information can be - // used for debug rendering. - winrt::Windows::Foundation::IReference lastUpdatePosInRenderSpace; - if (lastUpdateLocation) - { - auto lastUpdateCS = lastUpdateLocation.CoordinateSystem(); - auto lastUpdateLocationToRender = lastUpdateCS.TryGetTransformTo(renderingCoordinateSystem); - if (lastUpdateLocationToRender) - { - lastUpdatePosInRenderSpace = winrt::Windows::Foundation::Numerics::transform({0, 0, 0}, lastUpdateLocationToRender.Value()); - } - } - - // Lambda to execute for each quad returned by SU. Adds the quad to the vertex buffer for rendering, using - // the color indicated by the label dictionary for the quad's owner entity's type. Optionally draws debug - // rays from the last update position to each quad. - auto processQuadForRendering = [this, &renderingCoordinateSystem, &lastUpdatePosInRenderSpace]( - const winrt::SceneUnderstanding::Entity& entity, - const winrt::SceneUnderstanding::Quad& quad, - const winrt::Windows::Foundation::Numerics::float4x4& entityToAnchorTransform, - const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& entityAnchorCS) { - // Determine the transform to go from entity space to rendering space - winrt::Windows::Foundation::IReference anchorToRenderingRef = - entityAnchorCS.TryGetTransformTo(renderingCoordinateSystem); - if (!anchorToRenderingRef) - { - return; - } - winrt::Windows::Foundation::Numerics::float4x4 anchorToRenderingTransform = anchorToRenderingRef.Value(); - winrt::Windows::Foundation::Numerics::float4x4 entityToRenderingTransform = entityToAnchorTransform * anchorToRenderingTransform; - - // Create the quad's corner points in entity space and transform them to rendering space - const float width = quad.WidthInMeters(); - const float height = quad.HeightInMeters(); - winrt::Windows::Foundation::Numerics::float3 positions[4] = { - {-width / 2, -height / 2, 0.0f}, {width / 2, -height / 2, 0.0f}, {-width / 2, height / 2, 0.0f}, {width / 2, height / 2, 0.0f}}; - for (int i = 0; i < 4; ++i) - { - positions[i] = winrt::Windows::Foundation::Numerics::transform(positions[i], entityToRenderingTransform); - } - - // Determine the color with which to draw the quad - winrt::Windows::Foundation::Numerics::float3 color{1.0f, 1.0f, 0.0f}; - auto labelPos = Labels.find(static_cast(entity.Label())); - if (labelPos != Labels.end()) - { - const Label& label = *labelPos->second; - color = {label.RGB[0] / 255.0f, label.RGB[1] / 255.0f, label.RGB[2] / 255.0f}; - } - - // Add triangles to render the quad (both winding orders to guarantee double-sided rendering) - AppendColoredTriangle(positions[0], positions[3], positions[1], color, m_vertices); - AppendColoredTriangle(positions[0], positions[2], positions[3], color, m_vertices); - AppendColoredTriangle(positions[1], positions[3], positions[0], color, m_vertices); - AppendColoredTriangle(positions[3], positions[2], positions[0], color, m_vertices); - - /** / - // Debug code: draw a ray from the last update position to the center of each visible quad - if (lastUpdatePosInRenderSpace) - { - float rayEndRadius = 0.05f; - winrt::Windows::Foundation::Numerics::float3 rayEndPositions[4] = { - {-rayEndRadius, 0.0f, 0.0f}, - {rayEndRadius, 0.0f, 0.0f}, - {0.0f, -rayEndRadius, 0.0f}, - {0.0f, rayEndRadius, 0.0f}, - }; - for (int i = 0; i < 4; ++i) - { - rayEndPositions[i] = winrt::Windows::Foundation::Numerics::transform(rayEndPositions[i], entityToRenderingTransform); - } - AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[0], rayEndPositions[1], color, m_vertices); - AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[1], rayEndPositions[0], color, m_vertices); - AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[2], rayEndPositions[3], color, m_vertices); - AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[3], rayEndPositions[2], color, m_vertices); - } - /**/ - }; - - // Execute the above lambda for each quad known by the SceneProcessor - ForEachQuad(sceneProcessor, processQuadForRendering); - - // The geometry we added is already in rendering space, so the model transform must be identity. - auto modelTransform = winrt::Windows::Foundation::Numerics::float4x4::identity(); - UpdateModelConstantBuffer(modelTransform); -} - -void SceneUnderstandingRenderer::DebugLogState( - winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, - winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation) -{ - // Calculate the head position at the time of the last SU update in render space. This information can be - // used for debug rendering. - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem lastUpdateCS = lastUpdateLocation.CoordinateSystem(); - winrt::Windows::Foundation::IReference lastUpdatePosInRenderSpaceRef; - if (lastUpdateLocation) - { - auto lastUpdateLocationToRender = lastUpdateCS.TryGetTransformTo(renderingCoordinateSystem); - if (lastUpdateLocationToRender) - { - lastUpdatePosInRenderSpaceRef = winrt::Windows::Foundation::Numerics::transform({0, 0, 0}, lastUpdateLocationToRender.Value()); - } - } - if (!lastUpdatePosInRenderSpaceRef) - { - return; - } - winrt::Windows::Foundation::Numerics::float3 lastUpdatePosInRenderSpace = lastUpdatePosInRenderSpaceRef.Value(); - - auto logQuad = [this, &lastUpdateCS]( - const winrt::SceneUnderstanding::Entity& entity, - const winrt::SceneUnderstanding::Quad& quad, - const winrt::Windows::Foundation::Numerics::float4x4& entityToAnchorTransform, - const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& entityAnchorCS) { - // Determine transform from entity space to last update pose space - winrt::Windows::Foundation::IReference anchorToLastUpdateRef = - entityAnchorCS.TryGetTransformTo(lastUpdateCS); - if (!anchorToLastUpdateRef) - { - return; - } - winrt::Windows::Foundation::Numerics::float4x4 anchorToLastUpdateTransform = anchorToLastUpdateRef.Value(); - winrt::Windows::Foundation::Numerics::float4x4 entityToLastUpdateTransform = entityToAnchorTransform * anchorToLastUpdateTransform; - - // Determine various sizes, position, and distance from head - const float width = quad.WidthInMeters(); - const float height = quad.HeightInMeters(); - const float radius = sqrtf(width * width + height * height) / 2; - - const winrt::Windows::Foundation::Numerics::float3 position = winrt::Windows::Foundation::Numerics::transform( - winrt::Windows::Foundation::Numerics::float3::zero(), entityToLastUpdateTransform); - const float distance = winrt::Windows::Foundation::Numerics::length(position); - - const wchar_t* labelName = L""; - auto labelPos = Labels.find(static_cast(entity.Label())); - if (labelPos != Labels.end()) - { - const Label& label = *labelPos->second; - labelName = label.Name; - } - - DebugLog( - L" %s (%.2f x %.2f m, radius: %.2f m) at %.2f;%.2f;%.2f (distance: %.2f m)", - labelName, - width, - height, - radius, - position.x, - position.y, - position.z, - distance); - }; - - DebugLog(L"--- SU Update ---"); - DebugLog( - L" Update position (in root space): (%.2f; %.2f; %.2f)", - lastUpdatePosInRenderSpace.x, - lastUpdatePosInRenderSpace.y, - lastUpdatePosInRenderSpace.z); - DebugLog(L" Quads (in head pose space):"); - ForEachQuad(sceneProcessor, logQuad); -} - -void SceneUnderstandingRenderer::Draw(unsigned int numInstances) -{ - if (m_vertices.empty()) - { - return; - } - - const UINT stride = sizeof(m_vertices[0]); - const UINT offset = 0; - D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; - vertexBufferData.pSysMem = m_vertices.data(); - const CD3D11_BUFFER_DESC vertexBufferDesc(static_cast(m_vertices.size() * stride), D3D11_BIND_VERTEX_BUFFER); - winrt::com_ptr vertexBuffer; - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, vertexBuffer.put())); - - auto context = m_deviceResources->GetD3DDeviceContext(); - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - ID3D11Buffer* pBuffer = vertexBuffer.get(); - context->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset); - context->DrawInstanced(static_cast(m_vertices.size()), numInstances, offset, 0); -} - -template -void SceneUnderstandingRenderer::ForEachQuad(winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, Func f) -{ - // Collect all components, then iterate to find quad entities - winrt::com_array components; - sceneProcessor.GetAllComponents(components); - for (auto& component : components) - { - winrt::SceneUnderstanding::Entity entity = component.try_as(); - if (!entity) - { - continue; - } - - winrt::SceneUnderstanding::Quad quad{nullptr}; - winrt::SceneUnderstanding::Transform transform{nullptr}; - winrt::SceneUnderstanding::SpatialCoordinateSystem spatialCS{nullptr}; - - winrt::com_array associatedComponentIds; - entity.GetAllAssociatedComponentIds(associatedComponentIds); - - for (auto& id : associatedComponentIds) - { - winrt::SceneUnderstanding::Component ac = sceneProcessor.GetComponent(id); - if (auto q = ac.try_as()) - { - quad = q; - continue; - } - if (auto t = ac.try_as()) - { - transform = t; - continue; - } - if (auto s = ac.try_as()) - { - spatialCS = s; - continue; - } - } - - // Don't proceed if any essential bit of data is missing - if (!quad || !transform || !spatialCS) - { - continue; - } - - // Determine the transform from the entity to its anchor - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem entityAnchorCS{nullptr}; - try - { - entityAnchorCS = winrt::Windows::Perception::Spatial::Preview::SpatialGraphInteropPreview::CreateCoordinateSystemForNode( - spatialCS.SpatialCoordinateGuid()); - } - catch (const winrt::hresult_error&) - { - continue; - } - - winrt::Windows::Foundation::Numerics::float4x4 entityToAnchorTransform = transform.TransformationMatrix(); - - f(entity, quad, entityToAnchorTransform, entityAnchorCS); - } -} +//********************************************************* +// +// 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 "../Common/DbgLog.h" +#include "../Common/DirectXHelper.h" + +#include "SceneUnderstandingRenderer.h" + +#include + +using namespace RemotingHostSample; + +namespace +{ + using namespace DirectX; + + void AppendColoredTriangle( + winrt::Windows::Foundation::Numerics::float3 p0, + winrt::Windows::Foundation::Numerics::float3 p1, + winrt::Windows::Foundation::Numerics::float3 p2, + winrt::Windows::Foundation::Numerics::float3 color, + std::vector& vertices) + { + VertexPositionNormalColor vertex; + vertex.color = XMFLOAT3(&color.x); + vertex.normal = XMFLOAT3(0.0f, 0.0f, 0.0f); + + vertex.pos = XMFLOAT3(&p0.x); + vertices.push_back(vertex); + vertex.pos = XMFLOAT3(&p1.x); + vertices.push_back(vertex); + vertex.pos = XMFLOAT3(&p2.x); + vertices.push_back(vertex); + } +} // namespace + +// Struct to hold one entity label type entry +struct Label +{ + const wchar_t* const Name; + uint32_t Index; + uint8_t RGB[3]; +}; + +// Entity label types +static const Label LabelStorage[] = { + {L"Background", 0, {243, 121, 223}}, + {L"Ignore", 255, {255, 255, 255}}, + {L"Wall", 1, {243, 126, 121}}, + {L"Floor", 2, {187, 243, 121}}, + {L"Ceiling", 3, {121, 152, 243}}, + {L"Table", 4, {121, 243, 227}}, + {L"Chair", 5, {243, 191, 121}}, + {L"Window", 6, {121, 243, 146}}, + {L"Door", 7, {156, 121, 243}}, + {L"Monitor", 8, {2, 159, 253}}, + {L"Pillar", 10, {253, 106, 2}}, + {L"Couch", 11, {72, 197, 126}}, + {L"Whiteboard", 12, {137, 159, 2}}, + {L"Beanbag", 13, {206, 112, 74}}, + {L"Cabinet", 14, {36, 43, 138}}, + {L"Nightstands", 15, {78, 231, 210}}, + {L"TVStands", 16, {26, 71, 66}}, + {L"Countertops", 17, {13, 60, 55}}, + {L"Dressers", 18, {29, 58, 55}}, + {L"Bench", 19, {105, 54, 136}}, + {L"Ottoman", 20, {99, 9, 44}}, + {L"Stool", 21, {255, 204, 153}}, + {L"GTEquipment", 22, {206, 199, 74}}, + {L"Telephone", 23, {243, 217, 121}}, + {L"Bookshelf", 24, {37, 117, 164}}, + {L"Laptop", 25, {96, 147, 234}}, + {L"Stanchion", 26, {29, 117, 40}}, + {L"Markers", 27, {111, 93, 167}}, + {L"Controller", 28, {230, 254, 251}}, + {L"Stairs", 9, {43, 174, 100}}, + {L"Empty", 254, {0, 0, 0}}, + {L"Appliances-CeilingLight", 30, {250, 24, 180}}, + {L"Appliances-DishWasher", 32, {38, 204, 168}}, + {L"Appliances-FloorLamp", 34, {106, 134, 187}}, + {L"Appliances-Lighting", 36, {156, 162, 56}}, + {L"Appliances-Microwave", 37, {6, 44, 91}}, + {L"Appliances-NotSpecified", 38, {35, 188, 199}}, + {L"Appliances-Oven", 39, {153, 60, 52}}, + {L"Appliances-SmallAppliances", 40, {255, 83, 112}}, + {L"Appliances-Stove", 41, {76, 175, 147}}, + {L"Appliances-Toaster", 42, {145, 58, 23}}, + {L"Appliances-WashingMachine", 44, {46, 66, 12}}, + {L"Appliances-DeskLamp", 45, {128, 86, 177}}, + {L"Appliances-Dryer", 46, {239, 162, 164}}, + {L"Appliances-Fridge", 47, {87, 243, 139}}, + {L"Appliances-WallLight", 50, {222, 49, 1}}, + {L"Bed-BunkBed", 51, {97, 174, 71}}, + {L"Bed-DoubleBed", 52, {85, 195, 111}}, + {L"Bed-NotSpecified", 53, {212, 26, 75}}, + {L"Bed-SingleBed", 54, {200, 219, 241}}, + {L"Ceiling-Unassigned", 55, {48, 120, 115}}, + {L"Ceiling-NotSpecified", 56, {205, 144, 139}}, + {L"Chair-Beanbag", 57, {136, 175, 192}}, + {L"Chair-Bench", 58, {89, 41, 203}}, + {L"Chair-ArmChair", 59, {192, 1, 27}}, + {L"Chair-ArmOfAChair", 60, {194, 241, 101}}, + {L"Chair-BarStool", 61, {146, 21, 8}}, + {L"Chair-ChaiseLounge", 62, {178, 31, 121}}, + {L"Chair-DiningChair", 63, {76, 10, 219}}, + {L"Chair-LoungeChair", 64, {174, 165, 77}}, + {L"Chair-NotSpecified", 65, {186, 217, 58}}, + {L"Chair-OfficeChair", 66, {177, 29, 181}}, + {L"Chair-Unknown", 67, {155, 128, 196}}, + {L"Chair-Ottoman", 68, {28, 75, 247}}, + {L"Chair-Stool", 69, {60, 243, 241}}, + {L"Door-DoubleDoors", 70, {220, 101, 83}}, + {L"Door-NotSpecified", 71, {219, 20, 187}}, + {L"Door-Revolving", 72, {211, 229, 158}}, + {L"Door-SingleDoor", 73, {10, 100, 12}}, + {L"Door-Sliding", 74, {73, 197, 108}}, + {L"Electronics-Desktop", 75, {181, 22, 191}}, + {L"Electronics-DVDPlayer", 76, {5, 131, 13}}, + {L"Electronics-Headphones", 77, {169, 60, 180}}, + {L"Electronics-Keyboard", 78, {6, 92, 79}}, + {L"Electronics-Laptop", 79, {252, 108, 50}}, + {L"Electronics-Mobile", 80, {35, 73, 64}}, + {L"Electronics-Mouse", 81, {3, 112, 214}}, + {L"Electronics-Mousepad", 82, {106, 70, 62}}, + {L"Electronics-NotSpecified", 83, {63, 100, 209}}, + {L"Electronics-Phone", 84, {64, 32, 142}}, + {L"Electronics-Printer", 85, {70, 188, 0}}, + {L"Electronics-Projector", 86, {72, 100, 38}}, + {L"Electronics-Speakers", 87, {202, 60, 135}}, + {L"Electronics-Tablet", 88, {126, 2, 49}}, + {L"Electronics-TVMonitor", 89, {188, 184, 46}}, + {L"Electronics-Xbox", 90, {6, 218, 26}}, + {L"Electronics-Monitor", 91, {179, 160, 177}}, + {L"Floor-Unassigned", 92, {9, 42, 145}}, + {L"Human-Female", 93, {52, 156, 230}}, + {L"Human-Male", 94, {231, 88, 138}}, + {L"Human-Other", 95, {0, 0, 255}}, + {L"NotSpecified-Ax", 96, {230, 228, 24}}, + {L"NotSpecified-Backpack", 97, {228, 104, 245}}, + {L"NotSpecified-Bag", 98, {215, 41, 202}}, + {L"NotSpecified-Barbell", 99, {100, 125, 112}}, + {L"NotSpecified-BlackBoard", 100, {65, 166, 116}}, + {L"NotSpecified-Bottle", 101, {140, 68, 191}}, + {L"NotSpecified-box", 102, {145, 146, 89}}, + {L"NotSpecified-Cable", 103, {170, 1, 118}}, + {L"NotSpecified-Can", 104, {205, 195, 201}}, + {L"NotSpecified-Cart", 105, {156, 159, 0}}, + {L"NotSpecified-case", 106, {208, 70, 137}}, + {L"NotSpecified-CeilingFan", 107, {9, 227, 245}}, + {L"NotSpecified-Clothes", 108, {181, 123, 192}}, + {L"NotSpecified-Coat", 109, {189, 249, 62}}, + {L"NotSpecified-Coatrack", 110, {136, 15, 19}}, + {L"NotSpecified-CorkBoard", 111, {167, 98, 139}}, + {L"NotSpecified-CounterTop", 112, {6, 14, 93}}, + {L"NotSpecified-Drawers", 113, {216, 156, 242}}, + {L"NotSpecified-Drinkcontainer", 114, {238, 153, 75}}, + {L"NotSpecified-Dumbbell", 115, {183, 111, 41}}, + {L"NotSpecified-ElectricalOutlet", 116, {191, 199, 36}}, + {L"NotSpecified-ElectricalSwitch", 117, {31, 81, 127}}, + {L"NotSpecified-Elliptical", 118, {244, 92, 59}}, + {L"NotSpecified-Food", 119, {221, 210, 211}}, + {L"NotSpecified-Footwear", 120, {163, 245, 159}}, + {L"NotSpecified-Hammer", 121, {118, 176, 85}}, + {L"NotSpecified-LaptopBag", 122, {225, 32, 60}}, + {L"NotSpecified-LIDAR", 123, {26, 105, 172}}, + {L"NotSpecified-Mannequin", 124, {131, 135, 194}}, + {L"NotSpecified-Markers", 125, {124, 23, 155}}, + {L"NotSpecified-Microscope", 126, {128, 143, 248}}, + {L"NotSpecified-NDI", 127, {220, 39, 237}}, + {L"NotSpecified-Pinwheel", 128, {155, 24, 46}}, + {L"NotSpecified-PunchingBag", 129, {152, 215, 122}}, + {L"NotSpecified-Shower", 130, {78, 243, 86}}, + {L"NotSpecified-Sign", 131, {29, 159, 136}}, + {L"NotSpecified-Sink", 132, {209, 19, 236}}, + {L"NotSpecified-Sissors", 133, {31, 229, 162}}, + {L"NotSpecified-Sphere", 134, {151, 86, 155}}, + {L"NotSpecified-StairClimber", 135, {52, 236, 130}}, + {L"NotSpecified-stanchion", 136, {6, 76, 221}}, + {L"NotSpecified-Stand", 137, {2, 12, 172}}, + {L"NotSpecified-StationaryBike", 138, {69, 190, 196}}, + {L"NotSpecified-Tape", 139, {176, 3, 131}}, + {L"NotSpecified-Thermostat", 140, {33, 22, 47}}, + {L"NotSpecified-Toilet", 141, {107, 45, 152}}, + {L"NotSpecified-TrashCan", 142, {128, 72, 143}}, + {L"NotSpecified-Tripod", 143, {225, 31, 162}}, + {L"NotSpecified-Tub", 144, {110, 147, 77}}, + {L"NotSpecified-Vent", 145, {137, 170, 110}}, + {L"NotSpecified-WeightBench", 146, {183, 79, 90}}, + {L"NotSpecified-Wire", 147, {0, 255, 38}}, + {L"NotSpecified-Wrench", 148, {116, 3, 22}}, + {L"NotSpecified-Pillar", 149, {128, 184, 144}}, + {L"NotSpecified-Whiteboard", 150, {94, 240, 206}}, + {L"Plant-Fake", 151, {216, 230, 169}}, + {L"Plant-NotSpecified", 152, {182, 43, 63}}, + {L"Plant-Organic", 153, {197, 86, 148}}, + {L"Props-Book", 154, {247, 3, 157}}, + {L"Props-Cushion", 155, {13, 94, 49}}, + {L"Props-FloorVase", 156, {55, 213, 231}}, + {L"Props-FlowerPot", 157, {239, 172, 43}}, + {L"Props-Magazine", 158, {138, 164, 178}}, + {L"Props-Mirror", 159, {116, 236, 157}}, + {L"Props-NewsPaper", 160, {62, 80, 43}}, + {L"Props-NotSpecified", 161, {9, 106, 45}}, + {L"Props-Paintings", 162, {164, 117, 118}}, + {L"Props-PaperSheet", 163, {85, 190, 229}}, + {L"Props-PhotoFrame", 164, {18, 95, 80}}, + {L"Props-Rug", 165, {192, 82, 167}}, + {L"Props-Sculpture", 166, {130, 15, 64}}, + {L"Props-Toys", 167, {136, 130, 225}}, + {L"Sofa-ChaiseLounge", 168, {241, 154, 12}}, + {L"Sofa-NotSpecified", 169, {113, 197, 139}}, + {L"Sofa-Sectional", 170, {24, 132, 64}}, + {L"Sofa-Straight", 171, {248, 137, 194}}, + {L"Storage-Bookshelf", 172, {4, 69, 174}}, + {L"Storage-ChinaCabinet", 173, {216, 165, 83}}, + {L"Storage-Dresser", 174, {156, 24, 110}}, + {L"Storage-FileCabinet", 175, {78, 78, 12}}, + {L"Storage-MediaCabinet", 176, {168, 234, 45}}, + {L"Storage-NotSpecified", 177, {29, 232, 238}}, + {L"Storage-Rack", 178, {161, 36, 92}}, + {L"Storage-Shelf", 179, {57, 187, 87}}, + {L"Storage-Cabinet", 180, {164, 23, 45}}, + {L"Storage-Stairs", 181, {10, 13, 61}}, + {L"Table-CoffeeTable", 182, {178, 214, 30}}, + {L"Table-ConferenceTable", 183, {25, 153, 182}}, + {L"Table-Desk", 184, {171, 128, 231}}, + {L"Table-DiningTable", 185, {12, 169, 156}}, + {L"Table-Nightstand", 186, {247, 131, 122}}, + {L"Table-NotSpecified", 187, {227, 214, 90}}, + {L"Table-OfficeDesk", 188, {122, 253, 7}}, + {L"Table-OfficeTable", 189, {6, 20, 5}}, + {L"Table-SideTable", 190, {230, 211, 253}}, + {L"Unassigned-Unassigned", 191, {141, 204, 180}}, + {L"Utensils-Bowl", 192, {108, 89, 46}}, + {L"Utensils-Cups", 193, {90, 250, 131}}, + {L"Utensils-Knife", 194, {28, 67, 176}}, + {L"Utensils-Mug", 195, {152, 218, 150}}, + {L"Utensils-NotSpecified", 196, {211, 96, 157}}, + {L"Utensils-Pans", 197, {73, 159, 109}}, + {L"Utensils-Pots", 198, {7, 193, 112}}, + {L"Utensils-Tray", 199, {60, 152, 1}}, + {L"Vehicle-Car", 200, {189, 149, 61}}, + {L"Vehicle-MotorCycle", 201, {2, 164, 102}}, + {L"Vehicle-Segway", 202, {198, 165, 85}}, + {L"Vehicle-Truck", 203, {134, 46, 106}}, + {L"Wall-Blinds", 204, {9, 13, 13}}, + {L"Wall-Curtain", 205, {52, 74, 241}}, + {L"Wall-Unassigned", 206, {83, 158, 59}}, + {L"Wall-Window", 207, {117, 162, 84}}, + {L"Storage-BathroomVanity", 208, {127, 151, 35}}, + {L"NotSpecified-Unassigned", 209, {143, 133, 123}}, + {L"Storage-Nightstand", 210, {181, 112, 177}}, + {L"Storage-Unassigned", 211, {73, 125, 140}}, + {L"Props-Unassigned", 212, {156, 127, 134}}, + {L"Storage-ArmChair", 213, {102, 111, 19}}, + {L"NotSpecified-LaundryBasket", 214, {106, 168, 192}}, + {L"Props-Decorations", 215, {49, 242, 177}}, + {L"NotSpecified-Fireplace", 216, {96, 128, 236}}, + {L"NotSpecified-Drinkware", 217, {6, 247, 22}}, + {L"Sofa-LoungeChair", 218, {167, 92, 66}}, + {L"NotSpecified-NotSpecified", 219, {174, 127, 40}}, + {L"Mouse", 220, {65, 33, 210}}, + {L"Bag", 221, {168, 71, 185}}, + {L"Fridge", 222, {255, 127, 94}}, + {L"Stand", 223, {246, 160, 193}}, + {L"Sign", 224, {143, 221, 54}}, + {L"Sphere", 225, {255, 207, 172}}, + {L"Tripod", 227, {255, 235, 46}}, + {L"PinWheel", 228, {13, 92, 139}}, + {L"Kart", 229, {49, 3, 27}}, + {L"Box", 230, {134, 215, 144}}, + {L"Light", 231, {140, 3, 56}}, + {L"Keyboard ", 232, {7, 66, 58}}, + {L"Scupture", 233, {240, 191, 82}}, + {L"Lamp", 234, {189, 8, 78}}, + {L"Microscope ", 235, {255, 211, 112}}, + {L"Case ", 236, {59, 155, 70}}, + {L"Ax", 237, {157, 117, 29}}, + {L"Manikin_Parts ", 238, {67, 141, 186}}, + {L"Clothing ", 239, {4, 122, 55}}, + {L"CoatRack", 240, {211, 52, 114}}, + {L"DrinkContainer ", 241, {35, 23, 0}}, + {L"MousePad", 242, {68, 28, 0}}, + {L"Tape", 243, {107, 173, 211}}, + {L"Sissors ", 245, {53, 24, 143}}, + {L"Headphones ", 246, {45, 212, 189}}, +}; + +constexpr auto NumLabels = sizeof(LabelStorage) / sizeof(Label); + +// Dictionary to quickly access labels by numeric label ID +using LabelDictionary = std::map; +static LabelDictionary Labels; + +SceneUnderstandingRenderer::SceneUnderstandingRenderer(const std::shared_ptr& deviceResources) + : RenderableObject(deviceResources) +{ + // If the label dictionary is still empty, build it from static data + if (Labels.empty()) + { + for (size_t i = 0; i < NumLabels; ++i) + { + Labels[LabelStorage[i].Index] = &LabelStorage[i]; + } + } +} + +void SceneUnderstandingRenderer::Update( + winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, + winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation) +{ + m_vertices.clear(); + + // Calculate the head position at the time of the last SU update in render space. This information can be + // used for debug rendering. + winrt::Windows::Foundation::IReference lastUpdatePosInRenderSpace; + if (lastUpdateLocation) + { + auto lastUpdateCS = lastUpdateLocation.CoordinateSystem(); + auto lastUpdateLocationToRender = lastUpdateCS.TryGetTransformTo(renderingCoordinateSystem); + if (lastUpdateLocationToRender) + { + lastUpdatePosInRenderSpace = winrt::Windows::Foundation::Numerics::transform({0, 0, 0}, lastUpdateLocationToRender.Value()); + } + } + + // Lambda to execute for each quad returned by SU. Adds the quad to the vertex buffer for rendering, using + // the color indicated by the label dictionary for the quad's owner entity's type. Optionally draws debug + // rays from the last update position to each quad. + auto processQuadForRendering = [this, &renderingCoordinateSystem, &lastUpdatePosInRenderSpace]( + const winrt::SceneUnderstanding::Entity& entity, + const winrt::SceneUnderstanding::Quad& quad, + const winrt::Windows::Foundation::Numerics::float4x4& entityToAnchorTransform, + const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& entityAnchorCS) { + // Determine the transform to go from entity space to rendering space + winrt::Windows::Foundation::IReference anchorToRenderingRef = + entityAnchorCS.TryGetTransformTo(renderingCoordinateSystem); + if (!anchorToRenderingRef) + { + return; + } + winrt::Windows::Foundation::Numerics::float4x4 anchorToRenderingTransform = anchorToRenderingRef.Value(); + winrt::Windows::Foundation::Numerics::float4x4 entityToRenderingTransform = entityToAnchorTransform * anchorToRenderingTransform; + + // Create the quad's corner points in entity space and transform them to rendering space + const float width = quad.WidthInMeters(); + const float height = quad.HeightInMeters(); + winrt::Windows::Foundation::Numerics::float3 positions[4] = { + {-width / 2, -height / 2, 0.0f}, {width / 2, -height / 2, 0.0f}, {-width / 2, height / 2, 0.0f}, {width / 2, height / 2, 0.0f}}; + for (int i = 0; i < 4; ++i) + { + positions[i] = winrt::Windows::Foundation::Numerics::transform(positions[i], entityToRenderingTransform); + } + + // Determine the color with which to draw the quad + winrt::Windows::Foundation::Numerics::float3 color{1.0f, 1.0f, 0.0f}; + auto labelPos = Labels.find(static_cast(entity.Label())); + if (labelPos != Labels.end()) + { + const Label& label = *labelPos->second; + color = {label.RGB[0] / 255.0f, label.RGB[1] / 255.0f, label.RGB[2] / 255.0f}; + } + + // Add triangles to render the quad (both winding orders to guarantee double-sided rendering) + AppendColoredTriangle(positions[0], positions[3], positions[1], color, m_vertices); + AppendColoredTriangle(positions[0], positions[2], positions[3], color, m_vertices); + AppendColoredTriangle(positions[1], positions[3], positions[0], color, m_vertices); + AppendColoredTriangle(positions[3], positions[2], positions[0], color, m_vertices); + + /** / + // Debug code: draw a ray from the last update position to the center of each visible quad + if (lastUpdatePosInRenderSpace) + { + float rayEndRadius = 0.05f; + winrt::Windows::Foundation::Numerics::float3 rayEndPositions[4] = { + {-rayEndRadius, 0.0f, 0.0f}, + {rayEndRadius, 0.0f, 0.0f}, + {0.0f, -rayEndRadius, 0.0f}, + {0.0f, rayEndRadius, 0.0f}, + }; + for (int i = 0; i < 4; ++i) + { + rayEndPositions[i] = winrt::Windows::Foundation::Numerics::transform(rayEndPositions[i], entityToRenderingTransform); + } + AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[0], rayEndPositions[1], color, m_vertices); + AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[1], rayEndPositions[0], color, m_vertices); + AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[2], rayEndPositions[3], color, m_vertices); + AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[3], rayEndPositions[2], color, m_vertices); + } + /**/ + }; + + // Execute the above lambda for each quad known by the SceneProcessor + ForEachQuad(sceneProcessor, processQuadForRendering); + + // The geometry we added is already in rendering space, so the model transform must be identity. + auto modelTransform = winrt::Windows::Foundation::Numerics::float4x4::identity(); + UpdateModelConstantBuffer(modelTransform); +} + +void SceneUnderstandingRenderer::DebugLogState( + winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, + winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation) +{ + // Calculate the head position at the time of the last SU update in render space. This information can be + // used for debug rendering. + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem lastUpdateCS = lastUpdateLocation.CoordinateSystem(); + winrt::Windows::Foundation::IReference lastUpdatePosInRenderSpaceRef; + if (lastUpdateLocation) + { + auto lastUpdateLocationToRender = lastUpdateCS.TryGetTransformTo(renderingCoordinateSystem); + if (lastUpdateLocationToRender) + { + lastUpdatePosInRenderSpaceRef = winrt::Windows::Foundation::Numerics::transform({0, 0, 0}, lastUpdateLocationToRender.Value()); + } + } + if (!lastUpdatePosInRenderSpaceRef) + { + return; + } + winrt::Windows::Foundation::Numerics::float3 lastUpdatePosInRenderSpace = lastUpdatePosInRenderSpaceRef.Value(); + + auto logQuad = [this, &lastUpdateCS]( + const winrt::SceneUnderstanding::Entity& entity, + const winrt::SceneUnderstanding::Quad& quad, + const winrt::Windows::Foundation::Numerics::float4x4& entityToAnchorTransform, + const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& entityAnchorCS) { + // Determine transform from entity space to last update pose space + winrt::Windows::Foundation::IReference anchorToLastUpdateRef = + entityAnchorCS.TryGetTransformTo(lastUpdateCS); + if (!anchorToLastUpdateRef) + { + return; + } + winrt::Windows::Foundation::Numerics::float4x4 anchorToLastUpdateTransform = anchorToLastUpdateRef.Value(); + winrt::Windows::Foundation::Numerics::float4x4 entityToLastUpdateTransform = entityToAnchorTransform * anchorToLastUpdateTransform; + + // Determine various sizes, position, and distance from head + const float width = quad.WidthInMeters(); + const float height = quad.HeightInMeters(); + const float radius = sqrtf(width * width + height * height) / 2; + + const winrt::Windows::Foundation::Numerics::float3 position = winrt::Windows::Foundation::Numerics::transform( + winrt::Windows::Foundation::Numerics::float3::zero(), entityToLastUpdateTransform); + const float distance = winrt::Windows::Foundation::Numerics::length(position); + + const wchar_t* labelName = L""; + auto labelPos = Labels.find(static_cast(entity.Label())); + if (labelPos != Labels.end()) + { + const Label& label = *labelPos->second; + labelName = label.Name; + } + + DebugLog( + L" %s (%.2f x %.2f m, radius: %.2f m) at %.2f;%.2f;%.2f (distance: %.2f m)", + labelName, + width, + height, + radius, + position.x, + position.y, + position.z, + distance); + }; + + DebugLog(L"--- SU Update ---"); + DebugLog( + L" Update position (in root space): (%.2f; %.2f; %.2f)", + lastUpdatePosInRenderSpace.x, + lastUpdatePosInRenderSpace.y, + lastUpdatePosInRenderSpace.z); + DebugLog(L" Quads (in head pose space):"); + ForEachQuad(sceneProcessor, logQuad); +} + +void SceneUnderstandingRenderer::Draw(unsigned int numInstances) +{ + if (m_vertices.empty()) + { + return; + } + + const UINT stride = sizeof(m_vertices[0]); + const UINT offset = 0; + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = m_vertices.data(); + const CD3D11_BUFFER_DESC vertexBufferDesc(static_cast(m_vertices.size() * stride), D3D11_BIND_VERTEX_BUFFER); + winrt::com_ptr vertexBuffer; + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, vertexBuffer.put())); + + auto context = m_deviceResources->GetD3DDeviceContext(); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + ID3D11Buffer* pBuffer = vertexBuffer.get(); + context->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset); + context->DrawInstanced(static_cast(m_vertices.size()), numInstances, offset, 0); +} + +template +void SceneUnderstandingRenderer::ForEachQuad(winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, Func f) +{ + // Collect all components, then iterate to find quad entities + winrt::com_array components; + sceneProcessor.GetAllComponents(components); + for (auto& component : components) + { + winrt::SceneUnderstanding::Entity entity = component.try_as(); + if (!entity) + { + continue; + } + + winrt::SceneUnderstanding::Quad quad{nullptr}; + winrt::SceneUnderstanding::Transform transform{nullptr}; + winrt::SceneUnderstanding::SpatialCoordinateSystem spatialCS{nullptr}; + + winrt::com_array associatedComponentIds; + entity.GetAllAssociatedComponentIds(associatedComponentIds); + + for (auto& id : associatedComponentIds) + { + winrt::SceneUnderstanding::Component ac = sceneProcessor.GetComponent(id); + if (auto q = ac.try_as()) + { + quad = q; + continue; + } + if (auto t = ac.try_as()) + { + transform = t; + continue; + } + if (auto s = ac.try_as()) + { + spatialCS = s; + continue; + } + } + + // Don't proceed if any essential bit of data is missing + if (!quad || !transform || !spatialCS) + { + continue; + } + + // Determine the transform from the entity to its anchor + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem entityAnchorCS{nullptr}; + try + { + entityAnchorCS = winrt::Windows::Perception::Spatial::Preview::SpatialGraphInteropPreview::CreateCoordinateSystemForNode( + spatialCS.SpatialCoordinateGuid()); + } + catch (const winrt::hresult_error&) + { + continue; + } + + winrt::Windows::Foundation::Numerics::float4x4 entityToAnchorTransform = transform.TransformationMatrix(); + + f(entity, quad, entityToAnchorTransform, entityAnchorCS); + } +} diff --git a/hostsampleapp/desktop/Content/SceneUnderstandingRenderer.h b/remote/desktop/Content/SceneUnderstandingRenderer.h similarity index 97% rename from hostsampleapp/desktop/Content/SceneUnderstandingRenderer.h rename to remote/desktop/Content/SceneUnderstandingRenderer.h index 6c07315..ad7a9df 100644 --- a/hostsampleapp/desktop/Content/SceneUnderstandingRenderer.h +++ b/remote/desktop/Content/SceneUnderstandingRenderer.h @@ -1,47 +1,47 @@ -//********************************************************* -// -// 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 "RenderableObject.h" - -#include - -#include -#include - -namespace RemotingHostSample -{ - class SceneUnderstandingRenderer : public RenderableObject - { - public: - SceneUnderstandingRenderer(const std::shared_ptr& deviceResources); - - void Update( - winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, - winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation); - - void DebugLogState( - winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, - winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation); - - private: - void Draw(unsigned int numInstances) override; - - template - void ForEachQuad(winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, Func f); - - private: - std::vector m_vertices; - }; -} // namespace RemotingHostSample +//********************************************************* +// +// 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 "RenderableObject.h" + +#include + +#include +#include + +namespace RemotingHostSample +{ + class SceneUnderstandingRenderer : public RenderableObject + { + public: + SceneUnderstandingRenderer(const std::shared_ptr& deviceResources); + + void Update( + winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, + winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation); + + void DebugLogState( + winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, + winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation); + + private: + void Draw(unsigned int numInstances) override; + + template + void ForEachQuad(winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, Func f); + + private: + std::vector m_vertices; + }; +} // namespace RemotingHostSample diff --git a/hostsampleapp/uwp/Content/ShaderStructures.h b/remote/desktop/Content/ShaderStructures.h similarity index 97% rename from hostsampleapp/uwp/Content/ShaderStructures.h rename to remote/desktop/Content/ShaderStructures.h index 1914109..0895217 100644 --- a/hostsampleapp/uwp/Content/ShaderStructures.h +++ b/remote/desktop/Content/ShaderStructures.h @@ -1,33 +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 - -// Constant buffer used to send hologram position transform to the shader pipeline. -struct ModelConstantBuffer -{ - DirectX::XMFLOAT4X4 model; - DirectX::XMFLOAT4X4 normal; // Normal transform matrix. -}; - -// Assert that the constant buffer remains 16-byte aligned (best practice). -static_assert( - (sizeof(ModelConstantBuffer) % (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 VertexPositionNormalColor -{ - DirectX::XMFLOAT3 pos; - DirectX::XMFLOAT3 normal; // Normal. - DirectX::XMFLOAT3 color; -}; +//********************************************************* +// +// 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 + +// Constant buffer used to send hologram position transform to the shader pipeline. +struct ModelConstantBuffer +{ + DirectX::XMFLOAT4X4 model; + DirectX::XMFLOAT4X4 normal; // Normal transform matrix. +}; + +// Assert that the constant buffer remains 16-byte aligned (best practice). +static_assert( + (sizeof(ModelConstantBuffer) % (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 VertexPositionNormalColor +{ + DirectX::XMFLOAT3 pos; + DirectX::XMFLOAT3 normal; // Normal. + DirectX::XMFLOAT3 color; +}; diff --git a/hostsampleapp/uwp/Content/SpatialInputHandler.cpp b/remote/desktop/Content/SpatialInputHandler.cpp similarity index 95% rename from hostsampleapp/uwp/Content/SpatialInputHandler.cpp rename to remote/desktop/Content/SpatialInputHandler.cpp index 47c38d2..458428a 100644 --- a/hostsampleapp/uwp/Content/SpatialInputHandler.cpp +++ b/remote/desktop/Content/SpatialInputHandler.cpp @@ -1,193 +1,190 @@ -//********************************************************* -// -// 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 "SpatialInputHandler.h" - -#include - - -// 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 = winrt::Windows::UI::Input::Spatial::SpatialInteractionManager::GetForCurrentView(); - m_gestureRecognizer = winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer( - winrt::Windows::UI::Input::Spatial::SpatialGestureSettings::Tap | - winrt::Windows::UI::Input::Spatial::SpatialGestureSettings::ManipulationTranslate); - - m_interactionDetectedEventToken = - m_interactionManager.InteractionDetected(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialInteractionManager, - winrt::Windows::UI::Input::Spatial::SpatialInteractionDetectedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialInteractionManager, - winrt::Windows::UI::Input::Spatial::SpatialInteractionDetectedEventArgs args) { - m_gestureRecognizer.CaptureInteraction(args.Interaction()); - })); - - m_tappedEventToken = m_gestureRecognizer.Tapped(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs args) { - std::lock_guard _lg(m_manipulationStateLock); - m_tapped = args; - })); - - m_manipulationStartedEventToken = - m_gestureRecognizer.ManipulationStarted(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs args) { - std::lock_guard _lg(m_manipulationStateLock); - m_manipulationStarted = args; - })); - - m_manipulationUpdatedEventToken = - m_gestureRecognizer.ManipulationUpdated(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs args) { - std::lock_guard _lg(m_manipulationStateLock); - m_manipulationUpdated = args; - })); - - m_manipulationCompletedEventToken = - m_gestureRecognizer.ManipulationCompleted(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationCompletedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationCompletedEventArgs) { - std::lock_guard _lg(m_manipulationStateLock); - m_manipulationResult = ManipulationResult::Completed; - })); - - m_manipulationCanceledEventToken = - m_gestureRecognizer.ManipulationCanceled(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationCanceledEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationCanceledEventArgs) { - std::lock_guard _lg(m_manipulationStateLock); - m_manipulationResult = ManipulationResult::Canceled; - })); - - - - m_navigationStartedEventToken = - m_gestureRecognizer.NavigationStarted(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationStartedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationStartedEventArgs args) { - char buf[128]; - sprintf_s( - buf, - "NS: %d %d %d\n", - static_cast(args.IsNavigatingX()), - static_cast(args.IsNavigatingY()), - static_cast(args.IsNavigatingZ())); - OutputDebugStringA(buf); - })); - - m_navigationUpdatedEventToken = - m_gestureRecognizer.NavigationUpdated(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationUpdatedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationUpdatedEventArgs args) { - winrt::Windows::Foundation::Numerics::float3 offset = args.NormalizedOffset(); - char buf[128]; - sprintf_s(buf, "NU: %f %f %f\n", offset.x, offset.y, offset.z); - OutputDebugStringA(buf); - })); - - m_navigationCompletedEventToken = - m_gestureRecognizer.NavigationCompleted(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationCompletedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationCompletedEventArgs args) { - winrt::Windows::Foundation::Numerics::float3 offset = args.NormalizedOffset(); - char buf[128]; - sprintf_s(buf, "NC: %f %f %f\n", offset.x, offset.y, offset.z); - OutputDebugStringA(buf); - })); - - m_navigationCanceledEventToken = - m_gestureRecognizer.NavigationCanceled(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationCanceledEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationCanceledEventArgs args) { - char buf[128]; - sprintf_s(buf, "N: canceled\n"); - OutputDebugStringA(buf); - })); -} - -SpatialInputHandler::~SpatialInputHandler() -{ - // Unregister our handler for the OnSourcePressed event. - m_interactionManager.InteractionDetected(m_interactionDetectedEventToken); - m_gestureRecognizer.Tapped(m_tappedEventToken); - m_gestureRecognizer.ManipulationStarted(m_manipulationStartedEventToken); - m_gestureRecognizer.ManipulationUpdated(m_manipulationUpdatedEventToken); - m_gestureRecognizer.ManipulationCompleted(m_manipulationCompletedEventToken); - m_gestureRecognizer.ManipulationCanceled(m_manipulationCanceledEventToken); -} - -// 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. -winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs SpatialInputHandler::CheckForTapped() -{ - std::lock_guard _lg(m_manipulationStateLock); - auto tapped = m_tapped; - m_tapped = nullptr; - return tapped; -} - -winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs SpatialInputHandler::CheckForManipulationStarted() -{ - std::lock_guard _lg(m_manipulationStateLock); - auto manipulationStarted = m_manipulationStarted; - m_manipulationStarted = nullptr; - return manipulationStarted; -} - -winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs SpatialInputHandler::CheckForManipulationUpdated() -{ - std::lock_guard _lg(m_manipulationStateLock); - auto manipulationUpdated = m_manipulationUpdated; - m_manipulationUpdated = nullptr; - return manipulationUpdated; -} - -SpatialInputHandler::ManipulationResult SpatialInputHandler::CheckForManipulationResult() -{ - std::lock_guard _lg(m_manipulationStateLock); - auto manipulationResult = m_manipulationResult; - m_manipulationResult = ManipulationResult::Unknown; - return manipulationResult; -} +//********************************************************* +// +// 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 "SpatialInputHandler.h" + +#include +#include + +// Creates and initializes a GestureRecognizer that listens to a Person. +SpatialInputHandler::SpatialInputHandler(winrt::Windows::UI::Input::Spatial::SpatialInteractionManager interactionManager) + : m_interactionManager(interactionManager) +{ + m_gestureRecognizer = winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer( + winrt::Windows::UI::Input::Spatial::SpatialGestureSettings::Tap | + winrt::Windows::UI::Input::Spatial::SpatialGestureSettings::ManipulationTranslate); + + m_interactionDetectedEventToken = + m_interactionManager.InteractionDetected(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialInteractionManager, + winrt::Windows::UI::Input::Spatial::SpatialInteractionDetectedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialInteractionManager, + winrt::Windows::UI::Input::Spatial::SpatialInteractionDetectedEventArgs args) { + m_gestureRecognizer.CaptureInteraction(args.Interaction()); + })); + + m_tappedEventToken = m_gestureRecognizer.Tapped(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs args) { + std::lock_guard _lg(m_manipulationStateLock); + m_tapped = args; + })); + + m_manipulationStartedEventToken = + m_gestureRecognizer.ManipulationStarted(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs args) { + std::lock_guard _lg(m_manipulationStateLock); + m_manipulationStarted = args; + })); + + m_manipulationUpdatedEventToken = + m_gestureRecognizer.ManipulationUpdated(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs args) { + std::lock_guard _lg(m_manipulationStateLock); + m_manipulationUpdated = args; + })); + + m_manipulationCompletedEventToken = + m_gestureRecognizer.ManipulationCompleted(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationCompletedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationCompletedEventArgs) { + std::lock_guard _lg(m_manipulationStateLock); + m_manipulationResult = ManipulationResult::Completed; + })); + + m_manipulationCanceledEventToken = + m_gestureRecognizer.ManipulationCanceled(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationCanceledEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationCanceledEventArgs) { + std::lock_guard _lg(m_manipulationStateLock); + m_manipulationResult = ManipulationResult::Canceled; + })); + + m_navigationStartedEventToken = + m_gestureRecognizer.NavigationStarted(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationStartedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationStartedEventArgs args) { + char buf[128]; + sprintf_s( + buf, + "NS: %d %d %d\n", + static_cast(args.IsNavigatingX()), + static_cast(args.IsNavigatingY()), + static_cast(args.IsNavigatingZ())); + OutputDebugStringA(buf); + })); + + m_navigationUpdatedEventToken = + m_gestureRecognizer.NavigationUpdated(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationUpdatedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationUpdatedEventArgs args) { + winrt::Windows::Foundation::Numerics::float3 offset = args.NormalizedOffset(); + char buf[128]; + sprintf_s(buf, "NU: %f %f %f\n", offset.x, offset.y, offset.z); + OutputDebugStringA(buf); + })); + + m_navigationCompletedEventToken = + m_gestureRecognizer.NavigationCompleted(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationCompletedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationCompletedEventArgs args) { + winrt::Windows::Foundation::Numerics::float3 offset = args.NormalizedOffset(); + char buf[128]; + sprintf_s(buf, "NC: %f %f %f\n", offset.x, offset.y, offset.z); + OutputDebugStringA(buf); + })); + + m_navigationCanceledEventToken = + m_gestureRecognizer.NavigationCanceled(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationCanceledEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationCanceledEventArgs args) { + char buf[128]; + sprintf_s(buf, "N: canceled\n"); + OutputDebugStringA(buf); + })); +} + +SpatialInputHandler::~SpatialInputHandler() +{ + // Unregister our handler for the OnSourcePressed event. + m_interactionManager.InteractionDetected(m_interactionDetectedEventToken); + m_gestureRecognizer.Tapped(m_tappedEventToken); + m_gestureRecognizer.ManipulationStarted(m_manipulationStartedEventToken); + m_gestureRecognizer.ManipulationUpdated(m_manipulationUpdatedEventToken); + m_gestureRecognizer.ManipulationCompleted(m_manipulationCompletedEventToken); + m_gestureRecognizer.ManipulationCanceled(m_manipulationCanceledEventToken); +} + +// 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. +winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs SpatialInputHandler::CheckForTapped() +{ + std::lock_guard _lg(m_manipulationStateLock); + auto tapped = m_tapped; + m_tapped = nullptr; + return tapped; +} + +winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs SpatialInputHandler::CheckForManipulationStarted() +{ + std::lock_guard _lg(m_manipulationStateLock); + auto manipulationStarted = m_manipulationStarted; + m_manipulationStarted = nullptr; + return manipulationStarted; +} + +winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs SpatialInputHandler::CheckForManipulationUpdated() +{ + std::lock_guard _lg(m_manipulationStateLock); + auto manipulationUpdated = m_manipulationUpdated; + m_manipulationUpdated = nullptr; + return manipulationUpdated; +} + +SpatialInputHandler::ManipulationResult SpatialInputHandler::CheckForManipulationResult() +{ + std::lock_guard _lg(m_manipulationStateLock); + auto manipulationResult = m_manipulationResult; + m_manipulationResult = ManipulationResult::Unknown; + return manipulationResult; +} diff --git a/hostsampleapp/uwp/Content/SpatialInputHandler.h b/remote/desktop/Content/SpatialInputHandler.h similarity index 95% rename from hostsampleapp/uwp/Content/SpatialInputHandler.h rename to remote/desktop/Content/SpatialInputHandler.h index b69cef7..b05eaa5 100644 --- a/hostsampleapp/uwp/Content/SpatialInputHandler.h +++ b/remote/desktop/Content/SpatialInputHandler.h @@ -1,62 +1,62 @@ -//********************************************************* -// -// 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 -#include - - -// 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(); - - enum class ManipulationResult - { - Unknown = 0, - Completed, - Canceled, - }; - - winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs CheckForTapped(); - winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs CheckForManipulationStarted(); - winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs CheckForManipulationUpdated(); - ManipulationResult CheckForManipulationResult(); - -private: - // API objects used to process gesture input, and generate gesture events. - winrt::Windows::UI::Input::Spatial::SpatialInteractionManager m_interactionManager = nullptr; - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer m_gestureRecognizer = nullptr; - - // Event registration token. - winrt::event_token m_interactionDetectedEventToken; - winrt::event_token m_tappedEventToken; - winrt::event_token m_manipulationStartedEventToken; - winrt::event_token m_manipulationUpdatedEventToken; - winrt::event_token m_manipulationCompletedEventToken; - winrt::event_token m_manipulationCanceledEventToken; - - winrt::event_token m_navigationStartedEventToken; - winrt::event_token m_navigationUpdatedEventToken; - winrt::event_token m_navigationCompletedEventToken; - winrt::event_token m_navigationCanceledEventToken; - - // Used to indicate that a Pressed input event was received this frame. - std::recursive_mutex m_manipulationStateLock; - - winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs m_tapped = nullptr; - winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs m_manipulationStarted = nullptr; - winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs m_manipulationUpdated = nullptr; - ManipulationResult m_manipulationResult = ManipulationResult::Unknown; -}; +//********************************************************* +// +// 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 +#include +#include + +// Sample gesture handler. +// Hooks up events to recognize a tap gesture, and keeps track of input using a boolean value. +class SpatialInputHandler +{ +public: + SpatialInputHandler(winrt::Windows::UI::Input::Spatial::SpatialInteractionManager interactionManager); + ~SpatialInputHandler(); + + enum class ManipulationResult + { + Unknown = 0, + Completed, + Canceled, + }; + + winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs CheckForTapped(); + winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs CheckForManipulationStarted(); + winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs CheckForManipulationUpdated(); + ManipulationResult CheckForManipulationResult(); + +private: + // API objects used to process gesture input, and generate gesture events. + winrt::Windows::UI::Input::Spatial::SpatialInteractionManager m_interactionManager = nullptr; + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer m_gestureRecognizer = nullptr; + + // Event registration token. + winrt::event_token m_interactionDetectedEventToken; + winrt::event_token m_tappedEventToken; + winrt::event_token m_manipulationStartedEventToken; + winrt::event_token m_manipulationUpdatedEventToken; + winrt::event_token m_manipulationCompletedEventToken; + winrt::event_token m_manipulationCanceledEventToken; + + winrt::event_token m_navigationStartedEventToken; + winrt::event_token m_navigationUpdatedEventToken; + winrt::event_token m_navigationCompletedEventToken; + winrt::event_token m_navigationCanceledEventToken; + + // Used to indicate that a Pressed input event was received this frame. + std::recursive_mutex m_manipulationStateLock; + + winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs m_tapped = nullptr; + winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs m_manipulationStarted = nullptr; + winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs m_manipulationUpdated = nullptr; + ManipulationResult m_manipulationResult = ManipulationResult::Unknown; +}; diff --git a/hostsampleapp/desktop/Content/SpatialInputRenderer.cpp b/remote/desktop/Content/SpatialInputRenderer.cpp similarity index 85% rename from hostsampleapp/desktop/Content/SpatialInputRenderer.cpp rename to remote/desktop/Content/SpatialInputRenderer.cpp index 45db281..65e45ab 100644 --- a/hostsampleapp/desktop/Content/SpatialInputRenderer.cpp +++ b/remote/desktop/Content/SpatialInputRenderer.cpp @@ -1,238 +1,268 @@ -//********************************************************* -// -// 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 "SpatialInputRenderer.h" - -#include -#include -#include - -#include "../Common/DirectXHelper.h" -#include - -namespace -{ - using namespace DirectX; - - void AppendColoredTriangle(XMFLOAT3 p0, XMFLOAT3 p1, XMFLOAT3 p2, XMFLOAT3 color, std::vector& vertices) - { - VertexPositionNormalColor vertex; - vertex.color = color; - vertex.normal = XMFLOAT3(0.0f, 0.0f, 0.0f); - - vertex.pos = p0; - vertices.push_back(vertex); - vertex.pos = p1; - vertices.push_back(vertex); - vertex.pos = p2; - vertices.push_back(vertex); - } -} // namespace - -SpatialInputRenderer::SpatialInputRenderer(const std::shared_ptr& deviceResources) - : RenderableObject(deviceResources) -{ - m_manager = winrt::Windows::UI::Input::Spatial::SpatialInteractionManager::GetForCurrentView(); - m_referenceFrame = winrt::Windows::Perception::Spatial::SpatialLocator::GetDefault().CreateAttachedFrameOfReferenceAtCurrentHeading(); -} - -void SpatialInputRenderer::Update( - winrt::Windows::Perception::PerceptionTimestamp timestamp, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) -{ - m_transforms.clear(); - m_joints.clear(); - - auto headingAdjustment = m_referenceFrame.TryGetRelativeHeadingAtTimestamp(timestamp); - if (headingAdjustment) - { - // keep coordinate systems facing user - m_referenceFrame.AdjustHeading(-headingAdjustment.Value()); - auto coordinateSystem = m_referenceFrame.GetStationaryCoordinateSystemAtTimestamp(timestamp); - - auto spatialPointerPose = winrt::Windows::UI::Input::Spatial::SpatialPointerPose::TryGetAtTimestamp(coordinateSystem, timestamp); - if (spatialPointerPose) - { - if (auto eyesPose = spatialPointerPose.Eyes()) - { - if (auto gaze = eyesPose.Gaze()) - { - auto position = gaze.Value().Origin + gaze.Value().Direction; - quaternion orientation = quaternion::identity(); - m_transforms.emplace_back(QTransform(position, orientation)); - } - } - } - - auto states = m_manager.GetDetectedSourcesAtTimestamp(timestamp); - - m_transforms.reserve(states.Size()); - for (const auto& state : states) - { - auto location = state.Properties().TryGetLocation(coordinateSystem); - if (location) - { - if (location.Position()) - { - using namespace winrt::Windows::Foundation::Numerics; - - auto position = location.Position().Value(); - quaternion orientation = quaternion::identity(); - - if (location.Orientation()) - { - orientation = location.Orientation().Value(); - } - - DirectX::XMVECTOR xmPosition = DirectX::XMLoadFloat3(&position); - DirectX::XMVECTOR xmOrientation = DirectX::XMLoadQuaternion(&orientation); - m_transforms.emplace_back(QTransform(xmPosition, xmOrientation)); - } - - if (auto sourcePose = location.SourcePointerPose()) - { - m_joints.push_back({sourcePose.Position(), sourcePose.Orientation(), 1.0f, 0.01f}); - } - } - - auto handPose = state.TryGetHandPose(); - if (handPose) - { - constexpr const winrt::Windows::Perception::People::HandJointKind jointKinds[] = { - winrt::Windows::Perception::People::HandJointKind::Palm, - winrt::Windows::Perception::People::HandJointKind::Wrist, - winrt::Windows::Perception::People::HandJointKind::ThumbMetacarpal, - winrt::Windows::Perception::People::HandJointKind::ThumbProximal, - winrt::Windows::Perception::People::HandJointKind::ThumbDistal, - winrt::Windows::Perception::People::HandJointKind::ThumbTip, - winrt::Windows::Perception::People::HandJointKind::IndexMetacarpal, - winrt::Windows::Perception::People::HandJointKind::IndexProximal, - winrt::Windows::Perception::People::HandJointKind::IndexIntermediate, - winrt::Windows::Perception::People::HandJointKind::IndexDistal, - winrt::Windows::Perception::People::HandJointKind::IndexTip, - winrt::Windows::Perception::People::HandJointKind::MiddleMetacarpal, - winrt::Windows::Perception::People::HandJointKind::MiddleProximal, - winrt::Windows::Perception::People::HandJointKind::MiddleIntermediate, - winrt::Windows::Perception::People::HandJointKind::MiddleDistal, - winrt::Windows::Perception::People::HandJointKind::MiddleTip, - winrt::Windows::Perception::People::HandJointKind::RingMetacarpal, - winrt::Windows::Perception::People::HandJointKind::RingProximal, - winrt::Windows::Perception::People::HandJointKind::RingIntermediate, - winrt::Windows::Perception::People::HandJointKind::RingDistal, - winrt::Windows::Perception::People::HandJointKind::RingTip, - winrt::Windows::Perception::People::HandJointKind::LittleMetacarpal, - winrt::Windows::Perception::People::HandJointKind::LittleProximal, - winrt::Windows::Perception::People::HandJointKind::LittleIntermediate, - winrt::Windows::Perception::People::HandJointKind::LittleDistal, - winrt::Windows::Perception::People::HandJointKind::LittleTip}; - constexpr const size_t jointCount = _countof(jointKinds); - winrt::Windows::Perception::People::JointPose jointPoses[jointCount] = {}; - - if (handPose.TryGetJoints(coordinateSystem, jointKinds, jointPoses)) - { - for (size_t jointIndex = 0; jointIndex < jointCount; ++jointIndex) - { - m_joints.push_back({jointPoses[jointIndex].Position, - jointPoses[jointIndex].Orientation, - jointPoses[jointIndex].Radius * 3, - jointPoses[jointIndex].Radius}); - } - } - } - } - - auto modelTransform = coordinateSystem.TryGetTransformTo(renderingCoordinateSystem); - if (modelTransform) - { - UpdateModelConstantBuffer(modelTransform.Value()); - } - } -} - -void SpatialInputRenderer::Draw(unsigned int numInstances) -{ - if (!m_transforms.empty()) - { - std::vector vertices; - for (const auto& transform : m_transforms) - { - DirectX::XMFLOAT3 trianglePositions[3] = { - DirectX::XMFLOAT3(0.0f, 0.03f, 0.0f), DirectX::XMFLOAT3(0.01f, 0.0f, 0.0f), DirectX::XMFLOAT3(-0.01f, 0.0f, 0.0f)}; - - AppendColoredTriangle( - transform.TransformPosition(trianglePositions[0]), - transform.TransformPosition(trianglePositions[1]), - transform.TransformPosition(trianglePositions[2]), - DirectX::XMFLOAT3{0, 0, 1}, - vertices); - } - - for (const auto& joint : m_joints) - { - auto jointVertices = CalculateJointVisualizationVertices(joint.position, joint.orientation, joint.length, joint.radius); - vertices.insert(vertices.end(), jointVertices.begin(), jointVertices.end()); - } - - const UINT stride = sizeof(vertices[0]); - const UINT offset = 0; - D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; - vertexBufferData.pSysMem = vertices.data(); - const CD3D11_BUFFER_DESC vertexBufferDesc(static_cast(vertices.size() * stride), D3D11_BIND_VERTEX_BUFFER); - winrt::com_ptr vertexBuffer; - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, vertexBuffer.put())); - - m_deviceResources->UseD3DDeviceContext([&](auto context) { - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - ID3D11Buffer* pBuffer = vertexBuffer.get(); - context->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset); - context->DrawInstanced(static_cast(vertices.size()), numInstances, offset, 0); - }); - } -} - - -std::vector SpatialInputRenderer::CalculateJointVisualizationVertices( - float3 jointPosition, quaternion jointOrientation, float jointLength, float jointRadius) -{ - using namespace DirectX; - - constexpr const size_t verticesCount = 2 * 4 * 3; - std::vector vertices; - vertices.reserve(verticesCount); - - float centerHeight = std::min(jointRadius, 0.5f * jointLength); - float centerXandY = jointRadius / sqrtf(2.0f); - - QTransform jointTransform = QTransform(jointPosition, jointOrientation); - - XMFLOAT3 baseVertexPosition = jointTransform.TransformPosition(XMFLOAT3(0.0f, 0.0f, 0.0f)); - XMFLOAT3 centerVertexPositions[4] = { - jointTransform.TransformPosition(XMFLOAT3(-centerXandY, -centerXandY, -centerHeight)), - jointTransform.TransformPosition(XMFLOAT3(-centerXandY, +centerXandY, -centerHeight)), - jointTransform.TransformPosition(XMFLOAT3(+centerXandY, +centerXandY, -centerHeight)), - jointTransform.TransformPosition(XMFLOAT3(+centerXandY, -centerXandY, -centerHeight)), - }; - XMFLOAT3 topVertexPosition = jointTransform.TransformPosition(XMFLOAT3(0.0f, 0.0f, -jointLength)); - - AppendColoredTriangle(baseVertexPosition, centerVertexPositions[0], centerVertexPositions[1], XMFLOAT3(0.0f, 0.0f, 0.4f), vertices); - AppendColoredTriangle(baseVertexPosition, centerVertexPositions[1], centerVertexPositions[2], XMFLOAT3(0.0f, 0.4f, 0.0f), vertices); - AppendColoredTriangle(baseVertexPosition, centerVertexPositions[2], centerVertexPositions[3], XMFLOAT3(0.4f, 0.0f, 0.0f), vertices); - AppendColoredTriangle(baseVertexPosition, centerVertexPositions[3], centerVertexPositions[0], XMFLOAT3(0.4f, 0.4f, 0.0f), vertices); - AppendColoredTriangle(topVertexPosition, centerVertexPositions[1], centerVertexPositions[0], XMFLOAT3(0.0f, 0.0f, 0.6f), vertices); - AppendColoredTriangle(topVertexPosition, centerVertexPositions[2], centerVertexPositions[1], XMFLOAT3(0.0f, 0.6f, 0.0f), vertices); - AppendColoredTriangle(topVertexPosition, centerVertexPositions[3], centerVertexPositions[2], XMFLOAT3(0.6f, 0.0f, 0.0f), vertices); - AppendColoredTriangle(topVertexPosition, centerVertexPositions[0], centerVertexPositions[3], XMFLOAT3(0.6f, 0.6f, 0.0f), vertices); - - return vertices; -} +//********************************************************* +// +// 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 "SpatialInputRenderer.h" + +#include +#include +#include +#include + +#include "../Common/DirectXHelper.h" +#include + +#include +#include + +namespace +{ + using namespace DirectX; + + void AppendColoredTriangle(XMFLOAT3 p0, XMFLOAT3 p1, XMFLOAT3 p2, XMFLOAT3 color, std::vector& vertices) + { + VertexPositionNormalColor vertex; + vertex.color = color; + vertex.normal = XMFLOAT3(0.0f, 0.0f, 0.0f); + + vertex.pos = p0; + vertices.push_back(vertex); + vertex.pos = p1; + vertices.push_back(vertex); + vertex.pos = p2; + vertices.push_back(vertex); + } +} // namespace + +SpatialInputRenderer::SpatialInputRenderer( + const std::shared_ptr& deviceResources, + winrt::Windows::UI::Input::Spatial::SpatialInteractionManager interactionManager) + : RenderableObject(deviceResources) + , m_interactionManager(interactionManager) +{ + m_referenceFrame = winrt::Windows::Perception::Spatial::SpatialLocator::GetDefault().CreateAttachedFrameOfReferenceAtCurrentHeading(); +} + +void SpatialInputRenderer::Update( + winrt::Windows::Perception::PerceptionTimestamp timestamp, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) +{ + m_transforms.clear(); + m_joints.clear(); + + auto headingAdjustment = m_referenceFrame.TryGetRelativeHeadingAtTimestamp(timestamp); + if (headingAdjustment) + { + + // keep coordinate systems facing user + m_referenceFrame.AdjustHeading(-headingAdjustment.Value()); + auto coordinateSystem = m_referenceFrame.GetStationaryCoordinateSystemAtTimestamp(timestamp); + + auto spatialPointerPose = winrt::Windows::UI::Input::Spatial::SpatialPointerPose::TryGetAtTimestamp(coordinateSystem, timestamp); + if (spatialPointerPose) + { + if (auto eyesPose = spatialPointerPose.Eyes()) + { + if (auto gaze = eyesPose.Gaze()) + { + auto position = gaze.Value().Origin + gaze.Value().Direction; + quaternion orientation = quaternion::identity(); + m_transforms.emplace_back(QTransform(position, orientation)); + } + } + } + + auto states = m_interactionManager.GetDetectedSourcesAtTimestamp(timestamp); + + m_transforms.reserve(states.Size()); + + for (const auto& state : states) + { + auto location = state.Properties().TryGetLocation(coordinateSystem); + QTransform currentTransform(float3::zero(), quaternion::identity()); + if (location) + { + if (location.Position()) + { + using namespace winrt::Windows::Foundation::Numerics; + + auto position = location.Position().Value(); + quaternion orientation = quaternion::identity(); + + if (location.Orientation()) + { + orientation = location.Orientation().Value(); + } + + DirectX::XMVECTOR xmPosition = DirectX::XMLoadFloat3(&position); + DirectX::XMVECTOR xmOrientation = DirectX::XMLoadQuaternion(&orientation); + currentTransform = QTransform(xmPosition, xmOrientation); + m_transforms.push_back(currentTransform); + } + + if (auto sourcePose = location.SourcePointerPose()) + { + m_joints.push_back({sourcePose.Position(), sourcePose.Orientation(), 1.0f, 0.01f}); + } + } + + auto handPose = state.TryGetHandPose(); + if (handPose) + { + constexpr const winrt::Windows::Perception::People::HandJointKind jointKinds[] = { + winrt::Windows::Perception::People::HandJointKind::Palm, + winrt::Windows::Perception::People::HandJointKind::Wrist, + winrt::Windows::Perception::People::HandJointKind::ThumbMetacarpal, + winrt::Windows::Perception::People::HandJointKind::ThumbProximal, + winrt::Windows::Perception::People::HandJointKind::ThumbDistal, + winrt::Windows::Perception::People::HandJointKind::ThumbTip, + winrt::Windows::Perception::People::HandJointKind::IndexMetacarpal, + winrt::Windows::Perception::People::HandJointKind::IndexProximal, + winrt::Windows::Perception::People::HandJointKind::IndexIntermediate, + winrt::Windows::Perception::People::HandJointKind::IndexDistal, + winrt::Windows::Perception::People::HandJointKind::IndexTip, + winrt::Windows::Perception::People::HandJointKind::MiddleMetacarpal, + winrt::Windows::Perception::People::HandJointKind::MiddleProximal, + winrt::Windows::Perception::People::HandJointKind::MiddleIntermediate, + winrt::Windows::Perception::People::HandJointKind::MiddleDistal, + winrt::Windows::Perception::People::HandJointKind::MiddleTip, + winrt::Windows::Perception::People::HandJointKind::RingMetacarpal, + winrt::Windows::Perception::People::HandJointKind::RingProximal, + winrt::Windows::Perception::People::HandJointKind::RingIntermediate, + winrt::Windows::Perception::People::HandJointKind::RingDistal, + winrt::Windows::Perception::People::HandJointKind::RingTip, + winrt::Windows::Perception::People::HandJointKind::LittleMetacarpal, + winrt::Windows::Perception::People::HandJointKind::LittleProximal, + winrt::Windows::Perception::People::HandJointKind::LittleIntermediate, + winrt::Windows::Perception::People::HandJointKind::LittleDistal, + winrt::Windows::Perception::People::HandJointKind::LittleTip}; + constexpr const size_t jointCount = _countof(jointKinds); + winrt::Windows::Perception::People::JointPose jointPoses[jointCount] = {}; + + if (handPose.TryGetJoints(coordinateSystem, jointKinds, jointPoses)) + { + for (size_t jointIndex = 0; jointIndex < jointCount; ++jointIndex) + { + m_joints.push_back( + {jointPoses[jointIndex].Position, + jointPoses[jointIndex].Orientation, + jointPoses[jointIndex].Radius * 3, + jointPoses[jointIndex].Radius}); + } + } + } + } + + auto modelTransform = coordinateSystem.TryGetTransformTo(renderingCoordinateSystem); + if (modelTransform) + { + UpdateModelConstantBuffer(modelTransform.Value()); + } + } +} + +void SpatialInputRenderer::Draw(unsigned int numInstances) +{ + if (!m_transforms.empty()) + { + std::vector vertices; + for (const auto& transform : m_transforms) + { + DirectX::XMFLOAT3 trianglePositions[3] = { + DirectX::XMFLOAT3(0.0f, 0.03f, 0.0f), DirectX::XMFLOAT3(0.01f, 0.0f, 0.0f), DirectX::XMFLOAT3(-0.01f, 0.0f, 0.0f)}; + + AppendColoredTriangle( + transform.TransformPosition(trianglePositions[0]), + transform.TransformPosition(trianglePositions[1]), + transform.TransformPosition(trianglePositions[2]), + DirectX::XMFLOAT3{0, 0, 1}, + vertices); + } + + for (const auto& joint : m_joints) + { + auto jointVertices = CalculateJointVisualizationVertices(joint.position, joint.orientation, joint.length, joint.radius); + vertices.insert(vertices.end(), jointVertices.begin(), jointVertices.end()); + } + + for (const auto& coloredTransform : m_coloredTransforms) + { + DirectX::XMFLOAT3 quadPositions[4] = { + DirectX::XMFLOAT3(-0.01f, 0.0f, -0.01f), + DirectX::XMFLOAT3(0.01f, 0.0f, -0.01f), + DirectX::XMFLOAT3(0.01f, 0.0f, 0.01f), + DirectX::XMFLOAT3(-0.01f, 0.0f, 0.01f)}; + DirectX::XMFLOAT3 transformedPositions[4]; + + for (uint32_t i = 0; i < 4; ++i) + { + transformedPositions[i] = coloredTransform.m_transform.TransformPosition(quadPositions[i]); + } + + AppendColoredTriangle( + transformedPositions[0], transformedPositions[1], transformedPositions[2], coloredTransform.m_color, vertices); + AppendColoredTriangle( + transformedPositions[2], transformedPositions[3], transformedPositions[0], coloredTransform.m_color, vertices); + } + + const UINT stride = sizeof(vertices[0]); + const UINT offset = 0; + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = vertices.data(); + const CD3D11_BUFFER_DESC vertexBufferDesc(static_cast(vertices.size() * stride), D3D11_BIND_VERTEX_BUFFER); + winrt::com_ptr vertexBuffer; + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, vertexBuffer.put())); + + m_deviceResources->UseD3DDeviceContext([&](auto context) { + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + ID3D11Buffer* pBuffer = vertexBuffer.get(); + context->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset); + context->DrawInstanced(static_cast(vertices.size()), numInstances, offset, 0); + }); + } +} + +std::vector SpatialInputRenderer::CalculateJointVisualizationVertices( + float3 jointPosition, quaternion jointOrientation, float jointLength, float jointRadius) +{ + using namespace DirectX; + + constexpr const size_t verticesCount = 2 * 4 * 3; + std::vector vertices; + vertices.reserve(verticesCount); + + float centerHeight = std::min(jointRadius, 0.5f * jointLength); + float centerXandY = jointRadius / sqrtf(2.0f); + + QTransform jointTransform = QTransform(jointPosition, jointOrientation); + + XMFLOAT3 baseVertexPosition = jointTransform.TransformPosition(XMFLOAT3(0.0f, 0.0f, 0.0f)); + XMFLOAT3 centerVertexPositions[4] = { + jointTransform.TransformPosition(XMFLOAT3(-centerXandY, -centerXandY, -centerHeight)), + jointTransform.TransformPosition(XMFLOAT3(-centerXandY, +centerXandY, -centerHeight)), + jointTransform.TransformPosition(XMFLOAT3(+centerXandY, +centerXandY, -centerHeight)), + jointTransform.TransformPosition(XMFLOAT3(+centerXandY, -centerXandY, -centerHeight)), + }; + XMFLOAT3 topVertexPosition = jointTransform.TransformPosition(XMFLOAT3(0.0f, 0.0f, -jointLength)); + + AppendColoredTriangle(baseVertexPosition, centerVertexPositions[0], centerVertexPositions[1], XMFLOAT3(0.0f, 0.0f, 0.4f), vertices); + AppendColoredTriangle(baseVertexPosition, centerVertexPositions[1], centerVertexPositions[2], XMFLOAT3(0.0f, 0.4f, 0.0f), vertices); + AppendColoredTriangle(baseVertexPosition, centerVertexPositions[2], centerVertexPositions[3], XMFLOAT3(0.4f, 0.0f, 0.0f), vertices); + AppendColoredTriangle(baseVertexPosition, centerVertexPositions[3], centerVertexPositions[0], XMFLOAT3(0.4f, 0.4f, 0.0f), vertices); + AppendColoredTriangle(topVertexPosition, centerVertexPositions[1], centerVertexPositions[0], XMFLOAT3(0.0f, 0.0f, 0.6f), vertices); + AppendColoredTriangle(topVertexPosition, centerVertexPositions[2], centerVertexPositions[1], XMFLOAT3(0.0f, 0.6f, 0.0f), vertices); + AppendColoredTriangle(topVertexPosition, centerVertexPositions[3], centerVertexPositions[2], XMFLOAT3(0.6f, 0.0f, 0.0f), vertices); + AppendColoredTriangle(topVertexPosition, centerVertexPositions[0], centerVertexPositions[3], XMFLOAT3(0.6f, 0.6f, 0.0f), vertices); + + return vertices; +} diff --git a/hostsampleapp/uwp/Content/SpatialInputRenderer.h b/remote/desktop/Content/SpatialInputRenderer.h similarity index 71% rename from hostsampleapp/uwp/Content/SpatialInputRenderer.h rename to remote/desktop/Content/SpatialInputRenderer.h index 0010241..cc51118 100644 --- a/hostsampleapp/uwp/Content/SpatialInputRenderer.h +++ b/remote/desktop/Content/SpatialInputRenderer.h @@ -1,85 +1,110 @@ -//********************************************************* -// -// 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 "RenderableObject.h" -#include - -#include - -using namespace winrt::Windows::Foundation::Numerics; - -struct QTransform -{ - QTransform() = default; - QTransform(const DirectX::XMVECTOR& position, const DirectX::XMVECTOR& orientation) - : m_position(position) - , m_orientation(orientation) - { - } - QTransform(const float3& position, const quaternion& orientation) - : m_position(DirectX::XMLoadFloat3(&position)) - , m_orientation(DirectX::XMLoadQuaternion(&orientation)) - { - } - - - DirectX::XMVECTOR TransformNormal(const DirectX::XMVECTOR& normal) const - { - return DirectX::XMVector3Rotate(normal, m_orientation); - } - - DirectX::XMVECTOR TransformPosition(const DirectX::XMVECTOR& position) const - { - DirectX::XMVECTOR rotated = TransformNormal(position); - return DirectX::XMVectorAdd(rotated, m_position); - } - - DirectX::XMFLOAT3 TransformPosition(const DirectX::XMFLOAT3& position) const - { - DirectX::XMFLOAT3 result; - XMStoreFloat3(&result, TransformPosition(DirectX::XMLoadFloat3(&position))); - return result; - } - - DirectX::XMVECTOR m_position; - DirectX::XMVECTOR m_orientation; -}; - -class SpatialInputRenderer : public RenderableObject -{ -public: - SpatialInputRenderer(const std::shared_ptr& deviceResources); - - void Update( - winrt::Windows::Perception::PerceptionTimestamp timestamp, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); - -private: - struct Joint - { - float3 position; - quaternion orientation; - float length; - float radius; - }; - -private: - static std::vector - CalculateJointVisualizationVertices(float3 jointPosition, quaternion jointOrientation, float jointLength, float jointRadius); - - void Draw(unsigned int numInstances) override; - - winrt::Windows::UI::Input::Spatial::SpatialInteractionManager m_manager{nullptr}; - winrt::Windows::Perception::Spatial::SpatialLocatorAttachedFrameOfReference m_referenceFrame{nullptr}; - std::vector m_transforms; - std::vector m_joints; -}; +//********************************************************* +// +// 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 "RenderableObject.h" +#include + +#include + +using namespace winrt::Windows::Foundation::Numerics; + +struct QTransform +{ + QTransform() = default; + QTransform(const DirectX::XMVECTOR& position, const DirectX::XMVECTOR& orientation) + : m_position(position) + , m_orientation(orientation) + { + } + QTransform(const float3& position, const quaternion& orientation) + : m_position(DirectX::XMLoadFloat3(&position)) + , m_orientation(DirectX::XMLoadQuaternion(&orientation)) + { + } + + DirectX::XMVECTOR TransformNormal(const DirectX::XMVECTOR& normal) const + { + return DirectX::XMVector3Rotate(normal, m_orientation); + } + + DirectX::XMVECTOR TransformPosition(const DirectX::XMVECTOR& position) const + { + DirectX::XMVECTOR rotated = TransformNormal(position); + return DirectX::XMVectorAdd(rotated, m_position); + } + + DirectX::XMFLOAT3 TransformPosition(const DirectX::XMFLOAT3& position) const + { + DirectX::XMFLOAT3 result; + XMStoreFloat3(&result, TransformPosition(DirectX::XMLoadFloat3(&position))); + return result; + } + + float3 TransformPosition(const float3& position) const + { + DirectX::XMFLOAT3 temp; + XMStoreFloat3(&temp, TransformPosition(DirectX::XMLoadFloat3(&position))); + return float3(temp.x, temp.y, temp.z); + } + + DirectX::XMVECTOR m_position; + DirectX::XMVECTOR m_orientation; +}; + +class SpatialInputRenderer : public RenderableObject +{ +public: + SpatialInputRenderer( + const std::shared_ptr& deviceResources, + winrt::Windows::UI::Input::Spatial::SpatialInteractionManager interactionManager); + + void Update( + winrt::Windows::Perception::PerceptionTimestamp timestamp, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); + +private: + struct Joint + { + float3 position; + quaternion orientation; + float length; + float radius; + }; + + struct ColoredTransform + { + ColoredTransform(const QTransform& transform, const DirectX::XMFLOAT3& color) + : m_transform(transform) + , m_color(color) + { + } + ColoredTransform(const float3& position, const quaternion& orientation, const DirectX::XMFLOAT3& colorIn) + : m_transform(position, orientation) + , m_color(colorIn) + { + } + QTransform m_transform; + DirectX::XMFLOAT3 m_color; + }; + +private: + static std::vector + CalculateJointVisualizationVertices(float3 jointPosition, quaternion jointOrientation, float jointLength, float jointRadius); + + void Draw(unsigned int numInstances) override; + + winrt::Windows::UI::Input::Spatial::SpatialInteractionManager m_interactionManager{nullptr}; + winrt::Windows::Perception::Spatial::SpatialLocatorAttachedFrameOfReference m_referenceFrame{nullptr}; + std::vector m_transforms; + std::vector m_joints; + std::vector m_coloredTransforms; +}; diff --git a/hostsampleapp/desktop/Content/SpatialSurfaceMeshRenderer.cpp b/remote/desktop/Content/SpatialSurfaceMeshRenderer.cpp similarity index 87% rename from hostsampleapp/desktop/Content/SpatialSurfaceMeshRenderer.cpp rename to remote/desktop/Content/SpatialSurfaceMeshRenderer.cpp index 12f51b4..7351408 100644 --- a/hostsampleapp/desktop/Content/SpatialSurfaceMeshRenderer.cpp +++ b/remote/desktop/Content/SpatialSurfaceMeshRenderer.cpp @@ -1,395 +1,423 @@ -//********************************************************* -// -// 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 "SpatialSurfaceMeshRenderer.h" - -#include "Common\DirectXHelper.h" - -using namespace winrt::Windows; -using namespace winrt::Windows::Perception::Spatial; -using namespace winrt::Windows::Graphics::DirectX; -using namespace winrt::Windows::Foundation::Numerics; -using namespace Concurrency; - -// for debugging -> remove -bool g_freeze = false; -bool g_freezeOnFrame = false; - -// Initializes D2D resources used for text rendering. -SpatialSurfaceMeshRenderer::SpatialSurfaceMeshRenderer(const std::shared_ptr& deviceResources) - : m_deviceResources(deviceResources) -{ - CreateDeviceDependentResources(); -} - -SpatialSurfaceMeshRenderer::~SpatialSurfaceMeshRenderer() -{ -} - - -std::future SpatialSurfaceMeshRenderer::CreateDeviceDependentResources() -{ - auto asyncAccess = Surfaces::SpatialSurfaceObserver::RequestAccessAsync(); - asyncAccess.Completed([this](auto handler, auto asyncStatus) { - m_surfaceObserver = Surfaces::SpatialSurfaceObserver(); - - m_observedSurfaceChangedToken = m_surfaceObserver.ObservedSurfacesChanged( - [this](Surfaces::SpatialSurfaceObserver, winrt::Windows::Foundation::IInspectable const& handler) { - OnObservedSurfaceChanged(); - }); - }); - - std::vector vertexShaderFileData = co_await DXHelper::ReadDataAsync(L"hsa_SRMeshVertexShader.cso"); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateVertexShader( - vertexShaderFileData.data(), vertexShaderFileData.size(), nullptr, m_vertexShader.put())); - - constexpr std::array vertexDesc = {{ - {"POSITION", 0, DXGI_FORMAT_R16G16B16A16_SNORM, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, - }}; - - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateInputLayout( - vertexDesc.data(), - static_cast(vertexDesc.size()), - vertexShaderFileData.data(), - static_cast(vertexShaderFileData.size()), - m_inputLayout.put())); - - std::vector geometryShaderFileData = co_await DXHelper::ReadDataAsync(L"hsa_SRMeshGeometryShader.cso"); - - // After the pass-through geometry shader file is loaded, create the shader. - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateGeometryShader( - geometryShaderFileData.data(), geometryShaderFileData.size(), nullptr, m_geometryShader.put())); - - std::vector pixelShaderFileData = co_await DXHelper::ReadDataAsync(L"hsa_SRMeshPixelShader.cso"); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreatePixelShader( - pixelShaderFileData.data(), pixelShaderFileData.size(), nullptr, m_pixelShader.put())); - - const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(SRMeshConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, m_modelConstantBuffer.put())); - - m_loadingComplete = true; -} - -void SpatialSurfaceMeshRenderer::ReleaseDeviceDependentResources() -{ - if (m_surfaceObserver) - { - m_surfaceObserver.ObservedSurfacesChanged(m_observedSurfaceChangedToken); - m_surfaceObserver = nullptr; - } - m_loadingComplete = false; - m_inputLayout = nullptr; - m_vertexShader = nullptr; - m_geometryShader = nullptr; - m_pixelShader = nullptr; - m_modelConstantBuffer = nullptr; -} - -void SpatialSurfaceMeshRenderer::OnObservedSurfaceChanged() -{ - if (g_freeze) - return; - - m_surfaceChangedCounter++; // just for debugging purposes - m_sufaceChanged = true; -} - -SpatialSurfaceMeshPart* SpatialSurfaceMeshRenderer::GetOrCreateMeshPart(winrt::guid id) -{ - GUID key = id; - auto found = m_meshParts.find(key); - if (found == m_meshParts.cend()) - { - m_meshParts[id] = std::make_unique(this); - return m_meshParts[id].get(); - } - - return found->second.get(); -} - -void SpatialSurfaceMeshRenderer::Update(winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) -{ - if (m_surfaceObserver == nullptr) - return; - - // update bounding volume (every frame) - { - SpatialBoundingBox axisAlignedBoundingBox = { - {-5.0f, -5.0f, -2.5f}, - {10.0f, 10.0f, 5.f}, - }; - - SpatialBoundingVolume volume = SpatialBoundingVolume::FromBox(renderingCoordinateSystem, axisAlignedBoundingBox); - m_surfaceObserver.SetBoundingVolume(volume); - } - - - if (m_sufaceChanged) - { - // first mark all as not used - for (auto& pair : m_meshParts) - { - pair.second->m_inUse = false; - } - - auto mapContainingSurfaceCollection = m_surfaceObserver.GetObservedSurfaces(); - - for (auto pair : mapContainingSurfaceCollection) - { - if (SpatialSurfaceMeshPart* meshPart = GetOrCreateMeshPart(pair.Key())) - { - meshPart->Update(pair.Value()); - g_freeze = g_freezeOnFrame; - } - } - - - // purge the ones not used - for (MeshPartMap::const_iterator itr = m_meshParts.cbegin(); itr != m_meshParts.cend();) - { - itr = itr->second->IsInUse() ? std::next(itr) : m_meshParts.erase(itr); - } - - m_sufaceChanged = false; - } - - // every frame, bring the model matrix to rendering space - for (auto& pair : m_meshParts) - { - pair.second->UpdateModelMatrix(renderingCoordinateSystem); - } -} - -void SpatialSurfaceMeshRenderer::Render(bool isStereo) -{ - if (!m_loadingComplete || m_meshParts.empty()) - return; - - m_deviceResources->UseD3DDeviceContext([&](auto context) { - // Each vertex is one instance of the VertexPositionColorTexture struct. - const uint32_t stride = sizeof(SpatialSurfaceMeshPart::Vertex_t); - const uint32_t offset = 0; - ID3D11Buffer* pBufferToSet; - 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. - pBufferToSet = m_modelConstantBuffer.get(); - context->VSSetConstantBuffers(0, 1, &pBufferToSet); - - // geometry shader - context->GSSetShader(m_geometryShader.get(), nullptr, 0); - - // pixel shader - context->PSSetShader(m_zfillOnly ? nullptr : m_pixelShader.get(), nullptr, 0); - - // Apply the model constant buffer to the pixel shader. - pBufferToSet = m_modelConstantBuffer.get(); - context->PSSetConstantBuffers(0, 1, &pBufferToSet); - - // render each mesh part - for (auto& pair : m_meshParts) - { - SpatialSurfaceMeshPart* part = pair.second.get(); - if (part->m_indexCount == 0) - continue; - - if (part->m_needsUpload) - { - part->UploadData(); - } - - // update part specific model matrix - context->UpdateSubresource(m_modelConstantBuffer.get(), 0, nullptr, &part->m_constantBufferData, 0, 0); - - ID3D11Buffer* pBufferToSet2 = part->m_vertexBuffer.get(); - context->IASetVertexBuffers(0, 1, &pBufferToSet2, &stride, &offset); - context->IASetIndexBuffer(part->m_indexBuffer.get(), DXGI_FORMAT_R16_UINT, 0); - // draw the mesh - context->DrawIndexedInstanced(part->m_indexCount, isStereo ? 2 : 1, 0, 0, 0); - } - - // set geometry shader back - context->GSSetShader(nullptr, nullptr, 0); - }); -} - - - -////////////////////////////////////////////////////////////////////////////////////////////////////////// -// SRMeshPart -////////////////////////////////////////////////////////////////////////////////////////////////////////// - -SpatialSurfaceMeshPart::SpatialSurfaceMeshPart(SpatialSurfaceMeshRenderer* owner) - : m_owner(owner) -{ - auto identity = DirectX::XMMatrixIdentity(); - m_constantBufferData.modelMatrix = reinterpret_cast(identity); - m_vertexScale.x = m_vertexScale.y = m_vertexScale.z = 1.0f; -} - - - -void SpatialSurfaceMeshPart::Update(Surfaces::SpatialSurfaceInfo surfaceInfo) -{ - m_inUse = true; - m_updateInProgress = true; - double TriangleDensity = 750.0; // from Hydrogen - auto asyncOpertation = surfaceInfo.TryComputeLatestMeshAsync(TriangleDensity); - asyncOpertation.Completed([this](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { - Surfaces::SpatialSurfaceMesh mesh = result.GetResults(); - UpdateMesh(mesh); - m_updateInProgress = false; - }); -} - - - -void SpatialSurfaceMeshPart::UpdateModelMatrix(winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) -{ - if (m_coordinateSystem == nullptr) - return; - - auto modelTransform = m_coordinateSystem.TryGetTransformTo(renderingCoordinateSystem); - if (modelTransform) - { - float4x4 matrixWinRt = transpose(modelTransform.Value()); - DirectX::XMMATRIX transformMatrix = DirectX::XMLoadFloat4x4(&matrixWinRt); - DirectX::XMMATRIX scaleMatrix = DirectX::XMMatrixScaling(m_vertexScale.x, m_vertexScale.y, m_vertexScale.z); - DirectX::XMMATRIX result = DirectX::XMMatrixMultiply(transformMatrix, scaleMatrix); - DirectX::XMStoreFloat4x4(&m_constantBufferData.modelMatrix, result); - } -} - - -void SpatialSurfaceMeshPart::UpdateMesh(Surfaces::SpatialSurfaceMesh mesh) -{ - m_coordinateSystem = mesh.CoordinateSystem(); - - Surfaces::SpatialSurfaceMeshBuffer vertexBuffer = mesh.VertexPositions(); - Surfaces::SpatialSurfaceMeshBuffer indexBuffer = mesh.TriangleIndices(); - - DirectXPixelFormat vertexFormat = vertexBuffer.Format(); - DirectXPixelFormat indexFormat = indexBuffer.Format(); - - assert(vertexFormat == DirectXPixelFormat::R16G16B16A16IntNormalized); - assert(indexFormat == DirectXPixelFormat::R16UInt); - - uint32_t vertexCount = vertexBuffer.ElementCount(); - uint32_t indexCount = indexBuffer.ElementCount(); - assert((indexCount % 3) == 0); - - if (vertexCount == 0 || indexCount == 0) - { - m_indexCount = 0; - return; - } - - // convert vertices: - { - Vertex_t* dest = MapVertices(vertexCount); - winrt::Windows::Storage::Streams::IBuffer vertexData = vertexBuffer.Data(); - uint8_t* vertexRaw = vertexData.data(); - int vertexStride = vertexData.Length() / vertexCount; - assert(vertexStride == 8); // DirectXPixelFormat::R16G16B16A16IntNormalized - winrt::Windows::Foundation::Numerics::float3 positionScale = mesh.VertexPositionScale(); - m_vertexScale.x = positionScale.x; - m_vertexScale.y = positionScale.y; - m_vertexScale.z = positionScale.z; - memcpy(dest, vertexRaw, vertexCount * sizeof(Vertex_t)); - UnmapVertices(); - } - - // convert indices - { - uint16_t* dest = MapIndices(indexCount); - winrt::Windows::Storage::Streams::IBuffer indexData = indexBuffer.Data(); - uint16_t* source = (uint16_t*)indexData.data(); - for (uint32_t i = 0; i < indexCount; i++) - { - assert(source[i] < vertexCount); - dest[i] = source[i]; - } - UnmapIndices(); - } - m_needsUpload = true; -} - -SpatialSurfaceMeshPart::Vertex_t* SpatialSurfaceMeshPart::MapVertices(uint32_t vertexCount) -{ - m_vertexCount = vertexCount; - if (vertexCount > m_vertexData.size()) - m_vertexData.resize(vertexCount); - return &m_vertexData[0]; -} - -void SpatialSurfaceMeshPart::UnmapVertices() -{ -} - -uint16_t* SpatialSurfaceMeshPart::MapIndices(uint32_t indexCount) -{ - m_indexCount = indexCount; - if (indexCount > m_indexData.size()) - m_indexData.resize(indexCount); - return &m_indexData[0]; -} - -void SpatialSurfaceMeshPart::UnmapIndices() -{ -} - -void SpatialSurfaceMeshPart::UploadData() -{ - if (m_vertexCount > m_allocatedVertexCount) - { - m_vertexBuffer = nullptr; - - const int alignment = 1024; - m_allocatedVertexCount = ((m_vertexCount + alignment - 1) / alignment) * alignment; // align to reasonable size - - const int elementSize = sizeof(Vertex_t); - const CD3D11_BUFFER_DESC vertexBufferDesc( - m_allocatedVertexCount * elementSize, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - - winrt::check_hresult(m_owner->m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, nullptr, m_vertexBuffer.put())); - } - - if (m_indexCount > m_allocatedIndexCount) - { - m_indexBuffer = nullptr; - const int alignment = 3 * 1024; - m_allocatedIndexCount = ((m_indexCount + alignment - 1) / alignment) * alignment; // align to reasonable size - - const int elementSize = sizeof(uint16_t); - const CD3D11_BUFFER_DESC indexBufferDesc( - m_allocatedIndexCount * elementSize, D3D11_BIND_INDEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - - winrt::check_hresult(m_owner->m_deviceResources->GetD3DDevice()->CreateBuffer(&indexBufferDesc, nullptr, m_indexBuffer.put())); - } - - // upload data - D3D11_MAPPED_SUBRESOURCE resource; - - m_owner->m_deviceResources->UseD3DDeviceContext([&](auto context) { - context->Map(m_vertexBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); - memcpy(resource.pData, &m_vertexData[0], sizeof(Vertex_t) * m_vertexCount); - context->Unmap(m_vertexBuffer.get(), 0); - - context->Map(m_indexBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); - memcpy(resource.pData, &m_indexData[0], sizeof(uint16_t) * m_indexCount); - context->Unmap(m_indexBuffer.get(), 0); - }); -} +//********************************************************* +// +// 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 "SpatialSurfaceMeshRenderer.h" + +#include "Common\DirectXHelper.h" + +using namespace winrt::Windows; +using namespace winrt::Windows::Perception::Spatial; +using namespace winrt::Windows::Graphics::DirectX; +using namespace winrt::Windows::Foundation::Numerics; +using namespace Concurrency; + +// for debugging -> remove +bool g_freeze = false; +bool g_freezeOnFrame = false; + +// Initializes D2D resources used for text rendering. +SpatialSurfaceMeshRenderer::SpatialSurfaceMeshRenderer(const std::shared_ptr& deviceResources) + : m_deviceResources(deviceResources) +{ + CreateDeviceDependentResources(); + + m_spatialLocator = SpatialLocator::GetDefault(); + if (m_spatialLocator) + { + m_spatialLocatorLocabilityChangedEventRevoker = + m_spatialLocator.LocatabilityChanged(winrt::auto_revoke, {this, &SpatialSurfaceMeshRenderer::OnLocatibilityChanged}); + + m_attachedFrameOfReference = m_spatialLocator.CreateAttachedFrameOfReferenceAtCurrentHeading(); + } +} + +SpatialSurfaceMeshRenderer::~SpatialSurfaceMeshRenderer() +{ +} + +std::future SpatialSurfaceMeshRenderer::CreateDeviceDependentResources() +{ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + std::wstring fileNamePrefix = L""; +#else + std::wstring fileNamePrefix = L"ms-appx:///"; +#endif + + auto asyncAccess = Surfaces::SpatialSurfaceObserver::RequestAccessAsync(); + asyncAccess.Completed([this](auto handler, auto asyncStatus) { + m_surfaceObserver = Surfaces::SpatialSurfaceObserver(); + + m_observedSurfaceChangedToken = m_surfaceObserver.ObservedSurfacesChanged( + [this](Surfaces::SpatialSurfaceObserver, winrt::Windows::Foundation::IInspectable const& handler) { + OnObservedSurfaceChanged(); + }); + }); + + std::vector vertexShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_SRMeshVertexShader.cso"); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateVertexShader( + vertexShaderFileData.data(), vertexShaderFileData.size(), nullptr, m_vertexShader.put())); + + constexpr std::array vertexDesc = {{ + {"POSITION", 0, DXGI_FORMAT_R16G16B16A16_SNORM, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }}; + + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateInputLayout( + vertexDesc.data(), + static_cast(vertexDesc.size()), + vertexShaderFileData.data(), + static_cast(vertexShaderFileData.size()), + m_inputLayout.put())); + + std::vector geometryShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_SRMeshGeometryShader.cso"); + + // After the pass-through geometry shader file is loaded, create the shader. + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateGeometryShader( + geometryShaderFileData.data(), geometryShaderFileData.size(), nullptr, m_geometryShader.put())); + + std::vector pixelShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_SRMeshPixelShader.cso"); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreatePixelShader( + pixelShaderFileData.data(), pixelShaderFileData.size(), nullptr, m_pixelShader.put())); + + const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(SRMeshConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, m_modelConstantBuffer.put())); + + m_loadingComplete = true; +} + +void SpatialSurfaceMeshRenderer::ReleaseDeviceDependentResources() +{ + if (m_surfaceObserver) + { + m_surfaceObserver.ObservedSurfacesChanged(m_observedSurfaceChangedToken); + m_surfaceObserver = nullptr; + } + m_loadingComplete = false; + m_inputLayout = nullptr; + m_vertexShader = nullptr; + m_geometryShader = nullptr; + m_pixelShader = nullptr; + m_modelConstantBuffer = nullptr; +} + +void SpatialSurfaceMeshRenderer::OnObservedSurfaceChanged() +{ + if (g_freeze) + return; + + m_surfaceChangedCounter++; // just for debugging purposes + m_sufaceChanged = true; +} + +void SpatialSurfaceMeshRenderer::OnLocatibilityChanged( + const SpatialLocator& spatialLocator, const winrt::Windows::Foundation::IInspectable&) +{ + SpatialLocatability locatibility = spatialLocator.Locatability(); + if (locatibility != SpatialLocatability::PositionalTrackingActive) + { + m_meshParts.clear(); + } +} + +SpatialSurfaceMeshPart* SpatialSurfaceMeshRenderer::GetOrCreateMeshPart(winrt::guid id) +{ + GUID key = id; + auto found = m_meshParts.find(key); + if (found == m_meshParts.cend()) + { + m_meshParts[id] = std::make_unique(this); + return m_meshParts[id].get(); + } + + return found->second.get(); +} + +void SpatialSurfaceMeshRenderer::Update( + winrt::Windows::Perception::PerceptionTimestamp timestamp, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) +{ + if (m_surfaceObserver == nullptr) + return; + + // update bounding volume (every frame) + { + SpatialBoundingBox axisAlignedBoundingBox = { + {-5.0f, -5.0f, -2.5f}, + {10.0f, 10.0f, 5.f}, + }; + + using namespace std::chrono_literals; + auto now = std::chrono::high_resolution_clock::now(); + auto delta = now - m_boundingVolumeUpdateTime; + + if (m_attachedFrameOfReference && delta > 1s) + { + SpatialCoordinateSystem attachedCoordinateSystem = + m_attachedFrameOfReference.GetStationaryCoordinateSystemAtTimestamp(timestamp); + SpatialBoundingVolume volume = SpatialBoundingVolume::FromBox(attachedCoordinateSystem, axisAlignedBoundingBox); + m_surfaceObserver.SetBoundingVolume(volume); + + m_boundingVolumeUpdateTime = now; + } + } + + if (m_sufaceChanged) + { + // first mark all as not used + for (auto& pair : m_meshParts) + { + pair.second->m_inUse = false; + } + + auto mapContainingSurfaceCollection = m_surfaceObserver.GetObservedSurfaces(); + + for (auto pair : mapContainingSurfaceCollection) + { + if (SpatialSurfaceMeshPart* meshPart = GetOrCreateMeshPart(pair.Key())) + { + meshPart->Update(pair.Value()); + g_freeze = g_freezeOnFrame; + } + } + + // purge the ones not used + for (MeshPartMap::const_iterator itr = m_meshParts.cbegin(); itr != m_meshParts.cend();) + { + itr = itr->second->IsInUse() ? std::next(itr) : m_meshParts.erase(itr); + } + + m_sufaceChanged = false; + } + + // every frame, bring the model matrix to rendering space + for (auto& pair : m_meshParts) + { + pair.second->UpdateModelMatrix(renderingCoordinateSystem); + } +} + +void SpatialSurfaceMeshRenderer::Render(bool isStereo) +{ + if (!m_loadingComplete || m_meshParts.empty()) + return; + + m_deviceResources->UseD3DDeviceContext([&](auto context) { + // Each vertex is one instance of the VertexPositionColorTexture struct. + const uint32_t stride = sizeof(SpatialSurfaceMeshPart::Vertex_t); + const uint32_t offset = 0; + ID3D11Buffer* pBufferToSet; + 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. + pBufferToSet = m_modelConstantBuffer.get(); + context->VSSetConstantBuffers(0, 1, &pBufferToSet); + + // geometry shader + context->GSSetShader(m_geometryShader.get(), nullptr, 0); + + // pixel shader + context->PSSetShader(m_zfillOnly ? nullptr : m_pixelShader.get(), nullptr, 0); + + // Apply the model constant buffer to the pixel shader. + pBufferToSet = m_modelConstantBuffer.get(); + context->PSSetConstantBuffers(0, 1, &pBufferToSet); + + // render each mesh part + for (auto& pair : m_meshParts) + { + SpatialSurfaceMeshPart* part = pair.second.get(); + if (part->m_indexCount == 0) + continue; + + if (part->m_needsUpload) + { + part->UploadData(); + } + + // update part specific model matrix + context->UpdateSubresource(m_modelConstantBuffer.get(), 0, nullptr, &part->m_constantBufferData, 0, 0); + + ID3D11Buffer* pBufferToSet2 = part->m_vertexBuffer.get(); + context->IASetVertexBuffers(0, 1, &pBufferToSet2, &stride, &offset); + context->IASetIndexBuffer(part->m_indexBuffer.get(), DXGI_FORMAT_R16_UINT, 0); + // draw the mesh + context->DrawIndexedInstanced(part->m_indexCount, isStereo ? 2 : 1, 0, 0, 0); + } + + // set geometry shader back + context->GSSetShader(nullptr, nullptr, 0); + }); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SRMeshPart +////////////////////////////////////////////////////////////////////////////////////////////////////////// + +SpatialSurfaceMeshPart::SpatialSurfaceMeshPart(SpatialSurfaceMeshRenderer* owner) + : m_owner(owner) +{ + auto identity = DirectX::XMMatrixIdentity(); + m_constantBufferData.modelMatrix = reinterpret_cast(identity); + m_vertexScale.x = m_vertexScale.y = m_vertexScale.z = 1.0f; +} + +void SpatialSurfaceMeshPart::Update(Surfaces::SpatialSurfaceInfo surfaceInfo) +{ + m_inUse = true; + m_updateInProgress = true; + double TriangleDensity = 750.0; // from Hydrogen + auto asyncOpertation = surfaceInfo.TryComputeLatestMeshAsync(TriangleDensity); + asyncOpertation.Completed([this](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { + Surfaces::SpatialSurfaceMesh mesh = result.GetResults(); + UpdateMesh(mesh); + m_updateInProgress = false; + }); +} + +void SpatialSurfaceMeshPart::UpdateModelMatrix(winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) +{ + if (m_coordinateSystem == nullptr) + return; + + auto modelTransform = m_coordinateSystem.TryGetTransformTo(renderingCoordinateSystem); + if (modelTransform) + { + float4x4 matrixWinRt = transpose(modelTransform.Value()); + DirectX::XMMATRIX transformMatrix = DirectX::XMLoadFloat4x4(&matrixWinRt); + DirectX::XMMATRIX scaleMatrix = DirectX::XMMatrixScaling(m_vertexScale.x, m_vertexScale.y, m_vertexScale.z); + DirectX::XMMATRIX result = DirectX::XMMatrixMultiply(transformMatrix, scaleMatrix); + DirectX::XMStoreFloat4x4(&m_constantBufferData.modelMatrix, result); + } +} + +void SpatialSurfaceMeshPart::UpdateMesh(Surfaces::SpatialSurfaceMesh mesh) +{ + m_coordinateSystem = mesh.CoordinateSystem(); + + Surfaces::SpatialSurfaceMeshBuffer vertexBuffer = mesh.VertexPositions(); + Surfaces::SpatialSurfaceMeshBuffer indexBuffer = mesh.TriangleIndices(); + + DirectXPixelFormat vertexFormat = vertexBuffer.Format(); + DirectXPixelFormat indexFormat = indexBuffer.Format(); + + assert(vertexFormat == DirectXPixelFormat::R16G16B16A16IntNormalized); + assert(indexFormat == DirectXPixelFormat::R16UInt); + + uint32_t vertexCount = vertexBuffer.ElementCount(); + uint32_t indexCount = indexBuffer.ElementCount(); + assert((indexCount % 3) == 0); + + if (vertexCount == 0 || indexCount == 0) + { + m_indexCount = 0; + return; + } + + // convert vertices: + { + Vertex_t* dest = MapVertices(vertexCount); + winrt::Windows::Storage::Streams::IBuffer vertexData = vertexBuffer.Data(); + uint8_t* vertexRaw = vertexData.data(); + int vertexStride = vertexData.Length() / vertexCount; + assert(vertexStride == 8); // DirectXPixelFormat::R16G16B16A16IntNormalized + winrt::Windows::Foundation::Numerics::float3 positionScale = mesh.VertexPositionScale(); + m_vertexScale.x = positionScale.x; + m_vertexScale.y = positionScale.y; + m_vertexScale.z = positionScale.z; + memcpy(dest, vertexRaw, vertexCount * sizeof(Vertex_t)); + UnmapVertices(); + } + + // convert indices + { + uint16_t* dest = MapIndices(indexCount); + winrt::Windows::Storage::Streams::IBuffer indexData = indexBuffer.Data(); + uint16_t* source = (uint16_t*)indexData.data(); + for (uint32_t i = 0; i < indexCount; i++) + { + assert(source[i] < vertexCount); + dest[i] = source[i]; + } + UnmapIndices(); + } + m_needsUpload = true; +} + +SpatialSurfaceMeshPart::Vertex_t* SpatialSurfaceMeshPart::MapVertices(uint32_t vertexCount) +{ + m_vertexCount = vertexCount; + if (vertexCount > m_vertexData.size()) + m_vertexData.resize(vertexCount); + return &m_vertexData[0]; +} + +void SpatialSurfaceMeshPart::UnmapVertices() +{ +} + +uint16_t* SpatialSurfaceMeshPart::MapIndices(uint32_t indexCount) +{ + m_indexCount = indexCount; + if (indexCount > m_indexData.size()) + m_indexData.resize(indexCount); + return &m_indexData[0]; +} + +void SpatialSurfaceMeshPart::UnmapIndices() +{ +} + +void SpatialSurfaceMeshPart::UploadData() +{ + if (m_vertexCount > m_allocatedVertexCount) + { + m_vertexBuffer = nullptr; + + const int alignment = 1024; + m_allocatedVertexCount = ((m_vertexCount + alignment - 1) / alignment) * alignment; // align to reasonable size + + const int elementSize = sizeof(Vertex_t); + const CD3D11_BUFFER_DESC vertexBufferDesc( + m_allocatedVertexCount * elementSize, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + + winrt::check_hresult(m_owner->m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, nullptr, m_vertexBuffer.put())); + } + + if (m_indexCount > m_allocatedIndexCount) + { + m_indexBuffer = nullptr; + const int alignment = 3 * 1024; + m_allocatedIndexCount = ((m_indexCount + alignment - 1) / alignment) * alignment; // align to reasonable size + + const int elementSize = sizeof(uint16_t); + const CD3D11_BUFFER_DESC indexBufferDesc( + m_allocatedIndexCount * elementSize, D3D11_BIND_INDEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + + winrt::check_hresult(m_owner->m_deviceResources->GetD3DDevice()->CreateBuffer(&indexBufferDesc, nullptr, m_indexBuffer.put())); + } + + // upload data + D3D11_MAPPED_SUBRESOURCE resource; + + m_owner->m_deviceResources->UseD3DDeviceContext([&](auto context) { + context->Map(m_vertexBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); + memcpy(resource.pData, &m_vertexData[0], sizeof(Vertex_t) * m_vertexCount); + context->Unmap(m_vertexBuffer.get(), 0); + + context->Map(m_indexBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); + memcpy(resource.pData, &m_indexData[0], sizeof(uint16_t) * m_indexCount); + context->Unmap(m_indexBuffer.get(), 0); + }); +} diff --git a/hostsampleapp/uwp/Content/SpatialSurfaceMeshRenderer.h b/remote/desktop/Content/SpatialSurfaceMeshRenderer.h similarity index 77% rename from hostsampleapp/uwp/Content/SpatialSurfaceMeshRenderer.h rename to remote/desktop/Content/SpatialSurfaceMeshRenderer.h index 437045b..0912b51 100644 --- a/hostsampleapp/uwp/Content/SpatialSurfaceMeshRenderer.h +++ b/remote/desktop/Content/SpatialSurfaceMeshRenderer.h @@ -1,130 +1,141 @@ -//********************************************************* -// -// 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 "..\Common\DeviceResources.h" -#include "..\Common\Utils.h" - -#include - -#include -#include - -// forward -class SpatialSurfaceMeshRenderer; - -struct SRMeshConstantBuffer -{ - DirectX::XMFLOAT4X4 modelMatrix; -}; - -// represents a single piece of mesh (SpatialSurfaceMesh) -class SpatialSurfaceMeshPart -{ -public: - struct Vertex_t - { - // float pos[4]; - int16_t pos[4]; - }; - SpatialSurfaceMeshPart(SpatialSurfaceMeshRenderer* owner); - void Update(winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceInfo surfaceInfo); - - void UpdateMesh(winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceMesh mesh); - - bool IsInUse() const - { - return m_inUse || m_updateInProgress; - } - -private: - Vertex_t* MapVertices(uint32_t vertexCount); - void UnmapVertices(); - uint16_t* MapIndices(uint32_t indexCount); - void UnmapIndices(); - void UploadData(); - void UpdateModelMatrix(winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); - - friend class SpatialSurfaceMeshRenderer; - SpatialSurfaceMeshRenderer* m_owner; - bool m_inUse = true; - bool m_needsUpload = false; - bool m_updateInProgress = false; - - GUID m_ID; - uint32_t m_allocatedVertexCount = 0; - uint32_t m_allocatedIndexCount = 0; - uint32_t m_vertexCount = 0; - uint32_t m_indexCount = 0; - winrt::com_ptr m_vertexBuffer; - winrt::com_ptr m_indexBuffer; - - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem m_coordinateSystem = nullptr; - - // double buffered data: - std::vector m_vertexData; - std::vector m_indexData; - SRMeshConstantBuffer m_constantBufferData; - DirectX::XMFLOAT3 m_vertexScale; -}; - - -// Renders the SR mesh -class SpatialSurfaceMeshRenderer -{ -public: - SpatialSurfaceMeshRenderer(const std::shared_ptr& deviceResources); - virtual ~SpatialSurfaceMeshRenderer(); - - void Update(winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); - - void Render(bool isStereo); - - std::future CreateDeviceDependentResources(); - void ReleaseDeviceDependentResources(); - -private: - void OnObservedSurfaceChanged(); - SpatialSurfaceMeshPart* GetOrCreateMeshPart(winrt::guid id); - -private: - friend class SpatialSurfaceMeshPart; - - // Cached pointer to device resources. - std::shared_ptr m_deviceResources; - - // Resources related to mesh rendering. - winrt::com_ptr m_shaderResourceView; - winrt::com_ptr m_pointSampler; - winrt::com_ptr m_renderTargetView; - - // observer: - int m_surfaceChangedCounter = 0; - bool m_sufaceChanged = false; - winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceObserver m_surfaceObserver = nullptr; - winrt::event_token m_observedSurfaceChangedToken; - - // mesh parts - using MeshPartMap = std::map, GUIDComparer>; - MeshPartMap m_meshParts; - - // rendering - bool m_zfillOnly = false; - bool m_loadingComplete = false; - winrt::com_ptr m_inputLayout; - - winrt::com_ptr m_vertexShader; - winrt::com_ptr m_geometryShader; - winrt::com_ptr m_pixelShader; - - winrt::com_ptr m_modelConstantBuffer; -}; +//********************************************************* +// +// 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 "..\Common\DeviceResources.h" +#include "..\Common\Utils.h" + +#include + +#include +#include + +// forward +class SpatialSurfaceMeshRenderer; + +struct SRMeshConstantBuffer +{ + DirectX::XMFLOAT4X4 modelMatrix; +}; + +// Assert that the constant buffer remains 16-byte aligned (best practice). +static_assert( + (sizeof(SRMeshConstantBuffer) % (sizeof(float) * 4)) == 0, + "SR mesh constant buffer size must be 16-byte aligned (16 bytes is the length of four floats)."); + +// represents a single piece of mesh (SpatialSurfaceMesh) +class SpatialSurfaceMeshPart +{ +public: + struct Vertex_t + { + // float pos[4]; + int16_t pos[4]; + }; + SpatialSurfaceMeshPart(SpatialSurfaceMeshRenderer* owner); + void Update(winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceInfo surfaceInfo); + + void UpdateMesh(winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceMesh mesh); + + bool IsInUse() const + { + return m_inUse || m_updateInProgress; + } + +private: + Vertex_t* MapVertices(uint32_t vertexCount); + void UnmapVertices(); + uint16_t* MapIndices(uint32_t indexCount); + void UnmapIndices(); + void UploadData(); + void UpdateModelMatrix(winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); + + friend class SpatialSurfaceMeshRenderer; + SpatialSurfaceMeshRenderer* m_owner; + bool m_inUse = true; + bool m_needsUpload = false; + bool m_updateInProgress = false; + + GUID m_ID; + uint32_t m_allocatedVertexCount = 0; + uint32_t m_allocatedIndexCount = 0; + uint32_t m_vertexCount = 0; + uint32_t m_indexCount = 0; + winrt::com_ptr m_vertexBuffer; + winrt::com_ptr m_indexBuffer; + + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem m_coordinateSystem = nullptr; + + // double buffered data: + std::vector m_vertexData; + std::vector m_indexData; + SRMeshConstantBuffer m_constantBufferData; + DirectX::XMFLOAT3 m_vertexScale; +}; + +// Renders the SR mesh +class SpatialSurfaceMeshRenderer +{ +public: + SpatialSurfaceMeshRenderer(const std::shared_ptr& deviceResources); + virtual ~SpatialSurfaceMeshRenderer(); + + void Update( + winrt::Windows::Perception::PerceptionTimestamp timestamp, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); + + void Render(bool isStereo); + + std::future CreateDeviceDependentResources(); + void ReleaseDeviceDependentResources(); + +private: + void OnObservedSurfaceChanged(); + void OnLocatibilityChanged( + const winrt::Windows::Perception::Spatial::SpatialLocator& spatialLocator, const winrt::Windows::Foundation::IInspectable&); + SpatialSurfaceMeshPart* GetOrCreateMeshPart(winrt::guid id); + +private: + friend class SpatialSurfaceMeshPart; + + // Cached pointer to device resources. + std::shared_ptr m_deviceResources; + + // observer: + int m_surfaceChangedCounter = 0; + bool m_sufaceChanged = false; + winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceObserver m_surfaceObserver = nullptr; + winrt::event_token m_observedSurfaceChangedToken; + + // mesh parts + using MeshPartMap = std::map, GUIDComparer>; + MeshPartMap m_meshParts; + + // rendering + bool m_zfillOnly = false; + bool m_loadingComplete = false; + winrt::com_ptr m_inputLayout; + + winrt::com_ptr m_vertexShader; + winrt::com_ptr m_geometryShader; + winrt::com_ptr m_pixelShader; + + winrt::com_ptr m_modelConstantBuffer; + + winrt::Windows::Perception::Spatial::SpatialLocator m_spatialLocator = nullptr; + winrt::Windows::Perception::Spatial::SpatialLocator::LocatabilityChanged_revoker m_spatialLocatorLocabilityChangedEventRevoker; + + // A attached frame of reference based on m_spatialLocator. + winrt::Windows::Perception::Spatial::SpatialLocatorAttachedFrameOfReference m_attachedFrameOfReference = nullptr; + + std::chrono::time_point m_boundingVolumeUpdateTime; +}; diff --git a/hostsampleapp/desktop/Content/SpinningCubeRenderer.cpp b/remote/desktop/Content/SpinningCubeRenderer.cpp similarity index 89% rename from hostsampleapp/desktop/Content/SpinningCubeRenderer.cpp rename to remote/desktop/Content/SpinningCubeRenderer.cpp index b1c4219..d680c23 100644 --- a/hostsampleapp/desktop/Content/SpinningCubeRenderer.cpp +++ b/remote/desktop/Content/SpinningCubeRenderer.cpp @@ -1,347 +1,353 @@ -//********************************************************* -// -// 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 "../Common/DirectXHelper.h" -#include "SpinningCubeRenderer.h" - -#include -#include -#include - -using namespace DirectX; - -// Loads vertex and pixel shaders from files and instantiates the cube geometry. -SpinningCubeRenderer::SpinningCubeRenderer(const std::shared_ptr& deviceResources) - : m_deviceResources(deviceResources) -{ - CreateDeviceDependentResources(); -} - -// This function uses a SpatialPointerPose to position the world-locked hologram -// two meters in front of the user's heading. -void SpinningCubeRenderer::PositionHologram(const winrt::Windows::UI::Input::Spatial::SpatialPointerPose& pointerPose) -{ - if (pointerPose != nullptr) - { - // Try to get the gaze from eyes. - winrt::Windows::Perception::People::EyesPose eyesPose = pointerPose.Eyes(); - if (eyesPose != nullptr) - { - winrt::Windows::Foundation::IReference gaze = eyesPose.Gaze(); - if (gaze != nullptr) - { - PositionHologram(gaze.Value().Origin, gaze.Value().Direction); - return; - } - } - - // Get the gaze direction from head. - const auto headPosition = pointerPose.Head().Position(); - const auto headDirection = pointerPose.Head().ForwardDirection(); - - PositionHologram(headPosition, headDirection); - } -} - -void SpinningCubeRenderer::SetColorFilter(DirectX::XMFLOAT4 color) -{ - m_filterColorData = color; -} - -// This function uses a point and a vector to position the world-locked hologram -// two meters in front of the user's heading. -void SpinningCubeRenderer::PositionHologram( - winrt::Windows::Foundation::Numerics::float3 headPosition, winrt::Windows::Foundation::Numerics::float3 headDirection) -{ - // The hologram is positioned two meters along the user's gaze direction. - static const float distanceFromUser = 2.0f; // meters - const auto 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(float totalSeconds) -{ - // Rotate the cube. - // Convert degrees to radians, then convert seconds to rotation angle. - const float radiansPerSecond = XMConvertToRadians(m_degreesPerSecond); - const double relativeRotation = totalSeconds * radiansPerSecond; - double totalRotation = m_rotationOffset; - switch (m_pauseState) - { - case PauseState::Unpaused: - totalRotation += relativeRotation; - break; - - case PauseState::Pausing: - m_rotationOffset += relativeRotation; - m_pauseState = PauseState::Paused; - case PauseState::Paused: - totalRotation = m_rotationOffset; - break; - - case PauseState::Unpausing: - m_rotationOffset -= relativeRotation; - m_pauseState = PauseState::Unpaused; - break; - } - const float radians = static_cast(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); - - // Store the normal transform. - XMStoreFloat4x4(&m_modelConstantBufferData.normal, XMMatrixTranspose(modelRotation)); - - // 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. - m_deviceResources->UseD3DDeviceContext([&](auto context) { - // 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(bool isStereo) -{ - // Loading is asynchronous. Resources must be created before drawing can occur. - if (!m_loadingComplete) - { - return; - } - - m_deviceResources->UseD3DDeviceContext([&](auto context) { - ID3D11Buffer* pBufferToSet = nullptr; - - // Each vertex is one instance of the VertexPositionColor struct. - const UINT stride = sizeof(VertexPositionNormalColor); - const UINT offset = 0; - - pBufferToSet = m_vertexBuffer.get(); - context->IASetVertexBuffers(0, 1, &pBufferToSet, &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. - pBufferToSet = m_modelConstantBuffer.get(); - context->VSSetConstantBuffers(0, 1, &pBufferToSet); - - 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); - } - - context->UpdateSubresource(m_filterColorBuffer.get(), 0, nullptr, &m_filterColorData, 0, 0); - - pBufferToSet = m_filterColorBuffer.get(); - context->PSSetConstantBuffers(2, 1, &pBufferToSet); - - // Attach the pixel shader. - context->PSSetShader(m_pixelShader.get(), nullptr, 0); - - // Draw the objects. - context->DrawIndexedInstanced( - m_indexCount, // Index count per instance. - isStereo ? 2 : 1, // Instance count. - 0, // Start index location. - 0, // Base vertex location. - 0 // Start instance location. - ); - }); -} - -std::future SpinningCubeRenderer::CreateDeviceDependentResources() -{ -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - std::wstring fileNamePrefix = L""; -#else - std::wstring fileNamePrefix = L"ms-appx:///"; -#endif - - 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"hsa_VprtVertexShader.cso" : L"hsa_VertexShader.cso"; - - std::vector vertexShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + vertexShaderFileName); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateVertexShader( - vertexShaderFileData.data(), vertexShaderFileData.size(), nullptr, m_vertexShader.put())); - - constexpr std::array vertexDesc = {{ - {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, - }}; - - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateInputLayout( - vertexDesc.data(), - static_cast(vertexDesc.size()), - vertexShaderFileData.data(), - static_cast(vertexShaderFileData.size()), - m_inputLayout.put())); - - std::vector pixelShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_PixelShader.cso"); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreatePixelShader( - pixelShaderFileData.data(), pixelShaderFileData.size(), nullptr, m_pixelShader.put())); - - const ModelConstantBuffer constantBuffer{ - reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), - reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), - }; - - const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, m_modelConstantBuffer.put())); - - const CD3D11_BUFFER_DESC filterColorBufferDesc(sizeof(XMFLOAT4), D3D11_BIND_CONSTANT_BUFFER); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&filterColorBufferDesc, nullptr, m_filterColorBuffer.put())); - - if (!m_usingVprtShaders) - { - // Load the pass-through geometry shader. - std::vector geometryShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_GeometryShader.cso"); - - // After the pass-through geometry shader file is loaded, create the shader. - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateGeometryShader( - geometryShaderFileData.data(), geometryShaderFileData.size(), nullptr, m_geometryShader.put())); - } - - // 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 VertexPositionNormalColor cubeVertices[] = { - {XMFLOAT3(-0.1f, -0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 0.0f, 0.0f)}, // vertex 0 non-debug - {XMFLOAT3(-0.1f, -0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 0.0f, 1.0f)}, - {XMFLOAT3(-0.1f, 0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 1.0f, 0.0f)}, - {XMFLOAT3(-0.1f, 0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 1.0f, 1.0f)}, - {XMFLOAT3(0.1f, -0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 0.0f, 0.0f)}, - {XMFLOAT3(0.1f, -0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 0.0f, 1.0f)}, - {XMFLOAT3(0.1f, 0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 1.0f, 0.0f)}, - {XMFLOAT3(0.1f, 0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 1.0f, 1.0f)}, - }; - - D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; - vertexBufferData.pSysMem = cubeVertices; - vertexBufferData.SysMemPitch = 0; - vertexBufferData.SysMemSlicePitch = 0; - const CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, m_vertexBuffer.put())); - - // 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. - static const unsigned short 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 = ARRAYSIZE(cubeIndices); - - D3D11_SUBRESOURCE_DATA indexBufferData = {0}; - indexBufferData.pSysMem = cubeIndices; - indexBufferData.SysMemPitch = 0; - indexBufferData.SysMemSlicePitch = 0; - const CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&indexBufferDesc, &indexBufferData, m_indexBuffer.put())); - - // Once the cube is loaded, the object is ready to be rendered. - m_loadingComplete = true; -} - -void SpinningCubeRenderer::ReleaseDeviceDependentResources() -{ - m_loadingComplete = false; - m_usingVprtShaders = false; - m_vertexShader = nullptr; - m_inputLayout = nullptr; - m_pixelShader = nullptr; - m_geometryShader = nullptr; - m_modelConstantBuffer = nullptr; - m_vertexBuffer = nullptr; - m_indexBuffer = nullptr; - m_filterColorBuffer = nullptr; -} - -void SpinningCubeRenderer::CreateWindowSizeDependentResources() -{ -} - -void SpinningCubeRenderer::TogglePauseState() -{ - if (m_pauseState == PauseState::Paused) - { - m_pauseState = PauseState::Unpausing; - } - else - { - m_pauseState = PauseState::Pausing; - } -} +//********************************************************* +// +// 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 + +#include + +#include +#include + +using namespace DirectX; + +// Loads vertex and pixel shaders from files and instantiates the cube geometry. +SpinningCubeRenderer::SpinningCubeRenderer(const std::shared_ptr& deviceResources) + : m_deviceResources(deviceResources) +{ + CreateDeviceDependentResources(); +} + +// This function uses a SpatialPointerPose to position the world-locked hologram +// two meters in front of the user's heading. +void SpinningCubeRenderer::PositionHologram(const winrt::Windows::UI::Input::Spatial::SpatialPointerPose& pointerPose) +{ + if (pointerPose != nullptr) + { + // Try to get the gaze from eyes. + winrt::Windows::Perception::People::EyesPose eyesPose = pointerPose.Eyes(); + if (eyesPose != nullptr) + { + winrt::Windows::Foundation::IReference gaze = eyesPose.Gaze(); + if (gaze != nullptr) + { + PositionHologram(gaze.Value().Origin, gaze.Value().Direction); + return; + } + } + + // Get the gaze direction from head. + const auto headPosition = pointerPose.Head().Position(); + const auto headDirection = pointerPose.Head().ForwardDirection(); + + PositionHologram(headPosition, headDirection); + } +} + +void SpinningCubeRenderer::SetColorFilter(DirectX::XMFLOAT4 color) +{ + m_filterColorData = color; +} + +// This function uses a point and a vector to position the world-locked hologram +// two meters in front of the user's heading. +void SpinningCubeRenderer::PositionHologram( + winrt::Windows::Foundation::Numerics::float3 headPosition, winrt::Windows::Foundation::Numerics::float3 headDirection) +{ + // The hologram is positioned two meters along the user's gaze direction. + static const float distanceFromUser = 2.0f; // meters + const auto 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( + float totalSeconds, + winrt::Windows::Perception::PerceptionTimestamp timestamp, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) +{ + // Rotate the cube. + // Convert degrees to radians, then convert seconds to rotation angle. + const float radiansPerSecond = XMConvertToRadians(m_degreesPerSecond); + const double relativeRotation = totalSeconds * radiansPerSecond; + double totalRotation = m_rotationOffset; + + switch (m_pauseState) + { + case PauseState::Unpaused: + totalRotation += relativeRotation; + break; + + case PauseState::Pausing: + m_rotationOffset += relativeRotation; + m_pauseState = PauseState::Paused; + case PauseState::Paused: + totalRotation = m_rotationOffset; + break; + + case PauseState::Unpausing: + m_rotationOffset -= relativeRotation; + m_pauseState = PauseState::Unpaused; + break; + } + const float radians = static_cast(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); + + // Store the normal transform. + XMStoreFloat4x4(&m_modelConstantBufferData.normal, XMMatrixTranspose(modelRotation)); + + // 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. + m_deviceResources->UseD3DDeviceContext([&](auto context) { + // 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(bool isStereo) +{ + // Loading is asynchronous. Resources must be created before drawing can occur. + if (!m_loadingComplete) + { + return; + } + + m_deviceResources->UseD3DDeviceContext([&](auto context) { + ID3D11Buffer* pBufferToSet = nullptr; + + // Each vertex is one instance of the VertexPositionColor struct. + const UINT stride = sizeof(VertexPositionNormalColor); + const UINT offset = 0; + + pBufferToSet = m_vertexBuffer.get(); + context->IASetVertexBuffers(0, 1, &pBufferToSet, &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. + pBufferToSet = m_modelConstantBuffer.get(); + context->VSSetConstantBuffers(0, 1, &pBufferToSet); + + 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); + } + + context->UpdateSubresource(m_filterColorBuffer.get(), 0, nullptr, &m_filterColorData, 0, 0); + + pBufferToSet = m_filterColorBuffer.get(); + context->PSSetConstantBuffers(2, 1, &pBufferToSet); + + // Attach the pixel shader. + context->PSSetShader(m_pixelShader.get(), nullptr, 0); + + // Draw the objects. + context->DrawIndexedInstanced( + m_indexCount, // Index count per instance. + isStereo ? 2 : 1, // Instance count. + 0, // Start index location. + 0, // Base vertex location. + 0 // Start instance location. + ); + }); +} + +std::future SpinningCubeRenderer::CreateDeviceDependentResources() +{ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + std::wstring fileNamePrefix = L""; +#else + std::wstring fileNamePrefix = L"ms-appx:///"; +#endif + + 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"hsa_VprtVertexShader.cso" : L"hsa_VertexShader.cso"; + + std::vector vertexShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + vertexShaderFileName); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateVertexShader( + vertexShaderFileData.data(), vertexShaderFileData.size(), nullptr, m_vertexShader.put())); + + constexpr std::array vertexDesc = {{ + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }}; + + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateInputLayout( + vertexDesc.data(), + static_cast(vertexDesc.size()), + vertexShaderFileData.data(), + static_cast(vertexShaderFileData.size()), + m_inputLayout.put())); + + std::vector pixelShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_PixelShader.cso"); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreatePixelShader( + pixelShaderFileData.data(), pixelShaderFileData.size(), nullptr, m_pixelShader.put())); + + const ModelConstantBuffer constantBuffer{ + reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), + reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), + }; + + const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, m_modelConstantBuffer.put())); + + const CD3D11_BUFFER_DESC filterColorBufferDesc(sizeof(XMFLOAT4), D3D11_BIND_CONSTANT_BUFFER); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&filterColorBufferDesc, nullptr, m_filterColorBuffer.put())); + + if (!m_usingVprtShaders) + { + // Load the pass-through geometry shader. + std::vector geometryShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_GeometryShader.cso"); + + // After the pass-through geometry shader file is loaded, create the shader. + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateGeometryShader( + geometryShaderFileData.data(), geometryShaderFileData.size(), nullptr, m_geometryShader.put())); + } + + // 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 VertexPositionNormalColor cubeVertices[] = { + {XMFLOAT3(-0.1f, -0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 0.0f, 0.0f)}, // vertex 0 non-debug + {XMFLOAT3(-0.1f, -0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 0.0f, 1.0f)}, + {XMFLOAT3(-0.1f, 0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 1.0f, 0.0f)}, + {XMFLOAT3(-0.1f, 0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 1.0f, 1.0f)}, + {XMFLOAT3(0.1f, -0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 0.0f, 0.0f)}, + {XMFLOAT3(0.1f, -0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 0.0f, 1.0f)}, + {XMFLOAT3(0.1f, 0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 1.0f, 0.0f)}, + {XMFLOAT3(0.1f, 0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 1.0f, 1.0f)}, + }; + + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = cubeVertices; + vertexBufferData.SysMemPitch = 0; + vertexBufferData.SysMemSlicePitch = 0; + const CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, m_vertexBuffer.put())); + + // 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. + static const unsigned short 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 = ARRAYSIZE(cubeIndices); + + D3D11_SUBRESOURCE_DATA indexBufferData = {0}; + indexBufferData.pSysMem = cubeIndices; + indexBufferData.SysMemPitch = 0; + indexBufferData.SysMemSlicePitch = 0; + const CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&indexBufferDesc, &indexBufferData, m_indexBuffer.put())); + + // Once everything is loaded, the object is ready to be rendered. + m_loadingComplete = true; +} + +void SpinningCubeRenderer::ReleaseDeviceDependentResources() +{ + m_loadingComplete = false; + m_usingVprtShaders = false; + m_vertexShader = nullptr; + m_inputLayout = nullptr; + m_pixelShader = nullptr; + m_geometryShader = nullptr; + m_modelConstantBuffer = nullptr; + m_vertexBuffer = nullptr; + m_indexBuffer = nullptr; + m_filterColorBuffer = nullptr; +} + +void SpinningCubeRenderer::CreateWindowSizeDependentResources() +{ +} + +void SpinningCubeRenderer::TogglePauseState() +{ + if (m_pauseState == PauseState::Paused) + { + m_pauseState = PauseState::Unpausing; + } + else + { + m_pauseState = PauseState::Pausing; + } +} diff --git a/hostsampleapp/desktop/Content/SpinningCubeRenderer.h b/remote/desktop/Content/SpinningCubeRenderer.h similarity index 90% rename from hostsampleapp/desktop/Content/SpinningCubeRenderer.h rename to remote/desktop/Content/SpinningCubeRenderer.h index cf57989..c390565 100644 --- a/hostsampleapp/desktop/Content/SpinningCubeRenderer.h +++ b/remote/desktop/Content/SpinningCubeRenderer.h @@ -1,93 +1,100 @@ -//********************************************************* -// -// 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 "..\Common\DeviceResources.h" -#include "ShaderStructures.h" -#include - -// This sample renderer instantiates a basic rendering pipeline. -class SpinningCubeRenderer -{ -public: - SpinningCubeRenderer(const std::shared_ptr& deviceResources); - void CreateWindowSizeDependentResources(); - std::future CreateDeviceDependentResources(); - void ReleaseDeviceDependentResources(); - void Update(float totalSeconds); - void SetColorFilter(DirectX::XMFLOAT4 color); - void Render(bool isStereo); - - // Repositions the sample hologram. - void PositionHologram(const winrt::Windows::UI::Input::Spatial::SpatialPointerPose& pointerPose); - - // Repositions the sample hologram, using direct measures. - void PositionHologram(winrt::Windows::Foundation::Numerics::float3 pos, winrt::Windows::Foundation::Numerics::float3 dir); - - // Property accessors. - void SetPosition(winrt::Windows::Foundation::Numerics::float3 pos) - { - m_position = pos; - } - const winrt::Windows::Foundation::Numerics::float3& GetPosition() - { - return m_position; - } - - void Pause() - { - m_pauseState = PauseState::Pausing; - } - void Unpause() - { - m_pauseState = PauseState::Unpausing; - } - void TogglePauseState(); - -private: - enum class PauseState - { - Unpaused = 0, - Pausing, - Paused, - Unpausing, - }; - - // Cached pointer to device resources. - std::shared_ptr m_deviceResources; - - // Direct3D resources for cube geometry. - winrt::com_ptr m_inputLayout; - winrt::com_ptr m_vertexBuffer; - winrt::com_ptr m_indexBuffer; - winrt::com_ptr m_vertexShader; - winrt::com_ptr m_geometryShader; - winrt::com_ptr m_pixelShader; - winrt::com_ptr m_modelConstantBuffer; - winrt::com_ptr m_filterColorBuffer; - - // System resources for cube geometry. - ModelConstantBuffer m_modelConstantBufferData; - uint32_t m_indexCount = 0; - DirectX::XMFLOAT4 m_filterColorData = {1, 1, 1, 1}; - - // Variables used with the rendering loop. - bool m_loadingComplete = false; - float m_degreesPerSecond = 180.0f; - winrt::Windows::Foundation::Numerics::float3 m_position = {0.0f, 0.0f, -2.0f}; - PauseState m_pauseState = PauseState::Unpaused; - double m_rotationOffset = 0; - - // 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; -}; +//********************************************************* +// +// 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 +#include + +#include + +#include + +// This sample renderer instantiates a basic rendering pipeline. +class SpinningCubeRenderer +{ +public: + SpinningCubeRenderer(const std::shared_ptr& deviceResources); + + void CreateWindowSizeDependentResources(); + std::future CreateDeviceDependentResources(); + void ReleaseDeviceDependentResources(); + void Update( + float totalSeconds, + winrt::Windows::Perception::PerceptionTimestamp timestamp, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); + void SetColorFilter(DirectX::XMFLOAT4 color); + void Render(bool isStereo); + + // Repositions the sample hologram. + void PositionHologram(const winrt::Windows::UI::Input::Spatial::SpatialPointerPose& pointerPose); + + // Repositions the sample hologram, using direct measures. + void PositionHologram(winrt::Windows::Foundation::Numerics::float3 pos, winrt::Windows::Foundation::Numerics::float3 dir); + + // Property accessors. + void SetPosition(winrt::Windows::Foundation::Numerics::float3 pos) + { + m_position = pos; + } + const winrt::Windows::Foundation::Numerics::float3& GetPosition() + { + return m_position; + } + + void Pause() + { + m_pauseState = PauseState::Pausing; + } + void Unpause() + { + m_pauseState = PauseState::Unpausing; + } + void TogglePauseState(); + +private: + enum class PauseState + { + Unpaused = 0, + Pausing, + Paused, + Unpausing, + }; + + // Cached pointer to device resources. + std::shared_ptr m_deviceResources; + + // Direct3D resources for cube geometry. + winrt::com_ptr m_inputLayout; + winrt::com_ptr m_vertexBuffer; + winrt::com_ptr m_indexBuffer; + winrt::com_ptr m_vertexShader; + winrt::com_ptr m_geometryShader; + winrt::com_ptr m_pixelShader; + winrt::com_ptr m_modelConstantBuffer; + winrt::com_ptr m_filterColorBuffer; + + // System resources for cube geometry. + ModelConstantBuffer m_modelConstantBufferData; + uint32_t m_indexCount = 0; + DirectX::XMFLOAT4 m_filterColorData = {1, 1, 1, 1}; + + // Variables used with the rendering loop. + bool m_loadingComplete = false; + float m_degreesPerSecond = 180.0f; + winrt::Windows::Foundation::Numerics::float3 m_position = {0.0f, 0.0f, -2.0f}; + PauseState m_pauseState = PauseState::Unpaused; + double m_rotationOffset = 0; + + // 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; +}; diff --git a/hostsampleapp/desktop/Content/shaders/hsa_GeometryShader.hlsl b/remote/desktop/Content/shaders/hsa_GeometryShader.hlsl similarity index 97% rename from hostsampleapp/desktop/Content/shaders/hsa_GeometryShader.hlsl rename to remote/desktop/Content/shaders/hsa_GeometryShader.hlsl index f3d71c0..957662c 100644 --- a/hostsampleapp/desktop/Content/shaders/hsa_GeometryShader.hlsl +++ b/remote/desktop/Content/shaders/hsa_GeometryShader.hlsl @@ -1,44 +1,44 @@ -//********************************************************* -// -// 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. -// -//********************************************************* - -// Per-vertex data from the vertex shader. -struct GeometryShaderInput -{ - float4 pos : SV_POSITION; - min16float3 color : COLOR0; - uint instId : TEXCOORD0; -}; - -// Per-vertex data passed to the rasterizer. -struct GeometryShaderOutput -{ - float4 pos : SV_POSITION; - min16float3 color : COLOR0; - uint idx : TEXCOORD0; - 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 outStream) -{ - GeometryShaderOutput output; - [unroll(3)] - for (int i = 0; i < 3; ++i) - { - output.pos = input[i].pos; - output.color = input[i].color; - output.idx = input[i].instId; - output.rtvId = input[i].instId; - outStream.Append(output); - } -} +//********************************************************* +// +// 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. +// +//********************************************************* + +// Per-vertex data from the vertex shader. +struct GeometryShaderInput +{ + float4 pos : SV_POSITION; + min16float3 color : COLOR0; + uint instId : TEXCOORD0; +}; + +// Per-vertex data passed to the rasterizer. +struct GeometryShaderOutput +{ + float4 pos : SV_POSITION; + min16float3 color : COLOR0; + uint idx : TEXCOORD0; + 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 outStream) +{ + GeometryShaderOutput output; + [unroll(3)] + for (int i = 0; i < 3; ++i) + { + output.pos = input[i].pos; + output.color = input[i].color; + output.idx = input[i].instId; + output.rtvId = input[i].instId; + outStream.Append(output); + } +} diff --git a/hostsampleapp/uwp/Content/shaders/hsa_PixelShader.hlsl b/remote/desktop/Content/shaders/hsa_PixelShader.hlsl similarity index 96% rename from hostsampleapp/uwp/Content/shaders/hsa_PixelShader.hlsl rename to remote/desktop/Content/shaders/hsa_PixelShader.hlsl index 2b13662..3a27d67 100644 --- a/hostsampleapp/uwp/Content/shaders/hsa_PixelShader.hlsl +++ b/remote/desktop/Content/shaders/hsa_PixelShader.hlsl @@ -1,42 +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. -// -//********************************************************* - -// A constant buffer that stores the model transform. -cbuffer ModelConstantBuffer : register(b0) -{ - float4x4 model; - float4x4 normal; -}; - -// A constant buffer that stores each set of view and projection matrices in column-major format. -cbuffer ViewProjectionConstantBuffer : register(b1) -{ - float4x4 viewProjection[2]; -}; - -cbuffer ColorFilterConstantBuffer : register(b2) -{ - float4 colorFilter; -}; - -// Per-pixel color data passed through the pixel shader. -struct PixelShaderInput -{ - float4 pos : SV_POSITION; - min16float3 color : COLOR0; - uint idx : TEXCOORD0; -}; - -// The pixel shader applies Blinn-Phong BRDF shading. -min16float4 main(PixelShaderInput input) : SV_TARGET -{ - return min16float4(input.color, 1.f) * min16float4(colorFilter); -} +//********************************************************* +// +// 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. +// +//********************************************************* + +// A constant buffer that stores the model transform. +cbuffer ModelConstantBuffer : register(b0) +{ + float4x4 model; + float4x4 normal; +}; + +// A constant buffer that stores each set of view and projection matrices in column-major format. +cbuffer ViewProjectionConstantBuffer : register(b1) +{ + float4x4 viewProjection[2]; +}; + +cbuffer ColorFilterConstantBuffer : register(b2) +{ + float4 colorFilter; +}; + +// Per-pixel color data passed through the pixel shader. +struct PixelShaderInput +{ + float4 pos : SV_POSITION; + min16float3 color : COLOR0; + uint idx : TEXCOORD0; +}; + +// The pixel shader applies Blinn-Phong BRDF shading. +min16float4 main(PixelShaderInput input) : SV_TARGET +{ + return min16float4(input.color, 1.f) * min16float4(colorFilter); +} diff --git a/hostsampleapp/uwp/Content/shaders/hsa_SRMeshGeometryShader.hlsl b/remote/desktop/Content/shaders/hsa_SRMeshGeometryShader.hlsl similarity index 96% rename from hostsampleapp/uwp/Content/shaders/hsa_SRMeshGeometryShader.hlsl rename to remote/desktop/Content/shaders/hsa_SRMeshGeometryShader.hlsl index 37c66cd..f1eae96 100644 --- a/hostsampleapp/uwp/Content/shaders/hsa_SRMeshGeometryShader.hlsl +++ b/remote/desktop/Content/shaders/hsa_SRMeshGeometryShader.hlsl @@ -1,48 +1,48 @@ -//********************************************************* -// -// 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. -// -//********************************************************* - -// Per-vertex data from the vertex shader. -struct GeometryShaderInput -{ - float4 pos : SV_POSITION; - uint instId : TEXCOORD1; -}; - -// Per-vertex data passed to the rasterizer. -struct GeometryShaderOutput -{ - float4 pos : SV_POSITION; - float3 barycentricCoords : TEXCOORD0; - 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 outStream) -{ - static const float3 barycentricVectors[3] = { - float3(1.0f, 0.0f, 0.0f), - float3(0.0f, 1.0f, 0.0f), - float3(0.0f, 0.0f, 1.0f) - }; - - GeometryShaderOutput output; - [unroll(3)] - for (int i = 0; i < 3; ++i) - { - output.pos = input[i].pos; - output.barycentricCoords = barycentricVectors[i]; - output.rtvId = input[i].instId; - - outStream.Append(output); - } -} +//********************************************************* +// +// 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. +// +//********************************************************* + +// Per-vertex data from the vertex shader. +struct GeometryShaderInput +{ + float4 pos : SV_POSITION; + uint instId : TEXCOORD1; +}; + +// Per-vertex data passed to the rasterizer. +struct GeometryShaderOutput +{ + float4 pos : SV_POSITION; + float3 barycentricCoords : TEXCOORD0; + 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 outStream) +{ + static const float3 barycentricVectors[3] = { + float3(1.0f, 0.0f, 0.0f), + float3(0.0f, 1.0f, 0.0f), + float3(0.0f, 0.0f, 1.0f) + }; + + GeometryShaderOutput output; + [unroll(3)] + for (int i = 0; i < 3; ++i) + { + output.pos = input[i].pos; + output.barycentricCoords = barycentricVectors[i]; + output.rtvId = input[i].instId; + + outStream.Append(output); + } +} diff --git a/hostsampleapp/desktop/Content/shaders/hsa_SRMeshPixelShader.hlsl b/remote/desktop/Content/shaders/hsa_SRMeshPixelShader.hlsl similarity index 97% rename from hostsampleapp/desktop/Content/shaders/hsa_SRMeshPixelShader.hlsl rename to remote/desktop/Content/shaders/hsa_SRMeshPixelShader.hlsl index 9cc83bb..e4917ab 100644 --- a/hostsampleapp/desktop/Content/shaders/hsa_SRMeshPixelShader.hlsl +++ b/remote/desktop/Content/shaders/hsa_SRMeshPixelShader.hlsl @@ -1,36 +1,36 @@ -//********************************************************* -// -// 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. -// -//********************************************************* - -// Per-pixel color data passed through the pixel shader. -struct PixelShaderInput -{ - float4 pos : SV_POSITION; - float3 barycentricCoords : TEXCOORD0; -}; - -#define LINE_WIDTH 2.0 - -float edgeFactor(float3 coords) -{ - float3 d = fwidth(coords); - float3 a3 = smoothstep(0.0, d*LINE_WIDTH, coords); - return min(min(a3.x, a3.y), a3.z); -} - -// The pixel shader passes through the color data. The color data from -// is interpolated and assigned to a pixel at the rasterization step. -float4 main(PixelShaderInput input) : SV_TARGET -{ - float lineBrightness = 1.0f - edgeFactor(input.barycentricCoords); - float4 result = float4(0.25, 0.25, 0.25, 1.0); - result.xyz *= lineBrightness; - return result; -} +//********************************************************* +// +// 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. +// +//********************************************************* + +// Per-pixel color data passed through the pixel shader. +struct PixelShaderInput +{ + float4 pos : SV_POSITION; + float3 barycentricCoords : TEXCOORD0; +}; + +#define LINE_WIDTH 2.0 + +float edgeFactor(float3 coords) +{ + float3 d = fwidth(coords); + float3 a3 = smoothstep(0.0, d*LINE_WIDTH, coords); + return min(min(a3.x, a3.y), a3.z); +} + +// The pixel shader passes through the color data. The color data from +// is interpolated and assigned to a pixel at the rasterization step. +float4 main(PixelShaderInput input) : SV_TARGET +{ + float lineBrightness = 1.0f - edgeFactor(input.barycentricCoords); + float4 result = float4(0.25, 0.25, 0.25, 1.0); + result.xyz *= lineBrightness; + return result; +} diff --git a/hostsampleapp/uwp/Content/shaders/hsa_SRMeshVertexShader.hlsl b/remote/desktop/Content/shaders/hsa_SRMeshVertexShader.hlsl similarity index 97% rename from hostsampleapp/uwp/Content/shaders/hsa_SRMeshVertexShader.hlsl rename to remote/desktop/Content/shaders/hsa_SRMeshVertexShader.hlsl index 55e2a1f..5c214df 100644 --- a/hostsampleapp/uwp/Content/shaders/hsa_SRMeshVertexShader.hlsl +++ b/remote/desktop/Content/shaders/hsa_SRMeshVertexShader.hlsl @@ -1,64 +1,64 @@ -//********************************************************* -// -// 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. -// -//********************************************************* - -// A constant buffer that stores the model transform. -cbuffer SRMeshConstantBuffer : register(b0) -{ - float4x4 model; -}; - -// 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 -{ - float4 pos : POSITION; - 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 -{ - float4 pos : SV_POSITION; - uint viewId : TEXCOORD1; // SV_InstanceID % 2 -}; - -// Simple shader to do vertex processing on the GPU. -VertexShaderOutput main(VertexShaderInput input) -{ - VertexShaderOutput output; - float4 pos = float4(input.pos.xyz, 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 = pos; - - // 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; -} +//********************************************************* +// +// 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. +// +//********************************************************* + +// A constant buffer that stores the model transform. +cbuffer SRMeshConstantBuffer : register(b0) +{ + float4x4 model; +}; + +// 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 +{ + float4 pos : POSITION; + 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 +{ + float4 pos : SV_POSITION; + uint viewId : TEXCOORD1; // SV_InstanceID % 2 +}; + +// Simple shader to do vertex processing on the GPU. +VertexShaderOutput main(VertexShaderInput input) +{ + VertexShaderOutput output; + float4 pos = float4(input.pos.xyz, 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 = pos; + + // 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; +} diff --git a/hostsampleapp/uwp/Content/shaders/hsa_VPRTVertexShader.hlsl b/remote/desktop/Content/shaders/hsa_VPRTVertexShader.hlsl similarity index 96% rename from hostsampleapp/uwp/Content/shaders/hsa_VPRTVertexShader.hlsl rename to remote/desktop/Content/shaders/hsa_VPRTVertexShader.hlsl index 83503bc..3770d3f 100644 --- a/hostsampleapp/uwp/Content/shaders/hsa_VPRTVertexShader.hlsl +++ b/remote/desktop/Content/shaders/hsa_VPRTVertexShader.hlsl @@ -1,72 +1,72 @@ -//********************************************************* -// -// 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. -// -//********************************************************* - -// A constant buffer that stores the model transform. -cbuffer ModelConstantBuffer : register(b0) -{ - float4x4 model; - float4x4 normal; -}; - -// 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 -{ - float3 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 -{ - float4 pos : SV_POSITION; - min16float3 color : COLOR0; - uint idx : TEXCOORD0; - 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]); - - // Write minimum-precision floating-point data. - output.pos = pos; - - // Pass the color through without modification. - output.color = input.color; - - // Set the render target array index. - output.rtvId = idx; - output.idx = idx; - - return output; -} +//********************************************************* +// +// 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. +// +//********************************************************* + +// A constant buffer that stores the model transform. +cbuffer ModelConstantBuffer : register(b0) +{ + float4x4 model; + float4x4 normal; +}; + +// 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 +{ + float3 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 +{ + float4 pos : SV_POSITION; + min16float3 color : COLOR0; + uint idx : TEXCOORD0; + 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]); + + // Write minimum-precision floating-point data. + output.pos = pos; + + // Pass the color through without modification. + output.color = input.color; + + // Set the render target array index. + output.rtvId = idx; + output.idx = idx; + + return output; +} diff --git a/hostsampleapp/desktop/Content/shaders/hsa_VertexShader.hlsl b/remote/desktop/Content/shaders/hsa_VertexShader.hlsl similarity index 97% rename from hostsampleapp/desktop/Content/shaders/hsa_VertexShader.hlsl rename to remote/desktop/Content/shaders/hsa_VertexShader.hlsl index 985257a..11f5f1e 100644 --- a/hostsampleapp/desktop/Content/shaders/hsa_VertexShader.hlsl +++ b/remote/desktop/Content/shaders/hsa_VertexShader.hlsl @@ -1,72 +1,72 @@ -//********************************************************* -// -// 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. -// -//********************************************************* - -// A constant buffer that stores the model transform. -cbuffer ModelConstantBuffer : register(b0) -{ - float4x4 model; - float4x4 normal; -}; - -// 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 -{ - float3 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 -{ - float4 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]); - - // Write minimum-precision floating-point data. - output.pos = pos; - - // Pass the color through without modification. - output.color = input.color; - - // 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; -} +//********************************************************* +// +// 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. +// +//********************************************************* + +// A constant buffer that stores the model transform. +cbuffer ModelConstantBuffer : register(b0) +{ + float4x4 model; + float4x4 normal; +}; + +// 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 +{ + float3 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 +{ + float4 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]); + + // Write minimum-precision floating-point data. + output.pos = pos; + + // Pass the color through without modification. + output.color = input.color; + + // 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; +} diff --git a/remote/desktop/Package.appxmanifest b/remote/desktop/Package.appxmanifest new file mode 100644 index 0000000..1923f24 --- /dev/null +++ b/remote/desktop/Package.appxmanifest @@ -0,0 +1,50 @@ + + + + + + RemotingHostSample + Microsoft Corporation + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/remote/desktop/SampleRemote.sln b/remote/desktop/SampleRemote.sln new file mode 100644 index 0000000..d4a2384 --- /dev/null +++ b/remote/desktop/SampleRemote.sln @@ -0,0 +1,32 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29806.167 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleRemote", "SampleRemote.vcxproj", "{D22B424F-B259-356A-8E4C-4937C36E783E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + RelWithDebInfo|x64 = RelWithDebInfo|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D22B424F-B259-356A-8E4C-4937C36E783E}.Debug|x64.ActiveCfg = Debug|x64 + {D22B424F-B259-356A-8E4C-4937C36E783E}.Debug|x64.Build.0 = Debug|x64 + {D22B424F-B259-356A-8E4C-4937C36E783E}.Debug|x64.Deploy.0 = Debug|x64 + {D22B424F-B259-356A-8E4C-4937C36E783E}.Release|x64.ActiveCfg = Release|x64 + {D22B424F-B259-356A-8E4C-4937C36E783E}.Release|x64.Build.0 = Release|x64 + {D22B424F-B259-356A-8E4C-4937C36E783E}.Release|x64.Deploy.0 = Release|x64 + {D22B424F-B259-356A-8E4C-4937C36E783E}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {D22B424F-B259-356A-8E4C-4937C36E783E}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {D22B424F-B259-356A-8E4C-4937C36E783E}.RelWithDebInfo|x64.Deploy.0 = RelWithDebInfo|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E8A3A1EC-E636-40D6-9E3D-C22347CC8162} + EndGlobalSection +EndGlobal + diff --git a/hostsampleapp/desktop/HolographicHostSample.vcxproj b/remote/desktop/SampleRemote.vcxproj similarity index 84% rename from hostsampleapp/desktop/HolographicHostSample.vcxproj rename to remote/desktop/SampleRemote.vcxproj index 941e9c9..62b21f2 100644 --- a/hostsampleapp/desktop/HolographicHostSample.vcxproj +++ b/remote/desktop/SampleRemote.vcxproj @@ -1,313 +1,320 @@ - - - - - Debug - x64 - - - Release - x64 - - - RelWithDebInfo - x64 - - - - {59F48F16-7CF3-36AB-AE6D-B56A9DA89747} - 10.0.18362.0 - Win32Proj - x64 - HolographicHostSample - NoUpgrade - - - - Application - MultiByte - v141 - - - Application - MultiByte - v141 - Spectre - - - Application - MultiByte - v141 - - - - - - - - - - - <_ProjectFileVersion>10.0.20506.1 - bin\Debug\ - HolographicHostSample.dir\Debug\ - HolographicHostSample - .exe - true - true - bin\Release\ - HolographicHostSample.dir\Release\ - HolographicHostSample - .exe - false - true - bin\RelWithDebInfo\ - HolographicHostSample.dir\RelWithDebInfo\ - HolographicHostSample - .exe - true - true - - - - .;%(AdditionalIncludeDirectories) - %(AdditionalOptions) /await - $(VCIDEInstallDir)vcpackages;$(WindowsSDK_UnionMetadataPath) - Debug/ - EnableFastChecks - CompileAsCpp - true - ProgramDatabase - 4503 - Sync - true - Disabled - stdcpp17 - true - Disabled - NotUsing - MultiThreadedDebugDLL - true - true - false - Level3 - WIN32;_WINDOWS;ALLOW_INSECURE_RANDOM_DEVICE=1;UNICODE;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WIN32;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="Debug";%(PreprocessorDefinitions) - $(IntDir) - - - WIN32;_DEBUG;_WINDOWS;ALLOW_INSECURE_RANDOM_DEVICE=1;UNICODE;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WIN32;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"Debug\";%(PreprocessorDefinitions) - .;%(AdditionalIncludeDirectories) - - - .;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - d2d1.lib;d3d11.lib;dxgi.lib;dwrite.lib;windowscodecs.lib;pathcch.lib;Mswsock.lib;mfreadwrite.lib;Mfplat.lib;mfuuid.lib;ntdll.lib;Secur32.lib;crypt32.lib;secur32.lib;avrt.lib;WindowsApp.lib;%(AdditionalDependencies) - %(AdditionalLibraryDirectories) - %(AdditionalOptions) /machine:x64 - false - true - %(IgnoreSpecificDefaultLibraries) - lib/Debug/HolographicHostSample.lib - false - bin/Debug/HolographicHostSample.pdb - Windows - - - false - - - - - .;%(AdditionalIncludeDirectories) - %(AdditionalOptions) /await - $(VCIDEInstallDir)vcpackages;$(WindowsSDK_UnionMetadataPath) - Release/ - CompileAsCpp - true - Guard - ProgramDatabase - 4503 - Sync - true - AnySuitable - stdcpp17 - true - MaxSpeed - NotUsing - MultiThreadedDLL - true - true - false - Level3 - WIN32;_WINDOWS;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;UNICODE;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WIN32;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="Release";%(PreprocessorDefinitions) - $(IntDir) - - - WIN32;_WINDOWS;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;UNICODE;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WIN32;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"Release\";%(PreprocessorDefinitions) - .;%(AdditionalIncludeDirectories) - - - .;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - d2d1.lib;d3d11.lib;dxgi.lib;dwrite.lib;windowscodecs.lib;pathcch.lib;Mswsock.lib;mfreadwrite.lib;Mfplat.lib;mfuuid.lib;ntdll.lib;Secur32.lib;crypt32.lib;secur32.lib;avrt.lib;WindowsApp.lib;%(AdditionalDependencies) - %(AdditionalLibraryDirectories) - %(AdditionalOptions) /machine:x64 - DebugFull - %(IgnoreSpecificDefaultLibraries) - lib/Release/HolographicHostSample.lib - bin/Release/HolographicHostSample.pdb - Windows - - - false - - - - - .;%(AdditionalIncludeDirectories) - %(AdditionalOptions) /await - $(VCIDEInstallDir)vcpackages;$(WindowsSDK_UnionMetadataPath) - RelWithDebInfo/ - CompileAsCpp - true - ProgramDatabase - 4503 - Sync - true - OnlyExplicitInline - stdcpp17 - true - MaxSpeed - NotUsing - MultiThreadedDLL - true - true - false - Level3 - WIN32;_WINDOWS;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;UNICODE;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WIN32;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="RelWithDebInfo";%(PreprocessorDefinitions) - $(IntDir) - - - WIN32;_WINDOWS;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;UNICODE;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WIN32;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"RelWithDebInfo\";%(PreprocessorDefinitions) - .;%(AdditionalIncludeDirectories) - - - .;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - d2d1.lib;d3d11.lib;dxgi.lib;dwrite.lib;windowscodecs.lib;pathcch.lib;Mswsock.lib;mfreadwrite.lib;Mfplat.lib;mfuuid.lib;ntdll.lib;Secur32.lib;crypt32.lib;secur32.lib;avrt.lib;WindowsApp.lib;%(AdditionalDependencies) - %(AdditionalLibraryDirectories) - %(AdditionalOptions) /machine:x64 - false - true - %(IgnoreSpecificDefaultLibraries) - lib/RelWithDebInfo/HolographicHostSample.lib - false - bin/RelWithDebInfo/HolographicHostSample.pdb - Windows - - - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Vertex - main - 5.0 - - - Vertex - main - 5.0 - - - Vertex - main - 5.0 - - - Pixel - main - 5.0 - - - Pixel - main - 5.0 - - - Geometry - main - 5.0 - - - Geometry - main - 5.0 - - - PreserveNewest - - - + + + + + x64 + + + + Debug + x64 + + + Release + x64 + + + RelWithDebInfo + x64 + + + + {D22B424F-B259-356A-8E4C-4937C36E783E} + 10.0.18362.0 + Win32Proj + x64 + SampleRemote + NoUpgrade + + + + Application + MultiByte + v142 + + + Application + MultiByte + v142 + Spectre + + + Application + MultiByte + v142 + + + + + + + + + + <_ProjectFileVersion>10.0.20506.1 + bin\Debug\ + SampleRemote.dir\Debug\ + SampleRemote + .exe + true + true + bin\Release\ + SampleRemote.dir\Release\ + SampleRemote + .exe + false + true + bin\RelWithDebInfo\ + SampleRemote.dir\RelWithDebInfo\ + SampleRemote + .exe + true + true + + + + .;%(AdditionalIncludeDirectories) + %(AdditionalOptions) /await + $(VCIDEInstallDir)vcpackages;$(WindowsSDK_UnionMetadataPath) + $(IntDir) + EnableFastChecks + CompileAsCpp + true + ProgramDatabase + 4503 + Sync + true + Disabled + stdcpp17 + true + Disabled + NotUsing + MultiThreadedDebugDLL + true + true + false + Level3 + WIN32;_WINDOWS;ALLOW_INSECURE_RANDOM_DEVICE=1;UNICODE;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WIN32;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="Debug";%(PreprocessorDefinitions) + $(IntDir) + + + WIN32;_DEBUG;_WINDOWS;ALLOW_INSECURE_RANDOM_DEVICE=1;UNICODE;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WIN32;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"Debug\";%(PreprocessorDefinitions) + .;%(AdditionalIncludeDirectories) + + + .;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + d2d1.lib;d3d11.lib;dxgi.lib;dwrite.lib;windowscodecs.lib;pathcch.lib;Mswsock.lib;mfreadwrite.lib;Mfplat.lib;mfuuid.lib;ntdll.lib;Secur32.lib;crypt32.lib;secur32.lib;avrt.lib;WindowsApp.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + %(AdditionalOptions) /machine:x64 + false + true + %(IgnoreSpecificDefaultLibraries) + lib/Debug/SampleRemote.lib + false + bin/Debug/SampleRemote.pdb + Windows + + + false + + + + + .;%(AdditionalIncludeDirectories) + %(AdditionalOptions) /await + $(VCIDEInstallDir)vcpackages;$(WindowsSDK_UnionMetadataPath) + $(IntDir) + CompileAsCpp + true + Guard + ProgramDatabase + 4503 + Sync + true + AnySuitable + stdcpp17 + true + MaxSpeed + NotUsing + MultiThreadedDLL + true + true + false + Level3 + WIN32;_WINDOWS;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;UNICODE;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WIN32;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="Release";%(PreprocessorDefinitions) + $(IntDir) + + + WIN32;_WINDOWS;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;UNICODE;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WIN32;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"Release\";%(PreprocessorDefinitions) + .;%(AdditionalIncludeDirectories) + + + .;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + d2d1.lib;d3d11.lib;dxgi.lib;dwrite.lib;windowscodecs.lib;pathcch.lib;Mswsock.lib;mfreadwrite.lib;Mfplat.lib;mfuuid.lib;ntdll.lib;Secur32.lib;crypt32.lib;secur32.lib;avrt.lib;WindowsApp.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + %(AdditionalOptions) /machine:x64 + DebugFull + %(IgnoreSpecificDefaultLibraries) + lib/Release/SampleRemote.lib + bin/Release/SampleRemote.pdb + Windows + + + false + + + + + .;%(AdditionalIncludeDirectories) + %(AdditionalOptions) /await + $(VCIDEInstallDir)vcpackages;$(WindowsSDK_UnionMetadataPath) + $(IntDir) + CompileAsCpp + true + ProgramDatabase + 4503 + Sync + true + OnlyExplicitInline + stdcpp17 + true + MaxSpeed + NotUsing + MultiThreadedDLL + true + true + false + Level3 + WIN32;_WINDOWS;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;UNICODE;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WIN32;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="RelWithDebInfo";%(PreprocessorDefinitions) + $(IntDir) + + + WIN32;_WINDOWS;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;UNICODE;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WIN32;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"RelWithDebInfo\";%(PreprocessorDefinitions) + .;%(AdditionalIncludeDirectories) + + + .;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + d2d1.lib;d3d11.lib;dxgi.lib;dwrite.lib;windowscodecs.lib;pathcch.lib;Mswsock.lib;mfreadwrite.lib;Mfplat.lib;mfuuid.lib;ntdll.lib;Secur32.lib;crypt32.lib;secur32.lib;avrt.lib;WindowsApp.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + %(AdditionalOptions) /machine:x64 + false + true + %(IgnoreSpecificDefaultLibraries) + lib/RelWithDebInfo/SampleRemote.lib + false + bin/RelWithDebInfo/SampleRemote.pdb + Windows + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Vertex + main + 5.0 + + + Vertex + main + 5.0 + + + Vertex + main + 5.0 + + + Pixel + main + 5.0 + + + Pixel + main + 5.0 + + + Geometry + main + 5.0 + + + Geometry + main + 5.0 + + + PreserveNewest + + + + + + + \ No newline at end of file diff --git a/hostsampleapp/uwp/SampleHostMain.cpp b/remote/desktop/SampleRemoteMain.cpp similarity index 59% rename from hostsampleapp/uwp/SampleHostMain.cpp rename to remote/desktop/SampleRemoteMain.cpp index 3f084d9..f1b681d 100644 --- a/hostsampleapp/uwp/SampleHostMain.cpp +++ b/remote/desktop/SampleRemoteMain.cpp @@ -1,894 +1,1152 @@ -//********************************************************* -// -// 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 "SampleHostMain.h" - -#include "Common\DbgLog.h" -#include "Common\DirectXHelper.h" -#include "Common\Speech.h" - -#include - -#include - -#include -#include - -#include -#include - - -using namespace concurrency; - -using namespace std::chrono_literals; - -using namespace winrt::Microsoft::Holographic::AppRemoting; -using namespace winrt::Windows::Foundation::Numerics; -using namespace winrt::Windows::Graphics::Holographic; -using namespace winrt::Windows::Perception::People; -using namespace winrt::Windows::Perception::Spatial; -using namespace winrt::Windows::UI::Input; - - -namespace -{ - const wchar_t* StreamerConnectionStateToString(ConnectionState state) - { - switch (state) - { - case ConnectionState::Disconnected: - return L"Disconnected"; - - case ConnectionState::Connecting: - return L"Connecting"; - - case ConnectionState::Connected: - return L"Connected"; - } - - return L"Unknown"; - } -} // namespace - - -SampleHostMain::SampleHostMain(std::weak_ptr window) - : m_window(window) -{ - m_deviceResources = std::make_shared(); - m_deviceResources->RegisterDeviceNotify(this); -} - -SampleHostMain::~SampleHostMain() -{ - ShutdownRemoteContext(); - - m_deviceResources->RegisterDeviceNotify(nullptr); - UnregisterHolographicEventHandlers(); -} - -HolographicFrame SampleHostMain::Update() -{ - auto timeDelta = std::chrono::high_resolution_clock::now() - m_windowTitleUpdateTime; - if (timeDelta >= 1s) - { - WindowUpdateTitle(); - - m_windowTitleUpdateTime = std::chrono::high_resolution_clock::now(); - m_framesPerSecond = 0; - } - - if (!m_holographicSpace) - { - return nullptr; - } - - // NOTE: DXHelper::DeviceResources::Present does not wait for the frame to finish. - // Instead we wait here before we do the call to CreateNextFrame on the HolographicSpace. - // We do this to avoid that PeekMessage causes frame delta time spikes, say if we wait - // after PeekMessage WaitForNextFrameReady will compensate any time spend in PeekMessage. - m_holographicSpace.WaitForNextFrameReady(); - - HolographicFrame holographicFrame = m_holographicSpace.CreateNextFrame(); - 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); - - SpatialCoordinateSystem coordinateSystem = nullptr; - { - coordinateSystem = m_referenceFrame.CoordinateSystem(); - } - - // Check for new input state since the last frame. - Spatial::SpatialTappedEventArgs tapped = m_spatialInputHandler->CheckForTapped(); - if (tapped) - { - Spatial::SpatialPointerPose pointerPose = tapped.TryGetPointerPose(coordinateSystem); - - // When the Tapped spatial input event is received, the sample hologram will be repositioned two meters in front of the user. - m_spinningCubeRenderer->PositionHologram(pointerPose); - - } - else - { - static float3 initialCubePosition = float3::zero(); - - auto manipulationStarted = m_spatialInputHandler->CheckForManipulationStarted(); - if (manipulationStarted) - { - initialCubePosition = m_spinningCubeRenderer->GetPosition(); - m_spinningCubeRenderer->Pause(); - } - else - { - auto manipulationUpdated = m_spatialInputHandler->CheckForManipulationUpdated(); - if (manipulationUpdated) - { - auto delta = manipulationUpdated.TryGetCumulativeDelta(coordinateSystem); - if (delta) - { - m_spinningCubeRenderer->SetPosition(initialCubePosition + delta.Translation()); - } - } - else - { - switch (m_spatialInputHandler->CheckForManipulationResult()) - { - case SpatialInputHandler::ManipulationResult::Canceled: - m_spinningCubeRenderer->SetPosition(initialCubePosition); - case SpatialInputHandler::ManipulationResult::Completed: - m_spinningCubeRenderer->Unpause(); - break; - } - } - } - } - - std::chrono::duration timeSinceStart = std::chrono::high_resolution_clock::now() - m_startTime; - m_spinningCubeRenderer->Update(timeSinceStart.count()); - - if (m_spatialSurfaceMeshRenderer != nullptr) - { - m_spatialSurfaceMeshRenderer->Update(coordinateSystem); - } - m_spatialInputRenderer->Update(prediction.Timestamp(), coordinateSystem); - m_qrCodeRenderer->Update(*m_perceptionDeviceHandler.get(), coordinateSystem); - - // We complete the frame update by using information about our content positioning to set the focus point. - for (auto cameraPose : prediction.CameraPoses()) - { - try - { - HolographicCameraRenderingParameters renderingParameters = holographicFrame.GetRenderingParameters(cameraPose); - - // Set the focus point for image stabilization to the center of the sample hologram. - // NOTE: A focus point can be set for every HolographicFrame. If a focus point is set on a HolographicFrame, - // it will get transmitted to the player and will get set during the PlayerContext::BlitRemoteFrame() call. - renderingParameters.SetFocusPoint(coordinateSystem, m_spinningCubeRenderer->GetPosition()); - } - catch (winrt::hresult_error&) - { - } - } - -#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE - timeDelta = std::chrono::high_resolution_clock::now() - m_customDataChannelSendTime; - if (timeDelta > 5s) - { - m_customDataChannelSendTime = std::chrono::high_resolution_clock::now(); - - // Send ping every couple of frames if we have a custom data channel. - std::lock_guard lock(m_customDataChannelLock); - if (m_customDataChannel) - { - uint8_t data = 1; - m_customDataChannel.SendData( - winrt::array_view(reinterpret_cast(&data), reinterpret_cast(&data + 1)), - true); - OutputDebugString(TEXT("Ping Sent.\n")); - } - } -#endif - - return holographicFrame; -} - -void SampleHostMain::Render(HolographicFrame holographicFrame) -{ - bool atLeastOneCameraRendered = false; - - m_deviceResources->UseHolographicCameraResources([this, holographicFrame, &atLeastOneCameraRendered]( - std::map>& cameraResourceMap) { - holographicFrame.UpdateCurrentPrediction(); - HolographicFramePrediction prediction = holographicFrame.CurrentPrediction(); - - SpatialCoordinateSystem coordinateSystem = nullptr; - { - coordinateSystem = m_referenceFrame.CoordinateSystem(); - } - - for (auto cameraPose : prediction.CameraPoses()) - { - try - { - DXHelper::CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get(); - - if (pCameraResources == nullptr) - { - continue; - } - - m_deviceResources->UseD3DDeviceContext([&](ID3D11DeviceContext3* context) { - // Clear the back buffer view. - context->ClearRenderTargetView(pCameraResources->GetBackBufferRenderTargetView(), DirectX::Colors::Transparent); - context->ClearDepthStencilView( - pCameraResources->GetDepthStencilView(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); - - // 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, coordinateSystem); - - // Set up the camera buffer. - bool cameraActive = pCameraResources->AttachViewProjectionBuffer(m_deviceResources); - - // Only render world-locked content when positional tracking is active. - if (cameraActive) - { - // Set the render target, and set the depth target drawing buffer. - ID3D11RenderTargetView* const targets[1] = {pCameraResources->GetBackBufferRenderTargetView()}; - context->OMSetRenderTargets(1, targets, pCameraResources->GetDepthStencilView()); - - // Render the scene objects. - m_spinningCubeRenderer->Render(pCameraResources->IsRenderingStereoscopic()); - if (m_spatialSurfaceMeshRenderer != nullptr) - { - m_spatialSurfaceMeshRenderer->Render(pCameraResources->IsRenderingStereoscopic()); - } - m_spatialInputRenderer->Render(pCameraResources->IsRenderingStereoscopic()); - m_qrCodeRenderer->Render(pCameraResources->IsRenderingStereoscopic()); - } - }); - - atLeastOneCameraRendered = true; - } - catch (const winrt::hresult_error&) - { - } - } - }); - - if (atLeastOneCameraRendered) - { - m_deviceResources->Present(holographicFrame); - } - - if (m_swapChain == nullptr && m_isInitialized) - { - // A device lost event has occurred. - // Reconnection is necessary because the holographic streamer uses the D3D device. - // The following resources depend on the D3D device: - // * Holographic streamer - // * Renderer - // * Holographic space - // The InitializeRemoteContext() function will call the functions necessary to recreate these resources. - ShutdownRemoteContext(); - InitializeRemoteContextAndConnectOrListen(); - } - - // Determine whether or not to copy to the preview buffer. - bool copyPreview = m_remoteContext == nullptr || m_remoteContext.ConnectionState() != ConnectionState::Connected; - if (copyPreview && m_isInitialized) - { - winrt::com_ptr spDevice; - spDevice.copy_from(GetDeviceResources()->GetD3DDevice()); - - winrt::com_ptr spBackBuffer; - winrt::check_hresult(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), spBackBuffer.put_void())); - - // 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. - winrt::com_ptr spRenderTargetView; - winrt::check_hresult(spDevice->CreateRenderTargetView(spBackBuffer.get(), nullptr, spRenderTargetView.put())); - - GetDeviceResources()->UseD3DDeviceContext( - [&](auto context) { context->ClearRenderTargetView(spRenderTargetView.get(), DirectX::Colors::CornflowerBlue); }); - - WindowPresentSwapChain(); - } - - m_framesPerSecond++; -} - -void SampleHostMain::SetHostOptions(bool listen, const std::wstring& hostname, uint32_t port) -{ - m_listen = listen; - m_hostname = hostname; - m_port = port; -} - -void SampleHostMain::OnKeyPress(char key) -{ - switch (key) - { - case ' ': - InitializeRemoteContextAndConnectOrListen(); - break; - - case 'd': - ShutdownRemoteContext(); - break; - - case 'p': - m_showPreview = !m_showPreview; - break; - - case 'l': - LoadPosition(); - break; - - case 's': - SavePosition(); - break; - - - case 'c': - m_spinningCubeRenderer->TogglePauseState(); - break; - } - - WindowUpdateTitle(); -} - -void SampleHostMain::OnResize(int width, int height) -{ - std::lock_guard _lg(m_deviceLock); - - if (width != m_width || height != m_height) - { - m_width = width; - m_height = height; - - if (m_swapChain) - { - winrt::check_hresult(m_swapChain->ResizeBuffers(2, m_width, m_height, DXGI_FORMAT_B8G8R8A8_UNORM, 0)); - } - } -} - -void SampleHostMain::OnRecognizedSpeech(const winrt::hstring& recognizedText) -{ - bool changedColor = false; - DirectX::XMFLOAT4 color = {1, 1, 1, 1}; - - if (recognizedText == L"Red") - { - color = {1, 0, 0, 1}; - changedColor = true; - } - else if (recognizedText == L"Blue") - { - color = {0, 0, 1, 1}; - changedColor = true; - } - else if (recognizedText == L"Green") - { - color = {0, 1, 0, 1}; - changedColor = true; - } - else if (recognizedText == L"Default") - { - color = {1, 1, 1, 1}; - changedColor = true; - } - else if (recognizedText == L"Aquamarine") - { - color = {0, 1, 1, 1}; - changedColor = true; - } - else if (recognizedText == L"Load position") - { - LoadPosition(); - } - else if (recognizedText == L"Save position") - { - SavePosition(); - } - - if (changedColor && m_spinningCubeRenderer) - { - m_spinningCubeRenderer->SetColorFilter(color); - } -} - -void SampleHostMain::InitializeRemoteContextAndConnectOrListen() -{ - if (!m_remoteContext) - { - // Create the RemoteContext - // IMPORTANT: This must be done before creating the HolographicSpace (or any other call to the Holographic API). - CreateRemoteContext(m_remoteContext, 20000, false, PreferredVideoCodec::Default); - - // Create the HolographicSpace - CreateHolographicSpaceAndDeviceResources(); - - if (auto remoteSpeech = m_remoteContext.GetRemoteSpeech()) - { - Speech::InitializeSpeechAsync(remoteSpeech, m_onRecognizedSpeechRevoker, weak_from_this()); - } - - winrt::com_ptr device; - device.copy_from(GetDeviceResources()->GetD3DDevice()); - WindowCreateSwapChain(device); - - DXGI_ADAPTER_DESC2 dxgiAdapterDesc; - if (SUCCEEDED(GetDeviceResources()->GetDXGIAdapter()->GetDesc2(&dxgiAdapterDesc)) && - (dxgiAdapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)) - { - DebugLog(L"Software video adapter is not supported for holographic streamer.\n"); - m_remoteContext = nullptr; - return; - } - - winrt::weak_ref remoteContextWeakRef = m_remoteContext; - - m_onConnectedEventRevoker = m_remoteContext.OnConnected(winrt::auto_revoke, [this, remoteContextWeakRef]() { - if (auto remoteContext = remoteContextWeakRef.get()) - { - WindowUpdateTitle(); - remoteContext.CreateDataChannel(0, DataChannelPriority::Low); - } - }); - - m_onDisconnectedEventRevoker = - m_remoteContext.OnDisconnected(winrt::auto_revoke, [this, remoteContextWeakRef](ConnectionFailureReason failureReason) { - if (auto remoteContext = remoteContextWeakRef.get()) - { - DebugLog(L"Disconnected with reason %d", failureReason); - WindowUpdateTitle(); - - // Reconnect if this is a transient failure. - if (failureReason == ConnectionFailureReason::HandshakeUnreachable || - failureReason == ConnectionFailureReason::TransportUnreachable || - failureReason == ConnectionFailureReason::ConnectionLost) - { - DebugLog(L"Reconnecting..."); - - ConnectOrListen(); - } - // Failure reason None indicates a normal disconnect. - else if (failureReason != ConnectionFailureReason::None) - { - DebugLog(L"Disconnected with unrecoverable error, not attempting to reconnect."); - } - } - }); - - m_onSendFrameEventRevoker = m_remoteContext.OnSendFrame( - winrt::auto_revoke, [this](const winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface& texture) { - if (m_showPreview) - { - winrt::com_ptr spDevice; - spDevice.copy_from(GetDeviceResources()->GetD3DDevice()); - - winrt::com_ptr spBackBuffer; - winrt::check_hresult(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), spBackBuffer.put_void())); - - winrt::com_ptr texturePtr; - { - winrt::com_ptr resource; - winrt::com_ptr<::IInspectable> inspectable = texture.as<::IInspectable>(); - winrt::com_ptr dxgiInterfaceAccess; - winrt::check_hresult(inspectable->QueryInterface(__uuidof(dxgiInterfaceAccess), dxgiInterfaceAccess.put_void())); - winrt::check_hresult(dxgiInterfaceAccess->GetInterface(__uuidof(resource), resource.put_void())); - resource.as(texturePtr); - } - - GetDeviceResources()->UseD3DDeviceContext([&](auto context) { - context->CopySubresourceRegion( - spBackBuffer.get(), // dest - 0, // dest subresource - 0, - 0, - 0, // dest x, y, z - texturePtr.get(), // source - 0, // source subresource - nullptr); // source box, null means the entire resource - }); - - WindowPresentSwapChain(); - } - }); - -#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE - m_onDataChannelCreatedEventRevoker = - m_remoteContext.OnDataChannelCreated(winrt::auto_revoke, [this](const IDataChannel& dataChannel, uint8_t channelId) { - std::lock_guard lock(m_customDataChannelLock); - m_customDataChannel = dataChannel; - - m_customChannelDataReceivedEventRevoker = m_customDataChannel.OnDataReceived( - winrt::auto_revoke, [this](winrt::array_view dataView) { OnCustomDataChannelDataReceived(); }); - - m_customChannelClosedEventRevoker = - m_customDataChannel.OnClosed(winrt::auto_revoke, [this]() { OnCustomDataChannelClosed(); }); - }); -#endif - - ConnectOrListen(); - } -} - -void SampleHostMain::CreateHolographicSpaceAndDeviceResources() -{ - UnregisterHolographicEventHandlers(); - - m_holographicSpace = HolographicSpace::CreateForCoreWindow(nullptr); - - m_deviceResources->SetHolographicSpace(m_holographicSpace); - - m_spinningCubeRenderer = std::make_unique(m_deviceResources); - - // Uncomment the below line to render spatial surfaces - // m_spatialSurfaceMeshRenderer = std::make_unique(m_deviceResources); - - m_spatialInputRenderer = std::make_unique(m_deviceResources); - m_spatialInputHandler = std::make_shared(); - - m_qrCodeRenderer = std::make_unique(m_deviceResources); - - m_perceptionDeviceHandler = std::make_shared(); - m_perceptionDeviceHandler->Start(); - - - m_locator = SpatialLocator::GetDefault(); - - // Be able to respond to changes in the positional tracking state. - m_locatabilityChangedToken = m_locator.LocatabilityChanged({this, &SampleHostMain::OnLocatabilityChanged}); - - m_cameraAddedToken = m_holographicSpace.CameraAdded({this, &SampleHostMain::OnCameraAdded}); - m_cameraRemovedToken = m_holographicSpace.CameraRemoved({this, &SampleHostMain::OnCameraRemoved}); - - { - m_referenceFrame = m_locator.CreateStationaryFrameOfReferenceAtCurrentLocation(float3::zero(), quaternion(0, 0, 0, 1), 0.0); - } - - m_isInitialized = true; -} - -void SampleHostMain::ConnectOrListen() -{ - // Try to establish a connection. - try - { - m_remoteContext.Disconnect(); - - // Request access to eyes pose data on every connection/listen attempt. - RequestEyesPoseAccess(); - - if (m_port == 0) - { - m_port = 8265; - } - - if (m_listen) - { - if (m_hostname.empty()) - { - m_hostname = L"0.0.0.0"; - } - m_remoteContext.Listen(m_hostname, m_port, m_port + 1); - } - else - { - if (m_hostname.empty()) - { - m_hostname = L"127.0.0.1"; - } - m_remoteContext.Connect(m_hostname, m_port); - } - } - catch (winrt::hresult_error& e) - { - if (m_listen) - { - DebugLog(L"Listen failed with hr = 0x%08X", e.code()); - } - else - { - DebugLog(L"Connect failed with hr = 0x%08X", e.code()); - } - } -} - -void SampleHostMain::LoadPosition() -{ - auto storeRequest = SpatialAnchorManager::RequestStoreAsync(); - storeRequest.Completed([this](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { - if (result.Status() != winrt::Windows::Foundation::AsyncStatus::Completed) - { - return; - } - - const SpatialAnchorStore& store = result.GetResults(); - if (store) - { - auto anchors = store.GetAllSavedAnchors(); - if (anchors.HasKey(L"position")) - { - auto position = anchors.Lookup(L"position"); - auto positionToOrigin = position.CoordinateSystem().TryGetTransformTo(m_referenceFrame.CoordinateSystem()); - if (positionToOrigin) - { - const float3 res = transform(float3::zero(), positionToOrigin.Value()); - m_spinningCubeRenderer->SetPosition(res); - OutputDebugStringW(L"Loaded cube position from SpatialAnchorStore.\n"); - } - } - } - }); -} - -void SampleHostMain::SavePosition() -{ - auto position = SpatialAnchor::TryCreateRelativeTo(m_referenceFrame.CoordinateSystem(), m_spinningCubeRenderer->GetPosition()); - - auto storeRequest = SpatialAnchorManager::RequestStoreAsync(); - storeRequest.Completed([position](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { - if (result.Status() != winrt::Windows::Foundation::AsyncStatus::Completed) - { - return; - } - - const SpatialAnchorStore& store = result.GetResults(); - if (store) - { - store.Clear(); - if (store.TrySave(L"position", position)) - { - OutputDebugStringW(L"Saved cube position to SpatialAnchorStore.\n"); - } - } - }); -} - - -void SampleHostMain::RequestEyesPoseAccess() -{ - try - { - auto asyncOpertation = winrt::Windows::Perception::People::EyesPose::RequestAccessAsync(); - asyncOpertation.Completed( - [this](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { - winrt::Windows::UI::Input::GazeInputAccessStatus status = result.GetResults(); - switch (status) - { - case winrt::Windows::UI::Input::GazeInputAccessStatus::Unspecified: - OutputDebugStringA("ParseGazeInputResponseData Unspecified\n"); - break; - case winrt::Windows::UI::Input::GazeInputAccessStatus::Allowed: - OutputDebugStringA("ParseGazeInputResponseData Allowed\n"); - break; - case winrt::Windows::UI::Input::GazeInputAccessStatus::DeniedByUser: - OutputDebugStringA("ParseGazeInputResponseData DeniedByUser\n"); - break; - case winrt::Windows::UI::Input::GazeInputAccessStatus::DeniedBySystem: - OutputDebugStringA("ParseGazeInputResponseData DeniedBySystem\n"); - break; - default: - break; - } - }); - } - catch (winrt::hresult_error&) - { - } -} - -void SampleHostMain::UnregisterHolographicEventHandlers() -{ - if (m_holographicSpace != nullptr) - { - m_holographicSpace.CameraAdded(m_cameraAddedToken); - m_holographicSpace.CameraRemoved(m_cameraRemovedToken); - } - - if (m_locator != nullptr) - { - m_locator.LocatabilityChanged(m_locatabilityChangedToken); - } -} - -void SampleHostMain::ShutdownRemoteContext() -{ - if (m_remoteContext != nullptr) - { - m_onConnectedEventRevoker.revoke(); - m_onDisconnectedEventRevoker.revoke(); - m_onSendFrameEventRevoker.revoke(); - m_onDataChannelCreatedEventRevoker.revoke(); - -#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE - { - std::lock_guard lock(m_customDataChannelLock); - m_customChannelDataReceivedEventRevoker.revoke(); - m_customChannelClosedEventRevoker.revoke(); - m_customDataChannel = nullptr; - } -#endif - - m_remoteContext.Close(); - m_remoteContext = nullptr; - } -} - -void SampleHostMain::OnDeviceLost() -{ - m_spinningCubeRenderer->ReleaseDeviceDependentResources(); - m_spatialInputRenderer->ReleaseDeviceDependentResources(); - m_qrCodeRenderer->ReleaseDeviceDependentResources(); - - if (m_spatialSurfaceMeshRenderer) - { - m_spatialSurfaceMeshRenderer->ReleaseDeviceDependentResources(); - } -} - -void SampleHostMain::OnDeviceRestored() -{ - m_spinningCubeRenderer->CreateDeviceDependentResources(); - m_spatialInputRenderer->CreateDeviceDependentResources(); - m_qrCodeRenderer->CreateDeviceDependentResources(); - - if (m_spatialSurfaceMeshRenderer) - { - m_spatialSurfaceMeshRenderer->CreateDeviceDependentResources(); - } -} - -void SampleHostMain::OnCameraAdded(const HolographicSpace& sender, const HolographicSpaceCameraAddedEventArgs& args) -{ - winrt::Windows::Foundation::Deferral deferral = args.GetDeferral(); - auto holographicCamera = args.Camera(); - create_task([this, deferral, holographicCamera]() { - m_deviceResources->AddHolographicCamera(holographicCamera); - - deferral.Complete(); - }); -} - -void SampleHostMain::OnCameraRemoved(const HolographicSpace& sender, const HolographicSpaceCameraRemovedEventArgs& args) -{ - m_deviceResources->RemoveHolographicCamera(args.Camera()); -} - -void SampleHostMain::OnLocatabilityChanged(const SpatialLocator& sender, const winrt::Windows::Foundation::IInspectable& args) -{ - const wchar_t* locatability = L""; - switch (sender.Locatability()) - { - case SpatialLocatability::Unavailable: - locatability = L"Unavailable"; - break; - - case SpatialLocatability::PositionalTrackingActivating: - locatability = L"PositionalTrackingActivating"; - break; - - case SpatialLocatability::OrientationOnly: - locatability = L"OrientationOnly"; - break; - - case SpatialLocatability::PositionalTrackingInhibited: - locatability = L"PositionalTrackingInhibited"; - break; - - case SpatialLocatability::PositionalTrackingActive: - locatability = L"PositionalTrackingActive"; - break; - } - - winrt::hstring message = L"Positional tracking is " + winrt::to_hstring(locatability) + L".\n"; - OutputDebugStringW(message.data()); -} - -void SampleHostMain::WindowCreateSwapChain(const winrt::com_ptr& device) -{ - std::lock_guard _lg(m_deviceLock); - - DXGI_SWAP_CHAIN_DESC1 desc = {0}; - desc.Width = m_width; - desc.Height = m_height; - desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - desc.Stereo = false; - desc.SampleDesc.Count = 1; // Don't use multi-sampling. - desc.SampleDesc.Quality = 0; - desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.BufferCount = 2; // Double buffered - desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; - desc.Flags = 0; - desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; - desc.Scaling = DXGI_SCALING_STRETCH; - - m_swapChain = nullptr; - - if (auto window = m_window.lock()) - { - m_swapChain = window->CreateSwapChain(device, &desc); - } -} - -void SampleHostMain::WindowPresentSwapChain() -{ - HRESULT hr = m_swapChain->Present(0, 0); - - if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) - { - // The D3D device is lost. - // This should be handled after the frame is complete. - m_swapChain = nullptr; - } - else - { - winrt::check_hresult(hr); - } -} - -void SampleHostMain::WindowUpdateTitle() -{ - std::wstring title = TITLE_TEXT; - std::wstring separator = TITLE_SEPARATOR; - - uint32_t fps = min(120, m_framesPerSecond); - title += separator + std::to_wstring(fps) + L" fps"; - - // Title | {ip} | {State} [| Press Space to Connect] [| Preview Disabled (p toggles)] - title += separator + m_hostname; - { - if (m_remoteContext) - { - auto connectionState = m_remoteContext.ConnectionState(); - title += separator + (m_isInitialized ? StreamerConnectionStateToString(connectionState) : L"Initializing"); - title += separator + ((connectionState == ConnectionState::Disconnected) ? TITLE_CONNECT_TEXT : TITLE_DISCONNECT_TEXT); - } - else - { - title += separator + TITLE_CONNECT_TEXT; - } - title += separator + (m_showPreview ? TITLE_DISABLE_PREVIEW_TEXT : TITLE_ENABLE_PREVIEW_TEXT); - } - - if (auto window = m_window.lock()) - { - window->SetWindowTitle(title); - } -} - -#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE -void SampleHostMain::OnCustomDataChannelDataReceived() -{ - // TODO: React on data received via the custom data channel here. -} - -void SampleHostMain::OnCustomDataChannelClosed() -{ - std::lock_guard lock(m_customDataChannelLock); - if (m_customDataChannel) - { - m_customChannelDataReceivedEventRevoker.revoke(); - m_customChannelClosedEventRevoker.revoke(); - m_customDataChannel = nullptr; - } -} -#endif +//********************************************************* +// +// 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 "SampleRemoteMain.h" + +#include "Common\DbgLog.h" +#include "Common\DirectXHelper.h" +#include "Common\Speech.h" + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +using namespace concurrency; + +using namespace std::chrono_literals; + +using namespace winrt::Microsoft::Holographic::AppRemoting; +using namespace winrt::Windows::Foundation::Numerics; +using namespace winrt::Windows::Graphics::Holographic; +using namespace winrt::Windows::Graphics::DirectX; +using namespace winrt::Windows::Perception::People; +using namespace winrt::Windows::Perception::Spatial; +using namespace winrt::Windows::UI::Input; +using namespace winrt::Windows::Security::Authorization::AppCapabilityAccess; + +namespace +{ + const wchar_t* StreamerConnectionStateToString(ConnectionState state, bool disconnectPending) + { + switch (state) + { + case ConnectionState::Disconnected: + return L"Disconnected"; + + case ConnectionState::Connecting: + return L"Connecting"; + + case ConnectionState::Connected: + return disconnectPending ? L"Disconnecting" : L"Connected"; + } + + return L"Unknown"; + } +} // namespace + +SampleRemoteMain::SampleRemoteMain(std::weak_ptr window) + : m_window(window) +{ + m_deviceResources = std::make_shared(); + m_deviceResources->RegisterDeviceNotify(this); + + m_canCommitDirect3D11DepthBuffer = winrt::Windows::Foundation::Metadata::ApiInformation::IsMethodPresent( + L"Windows.Graphics.Holographic.HolographicCameraRenderingParameters", L"CommitDirect3D11DepthBuffer"); +} + +SampleRemoteMain::~SampleRemoteMain() +{ + ShutdownRemoteContext(); + + m_deviceResources->RegisterDeviceNotify(nullptr); + UnregisterHolographicEventHandlers(); +} + +HolographicFrame SampleRemoteMain::Update() +{ + auto timeDelta = std::chrono::high_resolution_clock::now() - m_windowTitleUpdateTime; + if (timeDelta >= 1s) + { + WindowUpdateTitle(); + + m_windowTitleUpdateTime = std::chrono::high_resolution_clock::now(); + m_framesPerSecond = 0; + } + + if (!m_holographicSpace) + { + return nullptr; + } + + // NOTE: DXHelper::DeviceResources::Present does not wait for the frame to finish. + // Instead we wait here before we do the call to CreateNextFrame on the HolographicSpace. + // We do this to avoid that PeekMessage causes frame delta time spikes, say if we wait + // after PeekMessage WaitForNextFrameReady will compensate any time spend in PeekMessage. + m_holographicSpace.WaitForNextFrameReady(); + + HolographicFrame holographicFrame = m_holographicSpace.CreateNextFrame(); + 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); + + SpatialCoordinateSystem coordinateSystem = nullptr; + { + coordinateSystem = m_referenceFrame.CoordinateSystem(); + } + + // Check for new input state since the last frame. + Spatial::SpatialTappedEventArgs tapped = m_spatialInputHandler->CheckForTapped(); + if (tapped) + { + Spatial::SpatialPointerPose pointerPose = tapped.TryGetPointerPose(coordinateSystem); + + // When the Tapped spatial input event is received, the sample hologram will be repositioned two meters in front of the user. + m_spinningCubeRenderer->PositionHologram(pointerPose); + } + else + { + static float3 initialCubePosition = float3::zero(); + + auto manipulationStarted = m_spatialInputHandler->CheckForManipulationStarted(); + if (manipulationStarted) + { + initialCubePosition = m_spinningCubeRenderer->GetPosition(); + m_spinningCubeRenderer->Pause(); + } + else + { + auto manipulationUpdated = m_spatialInputHandler->CheckForManipulationUpdated(); + if (manipulationUpdated) + { + auto delta = manipulationUpdated.TryGetCumulativeDelta(coordinateSystem); + if (delta) + { + m_spinningCubeRenderer->SetPosition(initialCubePosition + delta.Translation()); + } + } + else + { + switch (m_spatialInputHandler->CheckForManipulationResult()) + { + case SpatialInputHandler::ManipulationResult::Canceled: + m_spinningCubeRenderer->SetPosition(initialCubePosition); + case SpatialInputHandler::ManipulationResult::Completed: + m_spinningCubeRenderer->Unpause(); + break; + } + } + } + } + + std::chrono::duration timeSinceStart = std::chrono::high_resolution_clock::now() - m_startTime; + m_spinningCubeRenderer->Update(timeSinceStart.count(), prediction.Timestamp(), coordinateSystem); + + if (m_spatialSurfaceMeshRenderer != nullptr) + { + m_spatialSurfaceMeshRenderer->Update(prediction.Timestamp(), coordinateSystem); + } + m_spatialInputRenderer->Update(prediction.Timestamp(), coordinateSystem); + if (m_perceptionDeviceHandler) + { + m_qrCodeRenderer->Update(*m_perceptionDeviceHandler, coordinateSystem); + } + + // We complete the frame update by using information about our content positioning to set the focus point. + if (!m_canCommitDirect3D11DepthBuffer || !m_commitDirect3D11DepthBuffer) + { + for (auto cameraPose : prediction.CameraPoses()) + { + try + { + HolographicCameraRenderingParameters renderingParameters = holographicFrame.GetRenderingParameters(cameraPose); + + // Set the focus point for image stabilization to the center of the sample hologram. + // NOTE: A focus point can be set for every HolographicFrame. If a focus point is set on a HolographicFrame, + // it will get transmitted to the player and will get set during the PlayerContext::BlitRemoteFrame() call. + renderingParameters.SetFocusPoint(coordinateSystem, m_spinningCubeRenderer->GetPosition()); + } + catch (winrt::hresult_error&) + { + } + } + } + +#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE + timeDelta = std::chrono::high_resolution_clock::now() - m_customDataChannelSendTime; + if (timeDelta > 5s) + { + m_customDataChannelSendTime = std::chrono::high_resolution_clock::now(); + + // Send ping every couple of frames if we have a custom data channel. + std::lock_guard lock(m_customDataChannelLock); + if (m_customDataChannel) + { + // Try to get send queue size. The send queue size returns the size of data, that has not been send yet, in bytes. + // A big number might indicate that more data is queued to send than the amount of data, that is actually sent. + // If possible skip sending data in this case, to help the queue getting smaller again. + uint32_t sendQueueSize = m_customDataChannel.SendQueueSize(); + + // Only send the packet if the send queue is smaller than 1MiB + if (sendQueueSize < 1 * 1024 * 1024) + { + uint8_t data = 1; + + try + { + m_customDataChannel.SendData( + winrt::array_view( + reinterpret_cast(&data), reinterpret_cast(&data + 1)), + true); + OutputDebugString(TEXT("Request Sent.\n")); + } + catch (...) + { + // SendData might throw if channel is closed, but we did not get or process the async closed event yet. + } + } + } + } +#endif + + return holographicFrame; +} + +void SampleRemoteMain::Render(HolographicFrame holographicFrame) +{ + bool atLeastOneCameraRendered = false; + + m_deviceResources->UseHolographicCameraResources([this, holographicFrame, &atLeastOneCameraRendered]( + std::map>& cameraResourceMap) { + holographicFrame.UpdateCurrentPrediction(); + HolographicFramePrediction prediction = holographicFrame.CurrentPrediction(); + + SpatialCoordinateSystem coordinateSystem = nullptr; + { + coordinateSystem = m_referenceFrame.CoordinateSystem(); + } + + for (auto cameraPose : prediction.CameraPoses()) + { + try + { + DXHelper::CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get(); + + if (pCameraResources == nullptr || pCameraResources->GetBackBufferRenderTargetView() == nullptr) + { + continue; + } + + m_deviceResources->UseD3DDeviceContext([&](ID3D11DeviceContext3* context) { + // Clear the back buffer view. + context->ClearRenderTargetView(pCameraResources->GetBackBufferRenderTargetView(), DirectX::Colors::Transparent); + context->ClearDepthStencilView( + pCameraResources->GetDepthStencilView(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); + + // 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, coordinateSystem); + + // Set up the camera buffer. + bool cameraActive = pCameraResources->AttachViewProjectionBuffer(m_deviceResources); + + // Only render world-locked content when positional tracking is active. + if (cameraActive) + { + // Set the render target, and set the depth target drawing buffer. + ID3D11RenderTargetView* const targets[1] = {pCameraResources->GetBackBufferRenderTargetView()}; + context->OMSetRenderTargets(1, targets, pCameraResources->GetDepthStencilView()); + + // Render the scene objects. + m_spinningCubeRenderer->Render(pCameraResources->IsRenderingStereoscopic()); + if (m_spatialSurfaceMeshRenderer != nullptr) + { + m_spatialSurfaceMeshRenderer->Render(pCameraResources->IsRenderingStereoscopic()); + } + m_spatialInputRenderer->Render(pCameraResources->IsRenderingStereoscopic()); + m_qrCodeRenderer->Render(pCameraResources->IsRenderingStereoscopic()); + + // Commit depth buffer if available and enabled. + if (m_canCommitDirect3D11DepthBuffer && m_commitDirect3D11DepthBuffer) + { + auto interopSurface = pCameraResources->GetDepthStencilTextureInteropObject(); + HolographicCameraRenderingParameters renderingParameters = holographicFrame.GetRenderingParameters(cameraPose); + renderingParameters.CommitDirect3D11DepthBuffer(interopSurface); + } + } + }); + + atLeastOneCameraRendered = true; + } + catch (const winrt::hresult_error&) + { + } + } + }); + + if (atLeastOneCameraRendered) + { + m_deviceResources->Present(holographicFrame); + } + + if (!m_isStandalone) + { + if (m_swapChain == nullptr && m_isInitialized) + { + // A device lost event has occurred. + // Reconnection is necessary because the holographic streamer uses the D3D device. + // The following resources depend on the D3D device: + // * Holographic streamer + // * Renderer + // * Holographic space + // The InitializeRemoteContext() function will call the functions necessary to recreate these resources. + ShutdownRemoteContext(); + InitializeRemoteContextAndConnectOrListen(); + } + + // Determine whether or not to copy to the preview buffer. + bool copyPreview; + { + std::lock_guard remoteContextLock(m_remoteContextAccess); + copyPreview = m_remoteContext == nullptr || m_remoteContext.ConnectionState() != ConnectionState::Connected; + } + if (copyPreview && m_isInitialized) + { + winrt::com_ptr spDevice; + spDevice.copy_from(GetDeviceResources()->GetD3DDevice()); + + winrt::com_ptr spBackBuffer; + winrt::check_hresult(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), spBackBuffer.put_void())); + + // 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. + winrt::com_ptr spRenderTargetView; + winrt::check_hresult(spDevice->CreateRenderTargetView(spBackBuffer.get(), nullptr, spRenderTargetView.put())); + + GetDeviceResources()->UseD3DDeviceContext( + [&](auto context) { context->ClearRenderTargetView(spRenderTargetView.get(), DirectX::Colors::CornflowerBlue); }); + + WindowPresentSwapChain(); + } + } + + m_framesPerSecond++; +} + +void SampleRemoteMain::ConfigureRemoting( + bool listen, const std::wstring& hostname, uint16_t port, uint16_t transportPort, bool ephemeralPort) +{ + if (!m_isInitialized) + { + m_listen = listen; + m_hostname = hostname; + m_port = port; + m_transportPort = transportPort; + m_ephemeralPort = ephemeralPort; + } +} + +void SampleRemoteMain::InitializeStandalone() +{ + if (!m_isInitialized) + { + m_isStandalone = true; + CreateHolographicSpaceAndDeviceResources(); + } +} + +void SampleRemoteMain::OnKeyPress(char key) +{ + switch (key) + { + case ' ': + InitializeRemoteContextAndConnectOrListen(); + break; + + case 'd': + { + std::lock_guard remoteContextLock(m_remoteContextAccess); + if (m_remoteContext && m_remoteContext.ConnectionState() != ConnectionState::Disconnected) + { + m_disconnectPending = true; + m_remoteContext.Disconnect(); + } + } + break; + + case 'p': + m_showPreview = !m_showPreview; + break; + + case 'l': + LoadPosition(); + break; + + case 's': + SavePosition(); + break; + + case 'e': + ExportPosition(); + break; + + case 'x': + m_commitDirect3D11DepthBuffer = !m_commitDirect3D11DepthBuffer; + break; + + case 'c': + m_spinningCubeRenderer->TogglePauseState(); + break; + } + + WindowUpdateTitle(); +} + +void SampleRemoteMain::OnResize(int width, int height) +{ + std::lock_guard _lg(m_deviceLock); + + if (width != m_width || height != m_height) + { + m_width = width; + m_height = height; + + if (m_swapChain) + { + winrt::check_hresult(m_swapChain->ResizeBuffers(2, m_width, m_height, DXGI_FORMAT_B8G8R8A8_UNORM, 0)); + } + } +} + +void SampleRemoteMain::OnRecognizedSpeech(const winrt::hstring& recognizedText) +{ + bool changedColor = false; + DirectX::XMFLOAT4 color = {1, 1, 1, 1}; + + if (recognizedText == L"Red") + { + color = {1, 0, 0, 1}; + changedColor = true; + } + else if (recognizedText == L"Blue") + { + color = {0, 0, 1, 1}; + changedColor = true; + } + else if (recognizedText == L"Green") + { + color = {0, 1, 0, 1}; + changedColor = true; + } + else if (recognizedText == L"Default") + { + color = {1, 1, 1, 1}; + changedColor = true; + } + else if (recognizedText == L"Aquamarine") + { + color = {0, 1, 1, 1}; + changedColor = true; + } + else if (recognizedText == L"Load position") + { + LoadPosition(); + } + else if (recognizedText == L"Save position") + { + SavePosition(); + } + + if (changedColor && m_spinningCubeRenderer) + { + m_spinningCubeRenderer->SetColorFilter(color); + } +} + +void SampleRemoteMain::InitializeRemoteContextAndConnectOrListen() +{ + std::lock_guard remoteContextLock(m_remoteContextAccess); + + if (!m_remoteContext && !m_isStandalone) + { + // Create the RemoteContext + // IMPORTANT: This must be done before creating the HolographicSpace (or any other call to the Holographic API). + CreateRemoteContext(m_remoteContext, 20000, true, PreferredVideoCodec::Any); + + // Configure for half-resolution depth. + m_remoteContext.ConfigureDepthVideoStream(DepthBufferStreamResolution::Half_Resolution); + + // Create the HolographicSpace + CreateHolographicSpaceAndDeviceResources(); + + if (auto remoteSpeech = m_remoteContext.GetRemoteSpeech()) + { + Speech::InitializeSpeechAsync(remoteSpeech, m_onRecognizedSpeechRevoker, weak_from_this()); + } + + winrt::com_ptr device; + device.copy_from(GetDeviceResources()->GetD3DDevice()); + WindowCreateSwapChain(device); + + DXGI_ADAPTER_DESC2 dxgiAdapterDesc; + if (SUCCEEDED(GetDeviceResources()->GetDXGIAdapter()->GetDesc2(&dxgiAdapterDesc)) && + (dxgiAdapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)) + { + DebugLog(L"Software video adapter is not supported for holographic streamer.\n"); + m_remoteContext = nullptr; + return; + } + + winrt::weak_ref remoteContextWeakRef = m_remoteContext; + + m_onConnectedEventRevoker = m_remoteContext.OnConnected(winrt::auto_revoke, [this, remoteContextWeakRef]() { + if (auto remoteContext = remoteContextWeakRef.get()) + { + WindowUpdateTitle(); + remoteContext.CreateDataChannel(0, DataChannelPriority::Low); + } + + // The spatial surface renderer needs to get recreated on every connect, because its SpatialSurfaceObserver stops working on + // disconnect. Uncomment the below line to render spatial surfaces + // m_spatialSurfaceMeshRenderer = std::make_unique(m_deviceResources); + }); + + m_onDisconnectedEventRevoker = + m_remoteContext.OnDisconnected(winrt::auto_revoke, [this, remoteContextWeakRef](ConnectionFailureReason failureReason) { + if (auto remoteContext = remoteContextWeakRef.get()) + { + OnDisconnected(failureReason); + } + + m_spatialSurfaceMeshRenderer = nullptr; + }); + + m_onSendFrameEventRevoker = m_remoteContext.OnSendFrame( + winrt::auto_revoke, [this](const winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface& texture) { + if (m_showPreview) + { + winrt::com_ptr spDevice; + spDevice.copy_from(GetDeviceResources()->GetD3DDevice()); + + winrt::com_ptr spBackBuffer; + winrt::check_hresult(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), spBackBuffer.put_void())); + + winrt::com_ptr texturePtr; + { + winrt::com_ptr resource; + winrt::com_ptr<::IInspectable> inspectable = texture.as<::IInspectable>(); + winrt::com_ptr dxgiInterfaceAccess; + winrt::check_hresult(inspectable->QueryInterface(__uuidof(dxgiInterfaceAccess), dxgiInterfaceAccess.put_void())); + winrt::check_hresult(dxgiInterfaceAccess->GetInterface(__uuidof(resource), resource.put_void())); + resource.as(texturePtr); + } + + // Get source/dest dimensions and adjust copy rect and destination position to avoid D3D errors + D3D11_TEXTURE2D_DESC backBufferDesc, textureDesc; + spBackBuffer->GetDesc(&backBufferDesc); + texturePtr->GetDesc(&textureDesc); + + UINT destX = 0, destY = 0; + D3D11_BOX srcBox{0, 0, 0, textureDesc.Width, textureDesc.Height, 1}; + + if (backBufferDesc.Width < textureDesc.Width) + { + // Target (BackBuffer) narrower than source (Texture) + srcBox.left = (textureDesc.Width - backBufferDesc.Width) / 2; + srcBox.right = srcBox.left + backBufferDesc.Width; + } + else if (backBufferDesc.Width > textureDesc.Width) + { + // Target (BackBuffer) wider than source (Texture) + destX = (backBufferDesc.Width - textureDesc.Width) / 2; + } + + if (backBufferDesc.Height < textureDesc.Height) + { + // Target (BackBuffer) shorter than source (Texture) + srcBox.top = (textureDesc.Height - backBufferDesc.Height) / 2; + srcBox.bottom = srcBox.top + backBufferDesc.Height; + } + else if (backBufferDesc.Height > textureDesc.Height) + { + // Target (BackBuffer) taller than source (Texture) + destY = (backBufferDesc.Height - textureDesc.Height) / 2; + } + + // Copy texture to back buffer + GetDeviceResources()->UseD3DDeviceContext([&](auto context) { + context->CopySubresourceRegion( + spBackBuffer.get(), // dest + 0, // dest subresource + destX, + destY, + 0, // dest x, y, z + texturePtr.get(), // source + 0, // source subresource + &srcBox); // source box, null means the entire resource + }); + + WindowPresentSwapChain(); + } + }); + +#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE + m_onDataChannelCreatedEventRevoker = + m_remoteContext.OnDataChannelCreated(winrt::auto_revoke, [this](const IDataChannel& dataChannel, uint8_t channelId) { + std::lock_guard lock(m_customDataChannelLock); + m_customDataChannel = dataChannel.as(); + + m_customChannelDataReceivedEventRevoker = m_customDataChannel.OnDataReceived( + winrt::auto_revoke, [this](winrt::array_view dataView) { OnCustomDataChannelDataReceived(); }); + + m_customChannelClosedEventRevoker = + m_customDataChannel.OnClosed(winrt::auto_revoke, [this]() { OnCustomDataChannelClosed(); }); + }); +#endif + + ConnectOrListen(); + } +} + +void SampleRemoteMain::CreateHolographicSpaceAndDeviceResources() +{ + UnregisterHolographicEventHandlers(); + + if (auto window = m_window.lock()) + { + m_holographicSpace = window->CreateHolographicSpace(); + m_interactionManager = window->CreateInteractionManager(); + } + + m_deviceResources->SetHolographicSpace(m_holographicSpace); + + m_spatialInputRenderer = std::make_shared(m_deviceResources, m_interactionManager); + m_spatialInputHandler = std::make_shared(m_interactionManager); + + { + m_spinningCubeRenderer = std::make_unique(m_deviceResources); + } + + m_qrCodeRenderer = std::make_unique(m_deviceResources); + + CreatePerceptionDeviceHandler(); + + m_locator = SpatialLocator::GetDefault(); + + // Be able to respond to changes in the positional tracking state. + m_locatabilityChangedToken = m_locator.LocatabilityChanged({this, &SampleRemoteMain::OnLocatabilityChanged}); + + m_cameraAddedToken = m_holographicSpace.CameraAdded({this, &SampleRemoteMain::OnCameraAdded}); + m_cameraRemovedToken = m_holographicSpace.CameraRemoved({this, &SampleRemoteMain::OnCameraRemoved}); + + { + m_referenceFrame = m_locator.CreateStationaryFrameOfReferenceAtCurrentLocation(float3::zero(), quaternion(0, 0, 0, 1), 0.0); + } + + m_isInitialized = true; +} + +void SampleRemoteMain::ConnectOrListen() +{ + std::lock_guard remoteContextLock(m_remoteContextAccess); + + if (!m_remoteContext || m_remoteContext.ConnectionState() != ConnectionState::Disconnected) + { + return; + } + + // Try to establish a connection. + try + { + // Request access to eyes pose data on every connection/listen attempt. + RequestEyesPoseAccess(); + + if (m_ephemeralPort) + { + m_port = 0; + } + else if (m_port == 0) + { + m_port = 8265; + } + + if (m_listen) + { + if (m_ephemeralPort) + { + m_transportPort = 0; + } + else if (m_transportPort == 0) + { + m_transportPort = m_port + 1; + } + + if (m_hostname.empty()) + { + m_hostname = L"0.0.0.0"; + } + m_remoteContext.Listen(m_hostname, m_port, m_transportPort); + } + else + { + if (m_hostname.empty()) + { + m_hostname = L"127.0.0.1"; + } + m_remoteContext.Connect(m_hostname, m_port); + } + } + catch (winrt::hresult_error& e) + { + if (m_listen) + { + DebugLog(L"Listen failed with hr = 0x%08X", e.code()); + } + else + { + DebugLog(L"Connect failed with hr = 0x%08X", e.code()); + } + } +} + +void SampleRemoteMain::LoadPosition() +{ + auto storeRequest = SpatialAnchorManager::RequestStoreAsync(); + storeRequest.Completed([this](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { + if (result.Status() != winrt::Windows::Foundation::AsyncStatus::Completed) + { + return; + } + + const SpatialAnchorStore& store = result.GetResults(); + if (store) + { + auto anchors = store.GetAllSavedAnchors(); + if (anchors.HasKey(L"position")) + { + auto position = anchors.Lookup(L"position"); + auto positionToOrigin = position.CoordinateSystem().TryGetTransformTo(m_referenceFrame.CoordinateSystem()); + if (positionToOrigin) + { + const float3 res = transform(float3::zero(), positionToOrigin.Value()); + m_spinningCubeRenderer->SetPosition(res); + OutputDebugStringW(L"Loaded cube position from SpatialAnchorStore.\n"); + } + } + } + }); +} + +void SampleRemoteMain::SavePosition() +{ + auto position = SpatialAnchor::TryCreateRelativeTo(m_referenceFrame.CoordinateSystem(), m_spinningCubeRenderer->GetPosition()); + + auto storeRequest = SpatialAnchorManager::RequestStoreAsync(); + storeRequest.Completed([position](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { + if (result.Status() != winrt::Windows::Foundation::AsyncStatus::Completed) + { + return; + } + + const SpatialAnchorStore& store = result.GetResults(); + if (store) + { + store.Clear(); + if (store.TrySave(L"position", position)) + { + OutputDebugStringW(L"Saved cube position to SpatialAnchorStore.\n"); + } + } + }); +} + +winrt::fire_and_forget SampleRemoteMain::ExportPosition() +{ + const auto purpose = winrt::Windows::Perception::Spatial::SpatialAnchorExportPurpose::Sharing; + + auto position = SpatialAnchor::TryCreateRelativeTo(m_referenceFrame.CoordinateSystem(), m_spinningCubeRenderer->GetPosition()); + + co_await winrt::resume_background(); + + try + { + using namespace winrt::Windows::Storage::Streams; + + auto status = SpatialAnchorExporter::RequestAccessAsync().get(); + if (status != SpatialPerceptionAccessStatus::Allowed) + { + co_return; + } + + auto exporter = SpatialAnchorExporter::GetDefault(); + auto sufficient = exporter.GetAnchorExportSufficiencyAsync(position, purpose).get(); + + if (!sufficient.IsMinimallySufficient()) + { + OutputDebugStringW(L"\r\nNot enough data for the anchor to export. Try again later."); + co_return; + } + + { + InMemoryRandomAccessStream stream = InMemoryRandomAccessStream(); + bool result = exporter.TryExportAnchorAsync(position, purpose, stream.GetOutputStreamAt(0)).get(); + + uint64_t size = stream.Size(); + if (size > UINT32_MAX) + { + co_return; + } + + std::vector data; + data.resize(size); + + DataReader reader(stream); + reader.LoadAsync(static_cast(size)); + reader.ReadBytes(winrt::array_view(data.data(), data.data() + data.size())); + + { + std::wostringstream debugMsg; + debugMsg << "\r\nSuccessfully exported anchor. Size is " << size << " bytes."; + OutputDebugStringW(debugMsg.str().c_str()); + } + } + } + catch (...) + { + } +} + +void SampleRemoteMain::RequestEyesPoseAccess() +{ + try + { + auto asyncOpertation = winrt::Windows::Perception::People::EyesPose::RequestAccessAsync(); + asyncOpertation.Completed( + [this](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { + winrt::Windows::UI::Input::GazeInputAccessStatus status = result.GetResults(); + switch (status) + { + case winrt::Windows::UI::Input::GazeInputAccessStatus::Unspecified: + OutputDebugStringA("ParseGazeInputResponseData Unspecified\n"); + break; + case winrt::Windows::UI::Input::GazeInputAccessStatus::Allowed: + OutputDebugStringA("ParseGazeInputResponseData Allowed\n"); + break; + case winrt::Windows::UI::Input::GazeInputAccessStatus::DeniedByUser: + OutputDebugStringA("ParseGazeInputResponseData DeniedByUser\n"); + break; + case winrt::Windows::UI::Input::GazeInputAccessStatus::DeniedBySystem: + OutputDebugStringA("ParseGazeInputResponseData DeniedBySystem\n"); + break; + default: + break; + } + }); + } + catch (winrt::hresult_error&) + { + } +} + +winrt::fire_and_forget SampleRemoteMain::CreatePerceptionDeviceHandler() +{ + AppCapabilityAccessStatus status; + if (m_isStandalone) + { + if (!winrt::Windows::Foundation::Metadata::ApiInformation::IsTypePresent( + L"Windows.Security.Authorization.AppCapabilityAccess.AppCapability")) + { + return; + } + + AppCapability webcamCapability = AppCapability::Create(L"webcam"); + if (!webcamCapability) + { + return; + } + auto webcamRequest = webcamCapability.RequestAccessAsync(); + status = webcamRequest.get(); + } + else + { + status = AppCapabilityAccessStatus::Allowed; + } + + auto weakThis = weak_from_this(); + co_await winrt::resume_background(); + + // Create the perception device if we have web cam access in standalone mode. + // Create the perception device if we do not use the standalone mode. In this case, the decision is made on the player side, whereby the + // assumption is that the access is allowed. + if (status == AppCapabilityAccessStatus::Allowed) + { + if (auto strongThis = weakThis.lock()) + { + auto perceptionDeviceHandler = std::make_shared(); + perceptionDeviceHandler->Start(); + + // Do not use the PerceptionDeviceHandler before initialization has been completed. + m_perceptionDeviceHandler = perceptionDeviceHandler; + } + } +} + +void SampleRemoteMain::UnregisterHolographicEventHandlers() +{ + if (m_holographicSpace != nullptr) + { + m_holographicSpace.CameraAdded(m_cameraAddedToken); + m_holographicSpace.CameraRemoved(m_cameraRemovedToken); + } + + if (m_locator != nullptr) + { + m_locator.LocatabilityChanged(m_locatabilityChangedToken); + } +} + +void SampleRemoteMain::ShutdownRemoteContext() +{ + std::lock_guard remoteContextLock(m_remoteContextAccess); + + if (m_remoteContext != nullptr) + { + m_onConnectedEventRevoker.revoke(); + m_onSendFrameEventRevoker.revoke(); + m_onDataChannelCreatedEventRevoker.revoke(); + +#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE + { + std::lock_guard lock(m_customDataChannelLock); + m_customChannelDataReceivedEventRevoker.revoke(); + m_customChannelClosedEventRevoker.revoke(); + m_customDataChannel = nullptr; + } +#endif + + m_remoteContext.Close(); + m_remoteContext = nullptr; + } +} + +void SampleRemoteMain::OnDeviceLost() +{ + m_spinningCubeRenderer->ReleaseDeviceDependentResources(); + m_spatialInputRenderer->ReleaseDeviceDependentResources(); + m_qrCodeRenderer->ReleaseDeviceDependentResources(); + + if (m_spatialSurfaceMeshRenderer) + { + m_spatialSurfaceMeshRenderer->ReleaseDeviceDependentResources(); + } +} + +void SampleRemoteMain::OnDeviceRestored() +{ + m_spinningCubeRenderer->CreateDeviceDependentResources(); + m_spatialInputRenderer->CreateDeviceDependentResources(); + m_qrCodeRenderer->CreateDeviceDependentResources(); + + if (m_spatialSurfaceMeshRenderer) + { + m_spatialSurfaceMeshRenderer->CreateDeviceDependentResources(); + } +} + +void SampleRemoteMain::OnCameraAdded(const HolographicSpace& sender, const HolographicSpaceCameraAddedEventArgs& args) +{ + winrt::Windows::Foundation::Deferral deferral = args.GetDeferral(); + auto holographicCamera = args.Camera(); + + HolographicViewConfiguration viewConfig = holographicCamera.ViewConfiguration(); + viewConfig.PixelFormat(DirectXPixelFormat::B8G8R8A8UIntNormalized); + + create_task([this, deferral, holographicCamera]() { + m_deviceResources->AddHolographicCamera(holographicCamera); + + deferral.Complete(); + }); +} + +void SampleRemoteMain::OnCameraRemoved(const HolographicSpace& sender, const HolographicSpaceCameraRemovedEventArgs& args) +{ + m_deviceResources->RemoveHolographicCamera(args.Camera()); +} + +void SampleRemoteMain::OnLocatabilityChanged(const SpatialLocator& sender, const winrt::Windows::Foundation::IInspectable& args) +{ + const wchar_t* locatability = L""; + switch (sender.Locatability()) + { + case SpatialLocatability::Unavailable: + locatability = L"Unavailable"; + break; + + case SpatialLocatability::PositionalTrackingActivating: + locatability = L"PositionalTrackingActivating"; + break; + + case SpatialLocatability::OrientationOnly: + locatability = L"OrientationOnly"; + break; + + case SpatialLocatability::PositionalTrackingInhibited: + locatability = L"PositionalTrackingInhibited"; + break; + + case SpatialLocatability::PositionalTrackingActive: + locatability = L"PositionalTrackingActive"; + break; + } + + winrt::hstring message = L"Positional tracking is " + winrt::to_hstring(locatability) + L".\n"; + OutputDebugStringW(message.data()); +} + +void SampleRemoteMain::OnDisconnected(winrt::Microsoft::Holographic::AppRemoting::ConnectionFailureReason failureReason) +{ + DebugLog(L"Disconnected with reason %d", failureReason); + + { + std::lock_guard remoteContextLock(m_remoteContextAccess); + m_disconnectPending = false; + } + + // Reconnect if this is a transient failure. + if (failureReason == ConnectionFailureReason::DisconnectRequest || failureReason == ConnectionFailureReason::PeerDisconnectRequest) + { + ShutdownRemoteContext(); + } + else if ( + failureReason == ConnectionFailureReason::HandshakeUnreachable || failureReason == ConnectionFailureReason::TransportUnreachable || + failureReason == ConnectionFailureReason::ConnectionLost) + { + DebugLog(L"Reconnecting..."); + ConnectOrListen(); + } + // Failure reason None indicates a normal disconnect. + else if (failureReason != ConnectionFailureReason::None) + { + DebugLog(L"Disconnected with unrecoverable error, not attempting to reconnect."); + ShutdownRemoteContext(); + } + + WindowUpdateTitle(); +} + +void SampleRemoteMain::WindowCreateSwapChain(const winrt::com_ptr& device) +{ + std::lock_guard _lg(m_deviceLock); + + DXGI_SWAP_CHAIN_DESC1 desc = {0}; + desc.Width = m_width; + desc.Height = m_height; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.Stereo = false; + desc.SampleDesc.Count = 1; // Don't use multi-sampling. + desc.SampleDesc.Quality = 0; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.BufferCount = 2; // Double buffered + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + desc.Flags = 0; + desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + desc.Scaling = DXGI_SCALING_STRETCH; + + m_swapChain = nullptr; + + if (auto window = m_window.lock()) + { + m_swapChain = window->CreateSwapChain(device, &desc); + } +} + +void SampleRemoteMain::WindowPresentSwapChain() +{ + HRESULT hr = m_swapChain->Present(0, 0); + + if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) + { + // The D3D device is lost. + // This should be handled after the frame is complete. + m_swapChain = nullptr; + } + else + { + winrt::check_hresult(hr); + } +} + +void SampleRemoteMain::WindowUpdateTitle() +{ + std::wstring title = TITLE_TEXT; + std::wstring separator = TITLE_SEPARATOR; + + uint32_t fps = min(120, m_framesPerSecond); + title += separator + std::to_wstring(fps) + L" fps"; + + // Title | {ip} | {State} [| Press Space to Connect] [| Preview Disabled (p toggles)] + title += separator + m_hostname; + { + std::lock_guard remoteContextLock(m_remoteContextAccess); + if (m_remoteContext) + { + auto connectionState = m_remoteContext.ConnectionState(); + title += + separator + (m_isInitialized ? StreamerConnectionStateToString(connectionState, m_disconnectPending) : L"Initializing"); + title += separator + ((connectionState == ConnectionState::Disconnected) ? TITLE_CONNECT_TEXT : TITLE_DISCONNECT_TEXT); + } + else if (!m_isStandalone) + { + title += separator + TITLE_CONNECT_TEXT; + } + + if (!m_isStandalone) + { + title += separator + (m_showPreview ? TITLE_DISABLE_PREVIEW_TEXT : TITLE_ENABLE_PREVIEW_TEXT); + } + } + + if (auto window = m_window.lock()) + { + window->SetWindowTitle(title); + } +} + +#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE +void SampleRemoteMain::OnCustomDataChannelDataReceived() +{ + // TODO: React on data received via the custom data channel here. + OutputDebugString(TEXT("Response Received.\n")); +} + +void SampleRemoteMain::OnCustomDataChannelClosed() +{ + std::lock_guard lock(m_customDataChannelLock); + if (m_customDataChannel) + { + m_customChannelDataReceivedEventRevoker.revoke(); + m_customChannelClosedEventRevoker.revoke(); + m_customDataChannel = nullptr; + } +} +#endif diff --git a/hostsampleapp/desktop/SampleHostMain.h b/remote/desktop/SampleRemoteMain.h similarity index 76% rename from hostsampleapp/desktop/SampleHostMain.h rename to remote/desktop/SampleRemoteMain.h index 71ef0a1..e34afce 100644 --- a/hostsampleapp/desktop/SampleHostMain.h +++ b/remote/desktop/SampleRemoteMain.h @@ -1,211 +1,240 @@ -//********************************************************* -// -// 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 "Common/DeviceResources.h" - -#include "Content/PerceptionDeviceHandler.h" -#include "Content/QRCodeRenderer.h" -#include "Content/SpatialInputHandler.h" -#include "Content/SpatialInputRenderer.h" -#include "Content/SpatialSurfaceMeshRenderer.h" -#include "Content/SpinningCubeRenderer.h" - -#include - -#include - - -#define INITIAL_WINDOW_WIDTH 1280 -#define INITIAL_WINDOW_HEIGHT 720 - -#define TITLE_TEXT L"Remoting Host Sample" -#define TITLE_SEPARATOR L" | " -#define TITLE_CONNECT_TEXT L"Press Space To Connect" -#define TITLE_DISCONNECT_TEXT L"Press D to Disconnect" -#define TITLE_ENABLE_PREVIEW_TEXT L"Preview Disabled (press P to enable)" -#define TITLE_DISABLE_PREVIEW_TEXT L"Preview Enabled (press P to disable)" - - -class SampleHostMain : public std::enable_shared_from_this, public DXHelper::IDeviceNotify -{ -public: - struct IWindow - { - virtual winrt::com_ptr - CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) = 0; - - virtual void SetWindowTitle(std::wstring title) = 0; - }; - - - -public: - SampleHostMain(std::weak_ptr window); - ~SampleHostMain(); - - // Creates a HolographicFrame and updates the content. - winrt::Windows::Graphics::Holographic::HolographicFrame Update(); - - // Renders the current frame to each holographic camera and presents it. - void Render(winrt::Windows::Graphics::Holographic::HolographicFrame holographicFrame); - - const std::shared_ptr& GetDeviceResources() - { - return m_deviceResources; - } - - void SetHostOptions(bool listen, const std::wstring& hostname, uint32_t port); - - // Responds to key presses. - void OnKeyPress(char key); - - // Responds to window changing its size. - void OnResize(int width, int height); - - // Responds to speech recognition results. - void OnRecognizedSpeech(const winrt::hstring& recognizedText); - - // IDeviceNotify methods - virtual void OnDeviceLost(); - virtual void OnDeviceRestored(); - -private: - // Initializes the RemoteContext and starts connecting or listening to the currently set network address - void InitializeRemoteContextAndConnectOrListen(); - - // Initializes the HolographicSpace and creates graphics device dependent resources - void CreateHolographicSpaceAndDeviceResources(); - - // Connects to or listens on the currently set network address - void ConnectOrListen(); - - // Loads the currently saved position of the spinning cube. - void LoadPosition(); - - // Saves the position of the spinning cube. - void SavePosition(); - - - // Request access for eyes pose data. - void RequestEyesPoseAccess(); - - // Clears event registration state. Used when changing to a new HolographicSpace - // and when tearing down SampleHostMain. - void UnregisterHolographicEventHandlers(); - - // Shuts down the RemoteContext (which will also disconnect, if currently connected) - void ShutdownRemoteContext(); - - // Creates a SwapChain for the host window - void WindowCreateSwapChain(const winrt::com_ptr& device); - - // Presents the SwapChain of the host window - void WindowPresentSwapChain(); - - // Updates the title of the host window - void WindowUpdateTitle(); - - // Asynchronously creates resources for new holographic cameras. - void OnCameraAdded( - const winrt::Windows::Graphics::Holographic::HolographicSpace& sender, - const winrt::Windows::Graphics::Holographic::HolographicSpaceCameraAddedEventArgs& args); - - // Synchronously releases resources for holographic cameras that are no longer - // attached to the system. - void OnCameraRemoved( - const winrt::Windows::Graphics::Holographic::HolographicSpace& sender, - const winrt::Windows::Graphics::Holographic::HolographicSpaceCameraRemovedEventArgs& args); - - // Used to notify the app when the positional tracking state changes. - void OnLocatabilityChanged( - const winrt::Windows::Perception::Spatial::SpatialLocator& sender, const winrt::Windows::Foundation::IInspectable& args); - -#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE - void OnCustomDataChannelDataReceived(); - void OnCustomDataChannelClosed(); -#endif - -private: - bool m_isInitialized = false; - - std::chrono::high_resolution_clock::time_point m_startTime = std::chrono::high_resolution_clock::now(); - - // RemoteContext used to connect with a Holographic Remoting player and display rendered frames - winrt::Microsoft::Holographic::AppRemoting::RemoteContext m_remoteContext = nullptr; - - // Represents the holographic space around the user. - winrt::Windows::Graphics::Holographic::HolographicSpace m_holographicSpace = nullptr; - - // Cached pointer to device resources. - std::shared_ptr m_deviceResources; - - // SpatialLocator that is attached to the primary camera. - winrt::Windows::Perception::Spatial::SpatialLocator m_locator = nullptr; - - // A reference frame that is positioned in the world. - winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference m_referenceFrame = nullptr; - - // Renders a colorful holographic cube that's 20 centimeters wide. This sample content - // is used to demonstrate world-locked rendering. - std::unique_ptr m_spinningCubeRenderer; - - // Renders the surface observed in the user's surroundings. - std::unique_ptr m_spatialSurfaceMeshRenderer; - - // Listens for the Pressed spatial input event. - std::shared_ptr m_spatialInputHandler; - std::unique_ptr m_spatialInputRenderer; - - // Handles perception root objects and their events/updates - std::shared_ptr m_perceptionDeviceHandler; - std::unique_ptr m_qrCodeRenderer; - - // Event registration tokens. - winrt::event_token m_cameraAddedToken; - winrt::event_token m_cameraRemovedToken; - winrt::event_token m_locatabilityChangedToken; - - // Event registration revokers - winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnConnected_revoker m_onConnectedEventRevoker; - winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnDisconnected_revoker m_onDisconnectedEventRevoker; - winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnSendFrame_revoker m_onSendFrameEventRevoker; - winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnDataChannelCreated_revoker m_onDataChannelCreatedEventRevoker; - winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker m_onRecognizedSpeechRevoker; - - // Host options - std::wstring m_hostname; - uint32_t m_port{0}; - bool m_showPreview = true; - bool m_listen{false}; - - // Host window related variables - std::weak_ptr m_window; - int m_width = INITIAL_WINDOW_WIDTH; - int m_height = INITIAL_WINDOW_HEIGHT; - - std::chrono::high_resolution_clock::time_point m_windowTitleUpdateTime; - uint32_t m_framesPerSecond = 0; - - std::recursive_mutex m_deviceLock; - winrt::com_ptr m_swapChain; - winrt::com_ptr m_spTexture; - -#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE - std::recursive_mutex m_customDataChannelLock; - winrt::Microsoft::Holographic::AppRemoting::IDataChannel m_customDataChannel = nullptr; - winrt::Microsoft::Holographic::AppRemoting::IDataChannel::OnDataReceived_revoker m_customChannelDataReceivedEventRevoker; - winrt::Microsoft::Holographic::AppRemoting::IDataChannel::OnClosed_revoker m_customChannelClosedEventRevoker; - std::chrono::high_resolution_clock::time_point m_customDataChannelSendTime = std::chrono::high_resolution_clock::now(); -#endif - -}; +//********************************************************* +// +// 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 "Common/DeviceResources.h" + +#include "Content/PerceptionDeviceHandler.h" +#include "Content/QRCodeRenderer.h" +#include "Content/SpatialInputHandler.h" +#include "Content/SpatialInputRenderer.h" +#include "Content/SpatialSurfaceMeshRenderer.h" +#include "Content/SpinningCubeRenderer.h" + +#include + +#include + +#define INITIAL_WINDOW_WIDTH 1280 +#define INITIAL_WINDOW_HEIGHT 720 + +#define TITLE_TEXT L"Remoting Host Sample" +#define TITLE_SEPARATOR L" | " +#define TITLE_CONNECT_TEXT L"Press Space To Connect" +#define TITLE_DISCONNECT_TEXT L"Press D to Disconnect" +#define TITLE_ENABLE_PREVIEW_TEXT L"Preview Disabled (press P to enable)" +#define TITLE_DISABLE_PREVIEW_TEXT L"Preview Enabled (press P to disable)" + +// #define ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE + +class SampleRemoteMain : public std::enable_shared_from_this, public DXHelper::IDeviceNotify +{ +public: + struct IWindow + { + virtual winrt::com_ptr + CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) = 0; + + virtual winrt::Windows::Graphics::Holographic::HolographicSpace CreateHolographicSpace() = 0; + + virtual winrt::Windows::UI::Input::Spatial::SpatialInteractionManager CreateInteractionManager() = 0; + + virtual void SetWindowTitle(std::wstring title) = 0; + }; + +public: + SampleRemoteMain(std::weak_ptr window); + ~SampleRemoteMain(); + + // Creates a HolographicFrame and updates the content. + winrt::Windows::Graphics::Holographic::HolographicFrame Update(); + + // Renders the current frame to each holographic camera and presents it. + void Render(winrt::Windows::Graphics::Holographic::HolographicFrame holographicFrame); + + const std::shared_ptr& GetDeviceResources() + { + return m_deviceResources; + } + + // Initialize SampleRemoteMain for remote rendering targeting a HolographicRemotingPlayer. + void + ConfigureRemoting(bool listen, const std::wstring& hostname, uint16_t port, uint16_t transportPort = 0, bool ephemeralPort = false); + + // Initialize SampleRemoteMain for local rendering targeting HoloLens or Windows Mixed Reality headsets. + void InitializeStandalone(); + + // Responds to key presses. + void OnKeyPress(char key); + + // Responds to window changing its size. + void OnResize(int width, int height); + + // Responds to speech recognition results. + void OnRecognizedSpeech(const winrt::hstring& recognizedText); + + // IDeviceNotify methods + virtual void OnDeviceLost(); + virtual void OnDeviceRestored(); + + // Initializes the RemoteContext and starts connecting or listening to the currently set network address + void InitializeRemoteContextAndConnectOrListen(); + +private: + // Initializes the HolographicSpace and creates graphics device dependent resources + void CreateHolographicSpaceAndDeviceResources(); + + // Connects to or listens on the currently set network address + void ConnectOrListen(); + + // Loads the currently saved position of the spinning cube. + void LoadPosition(); + + // Saves the position of the spinning cube. + void SavePosition(); + + // Exports a test anchor via SpatialAnchorExporter. + winrt::fire_and_forget ExportPosition(); + + // Request access for eyes pose data. + void RequestEyesPoseAccess(); + + // Create the perception device handler which is required for qr code tracking. + winrt::fire_and_forget CreatePerceptionDeviceHandler(); + + // Clears event registration state. Used when changing to a new HolographicSpace + // and when tearing down SampleRemoteMain. + void UnregisterHolographicEventHandlers(); + + // Shuts down the RemoteContext (which will also disconnect, if currently connected) + void ShutdownRemoteContext(); + + // Creates a SwapChain for the host window + void WindowCreateSwapChain(const winrt::com_ptr& device); + + // Presents the SwapChain of the host window + void WindowPresentSwapChain(); + + // Updates the title of the host window + void WindowUpdateTitle(); + + // Asynchronously creates resources for new holographic cameras. + void OnCameraAdded( + const winrt::Windows::Graphics::Holographic::HolographicSpace& sender, + const winrt::Windows::Graphics::Holographic::HolographicSpaceCameraAddedEventArgs& args); + + // Synchronously releases resources for holographic cameras that are no longer + // attached to the system. + void OnCameraRemoved( + const winrt::Windows::Graphics::Holographic::HolographicSpace& sender, + const winrt::Windows::Graphics::Holographic::HolographicSpaceCameraRemovedEventArgs& args); + + // Used to notify the app when the positional tracking state changes. + void OnLocatabilityChanged( + const winrt::Windows::Perception::Spatial::SpatialLocator& sender, const winrt::Windows::Foundation::IInspectable& args); + + void OnDisconnected(winrt::Microsoft::Holographic::AppRemoting::ConnectionFailureReason failureReason); + +#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE + void OnCustomDataChannelDataReceived(); + void OnCustomDataChannelClosed(); +#endif + +private: + bool m_isInitialized = false; + + std::chrono::high_resolution_clock::time_point m_startTime = std::chrono::high_resolution_clock::now(); + + // Lock to serialize remote context operations and event handlers + std::recursive_mutex m_remoteContextAccess; + + // RemoteContext used to connect with a Holographic Remoting player and display rendered frames + winrt::Microsoft::Holographic::AppRemoting::RemoteContext m_remoteContext = nullptr; + + // Whether a disconnect is currently pending. + bool m_disconnectPending{false}; + + // Represents the holographic space around the user. + winrt::Windows::Graphics::Holographic::HolographicSpace m_holographicSpace = nullptr; + + // The interaction manager provides an event that informs the app when spatial interactions are detected. + winrt::Windows::UI::Input::Spatial::SpatialInteractionManager m_interactionManager = nullptr; + + // Cached pointer to device resources. + std::shared_ptr m_deviceResources; + + // SpatialLocator that is attached to the primary camera. + winrt::Windows::Perception::Spatial::SpatialLocator m_locator = nullptr; + + // A reference frame that is positioned in the world. + winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference m_referenceFrame = nullptr; + + // Renders a colorful holographic cube that's 20 centimeters wide. This sample content + // is used to demonstrate world-locked rendering. + std::unique_ptr m_spinningCubeRenderer; + + // Renders the surface observed in the user's surroundings. + std::unique_ptr m_spatialSurfaceMeshRenderer; + + // Listens for the Pressed spatial input event. + std::shared_ptr m_spatialInputHandler; + std::shared_ptr m_spatialInputRenderer; + + // Handles perception root objects and their events/updates + std::shared_ptr m_perceptionDeviceHandler; + std::unique_ptr m_qrCodeRenderer; + + // Event registration tokens. + winrt::event_token m_cameraAddedToken; + winrt::event_token m_cameraRemovedToken; + winrt::event_token m_locatabilityChangedToken; + + // Event registration revokers + winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnConnected_revoker m_onConnectedEventRevoker; + winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnDisconnected_revoker m_onDisconnectedEventRevoker; + winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnSendFrame_revoker m_onSendFrameEventRevoker; + winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnDataChannelCreated_revoker m_onDataChannelCreatedEventRevoker; + winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker m_onRecognizedSpeechRevoker; + + // Host options + std::wstring m_hostname; + uint16_t m_port{0}; + uint16_t m_transportPort{0}; + bool m_ephemeralPort = false; + bool m_showPreview = true; + bool m_listen{false}; + + // Host window related variables + std::weak_ptr m_window; + int m_width = INITIAL_WINDOW_WIDTH; + int m_height = INITIAL_WINDOW_HEIGHT; + + std::chrono::high_resolution_clock::time_point m_windowTitleUpdateTime; + uint32_t m_framesPerSecond = 0; + + std::recursive_mutex m_deviceLock; + winrt::com_ptr m_swapChain; + winrt::com_ptr m_spTexture; + + bool m_canCommitDirect3D11DepthBuffer = false; + bool m_commitDirect3D11DepthBuffer = true; + + bool m_isStandalone = false; + +#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE + std::recursive_mutex m_customDataChannelLock; + winrt::Microsoft::Holographic::AppRemoting::IDataChannel2 m_customDataChannel = nullptr; + winrt::Microsoft::Holographic::AppRemoting::IDataChannel2::OnDataReceived_revoker m_customChannelDataReceivedEventRevoker; + winrt::Microsoft::Holographic::AppRemoting::IDataChannel2::OnClosed_revoker m_customChannelClosedEventRevoker; + std::chrono::high_resolution_clock::time_point m_customDataChannelSendTime = std::chrono::high_resolution_clock::now(); +#endif +}; diff --git a/hostsampleapp/uwp/SampleHostWindowUWP.cpp b/remote/desktop/SampleRemoteWindowUWP.cpp similarity index 67% rename from hostsampleapp/uwp/SampleHostWindowUWP.cpp rename to remote/desktop/SampleRemoteWindowUWP.cpp index 012b059..0f1c8e7 100644 --- a/hostsampleapp/uwp/SampleHostWindowUWP.cpp +++ b/remote/desktop/SampleRemoteWindowUWP.cpp @@ -1,301 +1,323 @@ -//********************************************************* -// -// 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 "SampleHostWindowUWP.h" - -#include "Common\DbgLog.h" -#include "Common\Speech.h" - -#include -#include - -#include - -#include - -#include -#include -#include - -#define INITIAL_WINDOW_WIDTH 1280 -#define INITIAL_WINDOW_HEIGHT 720 - -#define TITLE_SEPARATOR L" | " - -using namespace winrt::Windows::ApplicationModel; -using namespace winrt::Windows::ApplicationModel::Activation; -using namespace winrt::Windows::ApplicationModel::Core; -using namespace winrt::Windows::Graphics::Display; -using namespace winrt::Microsoft::Holographic::AppRemoting; -using namespace winrt::Windows::UI::Core; -using namespace winrt::Windows::UI::ViewManagement; - - -// The main function is only used to initialize our IFrameworkView class. -int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) -{ - winrt::init_apartment(); - CoreApplication::Run(winrt::make()); -} - -SampleHostWindowUWP::SampleHostWindowUWP() -{ - ApplicationView::PreferredLaunchViewSize(winrt::Windows::Foundation::Size(INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT)); -} - -// The first method called when the IFrameworkView is being created. -void SampleHostWindowUWP::Initialize(const CoreApplicationView& applicationView) -{ - CoreApplication::Suspending({this, &SampleHostWindowUWP::OnSuspending}); - CoreApplication::Resuming({this, &SampleHostWindowUWP::OnResuming}); - - applicationView.Activated({this, &SampleHostWindowUWP::OnViewActivated}); - - m_main = std::make_shared(weak_from_this()); -} - -// Called when the CoreWindow object is created (or re-created). -void SampleHostWindowUWP::SetWindow(const CoreWindow& window) -{ - m_window = window; - - window.SizeChanged({this, &SampleHostWindowUWP::OnWindowSizeChanged}); - window.VisibilityChanged({this, &SampleHostWindowUWP::OnVisibilityChanged}); - window.Closed({this, &SampleHostWindowUWP::OnWindowClosed}); - window.KeyDown({this, &SampleHostWindowUWP::OnKeyDown}); -} - -// Initializes scene resources, or loads a previously saved app state. -void SampleHostWindowUWP::Load(const winrt::hstring& entryPoint) -{ -} - -// This method is called after the window becomes active. -void SampleHostWindowUWP::Run() -{ - CoreWindow window = CoreWindow::GetForCurrentThread(); - window.Activate(); - - while (!m_windowClosed) - { - if (m_windowVisible) - { - CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent); - - if (m_main) - { - if (const HolographicFrame& holographicFrame = m_main->Update()) - { - m_main->Render(holographicFrame); - } - } - } - else - { - CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending); - } - } -} - -// Required for IFrameworkView. -// 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. -void SampleHostWindowUWP::Uninitialize() -{ -} - - -winrt::com_ptr - SampleHostWindowUWP::CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) -{ - winrt::com_ptr dxgiDevice; - device.as(dxgiDevice); - - winrt::com_ptr dxgiAdapter; - winrt::check_hresult(dxgiDevice->GetAdapter(dxgiAdapter.put())); - - winrt::com_ptr dxgiFactory; - winrt::check_hresult(dxgiAdapter->GetParent(__uuidof(dxgiFactory), dxgiFactory.put_void())); - - winrt::com_ptr swapChain; - winrt::check_hresult(dxgiFactory->CreateSwapChainForCoreWindow( - device.get(), static_cast<::IUnknown*>(winrt::get_abi(m_window)), desc, nullptr, swapChain.put())); - - return swapChain; -} - -void SampleHostWindowUWP::SetWindowTitle(std::wstring title) -{ - auto dispatcher = winrt::Windows::ApplicationModel::Core::CoreApplication::MainView().CoreWindow().Dispatcher(); - - auto doSetWindowTitle = [title]() { - try - { - if (auto view = winrt::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()) - { - view.Title(winrt::to_hstring(title.c_str())); - } - } - catch (const winrt::hresult_error&) - { - } - }; - - if (dispatcher.HasThreadAccess()) - { - doSetWindowTitle(); - } - else - { - dispatcher.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, doSetWindowTitle); - } -} - -// Application lifecycle event handlers. - -void SampleHostWindowUWP::OnSuspending(const winrt::Windows::Foundation::IInspectable& sender, const SuspendingEventArgs& args) -{ -} - -void SampleHostWindowUWP::OnResuming( - const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& 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. - - // Insert your code here. -} - -// Window event handlers. - -void SampleHostWindowUWP::OnWindowSizeChanged( - const winrt::Windows::Foundation::IInspectable& sender, const WindowSizeChangedEventArgs& args) -{ - winrt::Windows::Foundation::Size size = args.Size(); - m_main->OnResize(static_cast(size.Width + 0.5f), static_cast(size.Height + 0.5f)); -} - -void SampleHostWindowUWP::OnVisibilityChanged( - const winrt::Windows::Foundation::IInspectable& sender, const VisibilityChangedEventArgs& args) -{ - m_windowVisible = args.Visible(); -} - -void SampleHostWindowUWP::OnWindowClosed(const CoreWindow& window, const CoreWindowEventArgs& args) -{ - m_windowClosed = true; -} - -void SampleHostWindowUWP::OnKeyDown(const CoreWindow& window, const KeyEventArgs& args) -{ - int32_t key = static_cast(args.VirtualKey()); - if (key >= 0 && key <= 0xFF) - { - m_main->OnKeyPress(static_cast(tolower(key))); - } -} - -void SampleHostWindowUWP::OnViewActivated(CoreApplicationView const& sender, IActivatedEventArgs const& activationArgs) -{ - using namespace winrt::Windows::ApplicationModel; - using namespace Activation; - using namespace Core; - - std::wstring host = L"127.0.0.1"; - int32_t port = 8265; - - if (activationArgs != nullptr) - { - ActivationKind activationKind = activationArgs.Kind(); - if (activationKind == Activation::ActivationKind::Launch) - { - LaunchActivatedEventArgs launchArgs = activationArgs.as(); - - std::vector args; - std::wistringstream stream(std::wstring(launchArgs.Arguments())); - std::copy( - std::istream_iterator(stream), - std::istream_iterator(), - std::back_inserter(args)); - - for (const std::wstring& arg : args) - { - if (arg.size() == 0) - continue; - - size_t colonPos = arg.find(L':'); - if (colonPos != std::wstring::npos) - { - std::wstring portStr = arg.substr(colonPos + 1); - - host = arg.substr(0, colonPos); - port = std::wcstol(portStr.c_str(), nullptr, 10); - } - else - { - host = arg.c_str(); - } - } - } - } - - // check for invalid port numbers - if (port < 0 || port > 65535) - { - port = 0; - } - - m_ipAddress = host; - m_port = port; - - m_main->SetHostOptions(false, m_ipAddress, m_port); - - // Run() won't start until the CoreWindow is activated. - sender.CoreWindow().Activate(); -} - -SampleHostWindowUWPView::SampleHostWindowUWPView() -{ - m_window = std::make_shared(); -} - -winrt::Windows::ApplicationModel::Core::IFrameworkView SampleHostWindowUWPView::CreateView() -{ - return *this; -} - -void SampleHostWindowUWPView::Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView& applicationView) -{ - m_window->Initialize(applicationView); -} - -void SampleHostWindowUWPView::SetWindow(const winrt::Windows::UI::Core::CoreWindow& window) -{ - m_window->SetWindow(window); -} - -void SampleHostWindowUWPView::Load(const winrt::hstring& entryPoint) -{ - m_window->Load(entryPoint); -} - -void SampleHostWindowUWPView::Run() -{ - m_window->Run(); -} - -void SampleHostWindowUWPView::Uninitialize() -{ - m_window->Uninitialize(); -} +//********************************************************* +// +// 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 "SampleRemoteWindowUWP.h" + +#include "Common\DbgLog.h" +#include "Common\Speech.h" + +#include +#include + +#include + +#include + +#include +#include +#include + +#define INITIAL_WINDOW_WIDTH 1280 +#define INITIAL_WINDOW_HEIGHT 720 + +#define TITLE_SEPARATOR L" | " + +using namespace winrt::Windows::ApplicationModel; +using namespace winrt::Windows::ApplicationModel::Activation; +using namespace winrt::Windows::ApplicationModel::Core; +using namespace winrt::Windows::Graphics::Display; +using namespace winrt::Microsoft::Holographic::AppRemoting; +using namespace winrt::Windows::UI::Core; +using namespace winrt::Windows::UI::ViewManagement; + +// The main function is only used to initialize our IFrameworkView class. +int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) +{ + winrt::init_apartment(); + CoreApplication::Run(winrt::make()); +} + +SampleRemoteWindowUWP::SampleRemoteWindowUWP() +{ + ApplicationView::PreferredLaunchViewSize(winrt::Windows::Foundation::Size(INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT)); +} + +// The first method called when the IFrameworkView is being created. +void SampleRemoteWindowUWP::Initialize(const CoreApplicationView& applicationView) +{ + CoreApplication::Suspending({this, &SampleRemoteWindowUWP::OnSuspending}); + CoreApplication::Resuming({this, &SampleRemoteWindowUWP::OnResuming}); + + applicationView.Activated({this, &SampleRemoteWindowUWP::OnViewActivated}); + + m_main = std::make_shared(weak_from_this()); +} + +// Called when the CoreWindow object is created (or re-created). +void SampleRemoteWindowUWP::SetWindow(const CoreWindow& window) +{ + m_window = window; + + window.SizeChanged({this, &SampleRemoteWindowUWP::OnWindowSizeChanged}); + window.VisibilityChanged({this, &SampleRemoteWindowUWP::OnVisibilityChanged}); + window.Closed({this, &SampleRemoteWindowUWP::OnWindowClosed}); + window.KeyDown({this, &SampleRemoteWindowUWP::OnKeyDown}); +} + +// Initializes scene resources, or loads a previously saved app state. +void SampleRemoteWindowUWP::Load(const winrt::hstring& entryPoint) +{ +} + +// This method is called after the window becomes active. +void SampleRemoteWindowUWP::Run() +{ + CoreWindow window = CoreWindow::GetForCurrentThread(); + window.Activate(); + + while (!m_windowClosed) + { + if (m_windowVisible) + { + CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent); + + if (m_main) + { + if (const HolographicFrame& holographicFrame = m_main->Update()) + { + m_main->Render(holographicFrame); + } + } + } + else + { + CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending); + } + } +} + +// Required for IFrameworkView. +// 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. +void SampleRemoteWindowUWP::Uninitialize() +{ +} + +winrt::com_ptr + SampleRemoteWindowUWP::CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) +{ + winrt::com_ptr dxgiDevice; + device.as(dxgiDevice); + + winrt::com_ptr dxgiAdapter; + winrt::check_hresult(dxgiDevice->GetAdapter(dxgiAdapter.put())); + + winrt::com_ptr dxgiFactory; + winrt::check_hresult(dxgiAdapter->GetParent(__uuidof(dxgiFactory), dxgiFactory.put_void())); + + winrt::com_ptr swapChain; + winrt::check_hresult(dxgiFactory->CreateSwapChainForCoreWindow( + device.get(), static_cast<::IUnknown*>(winrt::get_abi(m_window)), desc, nullptr, swapChain.put())); + + return swapChain; +} + +winrt::Windows::Graphics::Holographic::HolographicSpace SampleRemoteWindowUWP::CreateHolographicSpace() +{ + return HolographicSpace::CreateForCoreWindow(m_window); +} + +winrt::Windows::UI::Input::Spatial::SpatialInteractionManager SampleRemoteWindowUWP::CreateInteractionManager() +{ + return winrt::Windows::UI::Input::Spatial::SpatialInteractionManager::GetForCurrentView(); +} + +void SampleRemoteWindowUWP::SetWindowTitle(std::wstring title) +{ + auto dispatcher = winrt::Windows::ApplicationModel::Core::CoreApplication::MainView().CoreWindow().Dispatcher(); + + auto doSetWindowTitle = [title]() { + try + { + if (auto view = winrt::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()) + { + view.Title(winrt::to_hstring(title.c_str())); + } + } + catch (const winrt::hresult_error&) + { + } + }; + + if (dispatcher.HasThreadAccess()) + { + doSetWindowTitle(); + } + else + { + dispatcher.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, doSetWindowTitle); + } +} + +// Application lifecycle event handlers. + +void SampleRemoteWindowUWP::OnSuspending(const winrt::Windows::Foundation::IInspectable& sender, const SuspendingEventArgs& args) +{ +} + +void SampleRemoteWindowUWP::OnResuming( + const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& 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. + + // Insert your code here. +} + +// Window event handlers. + +void SampleRemoteWindowUWP::OnWindowSizeChanged( + const winrt::Windows::Foundation::IInspectable& sender, const WindowSizeChangedEventArgs& args) +{ + winrt::Windows::Foundation::Size size = args.Size(); + m_main->OnResize(static_cast(size.Width + 0.5f), static_cast(size.Height + 0.5f)); +} + +void SampleRemoteWindowUWP::OnVisibilityChanged( + const winrt::Windows::Foundation::IInspectable& sender, const VisibilityChangedEventArgs& args) +{ + m_windowVisible = args.Visible(); +} + +void SampleRemoteWindowUWP::OnWindowClosed(const CoreWindow& window, const CoreWindowEventArgs& args) +{ + m_windowClosed = true; +} + +void SampleRemoteWindowUWP::OnKeyDown(const CoreWindow& window, const KeyEventArgs& args) +{ + int32_t key = static_cast(args.VirtualKey()); + if (key >= 0 && key <= 0xFF) + { + m_main->OnKeyPress(static_cast(tolower(key))); + } +} + +void SampleRemoteWindowUWP::OnViewActivated(CoreApplicationView const& sender, IActivatedEventArgs const& activationArgs) +{ + using namespace winrt::Windows::ApplicationModel; + using namespace Activation; + using namespace Core; + + std::wstring host = L"127.0.0.1"; + int32_t port = 8265; + bool isStandalone = false; + + if (activationArgs != nullptr) + { + ActivationKind activationKind = activationArgs.Kind(); + if (activationKind == Activation::ActivationKind::Launch) + { + LaunchActivatedEventArgs launchArgs = activationArgs.as(); + + std::vector args; + std::wistringstream stream(std::wstring(launchArgs.Arguments())); + std::copy( + std::istream_iterator(stream), + std::istream_iterator(), + std::back_inserter(args)); + + for (const std::wstring& arg : args) + { + if (arg.size() == 0) + continue; + + if (arg == L"-standalone") + { + isStandalone = true; + continue; + } + + size_t colonPos = arg.find(L':'); + if (colonPos != std::wstring::npos) + { + std::wstring portStr = arg.substr(colonPos + 1); + + host = arg.substr(0, colonPos); + port = std::wcstol(portStr.c_str(), nullptr, 10); + } + else + { + host = arg.c_str(); + } + } + } + } + + if (!isStandalone) + { + // check for invalid port numbers + if (port < 0 || port > 65535) + { + port = 0; + } + + m_ipAddress = host; + m_port = port; + + m_main->ConfigureRemoting(false, m_ipAddress, m_port); + } + else + { + m_main->InitializeStandalone(); + } + + // Run() won't start until the CoreWindow is activated. + sender.CoreWindow().Activate(); +} + +SampleRemoteWindowUWPView::SampleRemoteWindowUWPView() +{ + m_window = std::make_shared(); +} + +winrt::Windows::ApplicationModel::Core::IFrameworkView SampleRemoteWindowUWPView::CreateView() +{ + return *this; +} + +void SampleRemoteWindowUWPView::Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView& applicationView) +{ + m_window->Initialize(applicationView); +} + +void SampleRemoteWindowUWPView::SetWindow(const winrt::Windows::UI::Core::CoreWindow& window) +{ + m_window->SetWindow(window); +} + +void SampleRemoteWindowUWPView::Load(const winrt::hstring& entryPoint) +{ + m_window->Load(entryPoint); +} + +void SampleRemoteWindowUWPView::Run() +{ + m_window->Run(); +} + +void SampleRemoteWindowUWPView::Uninitialize() +{ + m_window->Uninitialize(); +} diff --git a/hostsampleapp/desktop/SampleHostWindowUWP.h b/remote/desktop/SampleRemoteWindowUWP.h similarity index 77% rename from hostsampleapp/desktop/SampleHostWindowUWP.h rename to remote/desktop/SampleRemoteWindowUWP.h index b214178..5f4ec3b 100644 --- a/hostsampleapp/desktop/SampleHostWindowUWP.h +++ b/remote/desktop/SampleRemoteWindowUWP.h @@ -1,89 +1,92 @@ -//********************************************************* -// -// 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 "SampleHostMain.h" - -#include "Common\DeviceResources.h" - -#include -#include - - -// Main entry point for our app. Connects the app with the Windows shell and handles application lifecycle events. -class SampleHostWindowUWP : public std::enable_shared_from_this, public SampleHostMain::IWindow -{ -public: - SampleHostWindowUWP(); - - // IFrameworkView methods - virtual void Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView& applicationView); - virtual void SetWindow(const winrt::Windows::UI::Core::CoreWindow& window); - virtual void Load(const winrt::hstring& entryPoint); - virtual void Run(); - virtual void Uninitialize(); - - // SampleHostMain::IWindow methods. - virtual winrt::com_ptr - CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) override; - - virtual void SetWindowTitle(std::wstring title) override; - -protected: - // Application lifecycle event handlers. - void OnSuspending( - const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::ApplicationModel::SuspendingEventArgs& args); - void OnResuming(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); - - // Activation handling - void OnViewActivated( - winrt::Windows::ApplicationModel::Core::CoreApplicationView const& sender, - winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs const& args); - - // Window event handlers. - void OnWindowSizeChanged( - const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Core::WindowSizeChangedEventArgs& args); - void OnVisibilityChanged( - const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Core::VisibilityChangedEventArgs& args); - void OnWindowClosed(const winrt::Windows::UI::Core::CoreWindow& window, const winrt::Windows::UI::Core::CoreWindowEventArgs& args); - void OnKeyDown(const winrt::Windows::UI::Core::CoreWindow& window, const winrt::Windows::UI::Core::KeyEventArgs& args); - -private: - winrt::Windows::UI::Core::CoreWindow m_window = nullptr; - std::shared_ptr m_main; - std::wstring m_ipAddress; - int32_t m_port = 8265; - bool m_windowClosed = false; - bool m_windowVisible = true; -}; - -class SampleHostWindowUWPView : public winrt::implements< - SampleHostWindowUWPView, - winrt::Windows::ApplicationModel::Core::IFrameworkViewSource, - winrt::Windows::ApplicationModel::Core::IFrameworkView> -{ -public: - SampleHostWindowUWPView(); - - // IFrameworkViewSource methods. - winrt::Windows::ApplicationModel::Core::IFrameworkView CreateView(); - - // IFrameworkView methods. - virtual void Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView& applicationView); - virtual void SetWindow(const winrt::Windows::UI::Core::CoreWindow& window); - virtual void Load(const winrt::hstring& entryPoint); - virtual void Run(); - virtual void Uninitialize(); - -private: - std::shared_ptr m_window; -}; +//********************************************************* +// +// 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 "SampleRemoteMain.h" + +#include "Common\DeviceResources.h" + +#include +#include + +// Main entry point for our app. Connects the app with the Windows shell and handles application lifecycle events. +class SampleRemoteWindowUWP : public std::enable_shared_from_this, public SampleRemoteMain::IWindow +{ +public: + SampleRemoteWindowUWP(); + + // IFrameworkView methods + virtual void Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView& applicationView); + virtual void SetWindow(const winrt::Windows::UI::Core::CoreWindow& window); + virtual void Load(const winrt::hstring& entryPoint); + virtual void Run(); + virtual void Uninitialize(); + + // SampleRemoteMain::IWindow methods. + virtual winrt::com_ptr + CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) override; + + virtual winrt::Windows::Graphics::Holographic::HolographicSpace CreateHolographicSpace() override; + + virtual winrt::Windows::UI::Input::Spatial::SpatialInteractionManager CreateInteractionManager() override; + + virtual void SetWindowTitle(std::wstring title) override; + +protected: + // Application lifecycle event handlers. + void OnSuspending( + const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::ApplicationModel::SuspendingEventArgs& args); + void OnResuming(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); + + // Activation handling + void OnViewActivated( + winrt::Windows::ApplicationModel::Core::CoreApplicationView const& sender, + winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs const& args); + + // Window event handlers. + void OnWindowSizeChanged( + const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Core::WindowSizeChangedEventArgs& args); + void OnVisibilityChanged( + const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Core::VisibilityChangedEventArgs& args); + void OnWindowClosed(const winrt::Windows::UI::Core::CoreWindow& window, const winrt::Windows::UI::Core::CoreWindowEventArgs& args); + void OnKeyDown(const winrt::Windows::UI::Core::CoreWindow& window, const winrt::Windows::UI::Core::KeyEventArgs& args); + +private: + winrt::Windows::UI::Core::CoreWindow m_window = nullptr; + std::shared_ptr m_main; + std::wstring m_ipAddress; + int32_t m_port = 8265; + bool m_windowClosed = false; + bool m_windowVisible = true; +}; + +class SampleRemoteWindowUWPView : public winrt::implements< + SampleRemoteWindowUWPView, + winrt::Windows::ApplicationModel::Core::IFrameworkViewSource, + winrt::Windows::ApplicationModel::Core::IFrameworkView> +{ +public: + SampleRemoteWindowUWPView(); + + // IFrameworkViewSource methods. + winrt::Windows::ApplicationModel::Core::IFrameworkView CreateView(); + + // IFrameworkView methods. + virtual void Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView& applicationView); + virtual void SetWindow(const winrt::Windows::UI::Core::CoreWindow& window); + virtual void Load(const winrt::hstring& entryPoint); + virtual void Run(); + virtual void Uninitialize(); + +private: + std::shared_ptr m_window; +}; diff --git a/remote/desktop/SampleRemoteWindowWin32.cpp b/remote/desktop/SampleRemoteWindowWin32.cpp new file mode 100644 index 0000000..80ea18e --- /dev/null +++ b/remote/desktop/SampleRemoteWindowWin32.cpp @@ -0,0 +1,363 @@ +//********************************************************* +// +// 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 +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#define WINDOWCLASSNAME L"SampleRemoteWindowWin32Class" + +LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static SampleRemoteWindowWin32* s_sampleHostWindow; + + LRESULT result = 0; + + switch (msg) + { + case WM_CREATE: + { + CREATESTRUCT* cs = reinterpret_cast(lParam); + s_sampleHostWindow = reinterpret_cast(cs->lpCreateParams); + + RECT clientRect; + GetClientRect(hWnd, &clientRect); + + s_sampleHostWindow->OnResize(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top); + result = 0; + } + break; + case WM_WINDOWPOSCHANGED: + { + auto windowPos = reinterpret_cast(lParam); + if ((windowPos->flags & SWP_NOSIZE) == 0) + { + RECT clientRect; + GetClientRect(hWnd, &clientRect); + + s_sampleHostWindow->OnResize(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top); + } + result = 0; + } + break; + case WM_DESTROY: + { + s_sampleHostWindow = nullptr; + result = 0; + PostQuitMessage(0); + } + break; + case WM_CLOSE: + { + DestroyWindow(hWnd); + result = 0; + } + break; + case WM_CHAR: + { + const int key = tolower(static_cast(wParam)); + s_sampleHostWindow->OnKeyPress(static_cast(key)); + } + break; + default: + result = DefWindowProc(hWnd, msg, wParam, lParam); + break; + } + + return result; +} + +namespace +{ + std::wstring SplitHostnameAndPortString(const std::wstring& address, uint16_t& port) + { + static std::basic_regex addressMatcher(L"(?:(\\[.*\\])|([^:]*))(?:[:](\\d+))?"); + std::match_results results; + if (std::regex_match(address, results, addressMatcher)) + { + if (results[3].matched) + { + std::wstring portStr = results[3].str(); + port = static_cast(std::wcstol(portStr.c_str(), nullptr, 10)); + } + + return (results[1].matched) ? results[1].str() : results[2].str(); + } + else + { + return address; + } + } +} // namespace + +void SampleRemoteWindowWin32::Initialize() +{ + m_main = std::make_shared(weak_from_this()); +} + +void SampleRemoteWindowWin32::InitializeHwnd(HWND hWnd) +{ + m_hWnd = hWnd; +} + +void SampleRemoteWindowWin32::ConfigureRemoting( + bool listen, const std::wstring& hostname, uint16_t port, uint16_t transportPort, bool ephemeralPort) +{ + m_main->ConfigureRemoting(listen, hostname, port, transportPort, ephemeralPort); +} + +void SampleRemoteWindowWin32::Connect() +{ + m_main->InitializeRemoteContextAndConnectOrListen(); +} + +void SampleRemoteWindowWin32::InitializeStandalone() +{ + m_main->InitializeStandalone(); +} + +void SampleRemoteWindowWin32::Tick() +{ + if (const HolographicFrame& holographicFrame = m_main->Update()) + { + m_main->Render(holographicFrame); + } +} + +void SampleRemoteWindowWin32::OnKeyPress(char key) +{ + m_main->OnKeyPress(key); +} + +void SampleRemoteWindowWin32::OnResize(int width, int height) +{ + m_main->OnResize(width, height); +} + +winrt::com_ptr + SampleRemoteWindowWin32::CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) +{ + winrt::com_ptr dxgiDevice; + device.as(dxgiDevice); + + winrt::com_ptr dxgiAdapter; + winrt::check_hresult(dxgiDevice->GetAdapter(dxgiAdapter.put())); + + winrt::com_ptr dxgiFactory; + winrt::check_hresult(dxgiAdapter->GetParent(__uuidof(IDXGIFactory2), dxgiFactory.put_void())); + + winrt::check_hresult(dxgiFactory->MakeWindowAssociation(m_hWnd, DXGI_MWA_NO_ALT_ENTER)); + + winrt::com_ptr swapChain = nullptr; + winrt::check_hresult(dxgiFactory->CreateSwapChainForHwnd(device.get(), m_hWnd, desc, nullptr, nullptr, swapChain.put())); + + return swapChain; +} + +void SampleRemoteWindowWin32::SetWindowTitle(std::wstring title) +{ + if (m_hWnd) + { + if (!SetWindowTextW(m_hWnd, title.c_str())) + { + winrt::check_hresult(HRESULT_FROM_WIN32(GetLastError())); + } + } +} + +winrt::Windows::Graphics::Holographic::HolographicSpace SampleRemoteWindowWin32::CreateHolographicSpace() +{ + // Use WinRT factory to create the holographic space. + // See https://docs.microsoft.com/en-us/windows/win32/api/holographicspaceinterop/ + winrt::com_ptr holographicSpaceInterop = + winrt::get_activation_factory(); + + winrt::com_ptr spHolographicSpace; + winrt::check_hresult(holographicSpaceInterop->CreateForWindow( + m_hWnd, __uuidof(ABI::Windows::Graphics::Holographic::IHolographicSpace), winrt::put_abi(spHolographicSpace))); + + return spHolographicSpace.as(); +} + +winrt::Windows::UI::Input::Spatial::SpatialInteractionManager SampleRemoteWindowWin32::CreateInteractionManager() +{ + using namespace winrt::Windows::UI::Input::Spatial; + + // Use WinRT factory to create the spatial interaction manager. + // See https://docs.microsoft.com/en-us/windows/win32/api/spatialinteractionmanagerinterop/ + winrt::com_ptr spatialInteractionManagerInterop = + winrt::get_activation_factory(); + + winrt::com_ptr spSpatialInteractionManager; + winrt::check_hresult(spatialInteractionManagerInterop->GetForWindow( + m_hWnd, __uuidof(ABI::Windows::UI::Input::Spatial::ISpatialInteractionManager), winrt::put_abi(spSpatialInteractionManager))); + + return spSpatialInteractionManager.as(); +} + +int main(Platform::Array ^ args) +{ + winrt::init_apartment(); + + bool listen{false}; + std::wstring host; + uint16_t port{0}; + uint16_t transportPort{0}; + bool isStandalone = false; + bool noUserWait = false; + bool useEphemeralPort = false; + + for (unsigned int i = 1; i < args->Length; ++i) + { + if (args[i]->Length() == 0) + continue; + + std::wstring arg = args[i]->Data(); + if (arg[0] == '-') + { + std::wstring param = arg.substr(1); + std::transform(param.begin(), param.end(), param.begin(), ::tolower); + + if (param == L"listen") + { + listen = true; + continue; + } + + if (param == L"standalone") + { + isStandalone = true; + continue; + } + + if (param == L"nouserwait") + { + noUserWait = true; + continue; + } + + if (param == L"ephemeralport") + { + useEphemeralPort = true; + continue; + } + + if (param == L"transportport") + { + if (args->Length > i + 1) + { + std::wstring transportPortStr = args[i + 1]->Data(); + transportPort = std::stoi(transportPortStr); + i++; + } + continue; + } + } + + host = SplitHostnameAndPortString(arg, port); + } + + std::shared_ptr sampleHostWindow = std::make_shared(); + sampleHostWindow->Initialize(); + + WNDCLASSEXW wcex = {}; + wcex.cbSize = sizeof(wcex); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = wndProc; + wcex.hInstance = 0; + wcex.hIcon = LoadIcon(0, IDI_APPLICATION); + wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); + wcex.hbrBackground = static_cast(GetStockObject(NULL_BRUSH)); + wcex.lpszClassName = WINDOWCLASSNAME; + RegisterClassExW(&wcex); + + RECT rc = {0, 0, INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT}; + AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW, FALSE, 0); + + std::wstring windowName = TITLE_TEXT; + + HWND hWnd = CreateWindowW( + WINDOWCLASSNAME, + windowName.c_str(), + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + rc.right - rc.left, + rc.bottom - rc.top, + nullptr, + nullptr, + 0, + sampleHostWindow.get()); + + RECT clientRect; + GetClientRect(hWnd, &clientRect); + + sampleHostWindow->InitializeHwnd(hWnd); + + if (!isStandalone) + { + sampleHostWindow->ConfigureRemoting(listen, host, port, transportPort, useEphemeralPort); + if (noUserWait) + { + sampleHostWindow->Connect(); + } + } + else + { + sampleHostWindow->InitializeStandalone(); + } + + ShowWindow(hWnd, SW_SHOWNORMAL); + bool quit = false; + while (!quit) + { + MSG msg = {0}; + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + quit = true; + } + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + { + try + { + sampleHostWindow->Tick(); + } + catch (...) + { + // Unhandeled exception during tick, exit program + return 1; + } + } + } + + return 0; +} diff --git a/hostsampleapp/desktop/SampleHostWindowWin32.h b/remote/desktop/SampleRemoteWindowWin32.h similarity index 57% rename from hostsampleapp/desktop/SampleHostWindowWin32.h rename to remote/desktop/SampleRemoteWindowWin32.h index 9eb4bde..ef7cb42 100644 --- a/hostsampleapp/desktop/SampleHostWindowWin32.h +++ b/remote/desktop/SampleRemoteWindowWin32.h @@ -1,41 +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. -// -//********************************************************* - -#pragma once - -//#include - -#include "SampleHostMain.h" - -// #define ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE - -class SampleHostWindowWin32 : public std::enable_shared_from_this, public SampleHostMain::IWindow -{ -public: - void Initialize(bool listen, const std::wstring& host, uint32_t port); - - void InitializeHwnd(HWND hWnd); - - void Tick(); - - void OnKeyPress(char key); - void OnResize(int width, int height); - - virtual winrt::com_ptr - CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) override; - - virtual void SetWindowTitle(std::wstring title) override; - -private: - HWND m_hWnd = 0; - - std::shared_ptr m_main; -}; +//********************************************************* +// +// 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 + +class SampleRemoteWindowWin32 : public std::enable_shared_from_this, public SampleRemoteMain::IWindow +{ +public: + void Initialize(); + + void InitializeHwnd(HWND hWnd); + + void ConfigureRemoting(bool listen, const std::wstring& hostname, uint16_t port, uint16_t transportPort, bool ephemeralPort); + void Connect(); + + void InitializeStandalone(); + + void Tick(); + + void OnKeyPress(char key); + void OnResize(int width, int height); + + virtual winrt::com_ptr + CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) override; + + virtual winrt::Windows::Graphics::Holographic::HolographicSpace CreateHolographicSpace() override; + + virtual winrt::Windows::UI::Input::Spatial::SpatialInteractionManager CreateInteractionManager() override; + + virtual void SetWindowTitle(std::wstring title) override; + +private: + HWND m_hWnd = 0; + + std::shared_ptr m_main; +}; diff --git a/hostsampleapp/desktop/SpeechGrammar.xml b/remote/desktop/SpeechGrammar.xml similarity index 96% rename from hostsampleapp/desktop/SpeechGrammar.xml rename to remote/desktop/SpeechGrammar.xml index f45638c..49f4f4c 100644 --- a/hostsampleapp/desktop/SpeechGrammar.xml +++ b/remote/desktop/SpeechGrammar.xml @@ -1,11 +1,11 @@ - - - - - - - Load position - Save position - - + + + + + + + Load position + Save position + + \ No newline at end of file diff --git a/remote/desktop/packages.config b/remote/desktop/packages.config new file mode 100644 index 0000000..4e4f68f --- /dev/null +++ b/remote/desktop/packages.config @@ -0,0 +1,5 @@ + + + + + diff --git a/hostsampleapp/uwp/pch.cpp b/remote/desktop/pch.cpp similarity index 97% rename from hostsampleapp/uwp/pch.cpp rename to remote/desktop/pch.cpp index 5149ada..3ca571e 100644 --- a/hostsampleapp/uwp/pch.cpp +++ b/remote/desktop/pch.cpp @@ -1,12 +1,12 @@ -//********************************************************* -// -// 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" +//********************************************************* +// +// 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" diff --git a/hostsampleapp/uwp/pch.h b/remote/desktop/pch.h similarity index 96% rename from hostsampleapp/uwp/pch.h rename to remote/desktop/pch.h index 7b76575..5eb544d 100644 --- a/hostsampleapp/uwp/pch.h +++ b/remote/desktop/pch.h @@ -1,21 +1,21 @@ -//********************************************************* -// -// 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 - -#include -#include - -#include - -#include +//********************************************************* +// +// 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 + +#include +#include + +#include + +#include diff --git a/hostsampleapp/desktop/Assets/LockScreenLogo.scale-200.png b/remote/uwp/Assets/LockScreenLogo.scale-200.png similarity index 100% rename from hostsampleapp/desktop/Assets/LockScreenLogo.scale-200.png rename to remote/uwp/Assets/LockScreenLogo.scale-200.png diff --git a/hostsampleapp/desktop/Assets/SplashScreen.scale-200.png b/remote/uwp/Assets/SplashScreen.scale-200.png similarity index 100% rename from hostsampleapp/desktop/Assets/SplashScreen.scale-200.png rename to remote/uwp/Assets/SplashScreen.scale-200.png diff --git a/hostsampleapp/desktop/Assets/Square150x150Logo.scale-200.png b/remote/uwp/Assets/Square150x150Logo.scale-200.png similarity index 100% rename from hostsampleapp/desktop/Assets/Square150x150Logo.scale-200.png rename to remote/uwp/Assets/Square150x150Logo.scale-200.png diff --git a/hostsampleapp/desktop/Assets/Square44x44Logo.scale-200.png b/remote/uwp/Assets/Square44x44Logo.scale-200.png similarity index 100% rename from hostsampleapp/desktop/Assets/Square44x44Logo.scale-200.png rename to remote/uwp/Assets/Square44x44Logo.scale-200.png diff --git a/hostsampleapp/desktop/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/remote/uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png similarity index 100% rename from hostsampleapp/desktop/Assets/Square44x44Logo.targetsize-24_altform-unplated.png rename to remote/uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png diff --git a/hostsampleapp/desktop/Assets/StoreLogo.png b/remote/uwp/Assets/StoreLogo.png similarity index 100% rename from hostsampleapp/desktop/Assets/StoreLogo.png rename to remote/uwp/Assets/StoreLogo.png diff --git a/hostsampleapp/desktop/Assets/Wide310x150Logo.scale-200.png b/remote/uwp/Assets/Wide310x150Logo.scale-200.png similarity index 100% rename from hostsampleapp/desktop/Assets/Wide310x150Logo.scale-200.png rename to remote/uwp/Assets/Wide310x150Logo.scale-200.png diff --git a/remote/uwp/Common/CameraResources.cpp b/remote/uwp/Common/CameraResources.cpp new file mode 100644 index 0000000..ed64cbe --- /dev/null +++ b/remote/uwp/Common/CameraResources.cpp @@ -0,0 +1,269 @@ +//********************************************************* +// +// 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 "CameraResources.h" +#include "DeviceResources.h" +#include "DirectXHelper.h" + +#include + +using namespace DirectX; +using namespace winrt::Windows::Graphics::Holographic; +using namespace winrt::Windows::Perception::Spatial; + +namespace DXHelper +{ + CameraResources::CameraResources(const 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 CameraResources::CreateResourcesForBackBuffer( + DeviceResources* pDeviceResources, const HolographicCameraRenderingParameters& cameraParameters) + { + const auto device = pDeviceResources->GetD3DDevice(); + + // 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. + winrt::com_ptr resource; + { + winrt::com_ptr<::IInspectable> inspectable = cameraParameters.Direct3D11BackBuffer().as<::IInspectable>(); + winrt::com_ptr dxgiInterfaceAccess; + + HRESULT hr = inspectable->QueryInterface(__uuidof(dxgiInterfaceAccess), dxgiInterfaceAccess.put_void()); + if (FAILED(hr)) + { + winrt::throw_hresult(hr); + } + + hr = dxgiInterfaceAccess->GetInterface(__uuidof(resource), resource.put_void()); + if (FAILED(hr)) + { + winrt::throw_hresult(hr); + } + } + + // Get a Direct3D interface for the holographic camera's back buffer. + winrt::com_ptr cameraBackBuffer; + 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 != cameraBackBuffer) + { + // 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; + + // 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; + + D3D11_RENDER_TARGET_VIEW_DESC viewDesc = {}; + viewDesc.ViewDimension = backBufferDesc.ArraySize > 1 ? D3D11_RTV_DIMENSION_TEXTURE2DARRAY : D3D11_RTV_DIMENSION_TEXTURE2D; + viewDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + if (backBufferDesc.ArraySize > 1) + { + viewDesc.Texture2DArray.ArraySize = backBufferDesc.ArraySize; + } + + // 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. + m_d3dRenderTargetView = nullptr; + winrt::check_hresult(device->CreateRenderTargetView(m_d3dBackBuffer.get(), &viewDesc, m_d3dRenderTargetView.put())); + + // Check for render target size changes. + winrt::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 = nullptr; + } + } + + // 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_R16_TYPELESS, + static_cast(m_d3dRenderTargetSize.Width), + static_cast(m_d3dRenderTargetSize.Height), + m_isStereo ? 2 : 1, // Create two textures when rendering in stereo. + 1, // Use a single mipmap level. + D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE); + + winrt::check_hresult(device->CreateTexture2D(&depthStencilDesc, nullptr, m_d3dDepthStencil.put())); + + CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc( + m_isStereo ? D3D11_DSV_DIMENSION_TEXTURE2DARRAY : D3D11_DSV_DIMENSION_TEXTURE2D); + depthStencilViewDesc.Format = DXGI_FORMAT_D16_UNORM; + + winrt::check_hresult( + device->CreateDepthStencilView(m_d3dDepthStencil.get(), &depthStencilViewDesc, m_d3dDepthStencilView.put())); + } + + // 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); + winrt::check_hresult(device->CreateBuffer(&constantBufferDesc, nullptr, m_viewProjectionConstantBuffer.put())); + } + } + + // Releases resources associated with a back buffer. + void CameraResources::ReleaseResourcesForBackBuffer(DeviceResources* pDeviceResources) + { + // Release camera-specific resources. + m_d3dBackBuffer = nullptr; + m_d3dDepthStencil = nullptr; + m_d3dRenderTargetView = nullptr; + m_d3dDepthStencilView = nullptr; + m_viewProjectionConstantBuffer = nullptr; + + // 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. + pDeviceResources->UseD3DDeviceContext([](auto 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 CameraResources::UpdateViewProjectionBuffer( + std::shared_ptr deviceResources, + const HolographicCameraPose& cameraPose, + const SpatialCoordinateSystem& coordinateSystem) + { + // The system changes the viewport on a per-frame basis for system optimizations. + m_d3dViewport = + CD3D11_VIEWPORT(cameraPose.Viewport().X, cameraPose.Viewport().Y, cameraPose.Viewport().Width, cameraPose.Viewport().Height); + + // The projection transform for each frame is provided by the HolographicCameraPose. + auto cameraProjectionTransform = cameraPose.ProjectionTransform(); + + // Get a container object with the view and projection matrices for the given + // pose in the given coordinate system. + auto 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. + ViewProjectionConstantBuffer viewProjectionConstantBufferData = {}; + bool viewTransformAcquired = viewTransformContainer != nullptr; + if (viewTransformAcquired) + { + // Otherwise, the set of view transforms can be retrieved. + auto 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. + deviceResources->UseD3DDeviceContext([&](auto context) { + // 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 CameraResources::AttachViewProjectionBuffer(std::shared_ptr deviceResources) + { + // This method uses Direct3D device-based resources. + return deviceResources->UseD3DDeviceContext([&](auto context) { + // 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. + ID3D11Buffer* pBuffer = m_viewProjectionConstantBuffer.get(); + context->VSSetConstantBuffers(1, 1, &pBuffer); + + // 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; + }); + } + + winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface CameraResources::GetDepthStencilTextureInteropObject() + { + // Direct3D interop APIs are used to provide the buffer to the WinRT API. + winrt::com_ptr depthStencilResource; + winrt::check_bool(m_d3dDepthStencil.try_as(depthStencilResource)); + winrt::com_ptr depthDxgiSurface; + winrt::check_hresult(depthStencilResource->CreateSubresourceSurface(0, depthDxgiSurface.put())); + winrt::com_ptr<::IInspectable> inspectableSurface; + winrt::check_hresult(CreateDirect3D11SurfaceFromDXGISurface( + depthDxgiSurface.get(), reinterpret_cast(winrt::put_abi(inspectableSurface)))); + return inspectableSurface.as(); + } +} // namespace DXHelper diff --git a/hostsampleapp/uwp/Common/CameraResources.h b/remote/uwp/Common/CameraResources.h similarity index 89% rename from hostsampleapp/uwp/Common/CameraResources.h rename to remote/uwp/Common/CameraResources.h index a1b560b..e277802 100644 --- a/hostsampleapp/uwp/Common/CameraResources.h +++ b/remote/uwp/Common/CameraResources.h @@ -1,115 +1,122 @@ -//********************************************************* -// -// 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 - -#include - -using namespace winrt::Windows::Graphics::Holographic; -using namespace winrt::Windows::Perception::Spatial; - -namespace DXHelper -{ - 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(const HolographicCamera& holographicCamera); - - void CreateResourcesForBackBuffer( - DXHelper::DeviceResources* pDeviceResources, const HolographicCameraRenderingParameters& cameraParameters); - void ReleaseResourcesForBackBuffer(DXHelper::DeviceResources* pDeviceResources); - - void UpdateViewProjectionBuffer( - std::shared_ptr deviceResources, - const HolographicCameraPose& cameraPose, - const SpatialCoordinateSystem& coordinateSystem); - - bool AttachViewProjectionBuffer(std::shared_ptr 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. - winrt::Windows::Foundation::Size GetRenderTargetSize() const - { - return m_d3dRenderTargetSize; - } - bool IsRenderingStereoscopic() const - { - return m_isStereo; - } - - // The holographic camera these resources are for. - const HolographicCamera& GetHolographicCamera() const - { - return m_holographicCamera; - } - - private: - // Direct3D rendering objects. Required for 3D. - winrt::com_ptr m_d3dRenderTargetView; - winrt::com_ptr m_d3dDepthStencilView; - winrt::com_ptr m_d3dBackBuffer; - - // Device resource to store view and projection matrices. - winrt::com_ptr m_viewProjectionConstantBuffer; - - // Direct3D rendering properties. - DXGI_FORMAT m_dxgiFormat; - winrt::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. - HolographicCamera m_holographicCamera = nullptr; - }; -} // namespace DXHelper +//********************************************************* +// +// 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 + +#include + +using namespace winrt::Windows::Graphics::Holographic; +using namespace winrt::Windows::Perception::Spatial; + +namespace DXHelper +{ + 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(const HolographicCamera& holographicCamera); + + void CreateResourcesForBackBuffer( + DXHelper::DeviceResources* pDeviceResources, const HolographicCameraRenderingParameters& cameraParameters); + void ReleaseResourcesForBackBuffer(DXHelper::DeviceResources* pDeviceResources); + + void UpdateViewProjectionBuffer( + std::shared_ptr deviceResources, + const HolographicCameraPose& cameraPose, + const SpatialCoordinateSystem& coordinateSystem); + + bool AttachViewProjectionBuffer(std::shared_ptr 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(); + } + ID3D11Texture2D* GetDepthStencilTexture2D() const + { + return m_d3dDepthStencil.get(); + } + D3D11_VIEWPORT GetViewport() const + { + return m_d3dViewport; + } + DXGI_FORMAT GetBackBufferDXGIFormat() const + { + return m_dxgiFormat; + } + + // Render target properties. + winrt::Windows::Foundation::Size GetRenderTargetSize() const + { + return m_d3dRenderTargetSize; + } + bool IsRenderingStereoscopic() const + { + return m_isStereo; + } + + // The holographic camera these resources are for. + const HolographicCamera& GetHolographicCamera() const + { + return m_holographicCamera; + } + + winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface GetDepthStencilTextureInteropObject(); + + private: + // Direct3D rendering objects. Required for 3D. + winrt::com_ptr m_d3dRenderTargetView; + winrt::com_ptr m_d3dDepthStencilView; + winrt::com_ptr m_d3dBackBuffer; + winrt::com_ptr m_d3dDepthStencil; + + // Device resource to store view and projection matrices. + winrt::com_ptr m_viewProjectionConstantBuffer; + + // Direct3D rendering properties. + DXGI_FORMAT m_dxgiFormat = DXGI_FORMAT_UNKNOWN; + winrt::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. + HolographicCamera m_holographicCamera = nullptr; + }; +} // namespace DXHelper diff --git a/hostsampleapp/desktop/Common/DbgLog.h b/remote/uwp/Common/DbgLog.h similarity index 96% rename from hostsampleapp/desktop/Common/DbgLog.h rename to remote/uwp/Common/DbgLog.h index d229cb8..f6648b1 100644 --- a/hostsampleapp/desktop/Common/DbgLog.h +++ b/remote/uwp/Common/DbgLog.h @@ -1,37 +1,37 @@ -//********************************************************* -// -// 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 - -static void DebugLog(_In_z_ LPCWSTR format, ...) -{ - wchar_t buffer[1024]; - LPWSTR bufEnd = nullptr; - - va_list args; - va_start(args, format); - HRESULT hr = - StringCchVPrintfExW(buffer, _countof(buffer), &bufEnd, nullptr, STRSAFE_FILL_BEHIND_NULL | STRSAFE_FILL_ON_FAILURE, format, args); - - if (SUCCEEDED(hr)) - { - if (*bufEnd != L'\n') - { - StringCchCatW(buffer, _countof(buffer), L"\r\n"); - } - - OutputDebugStringW(buffer); - } - - va_end(args); -} +//********************************************************* +// +// 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 + +static void DebugLog(_In_z_ LPCWSTR format, ...) +{ + wchar_t buffer[1024]; + LPWSTR bufEnd = nullptr; + + va_list args; + va_start(args, format); + HRESULT hr = + StringCchVPrintfExW(buffer, _countof(buffer), &bufEnd, nullptr, STRSAFE_FILL_BEHIND_NULL | STRSAFE_FILL_ON_FAILURE, format, args); + + if (SUCCEEDED(hr)) + { + if (*bufEnd != L'\n') + { + StringCchCatW(buffer, _countof(buffer), L"\r\n"); + } + + OutputDebugStringW(buffer); + } + + va_end(args); +} diff --git a/hostsampleapp/desktop/Common/DeviceResources.cpp b/remote/uwp/Common/DeviceResources.cpp similarity index 93% rename from hostsampleapp/desktop/Common/DeviceResources.cpp rename to remote/uwp/Common/DeviceResources.cpp index 8165604..bb2162e 100644 --- a/hostsampleapp/desktop/Common/DeviceResources.cpp +++ b/remote/uwp/Common/DeviceResources.cpp @@ -1,304 +1,305 @@ -//********************************************************* -// -// 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 "DeviceResources.h" -#include "DirectXHelper.h" - -#include - -using namespace D2D1; -using namespace Microsoft::WRL; -using namespace winrt::Windows::Graphics::DirectX::Direct3D11; -using namespace winrt::Windows::Graphics::Display; -using namespace winrt::Windows::Graphics::Holographic; - -// Constructor for DeviceResources. -DXHelper::DeviceResources::DeviceResources() -{ - CreateDeviceIndependentResources(); -} - -DXHelper::DeviceResources::~DeviceResources() -{ - if (m_d3dContext) - { - m_d3dContext->Flush(); - m_d3dContext->ClearState(); - } -} - -// Configures resources that don't depend on the Direct3D device. -void DXHelper::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. - winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory2), &options, m_d2dFactory.put_void())); - - // Initialize the DirectWrite Factory. - winrt::check_hresult( - DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), (::IUnknown**)m_dwriteFactory.put_void())); - - // Initialize the Windows Imaging Component (WIC) Factory. - winrt::check_hresult( - CoCreateInstance(CLSID_WICImagingFactory2, nullptr, CLSCTX_INPROC_SERVER, __uuidof(m_wicFactory), m_wicFactory.put_void())); -} - -void DXHelper::DeviceResources::SetHolographicSpace(HolographicSpace holographicSpace) -{ - // Cache the holographic space. Used to re-initalize during device-lost scenarios. - m_holographicSpace = holographicSpace; - - InitializeUsingHolographicSpace(); -} - -void DXHelper::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 (DXHelper::SdkLayersAvailable()) - { - createFlags |= DXGI_CREATE_FACTORY_DEBUG; - } -#endif - // Create the DXGI factory. - winrt::com_ptr dxgiFactory; - winrt::check_hresult(CreateDXGIFactory2(createFlags, __uuidof(dxgiFactory), dxgiFactory.put_void())); - winrt::com_ptr dxgiFactory4; - dxgiFactory.as(dxgiFactory4); - - // Retrieve the adapter specified by the holographic space. - winrt::check_hresult(dxgiFactory4->EnumAdapterByLuid(id, __uuidof(m_dxgiAdapter), m_dxgiAdapter.put_void())); - } - else - { - m_dxgiAdapter = nullptr; - } - - CreateDeviceResources(); - - m_holographicSpace.SetDirect3D11Device(m_d3dInteropDevice); -} - -// Configures the Direct3D device, and stores handles to it and the device context. -void DXHelper::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 (DXHelper::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. - winrt::com_ptr device; - winrt::com_ptr context; - - const D3D_DRIVER_TYPE driverType = m_dxgiAdapter == nullptr ? D3D_DRIVER_TYPE_HARDWARE : D3D_DRIVER_TYPE_UNKNOWN; - const HRESULT hr = D3D11CreateDevice( - m_dxgiAdapter.get(), // Either nullptr, or the primary adapter determined by Windows Holographic. - driverType, // 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 Runtime apps. - device.put(), // Returns the Direct3D device created. - &m_d3dFeatureLevel, // Returns feature level of device created. - context.put() // 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 - winrt::check_hresult(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.put(), - &m_d3dFeatureLevel, - context.put())); - } - - // Store pointers to the Direct3D device and immediate context. - device.as(m_d3dDevice); - context.as(m_d3dContext); - - // Acquire the DXGI interface for the Direct3D device. - winrt::com_ptr dxgiDevice; - m_d3dDevice.as(dxgiDevice); - - // Wrap the native device using a WinRT interop object. - winrt::com_ptr<::IInspectable> object; - winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.get(), reinterpret_cast(winrt::put_abi(object)))); - m_d3dInteropDevice = object.as(); - - // Cache the DXGI adapter. - // This is for the case of no preferred DXGI adapter, or fallback to WARP. - winrt::com_ptr dxgiAdapter; - dxgiDevice->GetAdapter(dxgiAdapter.put()); - 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 DXHelper::DeviceResources::EnsureCameraResources(HolographicFrame frame, HolographicFramePrediction prediction) -{ - UseHolographicCameraResources([this, frame, prediction](std::map>& cameraResourceMap) { - for (HolographicCameraPose const& cameraPose : prediction.CameraPoses()) - { - try - { - HolographicCameraRenderingParameters renderingParameters = frame.GetRenderingParameters(cameraPose); - CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get(); - pCameraResources->CreateResourcesForBackBuffer(this, renderingParameters); - } - catch (const winrt::hresult_error&) - { - } - } - }); -} - -// Prepares to allocate resources and adds resource views for a camera. -// Locks the set of holographic camera resources until the function exits. -void DXHelper::DeviceResources::AddHolographicCamera(HolographicCamera camera) -{ - UseHolographicCameraResources([this, camera](std::map>& cameraResourceMap) { - cameraResourceMap[camera.Id()] = std::make_unique(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 DXHelper::DeviceResources::RemoveHolographicCamera(HolographicCamera camera) -{ - UseHolographicCameraResources([this, camera](std::map>& 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 DXHelper::DeviceResources::HandleDeviceLost() -{ - if (m_deviceNotify != nullptr) - { - m_deviceNotify->OnDeviceLost(); - } - - UseHolographicCameraResources([this](std::map>& 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 DXHelper::DeviceResources::RegisterDeviceNotify(DXHelper::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 DXHelper::DeviceResources::Trim() -{ - m_d3dContext->ClearState(); - - winrt::com_ptr dxgiDevice; - 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 DXHelper::DeviceResources::Present(HolographicFrame frame) -{ - // By default, this API waits for the frame to finish before it returns. - // For Holographic Remoting we do not wait but instead wait in SampleHostMain::Update to ensure that CreateNextFrame is called exactly - // with a delta of 16.6ms (in case of 60Hz). - HolographicFramePresentResult presentResult = - frame.PresentUsingCurrentPrediction(HolographicFramePresentWaitBehavior::DoNotWaitForFrameToFinish); - - // 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(); - } -} +//********************************************************* +// +// 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 "DeviceResources.h" +#include "DirectXHelper.h" + +#include + +using namespace D2D1; +using namespace Microsoft::WRL; +using namespace winrt::Windows::Graphics::DirectX::Direct3D11; +using namespace winrt::Windows::Graphics::Display; +using namespace winrt::Windows::Graphics::Holographic; + +// Constructor for DeviceResources. +DXHelper::DeviceResources::DeviceResources() +{ + CreateDeviceIndependentResources(); +} + +DXHelper::DeviceResources::~DeviceResources() +{ + if (m_d3dContext) + { + m_d3dContext->Flush(); + m_d3dContext->ClearState(); + } +} + +// Configures resources that don't depend on the Direct3D device. +void DXHelper::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. + winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory2), &options, m_d2dFactory.put_void())); + + // Initialize the DirectWrite Factory. + winrt::check_hresult( + DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), (::IUnknown**)m_dwriteFactory.put_void())); + + // Initialize the Windows Imaging Component (WIC) Factory. + winrt::check_hresult( + CoCreateInstance(CLSID_WICImagingFactory2, nullptr, CLSCTX_INPROC_SERVER, __uuidof(m_wicFactory), m_wicFactory.put_void())); +} + +void DXHelper::DeviceResources::SetHolographicSpace(HolographicSpace holographicSpace) +{ + // Cache the holographic space. Used to re-initalize during device-lost scenarios. + m_holographicSpace = holographicSpace; + + InitializeUsingHolographicSpace(); +} + +void DXHelper::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 (DXHelper::SdkLayersAvailable()) + { + createFlags |= DXGI_CREATE_FACTORY_DEBUG; + } +#endif + // Create the DXGI factory. + winrt::com_ptr dxgiFactory; + winrt::check_hresult(CreateDXGIFactory2(createFlags, __uuidof(dxgiFactory), dxgiFactory.put_void())); + winrt::com_ptr dxgiFactory4; + dxgiFactory.as(dxgiFactory4); + + // Retrieve the adapter specified by the holographic space. + winrt::check_hresult(dxgiFactory4->EnumAdapterByLuid(id, __uuidof(m_dxgiAdapter), m_dxgiAdapter.put_void())); + } + else + { + m_dxgiAdapter = nullptr; + } + + CreateDeviceResources(); + + m_holographicSpace.SetDirect3D11Device(m_d3dInteropDevice); +} + +// Configures the Direct3D device, and stores handles to it and the device context. +void DXHelper::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 (DXHelper::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. + winrt::com_ptr device; + winrt::com_ptr context; + + const D3D_DRIVER_TYPE driverType = m_dxgiAdapter == nullptr ? D3D_DRIVER_TYPE_HARDWARE : D3D_DRIVER_TYPE_UNKNOWN; + const HRESULT hr = D3D11CreateDevice( + m_dxgiAdapter.get(), // Either nullptr, or the primary adapter determined by Windows Holographic. + driverType, // 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 Runtime apps. + device.put(), // Returns the Direct3D device created. + &m_d3dFeatureLevel, // Returns feature level of device created. + context.put() // 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 + winrt::check_hresult(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.put(), + &m_d3dFeatureLevel, + context.put())); + } + + // Store pointers to the Direct3D device and immediate context. + device.as(m_d3dDevice); + context.as(m_d3dContext); + + // Acquire the DXGI interface for the Direct3D device. + winrt::com_ptr dxgiDevice; + m_d3dDevice.as(dxgiDevice); + + // Wrap the native device using a WinRT interop object. + winrt::com_ptr<::IInspectable> object; + winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.get(), reinterpret_cast(winrt::put_abi(object)))); + m_d3dInteropDevice = object.as(); + + // Cache the DXGI adapter. + // This is for the case of no preferred DXGI adapter, or fallback to WARP. + winrt::com_ptr dxgiAdapter; + dxgiDevice->GetAdapter(dxgiAdapter.put()); + 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 DXHelper::DeviceResources::EnsureCameraResources(HolographicFrame frame, HolographicFramePrediction prediction) +{ + UseHolographicCameraResources([this, frame, prediction](std::map>& cameraResourceMap) { + for (HolographicCameraPose const& cameraPose : prediction.CameraPoses()) + { + try + { + HolographicCameraRenderingParameters renderingParameters = frame.GetRenderingParameters(cameraPose); + CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get(); + pCameraResources->CreateResourcesForBackBuffer(this, renderingParameters); + } + catch (const winrt::hresult_error&) + { + } + } + }); +} + +// Prepares to allocate resources and adds resource views for a camera. +// Locks the set of holographic camera resources until the function exits. +void DXHelper::DeviceResources::AddHolographicCamera(HolographicCamera camera) +{ + UseHolographicCameraResources([this, camera](std::map>& cameraResourceMap) { + cameraResourceMap[camera.Id()] = std::make_unique(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 DXHelper::DeviceResources::RemoveHolographicCamera(HolographicCamera camera) +{ + UseHolographicCameraResources([this, camera](std::map>& 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 DXHelper::DeviceResources::HandleDeviceLost() +{ + if (m_deviceNotify != nullptr) + { + m_deviceNotify->OnDeviceLost(); + } + + UseHolographicCameraResources([this](std::map>& 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 DXHelper::DeviceResources::RegisterDeviceNotify(DXHelper::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 DXHelper::DeviceResources::Trim() +{ + m_d3dContext->ClearState(); + + winrt::com_ptr dxgiDevice; + 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 DXHelper::DeviceResources::Present(HolographicFrame frame) +{ + // By default, this API waits for the frame to finish before it returns. + // For Holographic Remoting we do not wait but instead wait in SampleRemoteMain::Update to ensure that CreateNextFrame is called exactly + // with a delta of 16.6ms (in case of 60Hz). + HolographicFramePresentResult presentResult = + frame.PresentUsingCurrentPrediction(HolographicFramePresentWaitBehavior::DoNotWaitForFrameToFinish); + + // 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(); + } +} diff --git a/hostsampleapp/uwp/Common/DeviceResources.h b/remote/uwp/Common/DeviceResources.h similarity index 97% rename from hostsampleapp/uwp/Common/DeviceResources.h rename to remote/uwp/Common/DeviceResources.h index a4feb62..3071fb6 100644 --- a/hostsampleapp/uwp/Common/DeviceResources.h +++ b/remote/uwp/Common/DeviceResources.h @@ -1,156 +1,157 @@ -//********************************************************* -// -// 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 "CameraResources.h" - -#include -#include -#include -#include -#include - -namespace DXHelper -{ - // 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(); - ~DeviceResources(); - - // Public methods related to Direct3D devices. - void HandleDeviceLost(); - void RegisterDeviceNotify(IDeviceNotify* deviceNotify); - void Trim(); - void Present(winrt::Windows::Graphics::Holographic::HolographicFrame frame); - - // Public methods related to holographic devices. - void SetHolographicSpace(winrt::Windows::Graphics::Holographic::HolographicSpace space); - void EnsureCameraResources( - winrt::Windows::Graphics::Holographic::HolographicFrame frame, - winrt::Windows::Graphics::Holographic::HolographicFramePrediction prediction); - - void AddHolographicCamera(winrt::Windows::Graphics::Holographic::HolographicCamera camera); - void RemoveHolographicCamera(winrt::Windows::Graphics::Holographic::HolographicCamera camera); - - // Holographic accessors. - template - void UseHolographicCameraResources(LCallback const& callback); - - winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice GetD3DInteropDevice() const - { - return m_d3dInteropDevice; - } - - // D3D accessors. - ID3D11Device4* GetD3DDevice() const - { - return m_d3dDevice.get(); - } - template - auto UseD3DDeviceContext(F func) const - { - std::scoped_lock lock(m_d3dContextMutex); - return func(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(); - } - - protected: - void CreateDeviceResources(); - - private: - // Private methods related to the Direct3D device, and resources based on that device. - void CreateDeviceIndependentResources(); - void InitializeUsingHolographicSpace(); - - protected: - // Direct3D objects. - winrt::com_ptr m_d3dDevice; - mutable std::recursive_mutex m_d3dContextMutex; - winrt::com_ptr m_d3dContext; - winrt::com_ptr m_dxgiAdapter; - - // Direct3D interop objects. - winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_d3dInteropDevice; - - // Direct2D factories. - winrt::com_ptr m_d2dFactory; - winrt::com_ptr m_dwriteFactory; - winrt::com_ptr m_wicFactory; - - // 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; - - private: - // The holographic space provides a preferred DXGI adapter ID. - winrt::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; - - // Back buffer resources, etc. for attached holographic cameras. - std::map> m_cameraResources; - std::mutex m_cameraResourcesLock; - }; -} // namespace DXHelper - -// 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>& -// through which the list of cameras will be accessed. -template -void DXHelper::DeviceResources::UseHolographicCameraResources(LCallback const& callback) -{ - std::lock_guard guard(m_cameraResourcesLock); - callback(m_cameraResources); -} +//********************************************************* +// +// 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 "CameraResources.h" + +#include +#include +#include +#include +#include +#include + +namespace DXHelper +{ + // 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(); + ~DeviceResources(); + + // Public methods related to Direct3D devices. + void HandleDeviceLost(); + void RegisterDeviceNotify(IDeviceNotify* deviceNotify); + void Trim(); + void Present(winrt::Windows::Graphics::Holographic::HolographicFrame frame); + + // Public methods related to holographic devices. + void SetHolographicSpace(winrt::Windows::Graphics::Holographic::HolographicSpace space); + void EnsureCameraResources( + winrt::Windows::Graphics::Holographic::HolographicFrame frame, + winrt::Windows::Graphics::Holographic::HolographicFramePrediction prediction); + + void AddHolographicCamera(winrt::Windows::Graphics::Holographic::HolographicCamera camera); + void RemoveHolographicCamera(winrt::Windows::Graphics::Holographic::HolographicCamera camera); + + // Holographic accessors. + template + void UseHolographicCameraResources(LCallback const& callback); + + winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice GetD3DInteropDevice() const + { + return m_d3dInteropDevice; + } + + // D3D accessors. + ID3D11Device4* GetD3DDevice() const + { + return m_d3dDevice.get(); + } + template + auto UseD3DDeviceContext(F func) const + { + std::scoped_lock lock(m_d3dContextMutex); + return func(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(); + } + + protected: + void CreateDeviceResources(); + + private: + // Private methods related to the Direct3D device, and resources based on that device. + void CreateDeviceIndependentResources(); + void InitializeUsingHolographicSpace(); + + protected: + // Direct3D objects. + winrt::com_ptr m_d3dDevice; + mutable std::recursive_mutex m_d3dContextMutex; + winrt::com_ptr m_d3dContext; + winrt::com_ptr m_dxgiAdapter; + + // Direct3D interop objects. + winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_d3dInteropDevice; + + // Direct2D factories. + winrt::com_ptr m_d2dFactory; + winrt::com_ptr m_dwriteFactory; + winrt::com_ptr m_wicFactory; + + // 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; + + private: + // The holographic space provides a preferred DXGI adapter ID. + winrt::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; + + // Back buffer resources, etc. for attached holographic cameras. + std::map> m_cameraResources; + std::mutex m_cameraResourcesLock; + }; +} // namespace DXHelper + +// 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>& +// through which the list of cameras will be accessed. +template +void DXHelper::DeviceResources::UseHolographicCameraResources(LCallback const& callback) +{ + std::lock_guard guard(m_cameraResourcesLock); + callback(m_cameraResources); +} diff --git a/hostsampleapp/desktop/Common/DirectXHelper.h b/remote/uwp/Common/DirectXHelper.h similarity index 97% rename from hostsampleapp/desktop/Common/DirectXHelper.h rename to remote/uwp/Common/DirectXHelper.h index 99f04c1..2955f5e 100644 --- a/hostsampleapp/desktop/Common/DirectXHelper.h +++ b/remote/uwp/Common/DirectXHelper.h @@ -1,87 +1,89 @@ -//********************************************************* -// -// 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 - -#include - -#include -#include - -#include - -#include - -#include -#include - -#include - -namespace DXHelper -{ - // Function that reads from a binary file asynchronously. - inline std::future> ReadDataAsync(const std::wstring_view& filename) - { - using namespace winrt::Windows::Storage; - using namespace winrt::Windows::Storage::Streams; - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - - wchar_t moduleFullyQualifiedFilename[MAX_PATH] = {}; - uint32_t moduleFileNameLength = GetModuleFileNameW(NULL, moduleFullyQualifiedFilename, _countof(moduleFullyQualifiedFilename)); - moduleFullyQualifiedFilename[moduleFileNameLength] = L'\0'; - - std::filesystem::path modulePath = moduleFullyQualifiedFilename; - // winrt::hstring moduleFilename = modulePath.filename().c_str(); - modulePath.replace_filename(filename); - winrt::hstring absoluteFilename = modulePath.c_str(); - - IBuffer fileBuffer = co_await PathIO::ReadBufferAsync(absoluteFilename); -#else - IBuffer fileBuffer = co_await PathIO::ReadBufferAsync(filename); -#endif - - std::vector returnBuffer; - returnBuffer.resize(fileBuffer.Length()); - DataReader::FromBuffer(fileBuffer).ReadBytes(winrt::array_view(returnBuffer)); - return returnBuffer; - } - - // Converts a length in device-independent pixels (DIPs) to a length in physical pixels. - inline float ConvertDipsToPixels(float dips, float dpi) - { - static const 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 Runtime 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 -} // namespace DXHelper +//********************************************************* +// +// 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 + +#include + +#include +#include + +#include + +#include + +#include + +#include +#include + +#include + +namespace DXHelper +{ + // Function that reads from a binary file asynchronously. + inline std::future> ReadDataAsync(const std::wstring_view& filename) + { + using namespace winrt::Windows::Storage; + using namespace winrt::Windows::Storage::Streams; + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + + wchar_t moduleFullyQualifiedFilename[MAX_PATH] = {}; + uint32_t moduleFileNameLength = GetModuleFileNameW(NULL, moduleFullyQualifiedFilename, _countof(moduleFullyQualifiedFilename) - 1); + moduleFullyQualifiedFilename[moduleFileNameLength] = L'\0'; + + std::filesystem::path modulePath = moduleFullyQualifiedFilename; + // winrt::hstring moduleFilename = modulePath.filename().c_str(); + modulePath.replace_filename(filename); + winrt::hstring absoluteFilename = modulePath.c_str(); + + IBuffer fileBuffer = co_await PathIO::ReadBufferAsync(absoluteFilename); +#else + IBuffer fileBuffer = co_await PathIO::ReadBufferAsync(filename); +#endif + + std::vector returnBuffer; + returnBuffer.resize(fileBuffer.Length()); + DataReader::FromBuffer(fileBuffer).ReadBytes(winrt::array_view(returnBuffer)); + return returnBuffer; + } + + // Converts a length in device-independent pixels (DIPs) to a length in physical pixels. + inline float ConvertDipsToPixels(float dips, float dpi) + { + static const 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 Runtime 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 +} // namespace DXHelper diff --git a/hostsampleapp/uwp/Common/PerceptionTypes.cpp b/remote/uwp/Common/PerceptionTypes.cpp similarity index 97% rename from hostsampleapp/uwp/Common/PerceptionTypes.cpp rename to remote/uwp/Common/PerceptionTypes.cpp index 72c1b74..fc8c9b0 100644 --- a/hostsampleapp/uwp/Common/PerceptionTypes.cpp +++ b/remote/uwp/Common/PerceptionTypes.cpp @@ -1,18 +1,18 @@ -//********************************************************* -// -// 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" - -// -- important: preserve order of these two includes (initguid before PerceptionTypes)! -#include - -#include "PerceptionTypes.h" -// -- +//********************************************************* +// +// 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" + +// -- important: preserve order of these two includes (initguid before PerceptionTypes)! +#include + +#include "PerceptionTypes.h" +// -- diff --git a/hostsampleapp/uwp/Common/PerceptionTypes.h b/remote/uwp/Common/PerceptionTypes.h similarity index 97% rename from hostsampleapp/uwp/Common/PerceptionTypes.h rename to remote/uwp/Common/PerceptionTypes.h index 2379971..112ac33 100644 --- a/hostsampleapp/uwp/Common/PerceptionTypes.h +++ b/remote/uwp/Common/PerceptionTypes.h @@ -1,33 +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 - -DEFINE_GUID(SPATIALPROP_QRTrackerObjectId, 0xf2e86326, 0xfbd8, 0x4088, 0xb5, 0xfb, 0xac, 0x61, 0xc, 0x3, 0x99, 0x7f); -DEFINE_GUID(SPATIALPROP_QRTracker_TrackingStatus, 0x270f00dc, 0xc0d9, 0x442c, 0x87, 0x25, 0x27, 0xb6, 0xbb, 0xd9, 0x43, 0xd); -DEFINE_GUID(SPATIALPROP_QRTracker_QRCodesList, 0x338b32f8, 0x1ce0, 0x4e75, 0x8d, 0xf4, 0x56, 0xd4, 0x2f, 0x73, 0x96, 0x74); -DEFINE_GUID(SPATIALPROP_QRCode_PhysicalSize, 0xcfb07ae5, 0x456a, 0x4aaf, 0x9d, 0x6a, 0xa2, 0x9d, 0x3, 0x9b, 0xc0, 0x56); -DEFINE_GUID(SPATIALPROP_QRCode_LastSeenTime, 0xb2b08c2d, 0xb531, 0x4f18, 0x87, 0x84, 0x44, 0x84, 0x46, 0x3d, 0x88, 0x53); -DEFINE_GUID(SPATIALPROP_QRCode_StreamInfo, 0x609143ea, 0x4ec5, 0x4b0e, 0xba, 0xef, 0x52, 0xa5, 0x5c, 0xfc, 0x23, 0x58); - - -#pragma pack(push, 1) -typedef struct SPATIAL_GRAPH_QR_CODE_STREAM_INFO -{ - UINT32 Version; - ULONG StreamSize; - - _Field_size_(StreamSize) BYTE StreamData[ANYSIZE_ARRAY]; - -} SPATIAL_GRAPH_QR_CODE_STREAM_INFO, *PSPATIAL_GRAPH_QR_CODE_STREAM_INFO; -#pragma pack(pop) +//********************************************************* +// +// 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 + +DEFINE_GUID(SPATIALPROP_QRTrackerObjectId, 0xf2e86326, 0xfbd8, 0x4088, 0xb5, 0xfb, 0xac, 0x61, 0xc, 0x3, 0x99, 0x7f); +DEFINE_GUID(SPATIALPROP_QRTracker_TrackingStatus, 0x270f00dc, 0xc0d9, 0x442c, 0x87, 0x25, 0x27, 0xb6, 0xbb, 0xd9, 0x43, 0xd); +DEFINE_GUID(SPATIALPROP_QRTracker_QRCodesList, 0x338b32f8, 0x1ce0, 0x4e75, 0x8d, 0xf4, 0x56, 0xd4, 0x2f, 0x73, 0x96, 0x74); +DEFINE_GUID(SPATIALPROP_QRCode_PhysicalSize, 0xcfb07ae5, 0x456a, 0x4aaf, 0x9d, 0x6a, 0xa2, 0x9d, 0x3, 0x9b, 0xc0, 0x56); +DEFINE_GUID(SPATIALPROP_QRCode_LastSeenTime, 0xb2b08c2d, 0xb531, 0x4f18, 0x87, 0x84, 0x44, 0x84, 0x46, 0x3d, 0x88, 0x53); +DEFINE_GUID(SPATIALPROP_QRCode_StreamInfo, 0x609143ea, 0x4ec5, 0x4b0e, 0xba, 0xef, 0x52, 0xa5, 0x5c, 0xfc, 0x23, 0x58); + +#pragma pack(push, 1) +typedef struct SPATIAL_GRAPH_QR_CODE_STREAM_INFO +{ + UINT32 Version; + ULONG StreamSize; + + _Field_size_(StreamSize) BYTE StreamData[ANYSIZE_ARRAY]; + +} SPATIAL_GRAPH_QR_CODE_STREAM_INFO, *PSPATIAL_GRAPH_QR_CODE_STREAM_INFO; +#pragma pack(pop) diff --git a/hostsampleapp/desktop/Common/Speech.cpp b/remote/uwp/Common/Speech.cpp similarity index 83% rename from hostsampleapp/desktop/Common/Speech.cpp rename to remote/uwp/Common/Speech.cpp index 96d0363..53f25c6 100644 --- a/hostsampleapp/desktop/Common/Speech.cpp +++ b/remote/uwp/Common/Speech.cpp @@ -1,70 +1,70 @@ -//********************************************************* -// -// 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 "SampleHostMain.h" -#include "Speech.h" - -#include -#include -#include - -#include - -namespace -{ - winrt::Windows::Foundation::IAsyncOperation LoadGrammarFileAsync() - { - const wchar_t* speechGrammarFile = L"SpeechGrammar.xml"; -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - wchar_t executablePath[MAX_PATH]; - - if (GetModuleFileNameW(NULL, executablePath, ARRAYSIZE(executablePath)) == 0) - { - winrt::throw_last_error(); - } - std::filesystem::path executableFolder(executablePath); - executableFolder.remove_filename(); - auto rootFolder = co_await winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(executableFolder.c_str()); - auto file = co_await rootFolder.GetFileAsync(speechGrammarFile); - co_return file; -#else - auto rootFolder = winrt::Windows::ApplicationModel::Package::Current().InstalledLocation(); - return rootFolder.GetFileAsync(speechGrammarFile); -#endif - } -} // namespace - -winrt::fire_and_forget Speech::InitializeSpeechAsync( - winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech remoteSpeech, - winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker& onRecognizedSpeechRevoker, - std::weak_ptr sampleHostMainWeak) -{ - onRecognizedSpeechRevoker = remoteSpeech.OnRecognizedSpeech( - winrt::auto_revoke, [sampleHostMainWeak](const winrt::Microsoft::Holographic::AppRemoting::RecognizedSpeech& recognizedSpeech) { - if (auto sampleHostMain = sampleHostMainWeak.lock()) - { - sampleHostMain->OnRecognizedSpeech(recognizedSpeech.RecognizedText); - } - }); - - auto grammarFile = co_await LoadGrammarFileAsync(); - - std::vector dictionary; - dictionary.push_back(L"Red"); - dictionary.push_back(L"Blue"); - dictionary.push_back(L"Green"); - dictionary.push_back(L"Default"); - dictionary.push_back(L"Aquamarine"); - - remoteSpeech.ApplyParameters(L"en-US", grammarFile, dictionary); -} +//********************************************************* +// +// 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 "SampleRemoteMain.h" +#include "Speech.h" + +#include +#include +#include + +#include + +namespace +{ + winrt::Windows::Foundation::IAsyncOperation LoadGrammarFileAsync() + { + const wchar_t* speechGrammarFile = L"SpeechGrammar.xml"; +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + wchar_t executablePath[MAX_PATH]; + + if (GetModuleFileNameW(NULL, executablePath, ARRAYSIZE(executablePath)) == 0) + { + winrt::throw_last_error(); + } + std::filesystem::path executableFolder(executablePath); + executableFolder.remove_filename(); + auto rootFolder = co_await winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(executableFolder.c_str()); + auto file = co_await rootFolder.GetFileAsync(speechGrammarFile); + co_return file; +#else + auto rootFolder = winrt::Windows::ApplicationModel::Package::Current().InstalledLocation(); + return rootFolder.GetFileAsync(speechGrammarFile); +#endif + } +} // namespace + +winrt::fire_and_forget Speech::InitializeSpeechAsync( + winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech remoteSpeech, + winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker& onRecognizedSpeechRevoker, + std::weak_ptr sampleRemoteMainWeak) +{ + onRecognizedSpeechRevoker = remoteSpeech.OnRecognizedSpeech( + winrt::auto_revoke, [sampleRemoteMainWeak](const winrt::Microsoft::Holographic::AppRemoting::RecognizedSpeech& recognizedSpeech) { + if (auto sampleRemoteMain = sampleRemoteMainWeak.lock()) + { + sampleRemoteMain->OnRecognizedSpeech(recognizedSpeech.RecognizedText); + } + }); + + auto grammarFile = co_await LoadGrammarFileAsync(); + + std::vector dictionary; + dictionary.push_back(L"Red"); + dictionary.push_back(L"Blue"); + dictionary.push_back(L"Green"); + dictionary.push_back(L"Default"); + dictionary.push_back(L"Aquamarine"); + + remoteSpeech.ApplyParameters(L"en-US", grammarFile, dictionary); +} diff --git a/hostsampleapp/desktop/Common/Speech.h b/remote/uwp/Common/Speech.h similarity index 88% rename from hostsampleapp/desktop/Common/Speech.h rename to remote/uwp/Common/Speech.h index 2aee153..92d44dc 100644 --- a/hostsampleapp/desktop/Common/Speech.h +++ b/remote/uwp/Common/Speech.h @@ -1,28 +1,27 @@ -//********************************************************* -// -// 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 - -#include -#include - - -class SampleHostMain; - -namespace Speech -{ - winrt::fire_and_forget InitializeSpeechAsync( - winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech remoteSpeech, - winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker& onRecognizedSpeechRevoker, - std::weak_ptr sampleHostMainWeak); -} +//********************************************************* +// +// 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 + +#include +#include + +class SampleRemoteMain; + +namespace Speech +{ + winrt::fire_and_forget InitializeSpeechAsync( + winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech remoteSpeech, + winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker& onRecognizedSpeechRevoker, + std::weak_ptr sampleRemoteMainWeak); +} diff --git a/hostsampleapp/desktop/Common/Utils.h b/remote/uwp/Common/Utils.h similarity index 96% rename from hostsampleapp/desktop/Common/Utils.h rename to remote/uwp/Common/Utils.h index 04e9bda..7ca263f 100644 --- a/hostsampleapp/desktop/Common/Utils.h +++ b/remote/uwp/Common/Utils.h @@ -1,31 +1,31 @@ -//********************************************************* -// -// 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 - -// comparison function to allow for GUID as a hash map key -struct GUIDComparer -{ - inline static int compare(const GUID& Left, const GUID& Right) - { - return memcmp(&Left, &Right, sizeof(GUID)); - } - - inline static bool equals(const GUID& Left, const GUID& Right) - { - return memcmp(&Left, &Right, sizeof(GUID)) == 0; - } - - bool operator()(const GUID& Left, const GUID& Right) const - { - return compare(Left, Right) < 0; - } -}; +//********************************************************* +// +// 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 + +// comparison function to allow for GUID as a hash map key +struct GUIDComparer +{ + inline static int compare(const GUID& Left, const GUID& Right) + { + return memcmp(&Left, &Right, sizeof(GUID)); + } + + inline static bool equals(const GUID& Left, const GUID& Right) + { + return memcmp(&Left, &Right, sizeof(GUID)) == 0; + } + + bool operator()(const GUID& Left, const GUID& Right) const + { + return compare(Left, Right) < 0; + } +}; diff --git a/hostsampleapp/desktop/Content/PerceptionDeviceHandler.cpp b/remote/uwp/Content/PerceptionDeviceHandler.cpp similarity index 95% rename from hostsampleapp/desktop/Content/PerceptionDeviceHandler.cpp rename to remote/uwp/Content/PerceptionDeviceHandler.cpp index 13689b9..e3b658d 100644 --- a/hostsampleapp/desktop/Content/PerceptionDeviceHandler.cpp +++ b/remote/uwp/Content/PerceptionDeviceHandler.cpp @@ -1,218 +1,211 @@ -//********************************************************* -// -// 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 "../Common/PerceptionTypes.h" -#include "../Common/Utils.h" -#include "PerceptionDeviceHandler.h" -#include "QRCodeTracker.h" - - -PerceptionRootObject::~PerceptionRootObject() -{ -} - -const GUID& PerceptionRootObject::GetPropertyId() const -{ - return m_typeId; -} - -const GUID& PerceptionRootObject::GetObjectId() const -{ - return m_objectId; -} - -PerceptionRootObject::PerceptionRootObject(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId) - : m_typeId(typeId) - , m_objectId(objectId) -{ - m_device.copy_from(device); -} - - - -PerceptionDeviceHandler::PerceptionDeviceHandler() -{ -} - -PerceptionDeviceHandler::~PerceptionDeviceHandler() -{ - Stop(); -} - -void PerceptionDeviceHandler::Start() -{ - std::lock_guard stateLock(m_stateProtect); - - if (m_running) - { - return; - } - - HRESULT hr = PerceptionDeviceCreateFactory(IID_PPV_ARGS(m_perceptionDeviceFactory.put())); - if (FAILED(hr)) - { - Stop(); - return; - } - - m_rootObjectChangeHandler = winrt::make_self(*this); - - std::array rootObjectIds{QRCodeTracker::GetStaticPropertyId()}; - for (size_t i = 0; i < rootObjectIds.size(); ++i) - { - winrt::com_ptr watcher; - hr = m_perceptionDeviceFactory->CreateRootObjectWatcher(1, &rootObjectIds[i], PerceptionDeviceOptions::None, watcher.put()); - if (FAILED(hr)) - { - Stop(); - return; - } - - hr = watcher->SetAddedHandler(m_rootObjectChangeHandler.get()); - if (FAILED(hr)) - { - Stop(); - return; - } - - hr = watcher->SetRemovedHandler(m_rootObjectChangeHandler.get()); - if (FAILED(hr)) - { - Stop(); - return; - } - - m_rootObjectWatchers.emplace_back(std::move(watcher)); - } - - m_running = true; - - for (auto& watcher : m_rootObjectWatchers) - { - hr = watcher->Start(); - if (FAILED(hr)) - { - Stop(); - return; - } - } -} - -void PerceptionDeviceHandler::Stop() -{ - std::lock_guard stateLock(m_stateProtect); - - m_running = false; - - for (auto& watcher : m_rootObjectWatchers) - { - watcher->Stop(); - } - m_rootObjectWatchers.clear(); - m_rootObjectChangeHandler = nullptr; - m_perceptionDeviceFactory = nullptr; -} - -HRESULT PerceptionDeviceHandler::HandleRootObjectAdded(IPerceptionDeviceRootObjectAddedEventArgs* args) -{ - std::lock_guard stateLock(m_stateProtect); - - if (!m_running) - { - return S_OK; - } - - RootObjectKey key{args->GetPropertyId(), args->GetObjectId()}; - if (m_rootObjects.find(key) != m_rootObjects.end()) - { - return S_FALSE; // Already have that root object; don't add it twice - } - - if (GUIDComparer::equals(key.propertyId, QRCodeTracker::GetStaticPropertyId())) - { - winrt::com_ptr device; - args->GetDevice(device.put()); - m_rootObjects.emplace(key, std::make_shared(device.get(), key.propertyId, key.objectId)); - } - - return S_OK; -} - -HRESULT PerceptionDeviceHandler::HandleRootObjectRemoved(IPerceptionDeviceRootObjectRemovedEventArgs* args) -{ - std::lock_guard stateLock(m_stateProtect); - - if (!m_running) - { - return S_OK; - } - - RootObjectKey key{args->GetPropertyId(), args->GetObjectId()}; - auto it = m_rootObjects.find(key); - if (it != m_rootObjects.end()) - { - m_rootObjects.erase(key); - } - - return S_OK; -} - - - -PerceptionDeviceHandler::RootObjectChangeHandler::RootObjectChangeHandler(PerceptionDeviceHandler& owner) - : m_weakOwner(owner.weak_from_this()) -{ -} - -STDMETHODIMP PerceptionDeviceHandler::RootObjectChangeHandler::Invoke( - _In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectAddedEventArgs* args) -{ - auto owner{m_weakOwner.lock()}; - if (owner) - { - return owner->HandleRootObjectAdded(args); - } - - return S_OK; -} - -STDMETHODIMP PerceptionDeviceHandler::RootObjectChangeHandler::Invoke( - _In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectRemovedEventArgs* args) -{ - auto owner{m_weakOwner.lock()}; - if (owner) - { - return owner->HandleRootObjectRemoved(args); - } - - return S_OK; -} - - - -bool PerceptionDeviceHandler::RootObjectKey::operator<(const RootObjectKey& other) const -{ - const auto typeIdRes = GUIDComparer::compare(propertyId, other.propertyId); - if (typeIdRes < 0) - { - return true; - } - else if (typeIdRes > 0) - { - return false; - } - else - { - return GUIDComparer::compare(objectId, other.objectId) < 0; - } -} +//********************************************************* +// +// 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 "../Common/PerceptionTypes.h" +#include "../Common/Utils.h" +#include "PerceptionDeviceHandler.h" +#include "QRCodeTracker.h" + +PerceptionRootObject::~PerceptionRootObject() +{ +} + +const GUID& PerceptionRootObject::GetPropertyId() const +{ + return m_typeId; +} + +const GUID& PerceptionRootObject::GetObjectId() const +{ + return m_objectId; +} + +PerceptionRootObject::PerceptionRootObject(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId) + : m_typeId(typeId) + , m_objectId(objectId) +{ + m_device.copy_from(device); +} + +PerceptionDeviceHandler::PerceptionDeviceHandler() +{ +} + +PerceptionDeviceHandler::~PerceptionDeviceHandler() +{ + Stop(); +} + +void PerceptionDeviceHandler::Start() +{ + std::lock_guard stateLock(m_stateProtect); + + if (m_running) + { + return; + } + + HRESULT hr = PerceptionDeviceCreateFactory(IID_PPV_ARGS(m_perceptionDeviceFactory.put())); + if (FAILED(hr)) + { + Stop(); + return; + } + + m_rootObjectChangeHandler = winrt::make_self(*this); + + std::array rootObjectIds{QRCodeTracker::GetStaticPropertyId()}; + for (size_t i = 0; i < rootObjectIds.size(); ++i) + { + winrt::com_ptr watcher; + hr = m_perceptionDeviceFactory->CreateRootObjectWatcher(1, &rootObjectIds[i], PerceptionDeviceOptions::None, watcher.put()); + if (FAILED(hr)) + { + Stop(); + return; + } + + hr = watcher->SetAddedHandler(m_rootObjectChangeHandler.get()); + if (FAILED(hr)) + { + Stop(); + return; + } + + hr = watcher->SetRemovedHandler(m_rootObjectChangeHandler.get()); + if (FAILED(hr)) + { + Stop(); + return; + } + + m_rootObjectWatchers.emplace_back(std::move(watcher)); + } + + m_running = true; + + for (auto& watcher : m_rootObjectWatchers) + { + hr = watcher->Start(); + if (FAILED(hr)) + { + Stop(); + return; + } + } +} + +void PerceptionDeviceHandler::Stop() +{ + std::lock_guard stateLock(m_stateProtect); + + m_running = false; + + for (auto& watcher : m_rootObjectWatchers) + { + watcher->Stop(); + } + m_rootObjectWatchers.clear(); + m_rootObjectChangeHandler = nullptr; + m_perceptionDeviceFactory = nullptr; +} + +HRESULT PerceptionDeviceHandler::HandleRootObjectAdded(IPerceptionDeviceRootObjectAddedEventArgs* args) +{ + std::lock_guard stateLock(m_stateProtect); + + if (!m_running) + { + return S_OK; + } + + RootObjectKey key{args->GetPropertyId(), args->GetObjectId()}; + if (m_rootObjects.find(key) != m_rootObjects.end()) + { + return S_FALSE; // Already have that root object; don't add it twice + } + + if (GUIDComparer::equals(key.propertyId, QRCodeTracker::GetStaticPropertyId())) + { + winrt::com_ptr device; + args->GetDevice(device.put()); + m_rootObjects.emplace(key, std::make_shared(device.get(), key.propertyId, key.objectId)); + } + + return S_OK; +} + +HRESULT PerceptionDeviceHandler::HandleRootObjectRemoved(IPerceptionDeviceRootObjectRemovedEventArgs* args) +{ + std::lock_guard stateLock(m_stateProtect); + + if (!m_running) + { + return S_OK; + } + + RootObjectKey key{args->GetPropertyId(), args->GetObjectId()}; + auto it = m_rootObjects.find(key); + if (it != m_rootObjects.end()) + { + m_rootObjects.erase(key); + } + + return S_OK; +} + +PerceptionDeviceHandler::RootObjectChangeHandler::RootObjectChangeHandler(PerceptionDeviceHandler& owner) + : m_weakOwner(owner.weak_from_this()) +{ +} + +STDMETHODIMP PerceptionDeviceHandler::RootObjectChangeHandler::Invoke( + _In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectAddedEventArgs* args) +{ + auto owner{m_weakOwner.lock()}; + if (owner) + { + return owner->HandleRootObjectAdded(args); + } + + return S_OK; +} + +STDMETHODIMP PerceptionDeviceHandler::RootObjectChangeHandler::Invoke( + _In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectRemovedEventArgs* args) +{ + auto owner{m_weakOwner.lock()}; + if (owner) + { + return owner->HandleRootObjectRemoved(args); + } + + return S_OK; +} + +bool PerceptionDeviceHandler::RootObjectKey::operator<(const RootObjectKey& other) const +{ + const auto typeIdRes = GUIDComparer::compare(propertyId, other.propertyId); + if (typeIdRes < 0) + { + return true; + } + else if (typeIdRes > 0) + { + return false; + } + else + { + return GUIDComparer::compare(objectId, other.objectId) < 0; + } +} diff --git a/hostsampleapp/uwp/Content/PerceptionDeviceHandler.h b/remote/uwp/Content/PerceptionDeviceHandler.h similarity index 96% rename from hostsampleapp/uwp/Content/PerceptionDeviceHandler.h rename to remote/uwp/Content/PerceptionDeviceHandler.h index 5d7d9f1..02474c3 100644 --- a/hostsampleapp/uwp/Content/PerceptionDeviceHandler.h +++ b/remote/uwp/Content/PerceptionDeviceHandler.h @@ -1,121 +1,119 @@ -//********************************************************* -// -// 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 - -#include - -#include - - -// Base class for perception root objects managed by the PerceptionDeviceHandler -class PerceptionRootObject -{ -public: - virtual ~PerceptionRootObject(); - - const GUID& GetPropertyId() const; - const GUID& GetObjectId() const; - -protected: - PerceptionRootObject(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId); - -protected: - winrt::com_ptr m_device; - GUID m_typeId; - GUID m_objectId; -}; - -// Sample perception device handler. Listens to the availability of perception devices (more accurately: -// perception root objects of known types), and retrieves data from these root objects. -class PerceptionDeviceHandler : public std::enable_shared_from_this -{ -public: - PerceptionDeviceHandler(); - ~PerceptionDeviceHandler(); - - // Starts monitoring for perception root object changes - void Start(); - - // Stops monitoring perception root object changes - void Stop(); - - // Iterates over all perception root objects currently known - template - void ForEachRootObject(Func& func) - { - std::lock_guard stateLock(m_stateProtect); - for (auto& rootObjectEntry : m_rootObjects) - { - func(*rootObjectEntry.second.get()); - } - } - - // Iterates over all root objects of a certain type - template - void ForEachRootObjectOfType(Func& func) - { - std::lock_guard stateLock(m_stateProtect); - for (auto& rootObjectEntry : m_rootObjects) - { - PerceptionRootObject& rootObject = *rootObjectEntry.second.get(); - if (GUIDComparer::equals(rootObject.GetPropertyId(), RootObjectType::GetStaticPropertyId())) - { - func(static_cast(rootObject)); - } - } - } - - -private: - struct RootObjectChangeHandler - : winrt::implements - { - RootObjectChangeHandler(PerceptionDeviceHandler& owner); - - IFACEMETHOD(Invoke) - (_In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectAddedEventArgs* args) override; - IFACEMETHOD(Invoke) - (_In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectRemovedEventArgs* args) override; - - private: - std::weak_ptr m_weakOwner; - }; - friend RootObjectChangeHandler; - - struct RootObjectKey - { - GUID propertyId; - GUID objectId; - - bool operator<(const RootObjectKey& other) const; - }; - - using RootObjectMap = std::map>; - - -private: - HRESULT HandleRootObjectAdded(IPerceptionDeviceRootObjectAddedEventArgs* args); - HRESULT HandleRootObjectRemoved(IPerceptionDeviceRootObjectRemovedEventArgs* args); - -private: - std::recursive_mutex m_stateProtect; - - bool m_running{false}; - - winrt::com_ptr m_perceptionDeviceFactory; - std::vector> m_rootObjectWatchers; - winrt::com_ptr m_rootObjectChangeHandler; - - RootObjectMap m_rootObjects; -}; +//********************************************************* +// +// 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 +#include + +#include + +#include + +// Base class for perception root objects managed by the PerceptionDeviceHandler +class PerceptionRootObject +{ +public: + virtual ~PerceptionRootObject(); + + const GUID& GetPropertyId() const; + const GUID& GetObjectId() const; + +protected: + PerceptionRootObject(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId); + +protected: + winrt::com_ptr m_device; + GUID m_typeId; + GUID m_objectId; +}; + +// Sample perception device handler. Listens to the availability of perception devices (more accurately: +// perception root objects of known types), and retrieves data from these root objects. +class PerceptionDeviceHandler : public std::enable_shared_from_this +{ +public: + PerceptionDeviceHandler(); + ~PerceptionDeviceHandler(); + + // Starts monitoring for perception root object changes + void Start(); + + // Stops monitoring perception root object changes + void Stop(); + + // Iterates over all perception root objects currently known + template + void ForEachRootObject(Func& func) + { + std::lock_guard stateLock(m_stateProtect); + for (auto& rootObjectEntry : m_rootObjects) + { + func(*rootObjectEntry.second.get()); + } + } + + // Iterates over all root objects of a certain type + template + void ForEachRootObjectOfType(Func& func) + { + std::lock_guard stateLock(m_stateProtect); + for (auto& rootObjectEntry : m_rootObjects) + { + PerceptionRootObject& rootObject = *rootObjectEntry.second.get(); + if (GUIDComparer::equals(rootObject.GetPropertyId(), RootObjectType::GetStaticPropertyId())) + { + func(static_cast(rootObject)); + } + } + } + +private: + struct RootObjectChangeHandler + : winrt::implements + { + RootObjectChangeHandler(PerceptionDeviceHandler& owner); + + IFACEMETHOD(Invoke) + (_In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectAddedEventArgs* args) override; + IFACEMETHOD(Invoke) + (_In_ IPerceptionDeviceRootObjectWatcher* sender, _In_ IPerceptionDeviceRootObjectRemovedEventArgs* args) override; + + private: + std::weak_ptr m_weakOwner; + }; + friend RootObjectChangeHandler; + + struct RootObjectKey + { + GUID propertyId; + GUID objectId; + + bool operator<(const RootObjectKey& other) const; + }; + + using RootObjectMap = std::map>; + +private: + HRESULT HandleRootObjectAdded(IPerceptionDeviceRootObjectAddedEventArgs* args); + HRESULT HandleRootObjectRemoved(IPerceptionDeviceRootObjectRemovedEventArgs* args); + +private: + std::recursive_mutex m_stateProtect; + + bool m_running{false}; + + winrt::com_ptr m_perceptionDeviceFactory; + std::vector> m_rootObjectWatchers; + winrt::com_ptr m_rootObjectChangeHandler; + + RootObjectMap m_rootObjects; +}; diff --git a/hostsampleapp/uwp/Content/QRCodeRenderer.cpp b/remote/uwp/Content/QRCodeRenderer.cpp similarity index 97% rename from hostsampleapp/uwp/Content/QRCodeRenderer.cpp rename to remote/uwp/Content/QRCodeRenderer.cpp index 8f3944c..531d7fd 100644 --- a/hostsampleapp/uwp/Content/QRCodeRenderer.cpp +++ b/remote/uwp/Content/QRCodeRenderer.cpp @@ -1,107 +1,108 @@ -//********************************************************* -// -// 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 "../Common/DirectXHelper.h" -#include "../Common/PerceptionTypes.h" -#include "PerceptionDeviceHandler.h" -#include "QRCodeRenderer.h" -#include "QRCodeTracker.h" - -namespace -{ - using namespace DirectX; - - void AppendColoredTriangle( - winrt::Windows::Foundation::Numerics::float3 p0, - winrt::Windows::Foundation::Numerics::float3 p1, - winrt::Windows::Foundation::Numerics::float3 p2, - winrt::Windows::Foundation::Numerics::float3 color, - std::vector& vertices) - { - VertexPositionNormalColor vertex; - vertex.color = XMFLOAT3(&color.x); - vertex.normal = XMFLOAT3(0.0f, 0.0f, 0.0f); - - vertex.pos = XMFLOAT3(&p0.x); - vertices.push_back(vertex); - vertex.pos = XMFLOAT3(&p1.x); - vertices.push_back(vertex); - vertex.pos = XMFLOAT3(&p2.x); - vertices.push_back(vertex); - } -} // namespace - - -QRCodeRenderer::QRCodeRenderer(const std::shared_ptr& deviceResources) - : RenderableObject(deviceResources) -{ -} - -void QRCodeRenderer::Update( - PerceptionDeviceHandler& perceptionDeviceHandler, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) -{ - auto processQRCode = [this, renderingCoordinateSystem](QRCode& code) { - auto codeCS = code.GetCoordinateSystem(); - float size = code.GetPhysicalSize(); - auto codeToRendering = codeCS.TryGetTransformTo(renderingCoordinateSystem); - if (!codeToRendering) - { - return; - } - - auto codeToRenderingV = codeToRendering.Value(); - winrt::Windows::Foundation::Numerics::float3 positions[4] = { - {0.0f, 0.0f, 0.0f}, {0.0f, size, 0.0f}, {size, size, 0.0f}, {size, 0.0f, 0.0f}}; - for (int i = 0; i < 4; ++i) - { - positions[i] = winrt::Windows::Foundation::Numerics::transform(positions[i], codeToRenderingV); - } - - winrt::Windows::Foundation::Numerics::float3 col{1.0f, 1.0f, 0.0f}; - AppendColoredTriangle(positions[0], positions[2], positions[1], col, m_vertices); - AppendColoredTriangle(positions[0], positions[3], positions[2], col, m_vertices); - }; - - auto processQRCodeTracker = [this, processQRCode](QRCodeTracker& tracker) { tracker.ForEachQRCode(processQRCode); }; - - m_vertices.clear(); - perceptionDeviceHandler.ForEachRootObjectOfType(processQRCodeTracker); - - auto modelTransform = winrt::Windows::Foundation::Numerics::float4x4::identity(); - UpdateModelConstantBuffer(modelTransform); -} - -void QRCodeRenderer::Draw(unsigned int numInstances) -{ - if (m_vertices.empty()) - { - return; - } - - const UINT stride = sizeof(m_vertices[0]); - const UINT offset = 0; - D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; - vertexBufferData.pSysMem = m_vertices.data(); - const CD3D11_BUFFER_DESC vertexBufferDesc(static_cast(m_vertices.size() * stride), D3D11_BIND_VERTEX_BUFFER); - winrt::com_ptr vertexBuffer; - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, vertexBuffer.put())); - - m_deviceResources->UseD3DDeviceContext([&](auto context) { - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - ID3D11Buffer* pBuffer = vertexBuffer.get(); - context->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset); - context->DrawInstanced(static_cast(m_vertices.size()), numInstances, offset, 0); - }); -} +//********************************************************* +// +// 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 "../Common/DirectXHelper.h" +#include "../Common/PerceptionTypes.h" +#include "PerceptionDeviceHandler.h" +#include "QRCodeRenderer.h" +#include "QRCodeTracker.h" + +#include + +namespace +{ + using namespace DirectX; + + void AppendColoredTriangle( + winrt::Windows::Foundation::Numerics::float3 p0, + winrt::Windows::Foundation::Numerics::float3 p1, + winrt::Windows::Foundation::Numerics::float3 p2, + winrt::Windows::Foundation::Numerics::float3 color, + std::vector& vertices) + { + VertexPositionNormalColor vertex; + vertex.color = XMFLOAT3(&color.x); + vertex.normal = XMFLOAT3(0.0f, 0.0f, 0.0f); + + vertex.pos = XMFLOAT3(&p0.x); + vertices.push_back(vertex); + vertex.pos = XMFLOAT3(&p1.x); + vertices.push_back(vertex); + vertex.pos = XMFLOAT3(&p2.x); + vertices.push_back(vertex); + } +} // namespace + +QRCodeRenderer::QRCodeRenderer(const std::shared_ptr& deviceResources) + : RenderableObject(deviceResources) +{ +} + +void QRCodeRenderer::Update( + PerceptionDeviceHandler& perceptionDeviceHandler, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) +{ + auto processQRCode = [this, renderingCoordinateSystem](QRCode& code) { + auto codeCS = code.GetCoordinateSystem(); + float size = code.GetPhysicalSize(); + auto codeToRendering = codeCS.TryGetTransformTo(renderingCoordinateSystem); + if (!codeToRendering) + { + return; + } + + auto codeToRenderingV = codeToRendering.Value(); + winrt::Windows::Foundation::Numerics::float3 positions[4] = { + {0.0f, 0.0f, 0.0f}, {0.0f, size, 0.0f}, {size, size, 0.0f}, {size, 0.0f, 0.0f}}; + for (int i = 0; i < 4; ++i) + { + positions[i] = winrt::Windows::Foundation::Numerics::transform(positions[i], codeToRenderingV); + } + + winrt::Windows::Foundation::Numerics::float3 col{1.0f, 1.0f, 0.0f}; + AppendColoredTriangle(positions[0], positions[2], positions[1], col, m_vertices); + AppendColoredTriangle(positions[0], positions[3], positions[2], col, m_vertices); + }; + + auto processQRCodeTracker = [this, processQRCode](QRCodeTracker& tracker) { tracker.ForEachQRCode(processQRCode); }; + + m_vertices.clear(); + perceptionDeviceHandler.ForEachRootObjectOfType(processQRCodeTracker); + + auto modelTransform = winrt::Windows::Foundation::Numerics::float4x4::identity(); + UpdateModelConstantBuffer(modelTransform); +} + +void QRCodeRenderer::Draw(unsigned int numInstances) +{ + if (m_vertices.empty()) + { + return; + } + + const UINT stride = sizeof(m_vertices[0]); + const UINT offset = 0; + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = m_vertices.data(); + const CD3D11_BUFFER_DESC vertexBufferDesc(static_cast(m_vertices.size() * stride), D3D11_BIND_VERTEX_BUFFER); + winrt::com_ptr vertexBuffer; + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, vertexBuffer.put())); + + m_deviceResources->UseD3DDeviceContext([&](auto context) { + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + ID3D11Buffer* pBuffer = vertexBuffer.get(); + context->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset); + context->DrawInstanced(static_cast(m_vertices.size()), numInstances, offset, 0); + }); +} diff --git a/hostsampleapp/uwp/Content/QRCodeRenderer.h b/remote/uwp/Content/QRCodeRenderer.h similarity index 96% rename from hostsampleapp/uwp/Content/QRCodeRenderer.h rename to remote/uwp/Content/QRCodeRenderer.h index 8592b9a..26cbaa8 100644 --- a/hostsampleapp/uwp/Content/QRCodeRenderer.h +++ b/remote/uwp/Content/QRCodeRenderer.h @@ -1,35 +1,35 @@ -//********************************************************* -// -// 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 "RenderableObject.h" -#include - -#include - -class PerceptionDeviceHandler; - -class QRCodeRenderer : public RenderableObject -{ -public: - QRCodeRenderer(const std::shared_ptr& deviceResources); - - void Update( - PerceptionDeviceHandler& perceptionDeviceHandler, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); - -private: - void Draw(unsigned int numInstances) override; - -private: - std::vector m_vertices; -}; +//********************************************************* +// +// 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 "RenderableObject.h" +#include + +#include + +class PerceptionDeviceHandler; + +class QRCodeRenderer : public RenderableObject +{ +public: + QRCodeRenderer(const std::shared_ptr& deviceResources); + + void Update( + PerceptionDeviceHandler& perceptionDeviceHandler, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); + +private: + void Draw(unsigned int numInstances) override; + +private: + std::vector m_vertices; +}; diff --git a/hostsampleapp/desktop/Content/QRCodeTracker.cpp b/remote/uwp/Content/QRCodeTracker.cpp similarity index 96% rename from hostsampleapp/desktop/Content/QRCodeTracker.cpp rename to remote/uwp/Content/QRCodeTracker.cpp index 79c2967..5e5dd22 100644 --- a/hostsampleapp/desktop/Content/QRCodeTracker.cpp +++ b/remote/uwp/Content/QRCodeTracker.cpp @@ -1,337 +1,332 @@ -//********************************************************* -// -// 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 - -#include "QRCodeTracker.h" - -#include - - -QRCode::QRCode( - const GUID& id, - PSPATIAL_GRAPH_QR_CODE_STREAM_INFO streamInfo, - const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& coordinateSystem) - : m_id(id) - , m_streamInfo(streamInfo) - , m_coordinateSystem(coordinateSystem) -{ -} - -QRCode::~QRCode() -{ - if (m_streamInfo) - { - CoTaskMemFree(m_streamInfo); - } -} - -const GUID& QRCode::GetId() const -{ - return m_id; -} - -float QRCode::GetPhysicalSize() const -{ - return m_physicalSizeInMeters; -} - -winrt::Windows::Perception::Spatial::SpatialCoordinateSystem QRCode::GetCoordinateSystem() const -{ - return m_coordinateSystem; -} - - - -QRCodeTracker::QRCodeTracker(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId) - : PerceptionRootObject(device, typeId, objectId) -{ - Start(); -} - -QRCodeTracker::~QRCodeTracker() -{ - Stop(); -} - -const GUID& QRCodeTracker::GetStaticPropertyId() -{ - return SPATIALPROP_QRTrackerObjectId; -} - -void QRCodeTracker::Start() -{ - std::lock_guard stateLock(m_stateProtect); - - if (m_running) - { - return; - } - - HRESULT hr = m_device->CreateObjectSubscription(m_objectId, UINT(1), m_qrTrackerSubscription.put()); - if (FAILED(hr)) - { - Stop(); - return; - } - - hr = m_device->CreatePropertyListener(GetObjectId(), SPATIALPROP_QRTracker_QRCodesList, m_qrListChangeListener.put()); - if (FAILED(hr)) - { - Stop(); - return; - } - - m_propertyChangeHandler = winrt::make_self(*this); - hr = m_qrListChangeListener->SetPropertyChangedHandler(m_propertyChangeHandler.get()); - if (FAILED(hr)) - { - Stop(); - return; - } - - hr = m_qrListChangeListener->Start(); - if (FAILED(hr)) - { - Stop(); - return; - } - - m_running = true; -} - -void QRCodeTracker::Stop() -{ - std::lock_guard stateLock(m_stateProtect); - - m_running = false; - - if (m_qrListChangeListener) - { - m_qrListChangeListener->Stop(); - } - - for (auto& qrByPointer : m_qrCodesByPointer) - { - QRCode* qrCode = qrByPointer.second.get(); - if (qrCode->m_propertyChangedListener) - { - qrCode->m_propertyChangedListener->Stop(); - qrCode->m_propertyChangedListener = nullptr; - } - } - - if (m_propertyChangeHandler) - { - m_propertyChangeHandler->Dispose(); - m_propertyChangeHandler = nullptr; - } -} - -HRESULT QRCodeTracker::HandlePropertyChange(IPerceptionDevicePropertyListener* sender, IPerceptionDevicePropertyChangedEventArgs* args) -{ - // Change event for QR code list? - if (sender == m_qrListChangeListener.get()) - { - const GUID* guids = static_cast(args->GetValue()); - UINT numGuids = args->GetValueSize() / sizeof(GUID); - return HandleQRCodeListChange(guids, numGuids); - } - - // Change event for single QR code? - { - std::lock_guard stateLock(m_stateProtect); - auto byListenerPos = m_qrCodesByListener.find(sender); - if (byListenerPos != m_qrCodesByListener.end()) - { - QRCode* qrCode = byListenerPos->second; - return UpdateQRCode(*qrCode); - } - } - - return S_OK; -} - -HRESULT QRCodeTracker::HandleQRCodeListChange(const GUID* guids, UINT numGuids) -{ - std::lock_guard stateLock(m_stateProtect); - - if (!m_running) - { - return S_FALSE; - } - - // Duplicate the list of known QR code IDs. We'll remove all entries from it that we see in - // the incoming list, and thus will end up with a list of the IDs of all removed QR codes. - std::set codesNotInList; - for (auto& kv : m_qrCodesByGUID) - { - codesNotInList.insert(kv.first); - } - - // Check each QR code on the incoming list, and update the local cache - // with new codes. - for (size_t qrIndex = 0; qrIndex < numGuids; ++qrIndex) - { - const GUID& qrCodeId = guids[qrIndex]; - auto it = m_qrCodesByGUID.find(qrCodeId); - if (it != m_qrCodesByGUID.end()) - { - // Code is already known. - codesNotInList.erase(qrCodeId); - continue; - } - - // Code is new. Read initial state, and add to collections. - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem coordinateSystem{nullptr}; - try - { - coordinateSystem = - winrt::Windows::Perception::Spatial::Preview::SpatialGraphInteropPreview::CreateCoordinateSystemForNode(qrCodeId); - } - catch (winrt::hresult_error const& ex) - { - return ex.to_abi(); - } - - if (coordinateSystem == nullptr) - { - return E_FAIL; - } - - void* streamData{nullptr}; - UINT streamDataSize{0}; - HRESULT hr = m_device->ReadVariableSizeProperty(qrCodeId, SPATIALPROP_QRCode_StreamInfo, &streamDataSize, &streamData, nullptr); - if (FAILED(hr)) - { - return hr; - } - - if (streamDataSize == 0) - { - CoTaskMemFree(streamData); - return E_FAIL; - } - - auto newCode = - std::make_unique(qrCodeId, reinterpret_cast(streamData), coordinateSystem); - QRCode* qrCode = newCode.get(); - - m_qrCodesByPointer.emplace(qrCode, std::move(newCode)); - m_qrCodesByGUID.emplace(qrCodeId, qrCode); - - hr = UpdateQRCode(*qrCode); - if (FAILED(hr)) - { - return hr; - } - - hr = m_device->CreatePropertyListener(qrCodeId, SPATIALPROP_QRCode_LastSeenTime, qrCode->m_propertyChangedListener.put()); - if (FAILED(hr)) - { - return hr; - } - - if (!m_propertyChangeHandler) - { - return E_UNEXPECTED; - } - - hr = qrCode->m_propertyChangedListener->SetPropertyChangedHandler( - m_propertyChangeHandler.as().get()); - if (FAILED(hr)) - { - return hr; - } - - hr = qrCode->m_propertyChangedListener->Start(); - if (FAILED(hr)) - { - return hr; - } - - m_qrCodesByListener.emplace(qrCode->m_propertyChangedListener.get(), qrCode); - } - - // Remove all QR codes that have not been seen in this update - for (auto& qrCodeId : codesNotInList) - { - auto byCodeIdPos = m_qrCodesByGUID.find(qrCodeId); - if (byCodeIdPos == m_qrCodesByGUID.end()) - { - // Not found (this should not ever happen) - continue; - } - - QRCode* qrCode = byCodeIdPos->second; - m_qrCodesByGUID.erase(byCodeIdPos); - - if (qrCode->m_propertyChangedListener) - { - qrCode->m_propertyChangedListener->Stop(); - qrCode->m_propertyChangedListener = nullptr; - - m_qrCodesByListener.erase(qrCode->m_propertyChangedListener.get()); - } - - m_qrCodesByPointer.erase(qrCode); - } - - return S_OK; -} - -HRESULT QRCodeTracker::UpdateQRCode(QRCode& qrCode) -{ - float physicalSizeInMeters{0}; - HRESULT hr = - m_device->ReadProperty(qrCode.m_id, SPATIALPROP_QRCode_PhysicalSize, sizeof(physicalSizeInMeters), &physicalSizeInMeters, nullptr); - if (FAILED(hr)) - { - return hr; - } - qrCode.m_physicalSizeInMeters = physicalSizeInMeters; - - LONGLONG lastSeenTime{0}; - hr = m_device->ReadProperty(qrCode.m_id, SPATIALPROP_QRCode_LastSeenTime, sizeof(lastSeenTime), &lastSeenTime, nullptr); - if (FAILED(hr)) - { - return hr; - } - qrCode.m_lastSeenTime = lastSeenTime; - - return S_OK; -} - - - -QRCodeTracker::PropertyChangeHandler::PropertyChangeHandler(QRCodeTracker& owner) - : m_owner(&owner) -{ -} - -void QRCodeTracker::PropertyChangeHandler::Dispose() -{ - m_owner = nullptr; -} - -STDMETHODIMP QRCodeTracker::PropertyChangeHandler::Invoke( - _In_ IPerceptionDevicePropertyListener* sender, _In_ IPerceptionDevicePropertyChangedEventArgs* eventArgs) -{ - auto owner = m_owner; - if (owner) - { - return owner->HandlePropertyChange(sender, eventArgs); - } - - return S_OK; -} +//********************************************************* +// +// 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 + +#include "QRCodeTracker.h" + +#include + +QRCode::QRCode( + const GUID& id, + PSPATIAL_GRAPH_QR_CODE_STREAM_INFO streamInfo, + const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& coordinateSystem) + : m_id(id) + , m_streamInfo(streamInfo) + , m_coordinateSystem(coordinateSystem) +{ +} + +QRCode::~QRCode() +{ + if (m_streamInfo) + { + CoTaskMemFree(m_streamInfo); + } +} + +const GUID& QRCode::GetId() const +{ + return m_id; +} + +float QRCode::GetPhysicalSize() const +{ + return m_physicalSizeInMeters; +} + +winrt::Windows::Perception::Spatial::SpatialCoordinateSystem QRCode::GetCoordinateSystem() const +{ + return m_coordinateSystem; +} + +QRCodeTracker::QRCodeTracker(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId) + : PerceptionRootObject(device, typeId, objectId) +{ + Start(); +} + +QRCodeTracker::~QRCodeTracker() +{ + Stop(); +} + +const GUID& QRCodeTracker::GetStaticPropertyId() +{ + return SPATIALPROP_QRTrackerObjectId; +} + +void QRCodeTracker::Start() +{ + std::lock_guard stateLock(m_stateProtect); + + if (m_running) + { + return; + } + + HRESULT hr = m_device->CreateObjectSubscription(m_objectId, UINT(1), m_qrTrackerSubscription.put()); + if (FAILED(hr)) + { + Stop(); + return; + } + + hr = m_device->CreatePropertyListener(GetObjectId(), SPATIALPROP_QRTracker_QRCodesList, m_qrListChangeListener.put()); + if (FAILED(hr)) + { + Stop(); + return; + } + + m_propertyChangeHandler = winrt::make_self(*this); + hr = m_qrListChangeListener->SetPropertyChangedHandler(m_propertyChangeHandler.get()); + if (FAILED(hr)) + { + Stop(); + return; + } + + hr = m_qrListChangeListener->Start(); + if (FAILED(hr)) + { + Stop(); + return; + } + + m_running = true; +} + +void QRCodeTracker::Stop() +{ + std::lock_guard stateLock(m_stateProtect); + + m_running = false; + + if (m_qrListChangeListener) + { + m_qrListChangeListener->Stop(); + } + + for (auto& qrByPointer : m_qrCodesByPointer) + { + QRCode* qrCode = qrByPointer.second.get(); + if (qrCode->m_propertyChangedListener) + { + qrCode->m_propertyChangedListener->Stop(); + qrCode->m_propertyChangedListener = nullptr; + } + } + + if (m_propertyChangeHandler) + { + m_propertyChangeHandler->Dispose(); + m_propertyChangeHandler = nullptr; + } +} + +HRESULT QRCodeTracker::HandlePropertyChange(IPerceptionDevicePropertyListener* sender, IPerceptionDevicePropertyChangedEventArgs* args) +{ + // Change event for QR code list? + if (sender == m_qrListChangeListener.get()) + { + const GUID* guids = static_cast(args->GetValue()); + UINT numGuids = args->GetValueSize() / sizeof(GUID); + return HandleQRCodeListChange(guids, numGuids); + } + + // Change event for single QR code? + { + std::lock_guard stateLock(m_stateProtect); + auto byListenerPos = m_qrCodesByListener.find(sender); + if (byListenerPos != m_qrCodesByListener.end()) + { + QRCode* qrCode = byListenerPos->second; + return UpdateQRCode(*qrCode); + } + } + + return S_OK; +} + +HRESULT QRCodeTracker::HandleQRCodeListChange(const GUID* guids, UINT numGuids) +{ + std::lock_guard stateLock(m_stateProtect); + + if (!m_running) + { + return S_FALSE; + } + + // Duplicate the list of known QR code IDs. We'll remove all entries from it that we see in + // the incoming list, and thus will end up with a list of the IDs of all removed QR codes. + std::set codesNotInList; + for (auto& kv : m_qrCodesByGUID) + { + codesNotInList.insert(kv.first); + } + + // Check each QR code on the incoming list, and update the local cache + // with new codes. + for (size_t qrIndex = 0; qrIndex < numGuids; ++qrIndex) + { + const GUID& qrCodeId = guids[qrIndex]; + auto it = m_qrCodesByGUID.find(qrCodeId); + if (it != m_qrCodesByGUID.end()) + { + // Code is already known. + codesNotInList.erase(qrCodeId); + continue; + } + + // Code is new. Read initial state, and add to collections. + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem coordinateSystem{nullptr}; + try + { + coordinateSystem = + winrt::Windows::Perception::Spatial::Preview::SpatialGraphInteropPreview::CreateCoordinateSystemForNode(qrCodeId); + } + catch (winrt::hresult_error const& ex) + { + return ex.to_abi(); + } + + if (coordinateSystem == nullptr) + { + return E_FAIL; + } + + void* streamData{nullptr}; + UINT streamDataSize{0}; + HRESULT hr = m_device->ReadVariableSizeProperty(qrCodeId, SPATIALPROP_QRCode_StreamInfo, &streamDataSize, &streamData, nullptr); + if (FAILED(hr)) + { + return hr; + } + + if (streamDataSize == 0) + { + CoTaskMemFree(streamData); + return E_FAIL; + } + + auto newCode = + std::make_unique(qrCodeId, reinterpret_cast(streamData), coordinateSystem); + QRCode* qrCode = newCode.get(); + + m_qrCodesByPointer.emplace(qrCode, std::move(newCode)); + m_qrCodesByGUID.emplace(qrCodeId, qrCode); + + hr = UpdateQRCode(*qrCode); + if (FAILED(hr)) + { + return hr; + } + + hr = m_device->CreatePropertyListener(qrCodeId, SPATIALPROP_QRCode_LastSeenTime, qrCode->m_propertyChangedListener.put()); + if (FAILED(hr)) + { + return hr; + } + + if (!m_propertyChangeHandler) + { + return E_UNEXPECTED; + } + + hr = qrCode->m_propertyChangedListener->SetPropertyChangedHandler( + m_propertyChangeHandler.as().get()); + if (FAILED(hr)) + { + return hr; + } + + hr = qrCode->m_propertyChangedListener->Start(); + if (FAILED(hr)) + { + return hr; + } + + m_qrCodesByListener.emplace(qrCode->m_propertyChangedListener.get(), qrCode); + } + + // Remove all QR codes that have not been seen in this update + for (auto& qrCodeId : codesNotInList) + { + auto byCodeIdPos = m_qrCodesByGUID.find(qrCodeId); + if (byCodeIdPos == m_qrCodesByGUID.end()) + { + // Not found (this should not ever happen) + continue; + } + + QRCode* qrCode = byCodeIdPos->second; + m_qrCodesByGUID.erase(byCodeIdPos); + + if (qrCode->m_propertyChangedListener) + { + qrCode->m_propertyChangedListener->Stop(); + qrCode->m_propertyChangedListener = nullptr; + + m_qrCodesByListener.erase(qrCode->m_propertyChangedListener.get()); + } + + m_qrCodesByPointer.erase(qrCode); + } + + return S_OK; +} + +HRESULT QRCodeTracker::UpdateQRCode(QRCode& qrCode) +{ + float physicalSizeInMeters{0}; + HRESULT hr = + m_device->ReadProperty(qrCode.m_id, SPATIALPROP_QRCode_PhysicalSize, sizeof(physicalSizeInMeters), &physicalSizeInMeters, nullptr); + if (FAILED(hr)) + { + return hr; + } + qrCode.m_physicalSizeInMeters = physicalSizeInMeters; + + LONGLONG lastSeenTime{0}; + hr = m_device->ReadProperty(qrCode.m_id, SPATIALPROP_QRCode_LastSeenTime, sizeof(lastSeenTime), &lastSeenTime, nullptr); + if (FAILED(hr)) + { + return hr; + } + qrCode.m_lastSeenTime = lastSeenTime; + + return S_OK; +} + +QRCodeTracker::PropertyChangeHandler::PropertyChangeHandler(QRCodeTracker& owner) + : m_owner(&owner) +{ +} + +void QRCodeTracker::PropertyChangeHandler::Dispose() +{ + m_owner = nullptr; +} + +STDMETHODIMP QRCodeTracker::PropertyChangeHandler::Invoke( + _In_ IPerceptionDevicePropertyListener* sender, _In_ IPerceptionDevicePropertyChangedEventArgs* eventArgs) +{ + auto owner = m_owner; + if (owner) + { + return owner->HandlePropertyChange(sender, eventArgs); + } + + return S_OK; +} diff --git a/hostsampleapp/desktop/Content/QRCodeTracker.h b/remote/uwp/Content/QRCodeTracker.h similarity index 97% rename from hostsampleapp/desktop/Content/QRCodeTracker.h rename to remote/uwp/Content/QRCodeTracker.h index 4628a29..97519db 100644 --- a/hostsampleapp/desktop/Content/QRCodeTracker.h +++ b/remote/uwp/Content/QRCodeTracker.h @@ -1,108 +1,108 @@ -//********************************************************* -// -// 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 "../Common/PerceptionTypes.h" -#include "../Common/Utils.h" -#include "PerceptionDeviceHandler.h" - -// Represents a single tracked QR code with position, size and last seen time. -class QRCode -{ -public: - QRCode( - const GUID& id, - PSPATIAL_GRAPH_QR_CODE_STREAM_INFO streamInfo, - const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& coordinateSystem); - ~QRCode(); - - const GUID& GetId() const; - float GetPhysicalSize() const; - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem GetCoordinateSystem() const; - -private: - friend class QRCodeTracker; - -private: - GUID m_id; - PSPATIAL_GRAPH_QR_CODE_STREAM_INFO m_streamInfo; - - __int64 m_lastSeenTime{0}; - float m_physicalSizeInMeters{0}; - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem m_coordinateSystem{nullptr}; - winrt::com_ptr m_propertyChangedListener; -}; - -// Manages all active QR codes. -// Listens for events from the perception device to add, remove or update QR codes. -class QRCodeTracker : public PerceptionRootObject -{ -public: - QRCodeTracker(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId); - ~QRCodeTracker(); - - // Helper function to iterate all QR codes in a thread safe manner. - template - void ForEachQRCode(Func& func) - { - std::lock_guard stateLock(m_stateProtect); - for (auto& qrCodeEntry : m_qrCodesByPointer) - { - func(*qrCodeEntry.second.get()); - } - } - -public: - static const GUID& GetStaticPropertyId(); - -private: - // Implementation of the IPerceptionDevicePropertyChangedHandler interface. - // Events from the perception device are propagated through an instance of this class. - struct PropertyChangeHandler : winrt::implements - { - PropertyChangeHandler(QRCodeTracker& owner); - - void Dispose(); - - STDMETHOD(Invoke) - (_In_ IPerceptionDevicePropertyListener* sender, _In_ IPerceptionDevicePropertyChangedEventArgs* eventArgs) override; - - private: - QRCodeTracker* m_owner; - }; - friend PropertyChangeHandler; - - using QRCodesByPointerMap = std::map>; - using QRCodesByGUIDMap = std::map; - using QRCodesByListenerMap = std::map; - -private: - void Start(); - void Stop(); - - HRESULT HandlePropertyChange(IPerceptionDevicePropertyListener* sender, IPerceptionDevicePropertyChangedEventArgs* args); - HRESULT HandleQRCodeListChange(const GUID* guids, UINT numGuids); - HRESULT UpdateQRCode(QRCode& qrCode); - -private: - std::recursive_mutex m_stateProtect; - - bool m_running{false}; - - winrt::com_ptr m_qrTrackerSubscription; - winrt::com_ptr m_qrListChangeListener; - winrt::com_ptr m_propertyChangeHandler; - - QRCodesByPointerMap m_qrCodesByPointer; - QRCodesByGUIDMap m_qrCodesByGUID; - QRCodesByListenerMap m_qrCodesByListener; -}; +//********************************************************* +// +// 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 "../Common/PerceptionTypes.h" +#include "../Common/Utils.h" +#include "PerceptionDeviceHandler.h" + +// Represents a single tracked QR code with position, size and last seen time. +class QRCode +{ +public: + QRCode( + const GUID& id, + PSPATIAL_GRAPH_QR_CODE_STREAM_INFO streamInfo, + const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& coordinateSystem); + ~QRCode(); + + const GUID& GetId() const; + float GetPhysicalSize() const; + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem GetCoordinateSystem() const; + +private: + friend class QRCodeTracker; + +private: + GUID m_id; + PSPATIAL_GRAPH_QR_CODE_STREAM_INFO m_streamInfo; + + __int64 m_lastSeenTime{0}; + float m_physicalSizeInMeters{0}; + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem m_coordinateSystem{nullptr}; + winrt::com_ptr m_propertyChangedListener; +}; + +// Manages all active QR codes. +// Listens for events from the perception device to add, remove or update QR codes. +class QRCodeTracker : public PerceptionRootObject +{ +public: + QRCodeTracker(IPerceptionDevice* device, const GUID& typeId, const GUID& objectId); + ~QRCodeTracker(); + + // Helper function to iterate all QR codes in a thread safe manner. + template + void ForEachQRCode(Func& func) + { + std::lock_guard stateLock(m_stateProtect); + for (auto& qrCodeEntry : m_qrCodesByPointer) + { + func(*qrCodeEntry.second.get()); + } + } + +public: + static const GUID& GetStaticPropertyId(); + +private: + // Implementation of the IPerceptionDevicePropertyChangedHandler interface. + // Events from the perception device are propagated through an instance of this class. + struct PropertyChangeHandler : winrt::implements + { + PropertyChangeHandler(QRCodeTracker& owner); + + void Dispose(); + + STDMETHOD(Invoke) + (_In_ IPerceptionDevicePropertyListener* sender, _In_ IPerceptionDevicePropertyChangedEventArgs* eventArgs) override; + + private: + QRCodeTracker* m_owner; + }; + friend PropertyChangeHandler; + + using QRCodesByPointerMap = std::map>; + using QRCodesByGUIDMap = std::map; + using QRCodesByListenerMap = std::map; + +private: + void Start(); + void Stop(); + + HRESULT HandlePropertyChange(IPerceptionDevicePropertyListener* sender, IPerceptionDevicePropertyChangedEventArgs* args); + HRESULT HandleQRCodeListChange(const GUID* guids, UINT numGuids); + HRESULT UpdateQRCode(QRCode& qrCode); + +private: + std::recursive_mutex m_stateProtect; + + bool m_running{false}; + + winrt::com_ptr m_qrTrackerSubscription; + winrt::com_ptr m_qrListChangeListener; + winrt::com_ptr m_propertyChangeHandler; + + QRCodesByPointerMap m_qrCodesByPointer; + QRCodesByGUIDMap m_qrCodesByGUID; + QRCodesByListenerMap m_qrCodesByListener; +}; diff --git a/hostsampleapp/uwp/Content/RenderableObject.cpp b/remote/uwp/Content/RenderableObject.cpp similarity index 97% rename from hostsampleapp/uwp/Content/RenderableObject.cpp rename to remote/uwp/Content/RenderableObject.cpp index 9934228..341c3b3 100644 --- a/hostsampleapp/uwp/Content/RenderableObject.cpp +++ b/remote/uwp/Content/RenderableObject.cpp @@ -1,148 +1,147 @@ -//********************************************************* -// -// 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 "RenderableObject.h" - -#include "../Common/DirectXHelper.h" - - -RenderableObject::RenderableObject(const std::shared_ptr& deviceResources) - : m_deviceResources(deviceResources) -{ - CreateDeviceDependentResources(); -} - -void RenderableObject::UpdateModelConstantBuffer(const winrt::Windows::Foundation::Numerics::float4x4& modelTransform) -{ - winrt::Windows::Foundation::Numerics::float4x4 normalTransform = modelTransform; - normalTransform.m41 = normalTransform.m42 = normalTransform.m43 = 0; - UpdateModelConstantBuffer(modelTransform, normalTransform); -} - -void RenderableObject::UpdateModelConstantBuffer( - const winrt::Windows::Foundation::Numerics::float4x4& modelTransform, - const winrt::Windows::Foundation::Numerics::float4x4& normalTransform) -{ - if (m_loadingComplete) - { - m_modelConstantBufferData.model = reinterpret_cast(transpose(modelTransform)); - m_modelConstantBufferData.normal = reinterpret_cast(transpose(normalTransform)); - - // Update the model transform buffer for the hologram. - m_deviceResources->UseD3DDeviceContext( - [&](auto context) { context->UpdateSubresource(m_modelConstantBuffer.get(), 0, nullptr, &m_modelConstantBufferData, 0, 0); }); - } -} - -void RenderableObject::Render(bool isStereo) -{ - if (!m_loadingComplete) - { - return; - } - - // Use the D3D device context to update Direct3D device-based resources. - m_deviceResources->UseD3DDeviceContext([&](auto context) { - context->IASetInputLayout(m_inputLayout.get()); - context->PSSetShader(m_pixelShader.get(), nullptr, 0); - - // Attach the vertex shader. - context->VSSetShader(m_vertexShader.get(), nullptr, 0); - - // Apply the model constant buffer to the vertex shader. - ID3D11Buffer* pBuffer = m_modelConstantBuffer.get(); - context->VSSetConstantBuffers(0, 1, &pBuffer); - - 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); - } - - Draw(isStereo ? 2 : 1); - }); -} - -std::future RenderableObject::CreateDeviceDependentResources() -{ -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - std::wstring fileNamePrefix = L""; -#else - std::wstring fileNamePrefix = L"ms-appx:///"; -#endif - - 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"hsa_VprtVertexShader.cso" : L"hsa_VertexShader.cso"; - - // Load shaders asynchronously. - std::vector vertexShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + vertexShaderFileName); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateVertexShader( - vertexShaderFileData.data(), vertexShaderFileData.size(), nullptr, m_vertexShader.put())); - - constexpr std::array vertexDesc = {{ - {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, - }}; - - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateInputLayout( - vertexDesc.data(), - static_cast(vertexDesc.size()), - vertexShaderFileData.data(), - static_cast(vertexShaderFileData.size()), - m_inputLayout.put())); - - std::vector pixelShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_PixelShader.cso"); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreatePixelShader( - pixelShaderFileData.data(), pixelShaderFileData.size(), nullptr, m_pixelShader.put())); - - const ModelConstantBuffer constantBuffer{ - reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), - reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), - }; - - const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, m_modelConstantBuffer.put())); - - if (!m_usingVprtShaders) - { - // Load the pass-through geometry shader. - std::vector geometryShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_GeometryShader.cso"); - - // After the pass-through geometry shader file is loaded, create the shader. - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateGeometryShader( - geometryShaderFileData.data(), geometryShaderFileData.size(), nullptr, m_geometryShader.put())); - } - - m_loadingComplete = true; -} - -void RenderableObject::ReleaseDeviceDependentResources() -{ - m_loadingComplete = false; - m_usingVprtShaders = false; - m_vertexShader = nullptr; - m_inputLayout = nullptr; - m_pixelShader = nullptr; - m_geometryShader = nullptr; - m_modelConstantBuffer = nullptr; -} +//********************************************************* +// +// 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 "RenderableObject.h" + +#include "../Common/DirectXHelper.h" + +RenderableObject::RenderableObject(const std::shared_ptr& deviceResources) + : m_deviceResources(deviceResources) +{ + CreateDeviceDependentResources(); +} + +void RenderableObject::UpdateModelConstantBuffer(const winrt::Windows::Foundation::Numerics::float4x4& modelTransform) +{ + winrt::Windows::Foundation::Numerics::float4x4 normalTransform = modelTransform; + normalTransform.m41 = normalTransform.m42 = normalTransform.m43 = 0; + UpdateModelConstantBuffer(modelTransform, normalTransform); +} + +void RenderableObject::UpdateModelConstantBuffer( + const winrt::Windows::Foundation::Numerics::float4x4& modelTransform, + const winrt::Windows::Foundation::Numerics::float4x4& normalTransform) +{ + if (m_loadingComplete) + { + m_modelConstantBufferData.model = reinterpret_cast(transpose(modelTransform)); + m_modelConstantBufferData.normal = reinterpret_cast(transpose(normalTransform)); + + // Update the model transform buffer for the hologram. + m_deviceResources->UseD3DDeviceContext( + [&](auto context) { context->UpdateSubresource(m_modelConstantBuffer.get(), 0, nullptr, &m_modelConstantBufferData, 0, 0); }); + } +} + +void RenderableObject::Render(bool isStereo) +{ + if (!m_loadingComplete) + { + return; + } + + // Use the D3D device context to update Direct3D device-based resources. + m_deviceResources->UseD3DDeviceContext([&](auto context) { + context->IASetInputLayout(m_inputLayout.get()); + context->PSSetShader(m_pixelShader.get(), nullptr, 0); + + // Attach the vertex shader. + context->VSSetShader(m_vertexShader.get(), nullptr, 0); + + // Apply the model constant buffer to the vertex shader. + ID3D11Buffer* pBuffer = m_modelConstantBuffer.get(); + context->VSSetConstantBuffers(0, 1, &pBuffer); + + 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); + } + + Draw(isStereo ? 2 : 1); + }); +} + +std::future RenderableObject::CreateDeviceDependentResources() +{ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + std::wstring fileNamePrefix = L""; +#else + std::wstring fileNamePrefix = L"ms-appx:///"; +#endif + + 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"hsa_VprtVertexShader.cso" : L"hsa_VertexShader.cso"; + + // Load shaders asynchronously. + std::vector vertexShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + vertexShaderFileName); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateVertexShader( + vertexShaderFileData.data(), vertexShaderFileData.size(), nullptr, m_vertexShader.put())); + + constexpr std::array vertexDesc = {{ + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }}; + + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateInputLayout( + vertexDesc.data(), + static_cast(vertexDesc.size()), + vertexShaderFileData.data(), + static_cast(vertexShaderFileData.size()), + m_inputLayout.put())); + + std::vector pixelShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_PixelShader.cso"); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreatePixelShader( + pixelShaderFileData.data(), pixelShaderFileData.size(), nullptr, m_pixelShader.put())); + + const ModelConstantBuffer constantBuffer{ + reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), + reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), + }; + + const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, m_modelConstantBuffer.put())); + + if (!m_usingVprtShaders) + { + // Load the pass-through geometry shader. + std::vector geometryShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_GeometryShader.cso"); + + // After the pass-through geometry shader file is loaded, create the shader. + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateGeometryShader( + geometryShaderFileData.data(), geometryShaderFileData.size(), nullptr, m_geometryShader.put())); + } + + m_loadingComplete = true; +} + +void RenderableObject::ReleaseDeviceDependentResources() +{ + m_loadingComplete = false; + m_usingVprtShaders = false; + m_vertexShader = nullptr; + m_inputLayout = nullptr; + m_pixelShader = nullptr; + m_geometryShader = nullptr; + m_modelConstantBuffer = nullptr; +} diff --git a/hostsampleapp/desktop/Content/RenderableObject.h b/remote/uwp/Content/RenderableObject.h similarity index 97% rename from hostsampleapp/desktop/Content/RenderableObject.h rename to remote/uwp/Content/RenderableObject.h index 8f28484..0422d6e 100644 --- a/hostsampleapp/desktop/Content/RenderableObject.h +++ b/remote/uwp/Content/RenderableObject.h @@ -1,61 +1,61 @@ -//********************************************************* -// -// 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 "..\Common\DeviceResources.h" -#include "ShaderStructures.h" - -#include - -class RenderableObject -{ -public: - RenderableObject(const std::shared_ptr& deviceResources); - virtual ~RenderableObject() - { - } - - virtual std::future CreateDeviceDependentResources(); - virtual void ReleaseDeviceDependentResources(); - - void Render(bool isStereo); - -protected: - void UpdateModelConstantBuffer(const winrt::Windows::Foundation::Numerics::float4x4& modelTransform); - void UpdateModelConstantBuffer( - const winrt::Windows::Foundation::Numerics::float4x4& modelTransform, - const winrt::Windows::Foundation::Numerics::float4x4& normalTransform); - - virtual void Draw(unsigned int numInstances) = 0; - - // Cached pointer to device resources. - std::shared_ptr m_deviceResources; - -private: - // Direct3D resources for geometry. - winrt::com_ptr m_inputLayout; - winrt::com_ptr m_vertexShader; - winrt::com_ptr m_geometryShader; - winrt::com_ptr m_pixelShader; - winrt::com_ptr m_modelConstantBuffer; - - // System resources for geometry. - ModelConstantBuffer m_modelConstantBufferData; - uint32_t m_indexCount = 0; - - // Variables used with the rendering loop. - bool m_loadingComplete = false; - - // 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; -}; +//********************************************************* +// +// 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 "..\Common\DeviceResources.h" +#include "ShaderStructures.h" + +#include + +class RenderableObject +{ +public: + RenderableObject(const std::shared_ptr& deviceResources); + virtual ~RenderableObject() + { + } + + virtual std::future CreateDeviceDependentResources(); + virtual void ReleaseDeviceDependentResources(); + + void Render(bool isStereo); + +protected: + void UpdateModelConstantBuffer(const winrt::Windows::Foundation::Numerics::float4x4& modelTransform); + void UpdateModelConstantBuffer( + const winrt::Windows::Foundation::Numerics::float4x4& modelTransform, + const winrt::Windows::Foundation::Numerics::float4x4& normalTransform); + + virtual void Draw(unsigned int numInstances) = 0; + + // Cached pointer to device resources. + std::shared_ptr m_deviceResources; + +private: + // Direct3D resources for geometry. + winrt::com_ptr m_inputLayout; + winrt::com_ptr m_vertexShader; + winrt::com_ptr m_geometryShader; + winrt::com_ptr m_pixelShader; + winrt::com_ptr m_modelConstantBuffer; + + // System resources for geometry. + ModelConstantBuffer m_modelConstantBufferData; + uint32_t m_indexCount = 0; + + // Variables used with the rendering loop. + bool m_loadingComplete = false; + + // 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; +}; diff --git a/hostsampleapp/uwp/Content/SceneUnderstandingRenderer.cpp b/remote/uwp/Content/SceneUnderstandingRenderer.cpp similarity index 97% rename from hostsampleapp/uwp/Content/SceneUnderstandingRenderer.cpp rename to remote/uwp/Content/SceneUnderstandingRenderer.cpp index 06b3792..4c8c5e8 100644 --- a/hostsampleapp/uwp/Content/SceneUnderstandingRenderer.cpp +++ b/remote/uwp/Content/SceneUnderstandingRenderer.cpp @@ -1,576 +1,575 @@ -//********************************************************* -// -// 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 "../Common/DbgLog.h" -#include "../Common/DirectXHelper.h" - -#include "SceneUnderstandingRenderer.h" - -#include - -using namespace RemotingHostSample; - -namespace -{ - using namespace DirectX; - - void AppendColoredTriangle( - winrt::Windows::Foundation::Numerics::float3 p0, - winrt::Windows::Foundation::Numerics::float3 p1, - winrt::Windows::Foundation::Numerics::float3 p2, - winrt::Windows::Foundation::Numerics::float3 color, - std::vector& vertices) - { - VertexPositionNormalColor vertex; - vertex.color = XMFLOAT3(&color.x); - vertex.normal = XMFLOAT3(0.0f, 0.0f, 0.0f); - - vertex.pos = XMFLOAT3(&p0.x); - vertices.push_back(vertex); - vertex.pos = XMFLOAT3(&p1.x); - vertices.push_back(vertex); - vertex.pos = XMFLOAT3(&p2.x); - vertices.push_back(vertex); - } -} // namespace - - -// Struct to hold one entity label type entry -struct Label -{ - const wchar_t* const Name; - uint32_t Index; - uint8_t RGB[3]; -}; - -// Entity label types -static const Label LabelStorage[] = { - {L"Background", 0, {243, 121, 223}}, - {L"Ignore", 255, {255, 255, 255}}, - {L"Wall", 1, {243, 126, 121}}, - {L"Floor", 2, {187, 243, 121}}, - {L"Ceiling", 3, {121, 152, 243}}, - {L"Table", 4, {121, 243, 227}}, - {L"Chair", 5, {243, 191, 121}}, - {L"Window", 6, {121, 243, 146}}, - {L"Door", 7, {156, 121, 243}}, - {L"Monitor", 8, {2, 159, 253}}, - {L"Pillar", 10, {253, 106, 2}}, - {L"Couch", 11, {72, 197, 126}}, - {L"Whiteboard", 12, {137, 159, 2}}, - {L"Beanbag", 13, {206, 112, 74}}, - {L"Cabinet", 14, {36, 43, 138}}, - {L"Nightstands", 15, {78, 231, 210}}, - {L"TVStands", 16, {26, 71, 66}}, - {L"Countertops", 17, {13, 60, 55}}, - {L"Dressers", 18, {29, 58, 55}}, - {L"Bench", 19, {105, 54, 136}}, - {L"Ottoman", 20, {99, 9, 44}}, - {L"Stool", 21, {255, 204, 153}}, - {L"GTEquipment", 22, {206, 199, 74}}, - {L"Telephone", 23, {243, 217, 121}}, - {L"Bookshelf", 24, {37, 117, 164}}, - {L"Laptop", 25, {96, 147, 234}}, - {L"Stanchion", 26, {29, 117, 40}}, - {L"Markers", 27, {111, 93, 167}}, - {L"Controller", 28, {230, 254, 251}}, - {L"Stairs", 9, {43, 174, 100}}, - {L"Empty", 254, {0, 0, 0}}, - {L"Appliances-CeilingLight", 30, {250, 24, 180}}, - {L"Appliances-DishWasher", 32, {38, 204, 168}}, - {L"Appliances-FloorLamp", 34, {106, 134, 187}}, - {L"Appliances-Lighting", 36, {156, 162, 56}}, - {L"Appliances-Microwave", 37, {6, 44, 91}}, - {L"Appliances-NotSpecified", 38, {35, 188, 199}}, - {L"Appliances-Oven", 39, {153, 60, 52}}, - {L"Appliances-SmallAppliances", 40, {255, 83, 112}}, - {L"Appliances-Stove", 41, {76, 175, 147}}, - {L"Appliances-Toaster", 42, {145, 58, 23}}, - {L"Appliances-WashingMachine", 44, {46, 66, 12}}, - {L"Appliances-DeskLamp", 45, {128, 86, 177}}, - {L"Appliances-Dryer", 46, {239, 162, 164}}, - {L"Appliances-Fridge", 47, {87, 243, 139}}, - {L"Appliances-WallLight", 50, {222, 49, 1}}, - {L"Bed-BunkBed", 51, {97, 174, 71}}, - {L"Bed-DoubleBed", 52, {85, 195, 111}}, - {L"Bed-NotSpecified", 53, {212, 26, 75}}, - {L"Bed-SingleBed", 54, {200, 219, 241}}, - {L"Ceiling-Unassigned", 55, {48, 120, 115}}, - {L"Ceiling-NotSpecified", 56, {205, 144, 139}}, - {L"Chair-Beanbag", 57, {136, 175, 192}}, - {L"Chair-Bench", 58, {89, 41, 203}}, - {L"Chair-ArmChair", 59, {192, 1, 27}}, - {L"Chair-ArmOfAChair", 60, {194, 241, 101}}, - {L"Chair-BarStool", 61, {146, 21, 8}}, - {L"Chair-ChaiseLounge", 62, {178, 31, 121}}, - {L"Chair-DiningChair", 63, {76, 10, 219}}, - {L"Chair-LoungeChair", 64, {174, 165, 77}}, - {L"Chair-NotSpecified", 65, {186, 217, 58}}, - {L"Chair-OfficeChair", 66, {177, 29, 181}}, - {L"Chair-Unknown", 67, {155, 128, 196}}, - {L"Chair-Ottoman", 68, {28, 75, 247}}, - {L"Chair-Stool", 69, {60, 243, 241}}, - {L"Door-DoubleDoors", 70, {220, 101, 83}}, - {L"Door-NotSpecified", 71, {219, 20, 187}}, - {L"Door-Revolving", 72, {211, 229, 158}}, - {L"Door-SingleDoor", 73, {10, 100, 12}}, - {L"Door-Sliding", 74, {73, 197, 108}}, - {L"Electronics-Desktop", 75, {181, 22, 191}}, - {L"Electronics-DVDPlayer", 76, {5, 131, 13}}, - {L"Electronics-Headphones", 77, {169, 60, 180}}, - {L"Electronics-Keyboard", 78, {6, 92, 79}}, - {L"Electronics-Laptop", 79, {252, 108, 50}}, - {L"Electronics-Mobile", 80, {35, 73, 64}}, - {L"Electronics-Mouse", 81, {3, 112, 214}}, - {L"Electronics-Mousepad", 82, {106, 70, 62}}, - {L"Electronics-NotSpecified", 83, {63, 100, 209}}, - {L"Electronics-Phone", 84, {64, 32, 142}}, - {L"Electronics-Printer", 85, {70, 188, 0}}, - {L"Electronics-Projector", 86, {72, 100, 38}}, - {L"Electronics-Speakers", 87, {202, 60, 135}}, - {L"Electronics-Tablet", 88, {126, 2, 49}}, - {L"Electronics-TVMonitor", 89, {188, 184, 46}}, - {L"Electronics-Xbox", 90, {6, 218, 26}}, - {L"Electronics-Monitor", 91, {179, 160, 177}}, - {L"Floor-Unassigned", 92, {9, 42, 145}}, - {L"Human-Female", 93, {52, 156, 230}}, - {L"Human-Male", 94, {231, 88, 138}}, - {L"Human-Other", 95, {0, 0, 255}}, - {L"NotSpecified-Ax", 96, {230, 228, 24}}, - {L"NotSpecified-Backpack", 97, {228, 104, 245}}, - {L"NotSpecified-Bag", 98, {215, 41, 202}}, - {L"NotSpecified-Barbell", 99, {100, 125, 112}}, - {L"NotSpecified-BlackBoard", 100, {65, 166, 116}}, - {L"NotSpecified-Bottle", 101, {140, 68, 191}}, - {L"NotSpecified-box", 102, {145, 146, 89}}, - {L"NotSpecified-Cable", 103, {170, 1, 118}}, - {L"NotSpecified-Can", 104, {205, 195, 201}}, - {L"NotSpecified-Cart", 105, {156, 159, 0}}, - {L"NotSpecified-case", 106, {208, 70, 137}}, - {L"NotSpecified-CeilingFan", 107, {9, 227, 245}}, - {L"NotSpecified-Clothes", 108, {181, 123, 192}}, - {L"NotSpecified-Coat", 109, {189, 249, 62}}, - {L"NotSpecified-Coatrack", 110, {136, 15, 19}}, - {L"NotSpecified-CorkBoard", 111, {167, 98, 139}}, - {L"NotSpecified-CounterTop", 112, {6, 14, 93}}, - {L"NotSpecified-Drawers", 113, {216, 156, 242}}, - {L"NotSpecified-Drinkcontainer", 114, {238, 153, 75}}, - {L"NotSpecified-Dumbbell", 115, {183, 111, 41}}, - {L"NotSpecified-ElectricalOutlet", 116, {191, 199, 36}}, - {L"NotSpecified-ElectricalSwitch", 117, {31, 81, 127}}, - {L"NotSpecified-Elliptical", 118, {244, 92, 59}}, - {L"NotSpecified-Food", 119, {221, 210, 211}}, - {L"NotSpecified-Footwear", 120, {163, 245, 159}}, - {L"NotSpecified-Hammer", 121, {118, 176, 85}}, - {L"NotSpecified-LaptopBag", 122, {225, 32, 60}}, - {L"NotSpecified-LIDAR", 123, {26, 105, 172}}, - {L"NotSpecified-Mannequin", 124, {131, 135, 194}}, - {L"NotSpecified-Markers", 125, {124, 23, 155}}, - {L"NotSpecified-Microscope", 126, {128, 143, 248}}, - {L"NotSpecified-NDI", 127, {220, 39, 237}}, - {L"NotSpecified-Pinwheel", 128, {155, 24, 46}}, - {L"NotSpecified-PunchingBag", 129, {152, 215, 122}}, - {L"NotSpecified-Shower", 130, {78, 243, 86}}, - {L"NotSpecified-Sign", 131, {29, 159, 136}}, - {L"NotSpecified-Sink", 132, {209, 19, 236}}, - {L"NotSpecified-Sissors", 133, {31, 229, 162}}, - {L"NotSpecified-Sphere", 134, {151, 86, 155}}, - {L"NotSpecified-StairClimber", 135, {52, 236, 130}}, - {L"NotSpecified-stanchion", 136, {6, 76, 221}}, - {L"NotSpecified-Stand", 137, {2, 12, 172}}, - {L"NotSpecified-StationaryBike", 138, {69, 190, 196}}, - {L"NotSpecified-Tape", 139, {176, 3, 131}}, - {L"NotSpecified-Thermostat", 140, {33, 22, 47}}, - {L"NotSpecified-Toilet", 141, {107, 45, 152}}, - {L"NotSpecified-TrashCan", 142, {128, 72, 143}}, - {L"NotSpecified-Tripod", 143, {225, 31, 162}}, - {L"NotSpecified-Tub", 144, {110, 147, 77}}, - {L"NotSpecified-Vent", 145, {137, 170, 110}}, - {L"NotSpecified-WeightBench", 146, {183, 79, 90}}, - {L"NotSpecified-Wire", 147, {0, 255, 38}}, - {L"NotSpecified-Wrench", 148, {116, 3, 22}}, - {L"NotSpecified-Pillar", 149, {128, 184, 144}}, - {L"NotSpecified-Whiteboard", 150, {94, 240, 206}}, - {L"Plant-Fake", 151, {216, 230, 169}}, - {L"Plant-NotSpecified", 152, {182, 43, 63}}, - {L"Plant-Organic", 153, {197, 86, 148}}, - {L"Props-Book", 154, {247, 3, 157}}, - {L"Props-Cushion", 155, {13, 94, 49}}, - {L"Props-FloorVase", 156, {55, 213, 231}}, - {L"Props-FlowerPot", 157, {239, 172, 43}}, - {L"Props-Magazine", 158, {138, 164, 178}}, - {L"Props-Mirror", 159, {116, 236, 157}}, - {L"Props-NewsPaper", 160, {62, 80, 43}}, - {L"Props-NotSpecified", 161, {9, 106, 45}}, - {L"Props-Paintings", 162, {164, 117, 118}}, - {L"Props-PaperSheet", 163, {85, 190, 229}}, - {L"Props-PhotoFrame", 164, {18, 95, 80}}, - {L"Props-Rug", 165, {192, 82, 167}}, - {L"Props-Sculpture", 166, {130, 15, 64}}, - {L"Props-Toys", 167, {136, 130, 225}}, - {L"Sofa-ChaiseLounge", 168, {241, 154, 12}}, - {L"Sofa-NotSpecified", 169, {113, 197, 139}}, - {L"Sofa-Sectional", 170, {24, 132, 64}}, - {L"Sofa-Straight", 171, {248, 137, 194}}, - {L"Storage-Bookshelf", 172, {4, 69, 174}}, - {L"Storage-ChinaCabinet", 173, {216, 165, 83}}, - {L"Storage-Dresser", 174, {156, 24, 110}}, - {L"Storage-FileCabinet", 175, {78, 78, 12}}, - {L"Storage-MediaCabinet", 176, {168, 234, 45}}, - {L"Storage-NotSpecified", 177, {29, 232, 238}}, - {L"Storage-Rack", 178, {161, 36, 92}}, - {L"Storage-Shelf", 179, {57, 187, 87}}, - {L"Storage-Cabinet", 180, {164, 23, 45}}, - {L"Storage-Stairs", 181, {10, 13, 61}}, - {L"Table-CoffeeTable", 182, {178, 214, 30}}, - {L"Table-ConferenceTable", 183, {25, 153, 182}}, - {L"Table-Desk", 184, {171, 128, 231}}, - {L"Table-DiningTable", 185, {12, 169, 156}}, - {L"Table-Nightstand", 186, {247, 131, 122}}, - {L"Table-NotSpecified", 187, {227, 214, 90}}, - {L"Table-OfficeDesk", 188, {122, 253, 7}}, - {L"Table-OfficeTable", 189, {6, 20, 5}}, - {L"Table-SideTable", 190, {230, 211, 253}}, - {L"Unassigned-Unassigned", 191, {141, 204, 180}}, - {L"Utensils-Bowl", 192, {108, 89, 46}}, - {L"Utensils-Cups", 193, {90, 250, 131}}, - {L"Utensils-Knife", 194, {28, 67, 176}}, - {L"Utensils-Mug", 195, {152, 218, 150}}, - {L"Utensils-NotSpecified", 196, {211, 96, 157}}, - {L"Utensils-Pans", 197, {73, 159, 109}}, - {L"Utensils-Pots", 198, {7, 193, 112}}, - {L"Utensils-Tray", 199, {60, 152, 1}}, - {L"Vehicle-Car", 200, {189, 149, 61}}, - {L"Vehicle-MotorCycle", 201, {2, 164, 102}}, - {L"Vehicle-Segway", 202, {198, 165, 85}}, - {L"Vehicle-Truck", 203, {134, 46, 106}}, - {L"Wall-Blinds", 204, {9, 13, 13}}, - {L"Wall-Curtain", 205, {52, 74, 241}}, - {L"Wall-Unassigned", 206, {83, 158, 59}}, - {L"Wall-Window", 207, {117, 162, 84}}, - {L"Storage-BathroomVanity", 208, {127, 151, 35}}, - {L"NotSpecified-Unassigned", 209, {143, 133, 123}}, - {L"Storage-Nightstand", 210, {181, 112, 177}}, - {L"Storage-Unassigned", 211, {73, 125, 140}}, - {L"Props-Unassigned", 212, {156, 127, 134}}, - {L"Storage-ArmChair", 213, {102, 111, 19}}, - {L"NotSpecified-LaundryBasket", 214, {106, 168, 192}}, - {L"Props-Decorations", 215, {49, 242, 177}}, - {L"NotSpecified-Fireplace", 216, {96, 128, 236}}, - {L"NotSpecified-Drinkware", 217, {6, 247, 22}}, - {L"Sofa-LoungeChair", 218, {167, 92, 66}}, - {L"NotSpecified-NotSpecified", 219, {174, 127, 40}}, - {L"Mouse", 220, {65, 33, 210}}, - {L"Bag", 221, {168, 71, 185}}, - {L"Fridge", 222, {255, 127, 94}}, - {L"Stand", 223, {246, 160, 193}}, - {L"Sign", 224, {143, 221, 54}}, - {L"Sphere", 225, {255, 207, 172}}, - {L"Tripod", 227, {255, 235, 46}}, - {L"PinWheel", 228, {13, 92, 139}}, - {L"Kart", 229, {49, 3, 27}}, - {L"Box", 230, {134, 215, 144}}, - {L"Light", 231, {140, 3, 56}}, - {L"Keyboard ", 232, {7, 66, 58}}, - {L"Scupture", 233, {240, 191, 82}}, - {L"Lamp", 234, {189, 8, 78}}, - {L"Microscope ", 235, {255, 211, 112}}, - {L"Case ", 236, {59, 155, 70}}, - {L"Ax", 237, {157, 117, 29}}, - {L"Manikin_Parts ", 238, {67, 141, 186}}, - {L"Clothing ", 239, {4, 122, 55}}, - {L"CoatRack", 240, {211, 52, 114}}, - {L"DrinkContainer ", 241, {35, 23, 0}}, - {L"MousePad", 242, {68, 28, 0}}, - {L"Tape", 243, {107, 173, 211}}, - {L"Sissors ", 245, {53, 24, 143}}, - {L"Headphones ", 246, {45, 212, 189}}, -}; - -constexpr auto NumLabels = sizeof(LabelStorage) / sizeof(Label); - -// Dictionary to quickly access labels by numeric label ID -using LabelDictionary = std::map; -static LabelDictionary Labels; - -SceneUnderstandingRenderer::SceneUnderstandingRenderer(const std::shared_ptr& deviceResources) - : RenderableObject(deviceResources) -{ - // If the label dictionary is still empty, build it from static data - if (Labels.empty()) - { - for (size_t i = 0; i < NumLabels; ++i) - { - Labels[LabelStorage[i].Index] = &LabelStorage[i]; - } - } -} - -void SceneUnderstandingRenderer::Update( - winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, - winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation) -{ - m_vertices.clear(); - - // Calculate the head position at the time of the last SU update in render space. This information can be - // used for debug rendering. - winrt::Windows::Foundation::IReference lastUpdatePosInRenderSpace; - if (lastUpdateLocation) - { - auto lastUpdateCS = lastUpdateLocation.CoordinateSystem(); - auto lastUpdateLocationToRender = lastUpdateCS.TryGetTransformTo(renderingCoordinateSystem); - if (lastUpdateLocationToRender) - { - lastUpdatePosInRenderSpace = winrt::Windows::Foundation::Numerics::transform({0, 0, 0}, lastUpdateLocationToRender.Value()); - } - } - - // Lambda to execute for each quad returned by SU. Adds the quad to the vertex buffer for rendering, using - // the color indicated by the label dictionary for the quad's owner entity's type. Optionally draws debug - // rays from the last update position to each quad. - auto processQuadForRendering = [this, &renderingCoordinateSystem, &lastUpdatePosInRenderSpace]( - const winrt::SceneUnderstanding::Entity& entity, - const winrt::SceneUnderstanding::Quad& quad, - const winrt::Windows::Foundation::Numerics::float4x4& entityToAnchorTransform, - const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& entityAnchorCS) { - // Determine the transform to go from entity space to rendering space - winrt::Windows::Foundation::IReference anchorToRenderingRef = - entityAnchorCS.TryGetTransformTo(renderingCoordinateSystem); - if (!anchorToRenderingRef) - { - return; - } - winrt::Windows::Foundation::Numerics::float4x4 anchorToRenderingTransform = anchorToRenderingRef.Value(); - winrt::Windows::Foundation::Numerics::float4x4 entityToRenderingTransform = entityToAnchorTransform * anchorToRenderingTransform; - - // Create the quad's corner points in entity space and transform them to rendering space - const float width = quad.WidthInMeters(); - const float height = quad.HeightInMeters(); - winrt::Windows::Foundation::Numerics::float3 positions[4] = { - {-width / 2, -height / 2, 0.0f}, {width / 2, -height / 2, 0.0f}, {-width / 2, height / 2, 0.0f}, {width / 2, height / 2, 0.0f}}; - for (int i = 0; i < 4; ++i) - { - positions[i] = winrt::Windows::Foundation::Numerics::transform(positions[i], entityToRenderingTransform); - } - - // Determine the color with which to draw the quad - winrt::Windows::Foundation::Numerics::float3 color{1.0f, 1.0f, 0.0f}; - auto labelPos = Labels.find(static_cast(entity.Label())); - if (labelPos != Labels.end()) - { - const Label& label = *labelPos->second; - color = {label.RGB[0] / 255.0f, label.RGB[1] / 255.0f, label.RGB[2] / 255.0f}; - } - - // Add triangles to render the quad (both winding orders to guarantee double-sided rendering) - AppendColoredTriangle(positions[0], positions[3], positions[1], color, m_vertices); - AppendColoredTriangle(positions[0], positions[2], positions[3], color, m_vertices); - AppendColoredTriangle(positions[1], positions[3], positions[0], color, m_vertices); - AppendColoredTriangle(positions[3], positions[2], positions[0], color, m_vertices); - - /** / - // Debug code: draw a ray from the last update position to the center of each visible quad - if (lastUpdatePosInRenderSpace) - { - float rayEndRadius = 0.05f; - winrt::Windows::Foundation::Numerics::float3 rayEndPositions[4] = { - {-rayEndRadius, 0.0f, 0.0f}, - {rayEndRadius, 0.0f, 0.0f}, - {0.0f, -rayEndRadius, 0.0f}, - {0.0f, rayEndRadius, 0.0f}, - }; - for (int i = 0; i < 4; ++i) - { - rayEndPositions[i] = winrt::Windows::Foundation::Numerics::transform(rayEndPositions[i], entityToRenderingTransform); - } - AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[0], rayEndPositions[1], color, m_vertices); - AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[1], rayEndPositions[0], color, m_vertices); - AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[2], rayEndPositions[3], color, m_vertices); - AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[3], rayEndPositions[2], color, m_vertices); - } - /**/ - }; - - // Execute the above lambda for each quad known by the SceneProcessor - ForEachQuad(sceneProcessor, processQuadForRendering); - - // The geometry we added is already in rendering space, so the model transform must be identity. - auto modelTransform = winrt::Windows::Foundation::Numerics::float4x4::identity(); - UpdateModelConstantBuffer(modelTransform); -} - -void SceneUnderstandingRenderer::DebugLogState( - winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, - winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation) -{ - // Calculate the head position at the time of the last SU update in render space. This information can be - // used for debug rendering. - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem lastUpdateCS = lastUpdateLocation.CoordinateSystem(); - winrt::Windows::Foundation::IReference lastUpdatePosInRenderSpaceRef; - if (lastUpdateLocation) - { - auto lastUpdateLocationToRender = lastUpdateCS.TryGetTransformTo(renderingCoordinateSystem); - if (lastUpdateLocationToRender) - { - lastUpdatePosInRenderSpaceRef = winrt::Windows::Foundation::Numerics::transform({0, 0, 0}, lastUpdateLocationToRender.Value()); - } - } - if (!lastUpdatePosInRenderSpaceRef) - { - return; - } - winrt::Windows::Foundation::Numerics::float3 lastUpdatePosInRenderSpace = lastUpdatePosInRenderSpaceRef.Value(); - - auto logQuad = [this, &lastUpdateCS]( - const winrt::SceneUnderstanding::Entity& entity, - const winrt::SceneUnderstanding::Quad& quad, - const winrt::Windows::Foundation::Numerics::float4x4& entityToAnchorTransform, - const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& entityAnchorCS) { - // Determine transform from entity space to last update pose space - winrt::Windows::Foundation::IReference anchorToLastUpdateRef = - entityAnchorCS.TryGetTransformTo(lastUpdateCS); - if (!anchorToLastUpdateRef) - { - return; - } - winrt::Windows::Foundation::Numerics::float4x4 anchorToLastUpdateTransform = anchorToLastUpdateRef.Value(); - winrt::Windows::Foundation::Numerics::float4x4 entityToLastUpdateTransform = entityToAnchorTransform * anchorToLastUpdateTransform; - - // Determine various sizes, position, and distance from head - const float width = quad.WidthInMeters(); - const float height = quad.HeightInMeters(); - const float radius = sqrtf(width * width + height * height) / 2; - - const winrt::Windows::Foundation::Numerics::float3 position = winrt::Windows::Foundation::Numerics::transform( - winrt::Windows::Foundation::Numerics::float3::zero(), entityToLastUpdateTransform); - const float distance = winrt::Windows::Foundation::Numerics::length(position); - - const wchar_t* labelName = L""; - auto labelPos = Labels.find(static_cast(entity.Label())); - if (labelPos != Labels.end()) - { - const Label& label = *labelPos->second; - labelName = label.Name; - } - - DebugLog( - L" %s (%.2f x %.2f m, radius: %.2f m) at %.2f;%.2f;%.2f (distance: %.2f m)", - labelName, - width, - height, - radius, - position.x, - position.y, - position.z, - distance); - }; - - DebugLog(L"--- SU Update ---"); - DebugLog( - L" Update position (in root space): (%.2f; %.2f; %.2f)", - lastUpdatePosInRenderSpace.x, - lastUpdatePosInRenderSpace.y, - lastUpdatePosInRenderSpace.z); - DebugLog(L" Quads (in head pose space):"); - ForEachQuad(sceneProcessor, logQuad); -} - -void SceneUnderstandingRenderer::Draw(unsigned int numInstances) -{ - if (m_vertices.empty()) - { - return; - } - - const UINT stride = sizeof(m_vertices[0]); - const UINT offset = 0; - D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; - vertexBufferData.pSysMem = m_vertices.data(); - const CD3D11_BUFFER_DESC vertexBufferDesc(static_cast(m_vertices.size() * stride), D3D11_BIND_VERTEX_BUFFER); - winrt::com_ptr vertexBuffer; - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, vertexBuffer.put())); - - auto context = m_deviceResources->GetD3DDeviceContext(); - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - ID3D11Buffer* pBuffer = vertexBuffer.get(); - context->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset); - context->DrawInstanced(static_cast(m_vertices.size()), numInstances, offset, 0); -} - -template -void SceneUnderstandingRenderer::ForEachQuad(winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, Func f) -{ - // Collect all components, then iterate to find quad entities - winrt::com_array components; - sceneProcessor.GetAllComponents(components); - for (auto& component : components) - { - winrt::SceneUnderstanding::Entity entity = component.try_as(); - if (!entity) - { - continue; - } - - winrt::SceneUnderstanding::Quad quad{nullptr}; - winrt::SceneUnderstanding::Transform transform{nullptr}; - winrt::SceneUnderstanding::SpatialCoordinateSystem spatialCS{nullptr}; - - winrt::com_array associatedComponentIds; - entity.GetAllAssociatedComponentIds(associatedComponentIds); - - for (auto& id : associatedComponentIds) - { - winrt::SceneUnderstanding::Component ac = sceneProcessor.GetComponent(id); - if (auto q = ac.try_as()) - { - quad = q; - continue; - } - if (auto t = ac.try_as()) - { - transform = t; - continue; - } - if (auto s = ac.try_as()) - { - spatialCS = s; - continue; - } - } - - // Don't proceed if any essential bit of data is missing - if (!quad || !transform || !spatialCS) - { - continue; - } - - // Determine the transform from the entity to its anchor - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem entityAnchorCS{nullptr}; - try - { - entityAnchorCS = winrt::Windows::Perception::Spatial::Preview::SpatialGraphInteropPreview::CreateCoordinateSystemForNode( - spatialCS.SpatialCoordinateGuid()); - } - catch (const winrt::hresult_error&) - { - continue; - } - - winrt::Windows::Foundation::Numerics::float4x4 entityToAnchorTransform = transform.TransformationMatrix(); - - f(entity, quad, entityToAnchorTransform, entityAnchorCS); - } -} +//********************************************************* +// +// 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 "../Common/DbgLog.h" +#include "../Common/DirectXHelper.h" + +#include "SceneUnderstandingRenderer.h" + +#include + +using namespace RemotingHostSample; + +namespace +{ + using namespace DirectX; + + void AppendColoredTriangle( + winrt::Windows::Foundation::Numerics::float3 p0, + winrt::Windows::Foundation::Numerics::float3 p1, + winrt::Windows::Foundation::Numerics::float3 p2, + winrt::Windows::Foundation::Numerics::float3 color, + std::vector& vertices) + { + VertexPositionNormalColor vertex; + vertex.color = XMFLOAT3(&color.x); + vertex.normal = XMFLOAT3(0.0f, 0.0f, 0.0f); + + vertex.pos = XMFLOAT3(&p0.x); + vertices.push_back(vertex); + vertex.pos = XMFLOAT3(&p1.x); + vertices.push_back(vertex); + vertex.pos = XMFLOAT3(&p2.x); + vertices.push_back(vertex); + } +} // namespace + +// Struct to hold one entity label type entry +struct Label +{ + const wchar_t* const Name; + uint32_t Index; + uint8_t RGB[3]; +}; + +// Entity label types +static const Label LabelStorage[] = { + {L"Background", 0, {243, 121, 223}}, + {L"Ignore", 255, {255, 255, 255}}, + {L"Wall", 1, {243, 126, 121}}, + {L"Floor", 2, {187, 243, 121}}, + {L"Ceiling", 3, {121, 152, 243}}, + {L"Table", 4, {121, 243, 227}}, + {L"Chair", 5, {243, 191, 121}}, + {L"Window", 6, {121, 243, 146}}, + {L"Door", 7, {156, 121, 243}}, + {L"Monitor", 8, {2, 159, 253}}, + {L"Pillar", 10, {253, 106, 2}}, + {L"Couch", 11, {72, 197, 126}}, + {L"Whiteboard", 12, {137, 159, 2}}, + {L"Beanbag", 13, {206, 112, 74}}, + {L"Cabinet", 14, {36, 43, 138}}, + {L"Nightstands", 15, {78, 231, 210}}, + {L"TVStands", 16, {26, 71, 66}}, + {L"Countertops", 17, {13, 60, 55}}, + {L"Dressers", 18, {29, 58, 55}}, + {L"Bench", 19, {105, 54, 136}}, + {L"Ottoman", 20, {99, 9, 44}}, + {L"Stool", 21, {255, 204, 153}}, + {L"GTEquipment", 22, {206, 199, 74}}, + {L"Telephone", 23, {243, 217, 121}}, + {L"Bookshelf", 24, {37, 117, 164}}, + {L"Laptop", 25, {96, 147, 234}}, + {L"Stanchion", 26, {29, 117, 40}}, + {L"Markers", 27, {111, 93, 167}}, + {L"Controller", 28, {230, 254, 251}}, + {L"Stairs", 9, {43, 174, 100}}, + {L"Empty", 254, {0, 0, 0}}, + {L"Appliances-CeilingLight", 30, {250, 24, 180}}, + {L"Appliances-DishWasher", 32, {38, 204, 168}}, + {L"Appliances-FloorLamp", 34, {106, 134, 187}}, + {L"Appliances-Lighting", 36, {156, 162, 56}}, + {L"Appliances-Microwave", 37, {6, 44, 91}}, + {L"Appliances-NotSpecified", 38, {35, 188, 199}}, + {L"Appliances-Oven", 39, {153, 60, 52}}, + {L"Appliances-SmallAppliances", 40, {255, 83, 112}}, + {L"Appliances-Stove", 41, {76, 175, 147}}, + {L"Appliances-Toaster", 42, {145, 58, 23}}, + {L"Appliances-WashingMachine", 44, {46, 66, 12}}, + {L"Appliances-DeskLamp", 45, {128, 86, 177}}, + {L"Appliances-Dryer", 46, {239, 162, 164}}, + {L"Appliances-Fridge", 47, {87, 243, 139}}, + {L"Appliances-WallLight", 50, {222, 49, 1}}, + {L"Bed-BunkBed", 51, {97, 174, 71}}, + {L"Bed-DoubleBed", 52, {85, 195, 111}}, + {L"Bed-NotSpecified", 53, {212, 26, 75}}, + {L"Bed-SingleBed", 54, {200, 219, 241}}, + {L"Ceiling-Unassigned", 55, {48, 120, 115}}, + {L"Ceiling-NotSpecified", 56, {205, 144, 139}}, + {L"Chair-Beanbag", 57, {136, 175, 192}}, + {L"Chair-Bench", 58, {89, 41, 203}}, + {L"Chair-ArmChair", 59, {192, 1, 27}}, + {L"Chair-ArmOfAChair", 60, {194, 241, 101}}, + {L"Chair-BarStool", 61, {146, 21, 8}}, + {L"Chair-ChaiseLounge", 62, {178, 31, 121}}, + {L"Chair-DiningChair", 63, {76, 10, 219}}, + {L"Chair-LoungeChair", 64, {174, 165, 77}}, + {L"Chair-NotSpecified", 65, {186, 217, 58}}, + {L"Chair-OfficeChair", 66, {177, 29, 181}}, + {L"Chair-Unknown", 67, {155, 128, 196}}, + {L"Chair-Ottoman", 68, {28, 75, 247}}, + {L"Chair-Stool", 69, {60, 243, 241}}, + {L"Door-DoubleDoors", 70, {220, 101, 83}}, + {L"Door-NotSpecified", 71, {219, 20, 187}}, + {L"Door-Revolving", 72, {211, 229, 158}}, + {L"Door-SingleDoor", 73, {10, 100, 12}}, + {L"Door-Sliding", 74, {73, 197, 108}}, + {L"Electronics-Desktop", 75, {181, 22, 191}}, + {L"Electronics-DVDPlayer", 76, {5, 131, 13}}, + {L"Electronics-Headphones", 77, {169, 60, 180}}, + {L"Electronics-Keyboard", 78, {6, 92, 79}}, + {L"Electronics-Laptop", 79, {252, 108, 50}}, + {L"Electronics-Mobile", 80, {35, 73, 64}}, + {L"Electronics-Mouse", 81, {3, 112, 214}}, + {L"Electronics-Mousepad", 82, {106, 70, 62}}, + {L"Electronics-NotSpecified", 83, {63, 100, 209}}, + {L"Electronics-Phone", 84, {64, 32, 142}}, + {L"Electronics-Printer", 85, {70, 188, 0}}, + {L"Electronics-Projector", 86, {72, 100, 38}}, + {L"Electronics-Speakers", 87, {202, 60, 135}}, + {L"Electronics-Tablet", 88, {126, 2, 49}}, + {L"Electronics-TVMonitor", 89, {188, 184, 46}}, + {L"Electronics-Xbox", 90, {6, 218, 26}}, + {L"Electronics-Monitor", 91, {179, 160, 177}}, + {L"Floor-Unassigned", 92, {9, 42, 145}}, + {L"Human-Female", 93, {52, 156, 230}}, + {L"Human-Male", 94, {231, 88, 138}}, + {L"Human-Other", 95, {0, 0, 255}}, + {L"NotSpecified-Ax", 96, {230, 228, 24}}, + {L"NotSpecified-Backpack", 97, {228, 104, 245}}, + {L"NotSpecified-Bag", 98, {215, 41, 202}}, + {L"NotSpecified-Barbell", 99, {100, 125, 112}}, + {L"NotSpecified-BlackBoard", 100, {65, 166, 116}}, + {L"NotSpecified-Bottle", 101, {140, 68, 191}}, + {L"NotSpecified-box", 102, {145, 146, 89}}, + {L"NotSpecified-Cable", 103, {170, 1, 118}}, + {L"NotSpecified-Can", 104, {205, 195, 201}}, + {L"NotSpecified-Cart", 105, {156, 159, 0}}, + {L"NotSpecified-case", 106, {208, 70, 137}}, + {L"NotSpecified-CeilingFan", 107, {9, 227, 245}}, + {L"NotSpecified-Clothes", 108, {181, 123, 192}}, + {L"NotSpecified-Coat", 109, {189, 249, 62}}, + {L"NotSpecified-Coatrack", 110, {136, 15, 19}}, + {L"NotSpecified-CorkBoard", 111, {167, 98, 139}}, + {L"NotSpecified-CounterTop", 112, {6, 14, 93}}, + {L"NotSpecified-Drawers", 113, {216, 156, 242}}, + {L"NotSpecified-Drinkcontainer", 114, {238, 153, 75}}, + {L"NotSpecified-Dumbbell", 115, {183, 111, 41}}, + {L"NotSpecified-ElectricalOutlet", 116, {191, 199, 36}}, + {L"NotSpecified-ElectricalSwitch", 117, {31, 81, 127}}, + {L"NotSpecified-Elliptical", 118, {244, 92, 59}}, + {L"NotSpecified-Food", 119, {221, 210, 211}}, + {L"NotSpecified-Footwear", 120, {163, 245, 159}}, + {L"NotSpecified-Hammer", 121, {118, 176, 85}}, + {L"NotSpecified-LaptopBag", 122, {225, 32, 60}}, + {L"NotSpecified-LIDAR", 123, {26, 105, 172}}, + {L"NotSpecified-Mannequin", 124, {131, 135, 194}}, + {L"NotSpecified-Markers", 125, {124, 23, 155}}, + {L"NotSpecified-Microscope", 126, {128, 143, 248}}, + {L"NotSpecified-NDI", 127, {220, 39, 237}}, + {L"NotSpecified-Pinwheel", 128, {155, 24, 46}}, + {L"NotSpecified-PunchingBag", 129, {152, 215, 122}}, + {L"NotSpecified-Shower", 130, {78, 243, 86}}, + {L"NotSpecified-Sign", 131, {29, 159, 136}}, + {L"NotSpecified-Sink", 132, {209, 19, 236}}, + {L"NotSpecified-Sissors", 133, {31, 229, 162}}, + {L"NotSpecified-Sphere", 134, {151, 86, 155}}, + {L"NotSpecified-StairClimber", 135, {52, 236, 130}}, + {L"NotSpecified-stanchion", 136, {6, 76, 221}}, + {L"NotSpecified-Stand", 137, {2, 12, 172}}, + {L"NotSpecified-StationaryBike", 138, {69, 190, 196}}, + {L"NotSpecified-Tape", 139, {176, 3, 131}}, + {L"NotSpecified-Thermostat", 140, {33, 22, 47}}, + {L"NotSpecified-Toilet", 141, {107, 45, 152}}, + {L"NotSpecified-TrashCan", 142, {128, 72, 143}}, + {L"NotSpecified-Tripod", 143, {225, 31, 162}}, + {L"NotSpecified-Tub", 144, {110, 147, 77}}, + {L"NotSpecified-Vent", 145, {137, 170, 110}}, + {L"NotSpecified-WeightBench", 146, {183, 79, 90}}, + {L"NotSpecified-Wire", 147, {0, 255, 38}}, + {L"NotSpecified-Wrench", 148, {116, 3, 22}}, + {L"NotSpecified-Pillar", 149, {128, 184, 144}}, + {L"NotSpecified-Whiteboard", 150, {94, 240, 206}}, + {L"Plant-Fake", 151, {216, 230, 169}}, + {L"Plant-NotSpecified", 152, {182, 43, 63}}, + {L"Plant-Organic", 153, {197, 86, 148}}, + {L"Props-Book", 154, {247, 3, 157}}, + {L"Props-Cushion", 155, {13, 94, 49}}, + {L"Props-FloorVase", 156, {55, 213, 231}}, + {L"Props-FlowerPot", 157, {239, 172, 43}}, + {L"Props-Magazine", 158, {138, 164, 178}}, + {L"Props-Mirror", 159, {116, 236, 157}}, + {L"Props-NewsPaper", 160, {62, 80, 43}}, + {L"Props-NotSpecified", 161, {9, 106, 45}}, + {L"Props-Paintings", 162, {164, 117, 118}}, + {L"Props-PaperSheet", 163, {85, 190, 229}}, + {L"Props-PhotoFrame", 164, {18, 95, 80}}, + {L"Props-Rug", 165, {192, 82, 167}}, + {L"Props-Sculpture", 166, {130, 15, 64}}, + {L"Props-Toys", 167, {136, 130, 225}}, + {L"Sofa-ChaiseLounge", 168, {241, 154, 12}}, + {L"Sofa-NotSpecified", 169, {113, 197, 139}}, + {L"Sofa-Sectional", 170, {24, 132, 64}}, + {L"Sofa-Straight", 171, {248, 137, 194}}, + {L"Storage-Bookshelf", 172, {4, 69, 174}}, + {L"Storage-ChinaCabinet", 173, {216, 165, 83}}, + {L"Storage-Dresser", 174, {156, 24, 110}}, + {L"Storage-FileCabinet", 175, {78, 78, 12}}, + {L"Storage-MediaCabinet", 176, {168, 234, 45}}, + {L"Storage-NotSpecified", 177, {29, 232, 238}}, + {L"Storage-Rack", 178, {161, 36, 92}}, + {L"Storage-Shelf", 179, {57, 187, 87}}, + {L"Storage-Cabinet", 180, {164, 23, 45}}, + {L"Storage-Stairs", 181, {10, 13, 61}}, + {L"Table-CoffeeTable", 182, {178, 214, 30}}, + {L"Table-ConferenceTable", 183, {25, 153, 182}}, + {L"Table-Desk", 184, {171, 128, 231}}, + {L"Table-DiningTable", 185, {12, 169, 156}}, + {L"Table-Nightstand", 186, {247, 131, 122}}, + {L"Table-NotSpecified", 187, {227, 214, 90}}, + {L"Table-OfficeDesk", 188, {122, 253, 7}}, + {L"Table-OfficeTable", 189, {6, 20, 5}}, + {L"Table-SideTable", 190, {230, 211, 253}}, + {L"Unassigned-Unassigned", 191, {141, 204, 180}}, + {L"Utensils-Bowl", 192, {108, 89, 46}}, + {L"Utensils-Cups", 193, {90, 250, 131}}, + {L"Utensils-Knife", 194, {28, 67, 176}}, + {L"Utensils-Mug", 195, {152, 218, 150}}, + {L"Utensils-NotSpecified", 196, {211, 96, 157}}, + {L"Utensils-Pans", 197, {73, 159, 109}}, + {L"Utensils-Pots", 198, {7, 193, 112}}, + {L"Utensils-Tray", 199, {60, 152, 1}}, + {L"Vehicle-Car", 200, {189, 149, 61}}, + {L"Vehicle-MotorCycle", 201, {2, 164, 102}}, + {L"Vehicle-Segway", 202, {198, 165, 85}}, + {L"Vehicle-Truck", 203, {134, 46, 106}}, + {L"Wall-Blinds", 204, {9, 13, 13}}, + {L"Wall-Curtain", 205, {52, 74, 241}}, + {L"Wall-Unassigned", 206, {83, 158, 59}}, + {L"Wall-Window", 207, {117, 162, 84}}, + {L"Storage-BathroomVanity", 208, {127, 151, 35}}, + {L"NotSpecified-Unassigned", 209, {143, 133, 123}}, + {L"Storage-Nightstand", 210, {181, 112, 177}}, + {L"Storage-Unassigned", 211, {73, 125, 140}}, + {L"Props-Unassigned", 212, {156, 127, 134}}, + {L"Storage-ArmChair", 213, {102, 111, 19}}, + {L"NotSpecified-LaundryBasket", 214, {106, 168, 192}}, + {L"Props-Decorations", 215, {49, 242, 177}}, + {L"NotSpecified-Fireplace", 216, {96, 128, 236}}, + {L"NotSpecified-Drinkware", 217, {6, 247, 22}}, + {L"Sofa-LoungeChair", 218, {167, 92, 66}}, + {L"NotSpecified-NotSpecified", 219, {174, 127, 40}}, + {L"Mouse", 220, {65, 33, 210}}, + {L"Bag", 221, {168, 71, 185}}, + {L"Fridge", 222, {255, 127, 94}}, + {L"Stand", 223, {246, 160, 193}}, + {L"Sign", 224, {143, 221, 54}}, + {L"Sphere", 225, {255, 207, 172}}, + {L"Tripod", 227, {255, 235, 46}}, + {L"PinWheel", 228, {13, 92, 139}}, + {L"Kart", 229, {49, 3, 27}}, + {L"Box", 230, {134, 215, 144}}, + {L"Light", 231, {140, 3, 56}}, + {L"Keyboard ", 232, {7, 66, 58}}, + {L"Scupture", 233, {240, 191, 82}}, + {L"Lamp", 234, {189, 8, 78}}, + {L"Microscope ", 235, {255, 211, 112}}, + {L"Case ", 236, {59, 155, 70}}, + {L"Ax", 237, {157, 117, 29}}, + {L"Manikin_Parts ", 238, {67, 141, 186}}, + {L"Clothing ", 239, {4, 122, 55}}, + {L"CoatRack", 240, {211, 52, 114}}, + {L"DrinkContainer ", 241, {35, 23, 0}}, + {L"MousePad", 242, {68, 28, 0}}, + {L"Tape", 243, {107, 173, 211}}, + {L"Sissors ", 245, {53, 24, 143}}, + {L"Headphones ", 246, {45, 212, 189}}, +}; + +constexpr auto NumLabels = sizeof(LabelStorage) / sizeof(Label); + +// Dictionary to quickly access labels by numeric label ID +using LabelDictionary = std::map; +static LabelDictionary Labels; + +SceneUnderstandingRenderer::SceneUnderstandingRenderer(const std::shared_ptr& deviceResources) + : RenderableObject(deviceResources) +{ + // If the label dictionary is still empty, build it from static data + if (Labels.empty()) + { + for (size_t i = 0; i < NumLabels; ++i) + { + Labels[LabelStorage[i].Index] = &LabelStorage[i]; + } + } +} + +void SceneUnderstandingRenderer::Update( + winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, + winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation) +{ + m_vertices.clear(); + + // Calculate the head position at the time of the last SU update in render space. This information can be + // used for debug rendering. + winrt::Windows::Foundation::IReference lastUpdatePosInRenderSpace; + if (lastUpdateLocation) + { + auto lastUpdateCS = lastUpdateLocation.CoordinateSystem(); + auto lastUpdateLocationToRender = lastUpdateCS.TryGetTransformTo(renderingCoordinateSystem); + if (lastUpdateLocationToRender) + { + lastUpdatePosInRenderSpace = winrt::Windows::Foundation::Numerics::transform({0, 0, 0}, lastUpdateLocationToRender.Value()); + } + } + + // Lambda to execute for each quad returned by SU. Adds the quad to the vertex buffer for rendering, using + // the color indicated by the label dictionary for the quad's owner entity's type. Optionally draws debug + // rays from the last update position to each quad. + auto processQuadForRendering = [this, &renderingCoordinateSystem, &lastUpdatePosInRenderSpace]( + const winrt::SceneUnderstanding::Entity& entity, + const winrt::SceneUnderstanding::Quad& quad, + const winrt::Windows::Foundation::Numerics::float4x4& entityToAnchorTransform, + const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& entityAnchorCS) { + // Determine the transform to go from entity space to rendering space + winrt::Windows::Foundation::IReference anchorToRenderingRef = + entityAnchorCS.TryGetTransformTo(renderingCoordinateSystem); + if (!anchorToRenderingRef) + { + return; + } + winrt::Windows::Foundation::Numerics::float4x4 anchorToRenderingTransform = anchorToRenderingRef.Value(); + winrt::Windows::Foundation::Numerics::float4x4 entityToRenderingTransform = entityToAnchorTransform * anchorToRenderingTransform; + + // Create the quad's corner points in entity space and transform them to rendering space + const float width = quad.WidthInMeters(); + const float height = quad.HeightInMeters(); + winrt::Windows::Foundation::Numerics::float3 positions[4] = { + {-width / 2, -height / 2, 0.0f}, {width / 2, -height / 2, 0.0f}, {-width / 2, height / 2, 0.0f}, {width / 2, height / 2, 0.0f}}; + for (int i = 0; i < 4; ++i) + { + positions[i] = winrt::Windows::Foundation::Numerics::transform(positions[i], entityToRenderingTransform); + } + + // Determine the color with which to draw the quad + winrt::Windows::Foundation::Numerics::float3 color{1.0f, 1.0f, 0.0f}; + auto labelPos = Labels.find(static_cast(entity.Label())); + if (labelPos != Labels.end()) + { + const Label& label = *labelPos->second; + color = {label.RGB[0] / 255.0f, label.RGB[1] / 255.0f, label.RGB[2] / 255.0f}; + } + + // Add triangles to render the quad (both winding orders to guarantee double-sided rendering) + AppendColoredTriangle(positions[0], positions[3], positions[1], color, m_vertices); + AppendColoredTriangle(positions[0], positions[2], positions[3], color, m_vertices); + AppendColoredTriangle(positions[1], positions[3], positions[0], color, m_vertices); + AppendColoredTriangle(positions[3], positions[2], positions[0], color, m_vertices); + + /** / + // Debug code: draw a ray from the last update position to the center of each visible quad + if (lastUpdatePosInRenderSpace) + { + float rayEndRadius = 0.05f; + winrt::Windows::Foundation::Numerics::float3 rayEndPositions[4] = { + {-rayEndRadius, 0.0f, 0.0f}, + {rayEndRadius, 0.0f, 0.0f}, + {0.0f, -rayEndRadius, 0.0f}, + {0.0f, rayEndRadius, 0.0f}, + }; + for (int i = 0; i < 4; ++i) + { + rayEndPositions[i] = winrt::Windows::Foundation::Numerics::transform(rayEndPositions[i], entityToRenderingTransform); + } + AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[0], rayEndPositions[1], color, m_vertices); + AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[1], rayEndPositions[0], color, m_vertices); + AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[2], rayEndPositions[3], color, m_vertices); + AppendColoredTriangle(lastUpdatePosInRenderSpace.Value(), rayEndPositions[3], rayEndPositions[2], color, m_vertices); + } + /**/ + }; + + // Execute the above lambda for each quad known by the SceneProcessor + ForEachQuad(sceneProcessor, processQuadForRendering); + + // The geometry we added is already in rendering space, so the model transform must be identity. + auto modelTransform = winrt::Windows::Foundation::Numerics::float4x4::identity(); + UpdateModelConstantBuffer(modelTransform); +} + +void SceneUnderstandingRenderer::DebugLogState( + winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, + winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation) +{ + // Calculate the head position at the time of the last SU update in render space. This information can be + // used for debug rendering. + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem lastUpdateCS = lastUpdateLocation.CoordinateSystem(); + winrt::Windows::Foundation::IReference lastUpdatePosInRenderSpaceRef; + if (lastUpdateLocation) + { + auto lastUpdateLocationToRender = lastUpdateCS.TryGetTransformTo(renderingCoordinateSystem); + if (lastUpdateLocationToRender) + { + lastUpdatePosInRenderSpaceRef = winrt::Windows::Foundation::Numerics::transform({0, 0, 0}, lastUpdateLocationToRender.Value()); + } + } + if (!lastUpdatePosInRenderSpaceRef) + { + return; + } + winrt::Windows::Foundation::Numerics::float3 lastUpdatePosInRenderSpace = lastUpdatePosInRenderSpaceRef.Value(); + + auto logQuad = [this, &lastUpdateCS]( + const winrt::SceneUnderstanding::Entity& entity, + const winrt::SceneUnderstanding::Quad& quad, + const winrt::Windows::Foundation::Numerics::float4x4& entityToAnchorTransform, + const winrt::Windows::Perception::Spatial::SpatialCoordinateSystem& entityAnchorCS) { + // Determine transform from entity space to last update pose space + winrt::Windows::Foundation::IReference anchorToLastUpdateRef = + entityAnchorCS.TryGetTransformTo(lastUpdateCS); + if (!anchorToLastUpdateRef) + { + return; + } + winrt::Windows::Foundation::Numerics::float4x4 anchorToLastUpdateTransform = anchorToLastUpdateRef.Value(); + winrt::Windows::Foundation::Numerics::float4x4 entityToLastUpdateTransform = entityToAnchorTransform * anchorToLastUpdateTransform; + + // Determine various sizes, position, and distance from head + const float width = quad.WidthInMeters(); + const float height = quad.HeightInMeters(); + const float radius = sqrtf(width * width + height * height) / 2; + + const winrt::Windows::Foundation::Numerics::float3 position = winrt::Windows::Foundation::Numerics::transform( + winrt::Windows::Foundation::Numerics::float3::zero(), entityToLastUpdateTransform); + const float distance = winrt::Windows::Foundation::Numerics::length(position); + + const wchar_t* labelName = L""; + auto labelPos = Labels.find(static_cast(entity.Label())); + if (labelPos != Labels.end()) + { + const Label& label = *labelPos->second; + labelName = label.Name; + } + + DebugLog( + L" %s (%.2f x %.2f m, radius: %.2f m) at %.2f;%.2f;%.2f (distance: %.2f m)", + labelName, + width, + height, + radius, + position.x, + position.y, + position.z, + distance); + }; + + DebugLog(L"--- SU Update ---"); + DebugLog( + L" Update position (in root space): (%.2f; %.2f; %.2f)", + lastUpdatePosInRenderSpace.x, + lastUpdatePosInRenderSpace.y, + lastUpdatePosInRenderSpace.z); + DebugLog(L" Quads (in head pose space):"); + ForEachQuad(sceneProcessor, logQuad); +} + +void SceneUnderstandingRenderer::Draw(unsigned int numInstances) +{ + if (m_vertices.empty()) + { + return; + } + + const UINT stride = sizeof(m_vertices[0]); + const UINT offset = 0; + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = m_vertices.data(); + const CD3D11_BUFFER_DESC vertexBufferDesc(static_cast(m_vertices.size() * stride), D3D11_BIND_VERTEX_BUFFER); + winrt::com_ptr vertexBuffer; + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, vertexBuffer.put())); + + auto context = m_deviceResources->GetD3DDeviceContext(); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + ID3D11Buffer* pBuffer = vertexBuffer.get(); + context->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset); + context->DrawInstanced(static_cast(m_vertices.size()), numInstances, offset, 0); +} + +template +void SceneUnderstandingRenderer::ForEachQuad(winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, Func f) +{ + // Collect all components, then iterate to find quad entities + winrt::com_array components; + sceneProcessor.GetAllComponents(components); + for (auto& component : components) + { + winrt::SceneUnderstanding::Entity entity = component.try_as(); + if (!entity) + { + continue; + } + + winrt::SceneUnderstanding::Quad quad{nullptr}; + winrt::SceneUnderstanding::Transform transform{nullptr}; + winrt::SceneUnderstanding::SpatialCoordinateSystem spatialCS{nullptr}; + + winrt::com_array associatedComponentIds; + entity.GetAllAssociatedComponentIds(associatedComponentIds); + + for (auto& id : associatedComponentIds) + { + winrt::SceneUnderstanding::Component ac = sceneProcessor.GetComponent(id); + if (auto q = ac.try_as()) + { + quad = q; + continue; + } + if (auto t = ac.try_as()) + { + transform = t; + continue; + } + if (auto s = ac.try_as()) + { + spatialCS = s; + continue; + } + } + + // Don't proceed if any essential bit of data is missing + if (!quad || !transform || !spatialCS) + { + continue; + } + + // Determine the transform from the entity to its anchor + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem entityAnchorCS{nullptr}; + try + { + entityAnchorCS = winrt::Windows::Perception::Spatial::Preview::SpatialGraphInteropPreview::CreateCoordinateSystemForNode( + spatialCS.SpatialCoordinateGuid()); + } + catch (const winrt::hresult_error&) + { + continue; + } + + winrt::Windows::Foundation::Numerics::float4x4 entityToAnchorTransform = transform.TransformationMatrix(); + + f(entity, quad, entityToAnchorTransform, entityAnchorCS); + } +} diff --git a/hostsampleapp/uwp/Content/SceneUnderstandingRenderer.h b/remote/uwp/Content/SceneUnderstandingRenderer.h similarity index 97% rename from hostsampleapp/uwp/Content/SceneUnderstandingRenderer.h rename to remote/uwp/Content/SceneUnderstandingRenderer.h index 6c07315..ad7a9df 100644 --- a/hostsampleapp/uwp/Content/SceneUnderstandingRenderer.h +++ b/remote/uwp/Content/SceneUnderstandingRenderer.h @@ -1,47 +1,47 @@ -//********************************************************* -// -// 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 "RenderableObject.h" - -#include - -#include -#include - -namespace RemotingHostSample -{ - class SceneUnderstandingRenderer : public RenderableObject - { - public: - SceneUnderstandingRenderer(const std::shared_ptr& deviceResources); - - void Update( - winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, - winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation); - - void DebugLogState( - winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, - winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation); - - private: - void Draw(unsigned int numInstances) override; - - template - void ForEachQuad(winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, Func f); - - private: - std::vector m_vertices; - }; -} // namespace RemotingHostSample +//********************************************************* +// +// 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 "RenderableObject.h" + +#include + +#include +#include + +namespace RemotingHostSample +{ + class SceneUnderstandingRenderer : public RenderableObject + { + public: + SceneUnderstandingRenderer(const std::shared_ptr& deviceResources); + + void Update( + winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, + winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation); + + void DebugLogState( + winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem, + winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference lastUpdateLocation); + + private: + void Draw(unsigned int numInstances) override; + + template + void ForEachQuad(winrt::SceneUnderstanding::SceneProcessor& sceneProcessor, Func f); + + private: + std::vector m_vertices; + }; +} // namespace RemotingHostSample diff --git a/hostsampleapp/desktop/Content/ShaderStructures.h b/remote/uwp/Content/ShaderStructures.h similarity index 97% rename from hostsampleapp/desktop/Content/ShaderStructures.h rename to remote/uwp/Content/ShaderStructures.h index 1914109..0895217 100644 --- a/hostsampleapp/desktop/Content/ShaderStructures.h +++ b/remote/uwp/Content/ShaderStructures.h @@ -1,33 +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 - -// Constant buffer used to send hologram position transform to the shader pipeline. -struct ModelConstantBuffer -{ - DirectX::XMFLOAT4X4 model; - DirectX::XMFLOAT4X4 normal; // Normal transform matrix. -}; - -// Assert that the constant buffer remains 16-byte aligned (best practice). -static_assert( - (sizeof(ModelConstantBuffer) % (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 VertexPositionNormalColor -{ - DirectX::XMFLOAT3 pos; - DirectX::XMFLOAT3 normal; // Normal. - DirectX::XMFLOAT3 color; -}; +//********************************************************* +// +// 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 + +// Constant buffer used to send hologram position transform to the shader pipeline. +struct ModelConstantBuffer +{ + DirectX::XMFLOAT4X4 model; + DirectX::XMFLOAT4X4 normal; // Normal transform matrix. +}; + +// Assert that the constant buffer remains 16-byte aligned (best practice). +static_assert( + (sizeof(ModelConstantBuffer) % (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 VertexPositionNormalColor +{ + DirectX::XMFLOAT3 pos; + DirectX::XMFLOAT3 normal; // Normal. + DirectX::XMFLOAT3 color; +}; diff --git a/hostsampleapp/desktop/Content/SpatialInputHandler.cpp b/remote/uwp/Content/SpatialInputHandler.cpp similarity index 95% rename from hostsampleapp/desktop/Content/SpatialInputHandler.cpp rename to remote/uwp/Content/SpatialInputHandler.cpp index 47c38d2..458428a 100644 --- a/hostsampleapp/desktop/Content/SpatialInputHandler.cpp +++ b/remote/uwp/Content/SpatialInputHandler.cpp @@ -1,193 +1,190 @@ -//********************************************************* -// -// 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 "SpatialInputHandler.h" - -#include - - -// 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 = winrt::Windows::UI::Input::Spatial::SpatialInteractionManager::GetForCurrentView(); - m_gestureRecognizer = winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer( - winrt::Windows::UI::Input::Spatial::SpatialGestureSettings::Tap | - winrt::Windows::UI::Input::Spatial::SpatialGestureSettings::ManipulationTranslate); - - m_interactionDetectedEventToken = - m_interactionManager.InteractionDetected(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialInteractionManager, - winrt::Windows::UI::Input::Spatial::SpatialInteractionDetectedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialInteractionManager, - winrt::Windows::UI::Input::Spatial::SpatialInteractionDetectedEventArgs args) { - m_gestureRecognizer.CaptureInteraction(args.Interaction()); - })); - - m_tappedEventToken = m_gestureRecognizer.Tapped(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs args) { - std::lock_guard _lg(m_manipulationStateLock); - m_tapped = args; - })); - - m_manipulationStartedEventToken = - m_gestureRecognizer.ManipulationStarted(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs args) { - std::lock_guard _lg(m_manipulationStateLock); - m_manipulationStarted = args; - })); - - m_manipulationUpdatedEventToken = - m_gestureRecognizer.ManipulationUpdated(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs args) { - std::lock_guard _lg(m_manipulationStateLock); - m_manipulationUpdated = args; - })); - - m_manipulationCompletedEventToken = - m_gestureRecognizer.ManipulationCompleted(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationCompletedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationCompletedEventArgs) { - std::lock_guard _lg(m_manipulationStateLock); - m_manipulationResult = ManipulationResult::Completed; - })); - - m_manipulationCanceledEventToken = - m_gestureRecognizer.ManipulationCanceled(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationCanceledEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialManipulationCanceledEventArgs) { - std::lock_guard _lg(m_manipulationStateLock); - m_manipulationResult = ManipulationResult::Canceled; - })); - - - - m_navigationStartedEventToken = - m_gestureRecognizer.NavigationStarted(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationStartedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationStartedEventArgs args) { - char buf[128]; - sprintf_s( - buf, - "NS: %d %d %d\n", - static_cast(args.IsNavigatingX()), - static_cast(args.IsNavigatingY()), - static_cast(args.IsNavigatingZ())); - OutputDebugStringA(buf); - })); - - m_navigationUpdatedEventToken = - m_gestureRecognizer.NavigationUpdated(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationUpdatedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationUpdatedEventArgs args) { - winrt::Windows::Foundation::Numerics::float3 offset = args.NormalizedOffset(); - char buf[128]; - sprintf_s(buf, "NU: %f %f %f\n", offset.x, offset.y, offset.z); - OutputDebugStringA(buf); - })); - - m_navigationCompletedEventToken = - m_gestureRecognizer.NavigationCompleted(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationCompletedEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationCompletedEventArgs args) { - winrt::Windows::Foundation::Numerics::float3 offset = args.NormalizedOffset(); - char buf[128]; - sprintf_s(buf, "NC: %f %f %f\n", offset.x, offset.y, offset.z); - OutputDebugStringA(buf); - })); - - m_navigationCanceledEventToken = - m_gestureRecognizer.NavigationCanceled(winrt::Windows::Foundation::TypedEventHandler< - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationCanceledEventArgs>( - [this]( - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, - winrt::Windows::UI::Input::Spatial::SpatialNavigationCanceledEventArgs args) { - char buf[128]; - sprintf_s(buf, "N: canceled\n"); - OutputDebugStringA(buf); - })); -} - -SpatialInputHandler::~SpatialInputHandler() -{ - // Unregister our handler for the OnSourcePressed event. - m_interactionManager.InteractionDetected(m_interactionDetectedEventToken); - m_gestureRecognizer.Tapped(m_tappedEventToken); - m_gestureRecognizer.ManipulationStarted(m_manipulationStartedEventToken); - m_gestureRecognizer.ManipulationUpdated(m_manipulationUpdatedEventToken); - m_gestureRecognizer.ManipulationCompleted(m_manipulationCompletedEventToken); - m_gestureRecognizer.ManipulationCanceled(m_manipulationCanceledEventToken); -} - -// 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. -winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs SpatialInputHandler::CheckForTapped() -{ - std::lock_guard _lg(m_manipulationStateLock); - auto tapped = m_tapped; - m_tapped = nullptr; - return tapped; -} - -winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs SpatialInputHandler::CheckForManipulationStarted() -{ - std::lock_guard _lg(m_manipulationStateLock); - auto manipulationStarted = m_manipulationStarted; - m_manipulationStarted = nullptr; - return manipulationStarted; -} - -winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs SpatialInputHandler::CheckForManipulationUpdated() -{ - std::lock_guard _lg(m_manipulationStateLock); - auto manipulationUpdated = m_manipulationUpdated; - m_manipulationUpdated = nullptr; - return manipulationUpdated; -} - -SpatialInputHandler::ManipulationResult SpatialInputHandler::CheckForManipulationResult() -{ - std::lock_guard _lg(m_manipulationStateLock); - auto manipulationResult = m_manipulationResult; - m_manipulationResult = ManipulationResult::Unknown; - return manipulationResult; -} +//********************************************************* +// +// 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 "SpatialInputHandler.h" + +#include +#include + +// Creates and initializes a GestureRecognizer that listens to a Person. +SpatialInputHandler::SpatialInputHandler(winrt::Windows::UI::Input::Spatial::SpatialInteractionManager interactionManager) + : m_interactionManager(interactionManager) +{ + m_gestureRecognizer = winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer( + winrt::Windows::UI::Input::Spatial::SpatialGestureSettings::Tap | + winrt::Windows::UI::Input::Spatial::SpatialGestureSettings::ManipulationTranslate); + + m_interactionDetectedEventToken = + m_interactionManager.InteractionDetected(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialInteractionManager, + winrt::Windows::UI::Input::Spatial::SpatialInteractionDetectedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialInteractionManager, + winrt::Windows::UI::Input::Spatial::SpatialInteractionDetectedEventArgs args) { + m_gestureRecognizer.CaptureInteraction(args.Interaction()); + })); + + m_tappedEventToken = m_gestureRecognizer.Tapped(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs args) { + std::lock_guard _lg(m_manipulationStateLock); + m_tapped = args; + })); + + m_manipulationStartedEventToken = + m_gestureRecognizer.ManipulationStarted(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs args) { + std::lock_guard _lg(m_manipulationStateLock); + m_manipulationStarted = args; + })); + + m_manipulationUpdatedEventToken = + m_gestureRecognizer.ManipulationUpdated(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs args) { + std::lock_guard _lg(m_manipulationStateLock); + m_manipulationUpdated = args; + })); + + m_manipulationCompletedEventToken = + m_gestureRecognizer.ManipulationCompleted(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationCompletedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationCompletedEventArgs) { + std::lock_guard _lg(m_manipulationStateLock); + m_manipulationResult = ManipulationResult::Completed; + })); + + m_manipulationCanceledEventToken = + m_gestureRecognizer.ManipulationCanceled(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationCanceledEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialManipulationCanceledEventArgs) { + std::lock_guard _lg(m_manipulationStateLock); + m_manipulationResult = ManipulationResult::Canceled; + })); + + m_navigationStartedEventToken = + m_gestureRecognizer.NavigationStarted(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationStartedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationStartedEventArgs args) { + char buf[128]; + sprintf_s( + buf, + "NS: %d %d %d\n", + static_cast(args.IsNavigatingX()), + static_cast(args.IsNavigatingY()), + static_cast(args.IsNavigatingZ())); + OutputDebugStringA(buf); + })); + + m_navigationUpdatedEventToken = + m_gestureRecognizer.NavigationUpdated(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationUpdatedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationUpdatedEventArgs args) { + winrt::Windows::Foundation::Numerics::float3 offset = args.NormalizedOffset(); + char buf[128]; + sprintf_s(buf, "NU: %f %f %f\n", offset.x, offset.y, offset.z); + OutputDebugStringA(buf); + })); + + m_navigationCompletedEventToken = + m_gestureRecognizer.NavigationCompleted(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationCompletedEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationCompletedEventArgs args) { + winrt::Windows::Foundation::Numerics::float3 offset = args.NormalizedOffset(); + char buf[128]; + sprintf_s(buf, "NC: %f %f %f\n", offset.x, offset.y, offset.z); + OutputDebugStringA(buf); + })); + + m_navigationCanceledEventToken = + m_gestureRecognizer.NavigationCanceled(winrt::Windows::Foundation::TypedEventHandler< + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationCanceledEventArgs>( + [this]( + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer, + winrt::Windows::UI::Input::Spatial::SpatialNavigationCanceledEventArgs args) { + char buf[128]; + sprintf_s(buf, "N: canceled\n"); + OutputDebugStringA(buf); + })); +} + +SpatialInputHandler::~SpatialInputHandler() +{ + // Unregister our handler for the OnSourcePressed event. + m_interactionManager.InteractionDetected(m_interactionDetectedEventToken); + m_gestureRecognizer.Tapped(m_tappedEventToken); + m_gestureRecognizer.ManipulationStarted(m_manipulationStartedEventToken); + m_gestureRecognizer.ManipulationUpdated(m_manipulationUpdatedEventToken); + m_gestureRecognizer.ManipulationCompleted(m_manipulationCompletedEventToken); + m_gestureRecognizer.ManipulationCanceled(m_manipulationCanceledEventToken); +} + +// 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. +winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs SpatialInputHandler::CheckForTapped() +{ + std::lock_guard _lg(m_manipulationStateLock); + auto tapped = m_tapped; + m_tapped = nullptr; + return tapped; +} + +winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs SpatialInputHandler::CheckForManipulationStarted() +{ + std::lock_guard _lg(m_manipulationStateLock); + auto manipulationStarted = m_manipulationStarted; + m_manipulationStarted = nullptr; + return manipulationStarted; +} + +winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs SpatialInputHandler::CheckForManipulationUpdated() +{ + std::lock_guard _lg(m_manipulationStateLock); + auto manipulationUpdated = m_manipulationUpdated; + m_manipulationUpdated = nullptr; + return manipulationUpdated; +} + +SpatialInputHandler::ManipulationResult SpatialInputHandler::CheckForManipulationResult() +{ + std::lock_guard _lg(m_manipulationStateLock); + auto manipulationResult = m_manipulationResult; + m_manipulationResult = ManipulationResult::Unknown; + return manipulationResult; +} diff --git a/hostsampleapp/desktop/Content/SpatialInputHandler.h b/remote/uwp/Content/SpatialInputHandler.h similarity index 95% rename from hostsampleapp/desktop/Content/SpatialInputHandler.h rename to remote/uwp/Content/SpatialInputHandler.h index b69cef7..b05eaa5 100644 --- a/hostsampleapp/desktop/Content/SpatialInputHandler.h +++ b/remote/uwp/Content/SpatialInputHandler.h @@ -1,62 +1,62 @@ -//********************************************************* -// -// 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 -#include - - -// 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(); - - enum class ManipulationResult - { - Unknown = 0, - Completed, - Canceled, - }; - - winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs CheckForTapped(); - winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs CheckForManipulationStarted(); - winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs CheckForManipulationUpdated(); - ManipulationResult CheckForManipulationResult(); - -private: - // API objects used to process gesture input, and generate gesture events. - winrt::Windows::UI::Input::Spatial::SpatialInteractionManager m_interactionManager = nullptr; - winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer m_gestureRecognizer = nullptr; - - // Event registration token. - winrt::event_token m_interactionDetectedEventToken; - winrt::event_token m_tappedEventToken; - winrt::event_token m_manipulationStartedEventToken; - winrt::event_token m_manipulationUpdatedEventToken; - winrt::event_token m_manipulationCompletedEventToken; - winrt::event_token m_manipulationCanceledEventToken; - - winrt::event_token m_navigationStartedEventToken; - winrt::event_token m_navigationUpdatedEventToken; - winrt::event_token m_navigationCompletedEventToken; - winrt::event_token m_navigationCanceledEventToken; - - // Used to indicate that a Pressed input event was received this frame. - std::recursive_mutex m_manipulationStateLock; - - winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs m_tapped = nullptr; - winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs m_manipulationStarted = nullptr; - winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs m_manipulationUpdated = nullptr; - ManipulationResult m_manipulationResult = ManipulationResult::Unknown; -}; +//********************************************************* +// +// 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 +#include +#include + +// Sample gesture handler. +// Hooks up events to recognize a tap gesture, and keeps track of input using a boolean value. +class SpatialInputHandler +{ +public: + SpatialInputHandler(winrt::Windows::UI::Input::Spatial::SpatialInteractionManager interactionManager); + ~SpatialInputHandler(); + + enum class ManipulationResult + { + Unknown = 0, + Completed, + Canceled, + }; + + winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs CheckForTapped(); + winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs CheckForManipulationStarted(); + winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs CheckForManipulationUpdated(); + ManipulationResult CheckForManipulationResult(); + +private: + // API objects used to process gesture input, and generate gesture events. + winrt::Windows::UI::Input::Spatial::SpatialInteractionManager m_interactionManager = nullptr; + winrt::Windows::UI::Input::Spatial::SpatialGestureRecognizer m_gestureRecognizer = nullptr; + + // Event registration token. + winrt::event_token m_interactionDetectedEventToken; + winrt::event_token m_tappedEventToken; + winrt::event_token m_manipulationStartedEventToken; + winrt::event_token m_manipulationUpdatedEventToken; + winrt::event_token m_manipulationCompletedEventToken; + winrt::event_token m_manipulationCanceledEventToken; + + winrt::event_token m_navigationStartedEventToken; + winrt::event_token m_navigationUpdatedEventToken; + winrt::event_token m_navigationCompletedEventToken; + winrt::event_token m_navigationCanceledEventToken; + + // Used to indicate that a Pressed input event was received this frame. + std::recursive_mutex m_manipulationStateLock; + + winrt::Windows::UI::Input::Spatial::SpatialTappedEventArgs m_tapped = nullptr; + winrt::Windows::UI::Input::Spatial::SpatialManipulationStartedEventArgs m_manipulationStarted = nullptr; + winrt::Windows::UI::Input::Spatial::SpatialManipulationUpdatedEventArgs m_manipulationUpdated = nullptr; + ManipulationResult m_manipulationResult = ManipulationResult::Unknown; +}; diff --git a/hostsampleapp/uwp/Content/SpatialInputRenderer.cpp b/remote/uwp/Content/SpatialInputRenderer.cpp similarity index 85% rename from hostsampleapp/uwp/Content/SpatialInputRenderer.cpp rename to remote/uwp/Content/SpatialInputRenderer.cpp index 45db281..65e45ab 100644 --- a/hostsampleapp/uwp/Content/SpatialInputRenderer.cpp +++ b/remote/uwp/Content/SpatialInputRenderer.cpp @@ -1,238 +1,268 @@ -//********************************************************* -// -// 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 "SpatialInputRenderer.h" - -#include -#include -#include - -#include "../Common/DirectXHelper.h" -#include - -namespace -{ - using namespace DirectX; - - void AppendColoredTriangle(XMFLOAT3 p0, XMFLOAT3 p1, XMFLOAT3 p2, XMFLOAT3 color, std::vector& vertices) - { - VertexPositionNormalColor vertex; - vertex.color = color; - vertex.normal = XMFLOAT3(0.0f, 0.0f, 0.0f); - - vertex.pos = p0; - vertices.push_back(vertex); - vertex.pos = p1; - vertices.push_back(vertex); - vertex.pos = p2; - vertices.push_back(vertex); - } -} // namespace - -SpatialInputRenderer::SpatialInputRenderer(const std::shared_ptr& deviceResources) - : RenderableObject(deviceResources) -{ - m_manager = winrt::Windows::UI::Input::Spatial::SpatialInteractionManager::GetForCurrentView(); - m_referenceFrame = winrt::Windows::Perception::Spatial::SpatialLocator::GetDefault().CreateAttachedFrameOfReferenceAtCurrentHeading(); -} - -void SpatialInputRenderer::Update( - winrt::Windows::Perception::PerceptionTimestamp timestamp, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) -{ - m_transforms.clear(); - m_joints.clear(); - - auto headingAdjustment = m_referenceFrame.TryGetRelativeHeadingAtTimestamp(timestamp); - if (headingAdjustment) - { - // keep coordinate systems facing user - m_referenceFrame.AdjustHeading(-headingAdjustment.Value()); - auto coordinateSystem = m_referenceFrame.GetStationaryCoordinateSystemAtTimestamp(timestamp); - - auto spatialPointerPose = winrt::Windows::UI::Input::Spatial::SpatialPointerPose::TryGetAtTimestamp(coordinateSystem, timestamp); - if (spatialPointerPose) - { - if (auto eyesPose = spatialPointerPose.Eyes()) - { - if (auto gaze = eyesPose.Gaze()) - { - auto position = gaze.Value().Origin + gaze.Value().Direction; - quaternion orientation = quaternion::identity(); - m_transforms.emplace_back(QTransform(position, orientation)); - } - } - } - - auto states = m_manager.GetDetectedSourcesAtTimestamp(timestamp); - - m_transforms.reserve(states.Size()); - for (const auto& state : states) - { - auto location = state.Properties().TryGetLocation(coordinateSystem); - if (location) - { - if (location.Position()) - { - using namespace winrt::Windows::Foundation::Numerics; - - auto position = location.Position().Value(); - quaternion orientation = quaternion::identity(); - - if (location.Orientation()) - { - orientation = location.Orientation().Value(); - } - - DirectX::XMVECTOR xmPosition = DirectX::XMLoadFloat3(&position); - DirectX::XMVECTOR xmOrientation = DirectX::XMLoadQuaternion(&orientation); - m_transforms.emplace_back(QTransform(xmPosition, xmOrientation)); - } - - if (auto sourcePose = location.SourcePointerPose()) - { - m_joints.push_back({sourcePose.Position(), sourcePose.Orientation(), 1.0f, 0.01f}); - } - } - - auto handPose = state.TryGetHandPose(); - if (handPose) - { - constexpr const winrt::Windows::Perception::People::HandJointKind jointKinds[] = { - winrt::Windows::Perception::People::HandJointKind::Palm, - winrt::Windows::Perception::People::HandJointKind::Wrist, - winrt::Windows::Perception::People::HandJointKind::ThumbMetacarpal, - winrt::Windows::Perception::People::HandJointKind::ThumbProximal, - winrt::Windows::Perception::People::HandJointKind::ThumbDistal, - winrt::Windows::Perception::People::HandJointKind::ThumbTip, - winrt::Windows::Perception::People::HandJointKind::IndexMetacarpal, - winrt::Windows::Perception::People::HandJointKind::IndexProximal, - winrt::Windows::Perception::People::HandJointKind::IndexIntermediate, - winrt::Windows::Perception::People::HandJointKind::IndexDistal, - winrt::Windows::Perception::People::HandJointKind::IndexTip, - winrt::Windows::Perception::People::HandJointKind::MiddleMetacarpal, - winrt::Windows::Perception::People::HandJointKind::MiddleProximal, - winrt::Windows::Perception::People::HandJointKind::MiddleIntermediate, - winrt::Windows::Perception::People::HandJointKind::MiddleDistal, - winrt::Windows::Perception::People::HandJointKind::MiddleTip, - winrt::Windows::Perception::People::HandJointKind::RingMetacarpal, - winrt::Windows::Perception::People::HandJointKind::RingProximal, - winrt::Windows::Perception::People::HandJointKind::RingIntermediate, - winrt::Windows::Perception::People::HandJointKind::RingDistal, - winrt::Windows::Perception::People::HandJointKind::RingTip, - winrt::Windows::Perception::People::HandJointKind::LittleMetacarpal, - winrt::Windows::Perception::People::HandJointKind::LittleProximal, - winrt::Windows::Perception::People::HandJointKind::LittleIntermediate, - winrt::Windows::Perception::People::HandJointKind::LittleDistal, - winrt::Windows::Perception::People::HandJointKind::LittleTip}; - constexpr const size_t jointCount = _countof(jointKinds); - winrt::Windows::Perception::People::JointPose jointPoses[jointCount] = {}; - - if (handPose.TryGetJoints(coordinateSystem, jointKinds, jointPoses)) - { - for (size_t jointIndex = 0; jointIndex < jointCount; ++jointIndex) - { - m_joints.push_back({jointPoses[jointIndex].Position, - jointPoses[jointIndex].Orientation, - jointPoses[jointIndex].Radius * 3, - jointPoses[jointIndex].Radius}); - } - } - } - } - - auto modelTransform = coordinateSystem.TryGetTransformTo(renderingCoordinateSystem); - if (modelTransform) - { - UpdateModelConstantBuffer(modelTransform.Value()); - } - } -} - -void SpatialInputRenderer::Draw(unsigned int numInstances) -{ - if (!m_transforms.empty()) - { - std::vector vertices; - for (const auto& transform : m_transforms) - { - DirectX::XMFLOAT3 trianglePositions[3] = { - DirectX::XMFLOAT3(0.0f, 0.03f, 0.0f), DirectX::XMFLOAT3(0.01f, 0.0f, 0.0f), DirectX::XMFLOAT3(-0.01f, 0.0f, 0.0f)}; - - AppendColoredTriangle( - transform.TransformPosition(trianglePositions[0]), - transform.TransformPosition(trianglePositions[1]), - transform.TransformPosition(trianglePositions[2]), - DirectX::XMFLOAT3{0, 0, 1}, - vertices); - } - - for (const auto& joint : m_joints) - { - auto jointVertices = CalculateJointVisualizationVertices(joint.position, joint.orientation, joint.length, joint.radius); - vertices.insert(vertices.end(), jointVertices.begin(), jointVertices.end()); - } - - const UINT stride = sizeof(vertices[0]); - const UINT offset = 0; - D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; - vertexBufferData.pSysMem = vertices.data(); - const CD3D11_BUFFER_DESC vertexBufferDesc(static_cast(vertices.size() * stride), D3D11_BIND_VERTEX_BUFFER); - winrt::com_ptr vertexBuffer; - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, vertexBuffer.put())); - - m_deviceResources->UseD3DDeviceContext([&](auto context) { - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - ID3D11Buffer* pBuffer = vertexBuffer.get(); - context->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset); - context->DrawInstanced(static_cast(vertices.size()), numInstances, offset, 0); - }); - } -} - - -std::vector SpatialInputRenderer::CalculateJointVisualizationVertices( - float3 jointPosition, quaternion jointOrientation, float jointLength, float jointRadius) -{ - using namespace DirectX; - - constexpr const size_t verticesCount = 2 * 4 * 3; - std::vector vertices; - vertices.reserve(verticesCount); - - float centerHeight = std::min(jointRadius, 0.5f * jointLength); - float centerXandY = jointRadius / sqrtf(2.0f); - - QTransform jointTransform = QTransform(jointPosition, jointOrientation); - - XMFLOAT3 baseVertexPosition = jointTransform.TransformPosition(XMFLOAT3(0.0f, 0.0f, 0.0f)); - XMFLOAT3 centerVertexPositions[4] = { - jointTransform.TransformPosition(XMFLOAT3(-centerXandY, -centerXandY, -centerHeight)), - jointTransform.TransformPosition(XMFLOAT3(-centerXandY, +centerXandY, -centerHeight)), - jointTransform.TransformPosition(XMFLOAT3(+centerXandY, +centerXandY, -centerHeight)), - jointTransform.TransformPosition(XMFLOAT3(+centerXandY, -centerXandY, -centerHeight)), - }; - XMFLOAT3 topVertexPosition = jointTransform.TransformPosition(XMFLOAT3(0.0f, 0.0f, -jointLength)); - - AppendColoredTriangle(baseVertexPosition, centerVertexPositions[0], centerVertexPositions[1], XMFLOAT3(0.0f, 0.0f, 0.4f), vertices); - AppendColoredTriangle(baseVertexPosition, centerVertexPositions[1], centerVertexPositions[2], XMFLOAT3(0.0f, 0.4f, 0.0f), vertices); - AppendColoredTriangle(baseVertexPosition, centerVertexPositions[2], centerVertexPositions[3], XMFLOAT3(0.4f, 0.0f, 0.0f), vertices); - AppendColoredTriangle(baseVertexPosition, centerVertexPositions[3], centerVertexPositions[0], XMFLOAT3(0.4f, 0.4f, 0.0f), vertices); - AppendColoredTriangle(topVertexPosition, centerVertexPositions[1], centerVertexPositions[0], XMFLOAT3(0.0f, 0.0f, 0.6f), vertices); - AppendColoredTriangle(topVertexPosition, centerVertexPositions[2], centerVertexPositions[1], XMFLOAT3(0.0f, 0.6f, 0.0f), vertices); - AppendColoredTriangle(topVertexPosition, centerVertexPositions[3], centerVertexPositions[2], XMFLOAT3(0.6f, 0.0f, 0.0f), vertices); - AppendColoredTriangle(topVertexPosition, centerVertexPositions[0], centerVertexPositions[3], XMFLOAT3(0.6f, 0.6f, 0.0f), vertices); - - return vertices; -} +//********************************************************* +// +// 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 "SpatialInputRenderer.h" + +#include +#include +#include +#include + +#include "../Common/DirectXHelper.h" +#include + +#include +#include + +namespace +{ + using namespace DirectX; + + void AppendColoredTriangle(XMFLOAT3 p0, XMFLOAT3 p1, XMFLOAT3 p2, XMFLOAT3 color, std::vector& vertices) + { + VertexPositionNormalColor vertex; + vertex.color = color; + vertex.normal = XMFLOAT3(0.0f, 0.0f, 0.0f); + + vertex.pos = p0; + vertices.push_back(vertex); + vertex.pos = p1; + vertices.push_back(vertex); + vertex.pos = p2; + vertices.push_back(vertex); + } +} // namespace + +SpatialInputRenderer::SpatialInputRenderer( + const std::shared_ptr& deviceResources, + winrt::Windows::UI::Input::Spatial::SpatialInteractionManager interactionManager) + : RenderableObject(deviceResources) + , m_interactionManager(interactionManager) +{ + m_referenceFrame = winrt::Windows::Perception::Spatial::SpatialLocator::GetDefault().CreateAttachedFrameOfReferenceAtCurrentHeading(); +} + +void SpatialInputRenderer::Update( + winrt::Windows::Perception::PerceptionTimestamp timestamp, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) +{ + m_transforms.clear(); + m_joints.clear(); + + auto headingAdjustment = m_referenceFrame.TryGetRelativeHeadingAtTimestamp(timestamp); + if (headingAdjustment) + { + + // keep coordinate systems facing user + m_referenceFrame.AdjustHeading(-headingAdjustment.Value()); + auto coordinateSystem = m_referenceFrame.GetStationaryCoordinateSystemAtTimestamp(timestamp); + + auto spatialPointerPose = winrt::Windows::UI::Input::Spatial::SpatialPointerPose::TryGetAtTimestamp(coordinateSystem, timestamp); + if (spatialPointerPose) + { + if (auto eyesPose = spatialPointerPose.Eyes()) + { + if (auto gaze = eyesPose.Gaze()) + { + auto position = gaze.Value().Origin + gaze.Value().Direction; + quaternion orientation = quaternion::identity(); + m_transforms.emplace_back(QTransform(position, orientation)); + } + } + } + + auto states = m_interactionManager.GetDetectedSourcesAtTimestamp(timestamp); + + m_transforms.reserve(states.Size()); + + for (const auto& state : states) + { + auto location = state.Properties().TryGetLocation(coordinateSystem); + QTransform currentTransform(float3::zero(), quaternion::identity()); + if (location) + { + if (location.Position()) + { + using namespace winrt::Windows::Foundation::Numerics; + + auto position = location.Position().Value(); + quaternion orientation = quaternion::identity(); + + if (location.Orientation()) + { + orientation = location.Orientation().Value(); + } + + DirectX::XMVECTOR xmPosition = DirectX::XMLoadFloat3(&position); + DirectX::XMVECTOR xmOrientation = DirectX::XMLoadQuaternion(&orientation); + currentTransform = QTransform(xmPosition, xmOrientation); + m_transforms.push_back(currentTransform); + } + + if (auto sourcePose = location.SourcePointerPose()) + { + m_joints.push_back({sourcePose.Position(), sourcePose.Orientation(), 1.0f, 0.01f}); + } + } + + auto handPose = state.TryGetHandPose(); + if (handPose) + { + constexpr const winrt::Windows::Perception::People::HandJointKind jointKinds[] = { + winrt::Windows::Perception::People::HandJointKind::Palm, + winrt::Windows::Perception::People::HandJointKind::Wrist, + winrt::Windows::Perception::People::HandJointKind::ThumbMetacarpal, + winrt::Windows::Perception::People::HandJointKind::ThumbProximal, + winrt::Windows::Perception::People::HandJointKind::ThumbDistal, + winrt::Windows::Perception::People::HandJointKind::ThumbTip, + winrt::Windows::Perception::People::HandJointKind::IndexMetacarpal, + winrt::Windows::Perception::People::HandJointKind::IndexProximal, + winrt::Windows::Perception::People::HandJointKind::IndexIntermediate, + winrt::Windows::Perception::People::HandJointKind::IndexDistal, + winrt::Windows::Perception::People::HandJointKind::IndexTip, + winrt::Windows::Perception::People::HandJointKind::MiddleMetacarpal, + winrt::Windows::Perception::People::HandJointKind::MiddleProximal, + winrt::Windows::Perception::People::HandJointKind::MiddleIntermediate, + winrt::Windows::Perception::People::HandJointKind::MiddleDistal, + winrt::Windows::Perception::People::HandJointKind::MiddleTip, + winrt::Windows::Perception::People::HandJointKind::RingMetacarpal, + winrt::Windows::Perception::People::HandJointKind::RingProximal, + winrt::Windows::Perception::People::HandJointKind::RingIntermediate, + winrt::Windows::Perception::People::HandJointKind::RingDistal, + winrt::Windows::Perception::People::HandJointKind::RingTip, + winrt::Windows::Perception::People::HandJointKind::LittleMetacarpal, + winrt::Windows::Perception::People::HandJointKind::LittleProximal, + winrt::Windows::Perception::People::HandJointKind::LittleIntermediate, + winrt::Windows::Perception::People::HandJointKind::LittleDistal, + winrt::Windows::Perception::People::HandJointKind::LittleTip}; + constexpr const size_t jointCount = _countof(jointKinds); + winrt::Windows::Perception::People::JointPose jointPoses[jointCount] = {}; + + if (handPose.TryGetJoints(coordinateSystem, jointKinds, jointPoses)) + { + for (size_t jointIndex = 0; jointIndex < jointCount; ++jointIndex) + { + m_joints.push_back( + {jointPoses[jointIndex].Position, + jointPoses[jointIndex].Orientation, + jointPoses[jointIndex].Radius * 3, + jointPoses[jointIndex].Radius}); + } + } + } + } + + auto modelTransform = coordinateSystem.TryGetTransformTo(renderingCoordinateSystem); + if (modelTransform) + { + UpdateModelConstantBuffer(modelTransform.Value()); + } + } +} + +void SpatialInputRenderer::Draw(unsigned int numInstances) +{ + if (!m_transforms.empty()) + { + std::vector vertices; + for (const auto& transform : m_transforms) + { + DirectX::XMFLOAT3 trianglePositions[3] = { + DirectX::XMFLOAT3(0.0f, 0.03f, 0.0f), DirectX::XMFLOAT3(0.01f, 0.0f, 0.0f), DirectX::XMFLOAT3(-0.01f, 0.0f, 0.0f)}; + + AppendColoredTriangle( + transform.TransformPosition(trianglePositions[0]), + transform.TransformPosition(trianglePositions[1]), + transform.TransformPosition(trianglePositions[2]), + DirectX::XMFLOAT3{0, 0, 1}, + vertices); + } + + for (const auto& joint : m_joints) + { + auto jointVertices = CalculateJointVisualizationVertices(joint.position, joint.orientation, joint.length, joint.radius); + vertices.insert(vertices.end(), jointVertices.begin(), jointVertices.end()); + } + + for (const auto& coloredTransform : m_coloredTransforms) + { + DirectX::XMFLOAT3 quadPositions[4] = { + DirectX::XMFLOAT3(-0.01f, 0.0f, -0.01f), + DirectX::XMFLOAT3(0.01f, 0.0f, -0.01f), + DirectX::XMFLOAT3(0.01f, 0.0f, 0.01f), + DirectX::XMFLOAT3(-0.01f, 0.0f, 0.01f)}; + DirectX::XMFLOAT3 transformedPositions[4]; + + for (uint32_t i = 0; i < 4; ++i) + { + transformedPositions[i] = coloredTransform.m_transform.TransformPosition(quadPositions[i]); + } + + AppendColoredTriangle( + transformedPositions[0], transformedPositions[1], transformedPositions[2], coloredTransform.m_color, vertices); + AppendColoredTriangle( + transformedPositions[2], transformedPositions[3], transformedPositions[0], coloredTransform.m_color, vertices); + } + + const UINT stride = sizeof(vertices[0]); + const UINT offset = 0; + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = vertices.data(); + const CD3D11_BUFFER_DESC vertexBufferDesc(static_cast(vertices.size() * stride), D3D11_BIND_VERTEX_BUFFER); + winrt::com_ptr vertexBuffer; + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, vertexBuffer.put())); + + m_deviceResources->UseD3DDeviceContext([&](auto context) { + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + ID3D11Buffer* pBuffer = vertexBuffer.get(); + context->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset); + context->DrawInstanced(static_cast(vertices.size()), numInstances, offset, 0); + }); + } +} + +std::vector SpatialInputRenderer::CalculateJointVisualizationVertices( + float3 jointPosition, quaternion jointOrientation, float jointLength, float jointRadius) +{ + using namespace DirectX; + + constexpr const size_t verticesCount = 2 * 4 * 3; + std::vector vertices; + vertices.reserve(verticesCount); + + float centerHeight = std::min(jointRadius, 0.5f * jointLength); + float centerXandY = jointRadius / sqrtf(2.0f); + + QTransform jointTransform = QTransform(jointPosition, jointOrientation); + + XMFLOAT3 baseVertexPosition = jointTransform.TransformPosition(XMFLOAT3(0.0f, 0.0f, 0.0f)); + XMFLOAT3 centerVertexPositions[4] = { + jointTransform.TransformPosition(XMFLOAT3(-centerXandY, -centerXandY, -centerHeight)), + jointTransform.TransformPosition(XMFLOAT3(-centerXandY, +centerXandY, -centerHeight)), + jointTransform.TransformPosition(XMFLOAT3(+centerXandY, +centerXandY, -centerHeight)), + jointTransform.TransformPosition(XMFLOAT3(+centerXandY, -centerXandY, -centerHeight)), + }; + XMFLOAT3 topVertexPosition = jointTransform.TransformPosition(XMFLOAT3(0.0f, 0.0f, -jointLength)); + + AppendColoredTriangle(baseVertexPosition, centerVertexPositions[0], centerVertexPositions[1], XMFLOAT3(0.0f, 0.0f, 0.4f), vertices); + AppendColoredTriangle(baseVertexPosition, centerVertexPositions[1], centerVertexPositions[2], XMFLOAT3(0.0f, 0.4f, 0.0f), vertices); + AppendColoredTriangle(baseVertexPosition, centerVertexPositions[2], centerVertexPositions[3], XMFLOAT3(0.4f, 0.0f, 0.0f), vertices); + AppendColoredTriangle(baseVertexPosition, centerVertexPositions[3], centerVertexPositions[0], XMFLOAT3(0.4f, 0.4f, 0.0f), vertices); + AppendColoredTriangle(topVertexPosition, centerVertexPositions[1], centerVertexPositions[0], XMFLOAT3(0.0f, 0.0f, 0.6f), vertices); + AppendColoredTriangle(topVertexPosition, centerVertexPositions[2], centerVertexPositions[1], XMFLOAT3(0.0f, 0.6f, 0.0f), vertices); + AppendColoredTriangle(topVertexPosition, centerVertexPositions[3], centerVertexPositions[2], XMFLOAT3(0.6f, 0.0f, 0.0f), vertices); + AppendColoredTriangle(topVertexPosition, centerVertexPositions[0], centerVertexPositions[3], XMFLOAT3(0.6f, 0.6f, 0.0f), vertices); + + return vertices; +} diff --git a/hostsampleapp/desktop/Content/SpatialInputRenderer.h b/remote/uwp/Content/SpatialInputRenderer.h similarity index 71% rename from hostsampleapp/desktop/Content/SpatialInputRenderer.h rename to remote/uwp/Content/SpatialInputRenderer.h index 0010241..cc51118 100644 --- a/hostsampleapp/desktop/Content/SpatialInputRenderer.h +++ b/remote/uwp/Content/SpatialInputRenderer.h @@ -1,85 +1,110 @@ -//********************************************************* -// -// 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 "RenderableObject.h" -#include - -#include - -using namespace winrt::Windows::Foundation::Numerics; - -struct QTransform -{ - QTransform() = default; - QTransform(const DirectX::XMVECTOR& position, const DirectX::XMVECTOR& orientation) - : m_position(position) - , m_orientation(orientation) - { - } - QTransform(const float3& position, const quaternion& orientation) - : m_position(DirectX::XMLoadFloat3(&position)) - , m_orientation(DirectX::XMLoadQuaternion(&orientation)) - { - } - - - DirectX::XMVECTOR TransformNormal(const DirectX::XMVECTOR& normal) const - { - return DirectX::XMVector3Rotate(normal, m_orientation); - } - - DirectX::XMVECTOR TransformPosition(const DirectX::XMVECTOR& position) const - { - DirectX::XMVECTOR rotated = TransformNormal(position); - return DirectX::XMVectorAdd(rotated, m_position); - } - - DirectX::XMFLOAT3 TransformPosition(const DirectX::XMFLOAT3& position) const - { - DirectX::XMFLOAT3 result; - XMStoreFloat3(&result, TransformPosition(DirectX::XMLoadFloat3(&position))); - return result; - } - - DirectX::XMVECTOR m_position; - DirectX::XMVECTOR m_orientation; -}; - -class SpatialInputRenderer : public RenderableObject -{ -public: - SpatialInputRenderer(const std::shared_ptr& deviceResources); - - void Update( - winrt::Windows::Perception::PerceptionTimestamp timestamp, - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); - -private: - struct Joint - { - float3 position; - quaternion orientation; - float length; - float radius; - }; - -private: - static std::vector - CalculateJointVisualizationVertices(float3 jointPosition, quaternion jointOrientation, float jointLength, float jointRadius); - - void Draw(unsigned int numInstances) override; - - winrt::Windows::UI::Input::Spatial::SpatialInteractionManager m_manager{nullptr}; - winrt::Windows::Perception::Spatial::SpatialLocatorAttachedFrameOfReference m_referenceFrame{nullptr}; - std::vector m_transforms; - std::vector m_joints; -}; +//********************************************************* +// +// 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 "RenderableObject.h" +#include + +#include + +using namespace winrt::Windows::Foundation::Numerics; + +struct QTransform +{ + QTransform() = default; + QTransform(const DirectX::XMVECTOR& position, const DirectX::XMVECTOR& orientation) + : m_position(position) + , m_orientation(orientation) + { + } + QTransform(const float3& position, const quaternion& orientation) + : m_position(DirectX::XMLoadFloat3(&position)) + , m_orientation(DirectX::XMLoadQuaternion(&orientation)) + { + } + + DirectX::XMVECTOR TransformNormal(const DirectX::XMVECTOR& normal) const + { + return DirectX::XMVector3Rotate(normal, m_orientation); + } + + DirectX::XMVECTOR TransformPosition(const DirectX::XMVECTOR& position) const + { + DirectX::XMVECTOR rotated = TransformNormal(position); + return DirectX::XMVectorAdd(rotated, m_position); + } + + DirectX::XMFLOAT3 TransformPosition(const DirectX::XMFLOAT3& position) const + { + DirectX::XMFLOAT3 result; + XMStoreFloat3(&result, TransformPosition(DirectX::XMLoadFloat3(&position))); + return result; + } + + float3 TransformPosition(const float3& position) const + { + DirectX::XMFLOAT3 temp; + XMStoreFloat3(&temp, TransformPosition(DirectX::XMLoadFloat3(&position))); + return float3(temp.x, temp.y, temp.z); + } + + DirectX::XMVECTOR m_position; + DirectX::XMVECTOR m_orientation; +}; + +class SpatialInputRenderer : public RenderableObject +{ +public: + SpatialInputRenderer( + const std::shared_ptr& deviceResources, + winrt::Windows::UI::Input::Spatial::SpatialInteractionManager interactionManager); + + void Update( + winrt::Windows::Perception::PerceptionTimestamp timestamp, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); + +private: + struct Joint + { + float3 position; + quaternion orientation; + float length; + float radius; + }; + + struct ColoredTransform + { + ColoredTransform(const QTransform& transform, const DirectX::XMFLOAT3& color) + : m_transform(transform) + , m_color(color) + { + } + ColoredTransform(const float3& position, const quaternion& orientation, const DirectX::XMFLOAT3& colorIn) + : m_transform(position, orientation) + , m_color(colorIn) + { + } + QTransform m_transform; + DirectX::XMFLOAT3 m_color; + }; + +private: + static std::vector + CalculateJointVisualizationVertices(float3 jointPosition, quaternion jointOrientation, float jointLength, float jointRadius); + + void Draw(unsigned int numInstances) override; + + winrt::Windows::UI::Input::Spatial::SpatialInteractionManager m_interactionManager{nullptr}; + winrt::Windows::Perception::Spatial::SpatialLocatorAttachedFrameOfReference m_referenceFrame{nullptr}; + std::vector m_transforms; + std::vector m_joints; + std::vector m_coloredTransforms; +}; diff --git a/hostsampleapp/uwp/Content/SpatialSurfaceMeshRenderer.cpp b/remote/uwp/Content/SpatialSurfaceMeshRenderer.cpp similarity index 87% rename from hostsampleapp/uwp/Content/SpatialSurfaceMeshRenderer.cpp rename to remote/uwp/Content/SpatialSurfaceMeshRenderer.cpp index 12f51b4..7351408 100644 --- a/hostsampleapp/uwp/Content/SpatialSurfaceMeshRenderer.cpp +++ b/remote/uwp/Content/SpatialSurfaceMeshRenderer.cpp @@ -1,395 +1,423 @@ -//********************************************************* -// -// 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 "SpatialSurfaceMeshRenderer.h" - -#include "Common\DirectXHelper.h" - -using namespace winrt::Windows; -using namespace winrt::Windows::Perception::Spatial; -using namespace winrt::Windows::Graphics::DirectX; -using namespace winrt::Windows::Foundation::Numerics; -using namespace Concurrency; - -// for debugging -> remove -bool g_freeze = false; -bool g_freezeOnFrame = false; - -// Initializes D2D resources used for text rendering. -SpatialSurfaceMeshRenderer::SpatialSurfaceMeshRenderer(const std::shared_ptr& deviceResources) - : m_deviceResources(deviceResources) -{ - CreateDeviceDependentResources(); -} - -SpatialSurfaceMeshRenderer::~SpatialSurfaceMeshRenderer() -{ -} - - -std::future SpatialSurfaceMeshRenderer::CreateDeviceDependentResources() -{ - auto asyncAccess = Surfaces::SpatialSurfaceObserver::RequestAccessAsync(); - asyncAccess.Completed([this](auto handler, auto asyncStatus) { - m_surfaceObserver = Surfaces::SpatialSurfaceObserver(); - - m_observedSurfaceChangedToken = m_surfaceObserver.ObservedSurfacesChanged( - [this](Surfaces::SpatialSurfaceObserver, winrt::Windows::Foundation::IInspectable const& handler) { - OnObservedSurfaceChanged(); - }); - }); - - std::vector vertexShaderFileData = co_await DXHelper::ReadDataAsync(L"hsa_SRMeshVertexShader.cso"); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateVertexShader( - vertexShaderFileData.data(), vertexShaderFileData.size(), nullptr, m_vertexShader.put())); - - constexpr std::array vertexDesc = {{ - {"POSITION", 0, DXGI_FORMAT_R16G16B16A16_SNORM, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, - }}; - - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateInputLayout( - vertexDesc.data(), - static_cast(vertexDesc.size()), - vertexShaderFileData.data(), - static_cast(vertexShaderFileData.size()), - m_inputLayout.put())); - - std::vector geometryShaderFileData = co_await DXHelper::ReadDataAsync(L"hsa_SRMeshGeometryShader.cso"); - - // After the pass-through geometry shader file is loaded, create the shader. - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateGeometryShader( - geometryShaderFileData.data(), geometryShaderFileData.size(), nullptr, m_geometryShader.put())); - - std::vector pixelShaderFileData = co_await DXHelper::ReadDataAsync(L"hsa_SRMeshPixelShader.cso"); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreatePixelShader( - pixelShaderFileData.data(), pixelShaderFileData.size(), nullptr, m_pixelShader.put())); - - const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(SRMeshConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, m_modelConstantBuffer.put())); - - m_loadingComplete = true; -} - -void SpatialSurfaceMeshRenderer::ReleaseDeviceDependentResources() -{ - if (m_surfaceObserver) - { - m_surfaceObserver.ObservedSurfacesChanged(m_observedSurfaceChangedToken); - m_surfaceObserver = nullptr; - } - m_loadingComplete = false; - m_inputLayout = nullptr; - m_vertexShader = nullptr; - m_geometryShader = nullptr; - m_pixelShader = nullptr; - m_modelConstantBuffer = nullptr; -} - -void SpatialSurfaceMeshRenderer::OnObservedSurfaceChanged() -{ - if (g_freeze) - return; - - m_surfaceChangedCounter++; // just for debugging purposes - m_sufaceChanged = true; -} - -SpatialSurfaceMeshPart* SpatialSurfaceMeshRenderer::GetOrCreateMeshPart(winrt::guid id) -{ - GUID key = id; - auto found = m_meshParts.find(key); - if (found == m_meshParts.cend()) - { - m_meshParts[id] = std::make_unique(this); - return m_meshParts[id].get(); - } - - return found->second.get(); -} - -void SpatialSurfaceMeshRenderer::Update(winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) -{ - if (m_surfaceObserver == nullptr) - return; - - // update bounding volume (every frame) - { - SpatialBoundingBox axisAlignedBoundingBox = { - {-5.0f, -5.0f, -2.5f}, - {10.0f, 10.0f, 5.f}, - }; - - SpatialBoundingVolume volume = SpatialBoundingVolume::FromBox(renderingCoordinateSystem, axisAlignedBoundingBox); - m_surfaceObserver.SetBoundingVolume(volume); - } - - - if (m_sufaceChanged) - { - // first mark all as not used - for (auto& pair : m_meshParts) - { - pair.second->m_inUse = false; - } - - auto mapContainingSurfaceCollection = m_surfaceObserver.GetObservedSurfaces(); - - for (auto pair : mapContainingSurfaceCollection) - { - if (SpatialSurfaceMeshPart* meshPart = GetOrCreateMeshPart(pair.Key())) - { - meshPart->Update(pair.Value()); - g_freeze = g_freezeOnFrame; - } - } - - - // purge the ones not used - for (MeshPartMap::const_iterator itr = m_meshParts.cbegin(); itr != m_meshParts.cend();) - { - itr = itr->second->IsInUse() ? std::next(itr) : m_meshParts.erase(itr); - } - - m_sufaceChanged = false; - } - - // every frame, bring the model matrix to rendering space - for (auto& pair : m_meshParts) - { - pair.second->UpdateModelMatrix(renderingCoordinateSystem); - } -} - -void SpatialSurfaceMeshRenderer::Render(bool isStereo) -{ - if (!m_loadingComplete || m_meshParts.empty()) - return; - - m_deviceResources->UseD3DDeviceContext([&](auto context) { - // Each vertex is one instance of the VertexPositionColorTexture struct. - const uint32_t stride = sizeof(SpatialSurfaceMeshPart::Vertex_t); - const uint32_t offset = 0; - ID3D11Buffer* pBufferToSet; - 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. - pBufferToSet = m_modelConstantBuffer.get(); - context->VSSetConstantBuffers(0, 1, &pBufferToSet); - - // geometry shader - context->GSSetShader(m_geometryShader.get(), nullptr, 0); - - // pixel shader - context->PSSetShader(m_zfillOnly ? nullptr : m_pixelShader.get(), nullptr, 0); - - // Apply the model constant buffer to the pixel shader. - pBufferToSet = m_modelConstantBuffer.get(); - context->PSSetConstantBuffers(0, 1, &pBufferToSet); - - // render each mesh part - for (auto& pair : m_meshParts) - { - SpatialSurfaceMeshPart* part = pair.second.get(); - if (part->m_indexCount == 0) - continue; - - if (part->m_needsUpload) - { - part->UploadData(); - } - - // update part specific model matrix - context->UpdateSubresource(m_modelConstantBuffer.get(), 0, nullptr, &part->m_constantBufferData, 0, 0); - - ID3D11Buffer* pBufferToSet2 = part->m_vertexBuffer.get(); - context->IASetVertexBuffers(0, 1, &pBufferToSet2, &stride, &offset); - context->IASetIndexBuffer(part->m_indexBuffer.get(), DXGI_FORMAT_R16_UINT, 0); - // draw the mesh - context->DrawIndexedInstanced(part->m_indexCount, isStereo ? 2 : 1, 0, 0, 0); - } - - // set geometry shader back - context->GSSetShader(nullptr, nullptr, 0); - }); -} - - - -////////////////////////////////////////////////////////////////////////////////////////////////////////// -// SRMeshPart -////////////////////////////////////////////////////////////////////////////////////////////////////////// - -SpatialSurfaceMeshPart::SpatialSurfaceMeshPart(SpatialSurfaceMeshRenderer* owner) - : m_owner(owner) -{ - auto identity = DirectX::XMMatrixIdentity(); - m_constantBufferData.modelMatrix = reinterpret_cast(identity); - m_vertexScale.x = m_vertexScale.y = m_vertexScale.z = 1.0f; -} - - - -void SpatialSurfaceMeshPart::Update(Surfaces::SpatialSurfaceInfo surfaceInfo) -{ - m_inUse = true; - m_updateInProgress = true; - double TriangleDensity = 750.0; // from Hydrogen - auto asyncOpertation = surfaceInfo.TryComputeLatestMeshAsync(TriangleDensity); - asyncOpertation.Completed([this](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { - Surfaces::SpatialSurfaceMesh mesh = result.GetResults(); - UpdateMesh(mesh); - m_updateInProgress = false; - }); -} - - - -void SpatialSurfaceMeshPart::UpdateModelMatrix(winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) -{ - if (m_coordinateSystem == nullptr) - return; - - auto modelTransform = m_coordinateSystem.TryGetTransformTo(renderingCoordinateSystem); - if (modelTransform) - { - float4x4 matrixWinRt = transpose(modelTransform.Value()); - DirectX::XMMATRIX transformMatrix = DirectX::XMLoadFloat4x4(&matrixWinRt); - DirectX::XMMATRIX scaleMatrix = DirectX::XMMatrixScaling(m_vertexScale.x, m_vertexScale.y, m_vertexScale.z); - DirectX::XMMATRIX result = DirectX::XMMatrixMultiply(transformMatrix, scaleMatrix); - DirectX::XMStoreFloat4x4(&m_constantBufferData.modelMatrix, result); - } -} - - -void SpatialSurfaceMeshPart::UpdateMesh(Surfaces::SpatialSurfaceMesh mesh) -{ - m_coordinateSystem = mesh.CoordinateSystem(); - - Surfaces::SpatialSurfaceMeshBuffer vertexBuffer = mesh.VertexPositions(); - Surfaces::SpatialSurfaceMeshBuffer indexBuffer = mesh.TriangleIndices(); - - DirectXPixelFormat vertexFormat = vertexBuffer.Format(); - DirectXPixelFormat indexFormat = indexBuffer.Format(); - - assert(vertexFormat == DirectXPixelFormat::R16G16B16A16IntNormalized); - assert(indexFormat == DirectXPixelFormat::R16UInt); - - uint32_t vertexCount = vertexBuffer.ElementCount(); - uint32_t indexCount = indexBuffer.ElementCount(); - assert((indexCount % 3) == 0); - - if (vertexCount == 0 || indexCount == 0) - { - m_indexCount = 0; - return; - } - - // convert vertices: - { - Vertex_t* dest = MapVertices(vertexCount); - winrt::Windows::Storage::Streams::IBuffer vertexData = vertexBuffer.Data(); - uint8_t* vertexRaw = vertexData.data(); - int vertexStride = vertexData.Length() / vertexCount; - assert(vertexStride == 8); // DirectXPixelFormat::R16G16B16A16IntNormalized - winrt::Windows::Foundation::Numerics::float3 positionScale = mesh.VertexPositionScale(); - m_vertexScale.x = positionScale.x; - m_vertexScale.y = positionScale.y; - m_vertexScale.z = positionScale.z; - memcpy(dest, vertexRaw, vertexCount * sizeof(Vertex_t)); - UnmapVertices(); - } - - // convert indices - { - uint16_t* dest = MapIndices(indexCount); - winrt::Windows::Storage::Streams::IBuffer indexData = indexBuffer.Data(); - uint16_t* source = (uint16_t*)indexData.data(); - for (uint32_t i = 0; i < indexCount; i++) - { - assert(source[i] < vertexCount); - dest[i] = source[i]; - } - UnmapIndices(); - } - m_needsUpload = true; -} - -SpatialSurfaceMeshPart::Vertex_t* SpatialSurfaceMeshPart::MapVertices(uint32_t vertexCount) -{ - m_vertexCount = vertexCount; - if (vertexCount > m_vertexData.size()) - m_vertexData.resize(vertexCount); - return &m_vertexData[0]; -} - -void SpatialSurfaceMeshPart::UnmapVertices() -{ -} - -uint16_t* SpatialSurfaceMeshPart::MapIndices(uint32_t indexCount) -{ - m_indexCount = indexCount; - if (indexCount > m_indexData.size()) - m_indexData.resize(indexCount); - return &m_indexData[0]; -} - -void SpatialSurfaceMeshPart::UnmapIndices() -{ -} - -void SpatialSurfaceMeshPart::UploadData() -{ - if (m_vertexCount > m_allocatedVertexCount) - { - m_vertexBuffer = nullptr; - - const int alignment = 1024; - m_allocatedVertexCount = ((m_vertexCount + alignment - 1) / alignment) * alignment; // align to reasonable size - - const int elementSize = sizeof(Vertex_t); - const CD3D11_BUFFER_DESC vertexBufferDesc( - m_allocatedVertexCount * elementSize, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - - winrt::check_hresult(m_owner->m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, nullptr, m_vertexBuffer.put())); - } - - if (m_indexCount > m_allocatedIndexCount) - { - m_indexBuffer = nullptr; - const int alignment = 3 * 1024; - m_allocatedIndexCount = ((m_indexCount + alignment - 1) / alignment) * alignment; // align to reasonable size - - const int elementSize = sizeof(uint16_t); - const CD3D11_BUFFER_DESC indexBufferDesc( - m_allocatedIndexCount * elementSize, D3D11_BIND_INDEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - - winrt::check_hresult(m_owner->m_deviceResources->GetD3DDevice()->CreateBuffer(&indexBufferDesc, nullptr, m_indexBuffer.put())); - } - - // upload data - D3D11_MAPPED_SUBRESOURCE resource; - - m_owner->m_deviceResources->UseD3DDeviceContext([&](auto context) { - context->Map(m_vertexBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); - memcpy(resource.pData, &m_vertexData[0], sizeof(Vertex_t) * m_vertexCount); - context->Unmap(m_vertexBuffer.get(), 0); - - context->Map(m_indexBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); - memcpy(resource.pData, &m_indexData[0], sizeof(uint16_t) * m_indexCount); - context->Unmap(m_indexBuffer.get(), 0); - }); -} +//********************************************************* +// +// 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 "SpatialSurfaceMeshRenderer.h" + +#include "Common\DirectXHelper.h" + +using namespace winrt::Windows; +using namespace winrt::Windows::Perception::Spatial; +using namespace winrt::Windows::Graphics::DirectX; +using namespace winrt::Windows::Foundation::Numerics; +using namespace Concurrency; + +// for debugging -> remove +bool g_freeze = false; +bool g_freezeOnFrame = false; + +// Initializes D2D resources used for text rendering. +SpatialSurfaceMeshRenderer::SpatialSurfaceMeshRenderer(const std::shared_ptr& deviceResources) + : m_deviceResources(deviceResources) +{ + CreateDeviceDependentResources(); + + m_spatialLocator = SpatialLocator::GetDefault(); + if (m_spatialLocator) + { + m_spatialLocatorLocabilityChangedEventRevoker = + m_spatialLocator.LocatabilityChanged(winrt::auto_revoke, {this, &SpatialSurfaceMeshRenderer::OnLocatibilityChanged}); + + m_attachedFrameOfReference = m_spatialLocator.CreateAttachedFrameOfReferenceAtCurrentHeading(); + } +} + +SpatialSurfaceMeshRenderer::~SpatialSurfaceMeshRenderer() +{ +} + +std::future SpatialSurfaceMeshRenderer::CreateDeviceDependentResources() +{ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + std::wstring fileNamePrefix = L""; +#else + std::wstring fileNamePrefix = L"ms-appx:///"; +#endif + + auto asyncAccess = Surfaces::SpatialSurfaceObserver::RequestAccessAsync(); + asyncAccess.Completed([this](auto handler, auto asyncStatus) { + m_surfaceObserver = Surfaces::SpatialSurfaceObserver(); + + m_observedSurfaceChangedToken = m_surfaceObserver.ObservedSurfacesChanged( + [this](Surfaces::SpatialSurfaceObserver, winrt::Windows::Foundation::IInspectable const& handler) { + OnObservedSurfaceChanged(); + }); + }); + + std::vector vertexShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_SRMeshVertexShader.cso"); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateVertexShader( + vertexShaderFileData.data(), vertexShaderFileData.size(), nullptr, m_vertexShader.put())); + + constexpr std::array vertexDesc = {{ + {"POSITION", 0, DXGI_FORMAT_R16G16B16A16_SNORM, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }}; + + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateInputLayout( + vertexDesc.data(), + static_cast(vertexDesc.size()), + vertexShaderFileData.data(), + static_cast(vertexShaderFileData.size()), + m_inputLayout.put())); + + std::vector geometryShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_SRMeshGeometryShader.cso"); + + // After the pass-through geometry shader file is loaded, create the shader. + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateGeometryShader( + geometryShaderFileData.data(), geometryShaderFileData.size(), nullptr, m_geometryShader.put())); + + std::vector pixelShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_SRMeshPixelShader.cso"); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreatePixelShader( + pixelShaderFileData.data(), pixelShaderFileData.size(), nullptr, m_pixelShader.put())); + + const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(SRMeshConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, m_modelConstantBuffer.put())); + + m_loadingComplete = true; +} + +void SpatialSurfaceMeshRenderer::ReleaseDeviceDependentResources() +{ + if (m_surfaceObserver) + { + m_surfaceObserver.ObservedSurfacesChanged(m_observedSurfaceChangedToken); + m_surfaceObserver = nullptr; + } + m_loadingComplete = false; + m_inputLayout = nullptr; + m_vertexShader = nullptr; + m_geometryShader = nullptr; + m_pixelShader = nullptr; + m_modelConstantBuffer = nullptr; +} + +void SpatialSurfaceMeshRenderer::OnObservedSurfaceChanged() +{ + if (g_freeze) + return; + + m_surfaceChangedCounter++; // just for debugging purposes + m_sufaceChanged = true; +} + +void SpatialSurfaceMeshRenderer::OnLocatibilityChanged( + const SpatialLocator& spatialLocator, const winrt::Windows::Foundation::IInspectable&) +{ + SpatialLocatability locatibility = spatialLocator.Locatability(); + if (locatibility != SpatialLocatability::PositionalTrackingActive) + { + m_meshParts.clear(); + } +} + +SpatialSurfaceMeshPart* SpatialSurfaceMeshRenderer::GetOrCreateMeshPart(winrt::guid id) +{ + GUID key = id; + auto found = m_meshParts.find(key); + if (found == m_meshParts.cend()) + { + m_meshParts[id] = std::make_unique(this); + return m_meshParts[id].get(); + } + + return found->second.get(); +} + +void SpatialSurfaceMeshRenderer::Update( + winrt::Windows::Perception::PerceptionTimestamp timestamp, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) +{ + if (m_surfaceObserver == nullptr) + return; + + // update bounding volume (every frame) + { + SpatialBoundingBox axisAlignedBoundingBox = { + {-5.0f, -5.0f, -2.5f}, + {10.0f, 10.0f, 5.f}, + }; + + using namespace std::chrono_literals; + auto now = std::chrono::high_resolution_clock::now(); + auto delta = now - m_boundingVolumeUpdateTime; + + if (m_attachedFrameOfReference && delta > 1s) + { + SpatialCoordinateSystem attachedCoordinateSystem = + m_attachedFrameOfReference.GetStationaryCoordinateSystemAtTimestamp(timestamp); + SpatialBoundingVolume volume = SpatialBoundingVolume::FromBox(attachedCoordinateSystem, axisAlignedBoundingBox); + m_surfaceObserver.SetBoundingVolume(volume); + + m_boundingVolumeUpdateTime = now; + } + } + + if (m_sufaceChanged) + { + // first mark all as not used + for (auto& pair : m_meshParts) + { + pair.second->m_inUse = false; + } + + auto mapContainingSurfaceCollection = m_surfaceObserver.GetObservedSurfaces(); + + for (auto pair : mapContainingSurfaceCollection) + { + if (SpatialSurfaceMeshPart* meshPart = GetOrCreateMeshPart(pair.Key())) + { + meshPart->Update(pair.Value()); + g_freeze = g_freezeOnFrame; + } + } + + // purge the ones not used + for (MeshPartMap::const_iterator itr = m_meshParts.cbegin(); itr != m_meshParts.cend();) + { + itr = itr->second->IsInUse() ? std::next(itr) : m_meshParts.erase(itr); + } + + m_sufaceChanged = false; + } + + // every frame, bring the model matrix to rendering space + for (auto& pair : m_meshParts) + { + pair.second->UpdateModelMatrix(renderingCoordinateSystem); + } +} + +void SpatialSurfaceMeshRenderer::Render(bool isStereo) +{ + if (!m_loadingComplete || m_meshParts.empty()) + return; + + m_deviceResources->UseD3DDeviceContext([&](auto context) { + // Each vertex is one instance of the VertexPositionColorTexture struct. + const uint32_t stride = sizeof(SpatialSurfaceMeshPart::Vertex_t); + const uint32_t offset = 0; + ID3D11Buffer* pBufferToSet; + 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. + pBufferToSet = m_modelConstantBuffer.get(); + context->VSSetConstantBuffers(0, 1, &pBufferToSet); + + // geometry shader + context->GSSetShader(m_geometryShader.get(), nullptr, 0); + + // pixel shader + context->PSSetShader(m_zfillOnly ? nullptr : m_pixelShader.get(), nullptr, 0); + + // Apply the model constant buffer to the pixel shader. + pBufferToSet = m_modelConstantBuffer.get(); + context->PSSetConstantBuffers(0, 1, &pBufferToSet); + + // render each mesh part + for (auto& pair : m_meshParts) + { + SpatialSurfaceMeshPart* part = pair.second.get(); + if (part->m_indexCount == 0) + continue; + + if (part->m_needsUpload) + { + part->UploadData(); + } + + // update part specific model matrix + context->UpdateSubresource(m_modelConstantBuffer.get(), 0, nullptr, &part->m_constantBufferData, 0, 0); + + ID3D11Buffer* pBufferToSet2 = part->m_vertexBuffer.get(); + context->IASetVertexBuffers(0, 1, &pBufferToSet2, &stride, &offset); + context->IASetIndexBuffer(part->m_indexBuffer.get(), DXGI_FORMAT_R16_UINT, 0); + // draw the mesh + context->DrawIndexedInstanced(part->m_indexCount, isStereo ? 2 : 1, 0, 0, 0); + } + + // set geometry shader back + context->GSSetShader(nullptr, nullptr, 0); + }); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SRMeshPart +////////////////////////////////////////////////////////////////////////////////////////////////////////// + +SpatialSurfaceMeshPart::SpatialSurfaceMeshPart(SpatialSurfaceMeshRenderer* owner) + : m_owner(owner) +{ + auto identity = DirectX::XMMatrixIdentity(); + m_constantBufferData.modelMatrix = reinterpret_cast(identity); + m_vertexScale.x = m_vertexScale.y = m_vertexScale.z = 1.0f; +} + +void SpatialSurfaceMeshPart::Update(Surfaces::SpatialSurfaceInfo surfaceInfo) +{ + m_inUse = true; + m_updateInProgress = true; + double TriangleDensity = 750.0; // from Hydrogen + auto asyncOpertation = surfaceInfo.TryComputeLatestMeshAsync(TriangleDensity); + asyncOpertation.Completed([this](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { + Surfaces::SpatialSurfaceMesh mesh = result.GetResults(); + UpdateMesh(mesh); + m_updateInProgress = false; + }); +} + +void SpatialSurfaceMeshPart::UpdateModelMatrix(winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) +{ + if (m_coordinateSystem == nullptr) + return; + + auto modelTransform = m_coordinateSystem.TryGetTransformTo(renderingCoordinateSystem); + if (modelTransform) + { + float4x4 matrixWinRt = transpose(modelTransform.Value()); + DirectX::XMMATRIX transformMatrix = DirectX::XMLoadFloat4x4(&matrixWinRt); + DirectX::XMMATRIX scaleMatrix = DirectX::XMMatrixScaling(m_vertexScale.x, m_vertexScale.y, m_vertexScale.z); + DirectX::XMMATRIX result = DirectX::XMMatrixMultiply(transformMatrix, scaleMatrix); + DirectX::XMStoreFloat4x4(&m_constantBufferData.modelMatrix, result); + } +} + +void SpatialSurfaceMeshPart::UpdateMesh(Surfaces::SpatialSurfaceMesh mesh) +{ + m_coordinateSystem = mesh.CoordinateSystem(); + + Surfaces::SpatialSurfaceMeshBuffer vertexBuffer = mesh.VertexPositions(); + Surfaces::SpatialSurfaceMeshBuffer indexBuffer = mesh.TriangleIndices(); + + DirectXPixelFormat vertexFormat = vertexBuffer.Format(); + DirectXPixelFormat indexFormat = indexBuffer.Format(); + + assert(vertexFormat == DirectXPixelFormat::R16G16B16A16IntNormalized); + assert(indexFormat == DirectXPixelFormat::R16UInt); + + uint32_t vertexCount = vertexBuffer.ElementCount(); + uint32_t indexCount = indexBuffer.ElementCount(); + assert((indexCount % 3) == 0); + + if (vertexCount == 0 || indexCount == 0) + { + m_indexCount = 0; + return; + } + + // convert vertices: + { + Vertex_t* dest = MapVertices(vertexCount); + winrt::Windows::Storage::Streams::IBuffer vertexData = vertexBuffer.Data(); + uint8_t* vertexRaw = vertexData.data(); + int vertexStride = vertexData.Length() / vertexCount; + assert(vertexStride == 8); // DirectXPixelFormat::R16G16B16A16IntNormalized + winrt::Windows::Foundation::Numerics::float3 positionScale = mesh.VertexPositionScale(); + m_vertexScale.x = positionScale.x; + m_vertexScale.y = positionScale.y; + m_vertexScale.z = positionScale.z; + memcpy(dest, vertexRaw, vertexCount * sizeof(Vertex_t)); + UnmapVertices(); + } + + // convert indices + { + uint16_t* dest = MapIndices(indexCount); + winrt::Windows::Storage::Streams::IBuffer indexData = indexBuffer.Data(); + uint16_t* source = (uint16_t*)indexData.data(); + for (uint32_t i = 0; i < indexCount; i++) + { + assert(source[i] < vertexCount); + dest[i] = source[i]; + } + UnmapIndices(); + } + m_needsUpload = true; +} + +SpatialSurfaceMeshPart::Vertex_t* SpatialSurfaceMeshPart::MapVertices(uint32_t vertexCount) +{ + m_vertexCount = vertexCount; + if (vertexCount > m_vertexData.size()) + m_vertexData.resize(vertexCount); + return &m_vertexData[0]; +} + +void SpatialSurfaceMeshPart::UnmapVertices() +{ +} + +uint16_t* SpatialSurfaceMeshPart::MapIndices(uint32_t indexCount) +{ + m_indexCount = indexCount; + if (indexCount > m_indexData.size()) + m_indexData.resize(indexCount); + return &m_indexData[0]; +} + +void SpatialSurfaceMeshPart::UnmapIndices() +{ +} + +void SpatialSurfaceMeshPart::UploadData() +{ + if (m_vertexCount > m_allocatedVertexCount) + { + m_vertexBuffer = nullptr; + + const int alignment = 1024; + m_allocatedVertexCount = ((m_vertexCount + alignment - 1) / alignment) * alignment; // align to reasonable size + + const int elementSize = sizeof(Vertex_t); + const CD3D11_BUFFER_DESC vertexBufferDesc( + m_allocatedVertexCount * elementSize, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + + winrt::check_hresult(m_owner->m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, nullptr, m_vertexBuffer.put())); + } + + if (m_indexCount > m_allocatedIndexCount) + { + m_indexBuffer = nullptr; + const int alignment = 3 * 1024; + m_allocatedIndexCount = ((m_indexCount + alignment - 1) / alignment) * alignment; // align to reasonable size + + const int elementSize = sizeof(uint16_t); + const CD3D11_BUFFER_DESC indexBufferDesc( + m_allocatedIndexCount * elementSize, D3D11_BIND_INDEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + + winrt::check_hresult(m_owner->m_deviceResources->GetD3DDevice()->CreateBuffer(&indexBufferDesc, nullptr, m_indexBuffer.put())); + } + + // upload data + D3D11_MAPPED_SUBRESOURCE resource; + + m_owner->m_deviceResources->UseD3DDeviceContext([&](auto context) { + context->Map(m_vertexBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); + memcpy(resource.pData, &m_vertexData[0], sizeof(Vertex_t) * m_vertexCount); + context->Unmap(m_vertexBuffer.get(), 0); + + context->Map(m_indexBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); + memcpy(resource.pData, &m_indexData[0], sizeof(uint16_t) * m_indexCount); + context->Unmap(m_indexBuffer.get(), 0); + }); +} diff --git a/hostsampleapp/desktop/Content/SpatialSurfaceMeshRenderer.h b/remote/uwp/Content/SpatialSurfaceMeshRenderer.h similarity index 77% rename from hostsampleapp/desktop/Content/SpatialSurfaceMeshRenderer.h rename to remote/uwp/Content/SpatialSurfaceMeshRenderer.h index 437045b..0912b51 100644 --- a/hostsampleapp/desktop/Content/SpatialSurfaceMeshRenderer.h +++ b/remote/uwp/Content/SpatialSurfaceMeshRenderer.h @@ -1,130 +1,141 @@ -//********************************************************* -// -// 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 "..\Common\DeviceResources.h" -#include "..\Common\Utils.h" - -#include - -#include -#include - -// forward -class SpatialSurfaceMeshRenderer; - -struct SRMeshConstantBuffer -{ - DirectX::XMFLOAT4X4 modelMatrix; -}; - -// represents a single piece of mesh (SpatialSurfaceMesh) -class SpatialSurfaceMeshPart -{ -public: - struct Vertex_t - { - // float pos[4]; - int16_t pos[4]; - }; - SpatialSurfaceMeshPart(SpatialSurfaceMeshRenderer* owner); - void Update(winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceInfo surfaceInfo); - - void UpdateMesh(winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceMesh mesh); - - bool IsInUse() const - { - return m_inUse || m_updateInProgress; - } - -private: - Vertex_t* MapVertices(uint32_t vertexCount); - void UnmapVertices(); - uint16_t* MapIndices(uint32_t indexCount); - void UnmapIndices(); - void UploadData(); - void UpdateModelMatrix(winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); - - friend class SpatialSurfaceMeshRenderer; - SpatialSurfaceMeshRenderer* m_owner; - bool m_inUse = true; - bool m_needsUpload = false; - bool m_updateInProgress = false; - - GUID m_ID; - uint32_t m_allocatedVertexCount = 0; - uint32_t m_allocatedIndexCount = 0; - uint32_t m_vertexCount = 0; - uint32_t m_indexCount = 0; - winrt::com_ptr m_vertexBuffer; - winrt::com_ptr m_indexBuffer; - - winrt::Windows::Perception::Spatial::SpatialCoordinateSystem m_coordinateSystem = nullptr; - - // double buffered data: - std::vector m_vertexData; - std::vector m_indexData; - SRMeshConstantBuffer m_constantBufferData; - DirectX::XMFLOAT3 m_vertexScale; -}; - - -// Renders the SR mesh -class SpatialSurfaceMeshRenderer -{ -public: - SpatialSurfaceMeshRenderer(const std::shared_ptr& deviceResources); - virtual ~SpatialSurfaceMeshRenderer(); - - void Update(winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); - - void Render(bool isStereo); - - std::future CreateDeviceDependentResources(); - void ReleaseDeviceDependentResources(); - -private: - void OnObservedSurfaceChanged(); - SpatialSurfaceMeshPart* GetOrCreateMeshPart(winrt::guid id); - -private: - friend class SpatialSurfaceMeshPart; - - // Cached pointer to device resources. - std::shared_ptr m_deviceResources; - - // Resources related to mesh rendering. - winrt::com_ptr m_shaderResourceView; - winrt::com_ptr m_pointSampler; - winrt::com_ptr m_renderTargetView; - - // observer: - int m_surfaceChangedCounter = 0; - bool m_sufaceChanged = false; - winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceObserver m_surfaceObserver = nullptr; - winrt::event_token m_observedSurfaceChangedToken; - - // mesh parts - using MeshPartMap = std::map, GUIDComparer>; - MeshPartMap m_meshParts; - - // rendering - bool m_zfillOnly = false; - bool m_loadingComplete = false; - winrt::com_ptr m_inputLayout; - - winrt::com_ptr m_vertexShader; - winrt::com_ptr m_geometryShader; - winrt::com_ptr m_pixelShader; - - winrt::com_ptr m_modelConstantBuffer; -}; +//********************************************************* +// +// 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 "..\Common\DeviceResources.h" +#include "..\Common\Utils.h" + +#include + +#include +#include + +// forward +class SpatialSurfaceMeshRenderer; + +struct SRMeshConstantBuffer +{ + DirectX::XMFLOAT4X4 modelMatrix; +}; + +// Assert that the constant buffer remains 16-byte aligned (best practice). +static_assert( + (sizeof(SRMeshConstantBuffer) % (sizeof(float) * 4)) == 0, + "SR mesh constant buffer size must be 16-byte aligned (16 bytes is the length of four floats)."); + +// represents a single piece of mesh (SpatialSurfaceMesh) +class SpatialSurfaceMeshPart +{ +public: + struct Vertex_t + { + // float pos[4]; + int16_t pos[4]; + }; + SpatialSurfaceMeshPart(SpatialSurfaceMeshRenderer* owner); + void Update(winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceInfo surfaceInfo); + + void UpdateMesh(winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceMesh mesh); + + bool IsInUse() const + { + return m_inUse || m_updateInProgress; + } + +private: + Vertex_t* MapVertices(uint32_t vertexCount); + void UnmapVertices(); + uint16_t* MapIndices(uint32_t indexCount); + void UnmapIndices(); + void UploadData(); + void UpdateModelMatrix(winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); + + friend class SpatialSurfaceMeshRenderer; + SpatialSurfaceMeshRenderer* m_owner; + bool m_inUse = true; + bool m_needsUpload = false; + bool m_updateInProgress = false; + + GUID m_ID; + uint32_t m_allocatedVertexCount = 0; + uint32_t m_allocatedIndexCount = 0; + uint32_t m_vertexCount = 0; + uint32_t m_indexCount = 0; + winrt::com_ptr m_vertexBuffer; + winrt::com_ptr m_indexBuffer; + + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem m_coordinateSystem = nullptr; + + // double buffered data: + std::vector m_vertexData; + std::vector m_indexData; + SRMeshConstantBuffer m_constantBufferData; + DirectX::XMFLOAT3 m_vertexScale; +}; + +// Renders the SR mesh +class SpatialSurfaceMeshRenderer +{ +public: + SpatialSurfaceMeshRenderer(const std::shared_ptr& deviceResources); + virtual ~SpatialSurfaceMeshRenderer(); + + void Update( + winrt::Windows::Perception::PerceptionTimestamp timestamp, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); + + void Render(bool isStereo); + + std::future CreateDeviceDependentResources(); + void ReleaseDeviceDependentResources(); + +private: + void OnObservedSurfaceChanged(); + void OnLocatibilityChanged( + const winrt::Windows::Perception::Spatial::SpatialLocator& spatialLocator, const winrt::Windows::Foundation::IInspectable&); + SpatialSurfaceMeshPart* GetOrCreateMeshPart(winrt::guid id); + +private: + friend class SpatialSurfaceMeshPart; + + // Cached pointer to device resources. + std::shared_ptr m_deviceResources; + + // observer: + int m_surfaceChangedCounter = 0; + bool m_sufaceChanged = false; + winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceObserver m_surfaceObserver = nullptr; + winrt::event_token m_observedSurfaceChangedToken; + + // mesh parts + using MeshPartMap = std::map, GUIDComparer>; + MeshPartMap m_meshParts; + + // rendering + bool m_zfillOnly = false; + bool m_loadingComplete = false; + winrt::com_ptr m_inputLayout; + + winrt::com_ptr m_vertexShader; + winrt::com_ptr m_geometryShader; + winrt::com_ptr m_pixelShader; + + winrt::com_ptr m_modelConstantBuffer; + + winrt::Windows::Perception::Spatial::SpatialLocator m_spatialLocator = nullptr; + winrt::Windows::Perception::Spatial::SpatialLocator::LocatabilityChanged_revoker m_spatialLocatorLocabilityChangedEventRevoker; + + // A attached frame of reference based on m_spatialLocator. + winrt::Windows::Perception::Spatial::SpatialLocatorAttachedFrameOfReference m_attachedFrameOfReference = nullptr; + + std::chrono::time_point m_boundingVolumeUpdateTime; +}; diff --git a/hostsampleapp/uwp/Content/SpinningCubeRenderer.cpp b/remote/uwp/Content/SpinningCubeRenderer.cpp similarity index 89% rename from hostsampleapp/uwp/Content/SpinningCubeRenderer.cpp rename to remote/uwp/Content/SpinningCubeRenderer.cpp index b1c4219..d680c23 100644 --- a/hostsampleapp/uwp/Content/SpinningCubeRenderer.cpp +++ b/remote/uwp/Content/SpinningCubeRenderer.cpp @@ -1,347 +1,353 @@ -//********************************************************* -// -// 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 "../Common/DirectXHelper.h" -#include "SpinningCubeRenderer.h" - -#include -#include -#include - -using namespace DirectX; - -// Loads vertex and pixel shaders from files and instantiates the cube geometry. -SpinningCubeRenderer::SpinningCubeRenderer(const std::shared_ptr& deviceResources) - : m_deviceResources(deviceResources) -{ - CreateDeviceDependentResources(); -} - -// This function uses a SpatialPointerPose to position the world-locked hologram -// two meters in front of the user's heading. -void SpinningCubeRenderer::PositionHologram(const winrt::Windows::UI::Input::Spatial::SpatialPointerPose& pointerPose) -{ - if (pointerPose != nullptr) - { - // Try to get the gaze from eyes. - winrt::Windows::Perception::People::EyesPose eyesPose = pointerPose.Eyes(); - if (eyesPose != nullptr) - { - winrt::Windows::Foundation::IReference gaze = eyesPose.Gaze(); - if (gaze != nullptr) - { - PositionHologram(gaze.Value().Origin, gaze.Value().Direction); - return; - } - } - - // Get the gaze direction from head. - const auto headPosition = pointerPose.Head().Position(); - const auto headDirection = pointerPose.Head().ForwardDirection(); - - PositionHologram(headPosition, headDirection); - } -} - -void SpinningCubeRenderer::SetColorFilter(DirectX::XMFLOAT4 color) -{ - m_filterColorData = color; -} - -// This function uses a point and a vector to position the world-locked hologram -// two meters in front of the user's heading. -void SpinningCubeRenderer::PositionHologram( - winrt::Windows::Foundation::Numerics::float3 headPosition, winrt::Windows::Foundation::Numerics::float3 headDirection) -{ - // The hologram is positioned two meters along the user's gaze direction. - static const float distanceFromUser = 2.0f; // meters - const auto 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(float totalSeconds) -{ - // Rotate the cube. - // Convert degrees to radians, then convert seconds to rotation angle. - const float radiansPerSecond = XMConvertToRadians(m_degreesPerSecond); - const double relativeRotation = totalSeconds * radiansPerSecond; - double totalRotation = m_rotationOffset; - switch (m_pauseState) - { - case PauseState::Unpaused: - totalRotation += relativeRotation; - break; - - case PauseState::Pausing: - m_rotationOffset += relativeRotation; - m_pauseState = PauseState::Paused; - case PauseState::Paused: - totalRotation = m_rotationOffset; - break; - - case PauseState::Unpausing: - m_rotationOffset -= relativeRotation; - m_pauseState = PauseState::Unpaused; - break; - } - const float radians = static_cast(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); - - // Store the normal transform. - XMStoreFloat4x4(&m_modelConstantBufferData.normal, XMMatrixTranspose(modelRotation)); - - // 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. - m_deviceResources->UseD3DDeviceContext([&](auto context) { - // 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(bool isStereo) -{ - // Loading is asynchronous. Resources must be created before drawing can occur. - if (!m_loadingComplete) - { - return; - } - - m_deviceResources->UseD3DDeviceContext([&](auto context) { - ID3D11Buffer* pBufferToSet = nullptr; - - // Each vertex is one instance of the VertexPositionColor struct. - const UINT stride = sizeof(VertexPositionNormalColor); - const UINT offset = 0; - - pBufferToSet = m_vertexBuffer.get(); - context->IASetVertexBuffers(0, 1, &pBufferToSet, &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. - pBufferToSet = m_modelConstantBuffer.get(); - context->VSSetConstantBuffers(0, 1, &pBufferToSet); - - 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); - } - - context->UpdateSubresource(m_filterColorBuffer.get(), 0, nullptr, &m_filterColorData, 0, 0); - - pBufferToSet = m_filterColorBuffer.get(); - context->PSSetConstantBuffers(2, 1, &pBufferToSet); - - // Attach the pixel shader. - context->PSSetShader(m_pixelShader.get(), nullptr, 0); - - // Draw the objects. - context->DrawIndexedInstanced( - m_indexCount, // Index count per instance. - isStereo ? 2 : 1, // Instance count. - 0, // Start index location. - 0, // Base vertex location. - 0 // Start instance location. - ); - }); -} - -std::future SpinningCubeRenderer::CreateDeviceDependentResources() -{ -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - std::wstring fileNamePrefix = L""; -#else - std::wstring fileNamePrefix = L"ms-appx:///"; -#endif - - 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"hsa_VprtVertexShader.cso" : L"hsa_VertexShader.cso"; - - std::vector vertexShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + vertexShaderFileName); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateVertexShader( - vertexShaderFileData.data(), vertexShaderFileData.size(), nullptr, m_vertexShader.put())); - - constexpr std::array vertexDesc = {{ - {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, - }}; - - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateInputLayout( - vertexDesc.data(), - static_cast(vertexDesc.size()), - vertexShaderFileData.data(), - static_cast(vertexShaderFileData.size()), - m_inputLayout.put())); - - std::vector pixelShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_PixelShader.cso"); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreatePixelShader( - pixelShaderFileData.data(), pixelShaderFileData.size(), nullptr, m_pixelShader.put())); - - const ModelConstantBuffer constantBuffer{ - reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), - reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), - }; - - const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, m_modelConstantBuffer.put())); - - const CD3D11_BUFFER_DESC filterColorBufferDesc(sizeof(XMFLOAT4), D3D11_BIND_CONSTANT_BUFFER); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&filterColorBufferDesc, nullptr, m_filterColorBuffer.put())); - - if (!m_usingVprtShaders) - { - // Load the pass-through geometry shader. - std::vector geometryShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_GeometryShader.cso"); - - // After the pass-through geometry shader file is loaded, create the shader. - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateGeometryShader( - geometryShaderFileData.data(), geometryShaderFileData.size(), nullptr, m_geometryShader.put())); - } - - // 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 VertexPositionNormalColor cubeVertices[] = { - {XMFLOAT3(-0.1f, -0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 0.0f, 0.0f)}, // vertex 0 non-debug - {XMFLOAT3(-0.1f, -0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 0.0f, 1.0f)}, - {XMFLOAT3(-0.1f, 0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 1.0f, 0.0f)}, - {XMFLOAT3(-0.1f, 0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 1.0f, 1.0f)}, - {XMFLOAT3(0.1f, -0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 0.0f, 0.0f)}, - {XMFLOAT3(0.1f, -0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 0.0f, 1.0f)}, - {XMFLOAT3(0.1f, 0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 1.0f, 0.0f)}, - {XMFLOAT3(0.1f, 0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 1.0f, 1.0f)}, - }; - - D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; - vertexBufferData.pSysMem = cubeVertices; - vertexBufferData.SysMemPitch = 0; - vertexBufferData.SysMemSlicePitch = 0; - const CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, m_vertexBuffer.put())); - - // 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. - static const unsigned short 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 = ARRAYSIZE(cubeIndices); - - D3D11_SUBRESOURCE_DATA indexBufferData = {0}; - indexBufferData.pSysMem = cubeIndices; - indexBufferData.SysMemPitch = 0; - indexBufferData.SysMemSlicePitch = 0; - const CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER); - winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&indexBufferDesc, &indexBufferData, m_indexBuffer.put())); - - // Once the cube is loaded, the object is ready to be rendered. - m_loadingComplete = true; -} - -void SpinningCubeRenderer::ReleaseDeviceDependentResources() -{ - m_loadingComplete = false; - m_usingVprtShaders = false; - m_vertexShader = nullptr; - m_inputLayout = nullptr; - m_pixelShader = nullptr; - m_geometryShader = nullptr; - m_modelConstantBuffer = nullptr; - m_vertexBuffer = nullptr; - m_indexBuffer = nullptr; - m_filterColorBuffer = nullptr; -} - -void SpinningCubeRenderer::CreateWindowSizeDependentResources() -{ -} - -void SpinningCubeRenderer::TogglePauseState() -{ - if (m_pauseState == PauseState::Paused) - { - m_pauseState = PauseState::Unpausing; - } - else - { - m_pauseState = PauseState::Pausing; - } -} +//********************************************************* +// +// 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 + +#include + +#include +#include + +using namespace DirectX; + +// Loads vertex and pixel shaders from files and instantiates the cube geometry. +SpinningCubeRenderer::SpinningCubeRenderer(const std::shared_ptr& deviceResources) + : m_deviceResources(deviceResources) +{ + CreateDeviceDependentResources(); +} + +// This function uses a SpatialPointerPose to position the world-locked hologram +// two meters in front of the user's heading. +void SpinningCubeRenderer::PositionHologram(const winrt::Windows::UI::Input::Spatial::SpatialPointerPose& pointerPose) +{ + if (pointerPose != nullptr) + { + // Try to get the gaze from eyes. + winrt::Windows::Perception::People::EyesPose eyesPose = pointerPose.Eyes(); + if (eyesPose != nullptr) + { + winrt::Windows::Foundation::IReference gaze = eyesPose.Gaze(); + if (gaze != nullptr) + { + PositionHologram(gaze.Value().Origin, gaze.Value().Direction); + return; + } + } + + // Get the gaze direction from head. + const auto headPosition = pointerPose.Head().Position(); + const auto headDirection = pointerPose.Head().ForwardDirection(); + + PositionHologram(headPosition, headDirection); + } +} + +void SpinningCubeRenderer::SetColorFilter(DirectX::XMFLOAT4 color) +{ + m_filterColorData = color; +} + +// This function uses a point and a vector to position the world-locked hologram +// two meters in front of the user's heading. +void SpinningCubeRenderer::PositionHologram( + winrt::Windows::Foundation::Numerics::float3 headPosition, winrt::Windows::Foundation::Numerics::float3 headDirection) +{ + // The hologram is positioned two meters along the user's gaze direction. + static const float distanceFromUser = 2.0f; // meters + const auto 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( + float totalSeconds, + winrt::Windows::Perception::PerceptionTimestamp timestamp, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem) +{ + // Rotate the cube. + // Convert degrees to radians, then convert seconds to rotation angle. + const float radiansPerSecond = XMConvertToRadians(m_degreesPerSecond); + const double relativeRotation = totalSeconds * radiansPerSecond; + double totalRotation = m_rotationOffset; + + switch (m_pauseState) + { + case PauseState::Unpaused: + totalRotation += relativeRotation; + break; + + case PauseState::Pausing: + m_rotationOffset += relativeRotation; + m_pauseState = PauseState::Paused; + case PauseState::Paused: + totalRotation = m_rotationOffset; + break; + + case PauseState::Unpausing: + m_rotationOffset -= relativeRotation; + m_pauseState = PauseState::Unpaused; + break; + } + const float radians = static_cast(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); + + // Store the normal transform. + XMStoreFloat4x4(&m_modelConstantBufferData.normal, XMMatrixTranspose(modelRotation)); + + // 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. + m_deviceResources->UseD3DDeviceContext([&](auto context) { + // 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(bool isStereo) +{ + // Loading is asynchronous. Resources must be created before drawing can occur. + if (!m_loadingComplete) + { + return; + } + + m_deviceResources->UseD3DDeviceContext([&](auto context) { + ID3D11Buffer* pBufferToSet = nullptr; + + // Each vertex is one instance of the VertexPositionColor struct. + const UINT stride = sizeof(VertexPositionNormalColor); + const UINT offset = 0; + + pBufferToSet = m_vertexBuffer.get(); + context->IASetVertexBuffers(0, 1, &pBufferToSet, &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. + pBufferToSet = m_modelConstantBuffer.get(); + context->VSSetConstantBuffers(0, 1, &pBufferToSet); + + 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); + } + + context->UpdateSubresource(m_filterColorBuffer.get(), 0, nullptr, &m_filterColorData, 0, 0); + + pBufferToSet = m_filterColorBuffer.get(); + context->PSSetConstantBuffers(2, 1, &pBufferToSet); + + // Attach the pixel shader. + context->PSSetShader(m_pixelShader.get(), nullptr, 0); + + // Draw the objects. + context->DrawIndexedInstanced( + m_indexCount, // Index count per instance. + isStereo ? 2 : 1, // Instance count. + 0, // Start index location. + 0, // Base vertex location. + 0 // Start instance location. + ); + }); +} + +std::future SpinningCubeRenderer::CreateDeviceDependentResources() +{ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + std::wstring fileNamePrefix = L""; +#else + std::wstring fileNamePrefix = L"ms-appx:///"; +#endif + + 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"hsa_VprtVertexShader.cso" : L"hsa_VertexShader.cso"; + + std::vector vertexShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + vertexShaderFileName); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateVertexShader( + vertexShaderFileData.data(), vertexShaderFileData.size(), nullptr, m_vertexShader.put())); + + constexpr std::array vertexDesc = {{ + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }}; + + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateInputLayout( + vertexDesc.data(), + static_cast(vertexDesc.size()), + vertexShaderFileData.data(), + static_cast(vertexShaderFileData.size()), + m_inputLayout.put())); + + std::vector pixelShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_PixelShader.cso"); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreatePixelShader( + pixelShaderFileData.data(), pixelShaderFileData.size(), nullptr, m_pixelShader.put())); + + const ModelConstantBuffer constantBuffer{ + reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), + reinterpret_cast(winrt::Windows::Foundation::Numerics::float4x4::identity()), + }; + + const CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&constantBufferDesc, nullptr, m_modelConstantBuffer.put())); + + const CD3D11_BUFFER_DESC filterColorBufferDesc(sizeof(XMFLOAT4), D3D11_BIND_CONSTANT_BUFFER); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&filterColorBufferDesc, nullptr, m_filterColorBuffer.put())); + + if (!m_usingVprtShaders) + { + // Load the pass-through geometry shader. + std::vector geometryShaderFileData = co_await DXHelper::ReadDataAsync(fileNamePrefix + L"hsa_GeometryShader.cso"); + + // After the pass-through geometry shader file is loaded, create the shader. + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateGeometryShader( + geometryShaderFileData.data(), geometryShaderFileData.size(), nullptr, m_geometryShader.put())); + } + + // 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 VertexPositionNormalColor cubeVertices[] = { + {XMFLOAT3(-0.1f, -0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 0.0f, 0.0f)}, // vertex 0 non-debug + {XMFLOAT3(-0.1f, -0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 0.0f, 1.0f)}, + {XMFLOAT3(-0.1f, 0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 1.0f, 0.0f)}, + {XMFLOAT3(-0.1f, 0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(0.0f, 1.0f, 1.0f)}, + {XMFLOAT3(0.1f, -0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 0.0f, 0.0f)}, + {XMFLOAT3(0.1f, -0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 0.0f, 1.0f)}, + {XMFLOAT3(0.1f, 0.1f, -0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 1.0f, 0.0f)}, + {XMFLOAT3(0.1f, 0.1f, 0.1f), XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT3(1.0f, 1.0f, 1.0f)}, + }; + + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = cubeVertices; + vertexBufferData.SysMemPitch = 0; + vertexBufferData.SysMemSlicePitch = 0; + const CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&vertexBufferDesc, &vertexBufferData, m_vertexBuffer.put())); + + // 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. + static const unsigned short 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 = ARRAYSIZE(cubeIndices); + + D3D11_SUBRESOURCE_DATA indexBufferData = {0}; + indexBufferData.pSysMem = cubeIndices; + indexBufferData.SysMemPitch = 0; + indexBufferData.SysMemSlicePitch = 0; + const CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER); + winrt::check_hresult(m_deviceResources->GetD3DDevice()->CreateBuffer(&indexBufferDesc, &indexBufferData, m_indexBuffer.put())); + + // Once everything is loaded, the object is ready to be rendered. + m_loadingComplete = true; +} + +void SpinningCubeRenderer::ReleaseDeviceDependentResources() +{ + m_loadingComplete = false; + m_usingVprtShaders = false; + m_vertexShader = nullptr; + m_inputLayout = nullptr; + m_pixelShader = nullptr; + m_geometryShader = nullptr; + m_modelConstantBuffer = nullptr; + m_vertexBuffer = nullptr; + m_indexBuffer = nullptr; + m_filterColorBuffer = nullptr; +} + +void SpinningCubeRenderer::CreateWindowSizeDependentResources() +{ +} + +void SpinningCubeRenderer::TogglePauseState() +{ + if (m_pauseState == PauseState::Paused) + { + m_pauseState = PauseState::Unpausing; + } + else + { + m_pauseState = PauseState::Pausing; + } +} diff --git a/hostsampleapp/uwp/Content/SpinningCubeRenderer.h b/remote/uwp/Content/SpinningCubeRenderer.h similarity index 90% rename from hostsampleapp/uwp/Content/SpinningCubeRenderer.h rename to remote/uwp/Content/SpinningCubeRenderer.h index cf57989..c390565 100644 --- a/hostsampleapp/uwp/Content/SpinningCubeRenderer.h +++ b/remote/uwp/Content/SpinningCubeRenderer.h @@ -1,93 +1,100 @@ -//********************************************************* -// -// 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 "..\Common\DeviceResources.h" -#include "ShaderStructures.h" -#include - -// This sample renderer instantiates a basic rendering pipeline. -class SpinningCubeRenderer -{ -public: - SpinningCubeRenderer(const std::shared_ptr& deviceResources); - void CreateWindowSizeDependentResources(); - std::future CreateDeviceDependentResources(); - void ReleaseDeviceDependentResources(); - void Update(float totalSeconds); - void SetColorFilter(DirectX::XMFLOAT4 color); - void Render(bool isStereo); - - // Repositions the sample hologram. - void PositionHologram(const winrt::Windows::UI::Input::Spatial::SpatialPointerPose& pointerPose); - - // Repositions the sample hologram, using direct measures. - void PositionHologram(winrt::Windows::Foundation::Numerics::float3 pos, winrt::Windows::Foundation::Numerics::float3 dir); - - // Property accessors. - void SetPosition(winrt::Windows::Foundation::Numerics::float3 pos) - { - m_position = pos; - } - const winrt::Windows::Foundation::Numerics::float3& GetPosition() - { - return m_position; - } - - void Pause() - { - m_pauseState = PauseState::Pausing; - } - void Unpause() - { - m_pauseState = PauseState::Unpausing; - } - void TogglePauseState(); - -private: - enum class PauseState - { - Unpaused = 0, - Pausing, - Paused, - Unpausing, - }; - - // Cached pointer to device resources. - std::shared_ptr m_deviceResources; - - // Direct3D resources for cube geometry. - winrt::com_ptr m_inputLayout; - winrt::com_ptr m_vertexBuffer; - winrt::com_ptr m_indexBuffer; - winrt::com_ptr m_vertexShader; - winrt::com_ptr m_geometryShader; - winrt::com_ptr m_pixelShader; - winrt::com_ptr m_modelConstantBuffer; - winrt::com_ptr m_filterColorBuffer; - - // System resources for cube geometry. - ModelConstantBuffer m_modelConstantBufferData; - uint32_t m_indexCount = 0; - DirectX::XMFLOAT4 m_filterColorData = {1, 1, 1, 1}; - - // Variables used with the rendering loop. - bool m_loadingComplete = false; - float m_degreesPerSecond = 180.0f; - winrt::Windows::Foundation::Numerics::float3 m_position = {0.0f, 0.0f, -2.0f}; - PauseState m_pauseState = PauseState::Unpaused; - double m_rotationOffset = 0; - - // 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; -}; +//********************************************************* +// +// 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 +#include + +#include + +#include + +// This sample renderer instantiates a basic rendering pipeline. +class SpinningCubeRenderer +{ +public: + SpinningCubeRenderer(const std::shared_ptr& deviceResources); + + void CreateWindowSizeDependentResources(); + std::future CreateDeviceDependentResources(); + void ReleaseDeviceDependentResources(); + void Update( + float totalSeconds, + winrt::Windows::Perception::PerceptionTimestamp timestamp, + winrt::Windows::Perception::Spatial::SpatialCoordinateSystem renderingCoordinateSystem); + void SetColorFilter(DirectX::XMFLOAT4 color); + void Render(bool isStereo); + + // Repositions the sample hologram. + void PositionHologram(const winrt::Windows::UI::Input::Spatial::SpatialPointerPose& pointerPose); + + // Repositions the sample hologram, using direct measures. + void PositionHologram(winrt::Windows::Foundation::Numerics::float3 pos, winrt::Windows::Foundation::Numerics::float3 dir); + + // Property accessors. + void SetPosition(winrt::Windows::Foundation::Numerics::float3 pos) + { + m_position = pos; + } + const winrt::Windows::Foundation::Numerics::float3& GetPosition() + { + return m_position; + } + + void Pause() + { + m_pauseState = PauseState::Pausing; + } + void Unpause() + { + m_pauseState = PauseState::Unpausing; + } + void TogglePauseState(); + +private: + enum class PauseState + { + Unpaused = 0, + Pausing, + Paused, + Unpausing, + }; + + // Cached pointer to device resources. + std::shared_ptr m_deviceResources; + + // Direct3D resources for cube geometry. + winrt::com_ptr m_inputLayout; + winrt::com_ptr m_vertexBuffer; + winrt::com_ptr m_indexBuffer; + winrt::com_ptr m_vertexShader; + winrt::com_ptr m_geometryShader; + winrt::com_ptr m_pixelShader; + winrt::com_ptr m_modelConstantBuffer; + winrt::com_ptr m_filterColorBuffer; + + // System resources for cube geometry. + ModelConstantBuffer m_modelConstantBufferData; + uint32_t m_indexCount = 0; + DirectX::XMFLOAT4 m_filterColorData = {1, 1, 1, 1}; + + // Variables used with the rendering loop. + bool m_loadingComplete = false; + float m_degreesPerSecond = 180.0f; + winrt::Windows::Foundation::Numerics::float3 m_position = {0.0f, 0.0f, -2.0f}; + PauseState m_pauseState = PauseState::Unpaused; + double m_rotationOffset = 0; + + // 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; +}; diff --git a/hostsampleapp/uwp/Content/shaders/hsa_GeometryShader.hlsl b/remote/uwp/Content/shaders/hsa_GeometryShader.hlsl similarity index 97% rename from hostsampleapp/uwp/Content/shaders/hsa_GeometryShader.hlsl rename to remote/uwp/Content/shaders/hsa_GeometryShader.hlsl index f3d71c0..957662c 100644 --- a/hostsampleapp/uwp/Content/shaders/hsa_GeometryShader.hlsl +++ b/remote/uwp/Content/shaders/hsa_GeometryShader.hlsl @@ -1,44 +1,44 @@ -//********************************************************* -// -// 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. -// -//********************************************************* - -// Per-vertex data from the vertex shader. -struct GeometryShaderInput -{ - float4 pos : SV_POSITION; - min16float3 color : COLOR0; - uint instId : TEXCOORD0; -}; - -// Per-vertex data passed to the rasterizer. -struct GeometryShaderOutput -{ - float4 pos : SV_POSITION; - min16float3 color : COLOR0; - uint idx : TEXCOORD0; - 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 outStream) -{ - GeometryShaderOutput output; - [unroll(3)] - for (int i = 0; i < 3; ++i) - { - output.pos = input[i].pos; - output.color = input[i].color; - output.idx = input[i].instId; - output.rtvId = input[i].instId; - outStream.Append(output); - } -} +//********************************************************* +// +// 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. +// +//********************************************************* + +// Per-vertex data from the vertex shader. +struct GeometryShaderInput +{ + float4 pos : SV_POSITION; + min16float3 color : COLOR0; + uint instId : TEXCOORD0; +}; + +// Per-vertex data passed to the rasterizer. +struct GeometryShaderOutput +{ + float4 pos : SV_POSITION; + min16float3 color : COLOR0; + uint idx : TEXCOORD0; + 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 outStream) +{ + GeometryShaderOutput output; + [unroll(3)] + for (int i = 0; i < 3; ++i) + { + output.pos = input[i].pos; + output.color = input[i].color; + output.idx = input[i].instId; + output.rtvId = input[i].instId; + outStream.Append(output); + } +} diff --git a/hostsampleapp/desktop/Content/shaders/hsa_PixelShader.hlsl b/remote/uwp/Content/shaders/hsa_PixelShader.hlsl similarity index 96% rename from hostsampleapp/desktop/Content/shaders/hsa_PixelShader.hlsl rename to remote/uwp/Content/shaders/hsa_PixelShader.hlsl index 2b13662..3a27d67 100644 --- a/hostsampleapp/desktop/Content/shaders/hsa_PixelShader.hlsl +++ b/remote/uwp/Content/shaders/hsa_PixelShader.hlsl @@ -1,42 +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. -// -//********************************************************* - -// A constant buffer that stores the model transform. -cbuffer ModelConstantBuffer : register(b0) -{ - float4x4 model; - float4x4 normal; -}; - -// A constant buffer that stores each set of view and projection matrices in column-major format. -cbuffer ViewProjectionConstantBuffer : register(b1) -{ - float4x4 viewProjection[2]; -}; - -cbuffer ColorFilterConstantBuffer : register(b2) -{ - float4 colorFilter; -}; - -// Per-pixel color data passed through the pixel shader. -struct PixelShaderInput -{ - float4 pos : SV_POSITION; - min16float3 color : COLOR0; - uint idx : TEXCOORD0; -}; - -// The pixel shader applies Blinn-Phong BRDF shading. -min16float4 main(PixelShaderInput input) : SV_TARGET -{ - return min16float4(input.color, 1.f) * min16float4(colorFilter); -} +//********************************************************* +// +// 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. +// +//********************************************************* + +// A constant buffer that stores the model transform. +cbuffer ModelConstantBuffer : register(b0) +{ + float4x4 model; + float4x4 normal; +}; + +// A constant buffer that stores each set of view and projection matrices in column-major format. +cbuffer ViewProjectionConstantBuffer : register(b1) +{ + float4x4 viewProjection[2]; +}; + +cbuffer ColorFilterConstantBuffer : register(b2) +{ + float4 colorFilter; +}; + +// Per-pixel color data passed through the pixel shader. +struct PixelShaderInput +{ + float4 pos : SV_POSITION; + min16float3 color : COLOR0; + uint idx : TEXCOORD0; +}; + +// The pixel shader applies Blinn-Phong BRDF shading. +min16float4 main(PixelShaderInput input) : SV_TARGET +{ + return min16float4(input.color, 1.f) * min16float4(colorFilter); +} diff --git a/hostsampleapp/desktop/Content/shaders/hsa_SRMeshGeometryShader.hlsl b/remote/uwp/Content/shaders/hsa_SRMeshGeometryShader.hlsl similarity index 96% rename from hostsampleapp/desktop/Content/shaders/hsa_SRMeshGeometryShader.hlsl rename to remote/uwp/Content/shaders/hsa_SRMeshGeometryShader.hlsl index 37c66cd..f1eae96 100644 --- a/hostsampleapp/desktop/Content/shaders/hsa_SRMeshGeometryShader.hlsl +++ b/remote/uwp/Content/shaders/hsa_SRMeshGeometryShader.hlsl @@ -1,48 +1,48 @@ -//********************************************************* -// -// 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. -// -//********************************************************* - -// Per-vertex data from the vertex shader. -struct GeometryShaderInput -{ - float4 pos : SV_POSITION; - uint instId : TEXCOORD1; -}; - -// Per-vertex data passed to the rasterizer. -struct GeometryShaderOutput -{ - float4 pos : SV_POSITION; - float3 barycentricCoords : TEXCOORD0; - 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 outStream) -{ - static const float3 barycentricVectors[3] = { - float3(1.0f, 0.0f, 0.0f), - float3(0.0f, 1.0f, 0.0f), - float3(0.0f, 0.0f, 1.0f) - }; - - GeometryShaderOutput output; - [unroll(3)] - for (int i = 0; i < 3; ++i) - { - output.pos = input[i].pos; - output.barycentricCoords = barycentricVectors[i]; - output.rtvId = input[i].instId; - - outStream.Append(output); - } -} +//********************************************************* +// +// 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. +// +//********************************************************* + +// Per-vertex data from the vertex shader. +struct GeometryShaderInput +{ + float4 pos : SV_POSITION; + uint instId : TEXCOORD1; +}; + +// Per-vertex data passed to the rasterizer. +struct GeometryShaderOutput +{ + float4 pos : SV_POSITION; + float3 barycentricCoords : TEXCOORD0; + 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 outStream) +{ + static const float3 barycentricVectors[3] = { + float3(1.0f, 0.0f, 0.0f), + float3(0.0f, 1.0f, 0.0f), + float3(0.0f, 0.0f, 1.0f) + }; + + GeometryShaderOutput output; + [unroll(3)] + for (int i = 0; i < 3; ++i) + { + output.pos = input[i].pos; + output.barycentricCoords = barycentricVectors[i]; + output.rtvId = input[i].instId; + + outStream.Append(output); + } +} diff --git a/hostsampleapp/uwp/Content/shaders/hsa_SRMeshPixelShader.hlsl b/remote/uwp/Content/shaders/hsa_SRMeshPixelShader.hlsl similarity index 97% rename from hostsampleapp/uwp/Content/shaders/hsa_SRMeshPixelShader.hlsl rename to remote/uwp/Content/shaders/hsa_SRMeshPixelShader.hlsl index 9cc83bb..e4917ab 100644 --- a/hostsampleapp/uwp/Content/shaders/hsa_SRMeshPixelShader.hlsl +++ b/remote/uwp/Content/shaders/hsa_SRMeshPixelShader.hlsl @@ -1,36 +1,36 @@ -//********************************************************* -// -// 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. -// -//********************************************************* - -// Per-pixel color data passed through the pixel shader. -struct PixelShaderInput -{ - float4 pos : SV_POSITION; - float3 barycentricCoords : TEXCOORD0; -}; - -#define LINE_WIDTH 2.0 - -float edgeFactor(float3 coords) -{ - float3 d = fwidth(coords); - float3 a3 = smoothstep(0.0, d*LINE_WIDTH, coords); - return min(min(a3.x, a3.y), a3.z); -} - -// The pixel shader passes through the color data. The color data from -// is interpolated and assigned to a pixel at the rasterization step. -float4 main(PixelShaderInput input) : SV_TARGET -{ - float lineBrightness = 1.0f - edgeFactor(input.barycentricCoords); - float4 result = float4(0.25, 0.25, 0.25, 1.0); - result.xyz *= lineBrightness; - return result; -} +//********************************************************* +// +// 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. +// +//********************************************************* + +// Per-pixel color data passed through the pixel shader. +struct PixelShaderInput +{ + float4 pos : SV_POSITION; + float3 barycentricCoords : TEXCOORD0; +}; + +#define LINE_WIDTH 2.0 + +float edgeFactor(float3 coords) +{ + float3 d = fwidth(coords); + float3 a3 = smoothstep(0.0, d*LINE_WIDTH, coords); + return min(min(a3.x, a3.y), a3.z); +} + +// The pixel shader passes through the color data. The color data from +// is interpolated and assigned to a pixel at the rasterization step. +float4 main(PixelShaderInput input) : SV_TARGET +{ + float lineBrightness = 1.0f - edgeFactor(input.barycentricCoords); + float4 result = float4(0.25, 0.25, 0.25, 1.0); + result.xyz *= lineBrightness; + return result; +} diff --git a/hostsampleapp/desktop/Content/shaders/hsa_SRMeshVertexShader.hlsl b/remote/uwp/Content/shaders/hsa_SRMeshVertexShader.hlsl similarity index 97% rename from hostsampleapp/desktop/Content/shaders/hsa_SRMeshVertexShader.hlsl rename to remote/uwp/Content/shaders/hsa_SRMeshVertexShader.hlsl index 55e2a1f..5c214df 100644 --- a/hostsampleapp/desktop/Content/shaders/hsa_SRMeshVertexShader.hlsl +++ b/remote/uwp/Content/shaders/hsa_SRMeshVertexShader.hlsl @@ -1,64 +1,64 @@ -//********************************************************* -// -// 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. -// -//********************************************************* - -// A constant buffer that stores the model transform. -cbuffer SRMeshConstantBuffer : register(b0) -{ - float4x4 model; -}; - -// 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 -{ - float4 pos : POSITION; - 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 -{ - float4 pos : SV_POSITION; - uint viewId : TEXCOORD1; // SV_InstanceID % 2 -}; - -// Simple shader to do vertex processing on the GPU. -VertexShaderOutput main(VertexShaderInput input) -{ - VertexShaderOutput output; - float4 pos = float4(input.pos.xyz, 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 = pos; - - // 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; -} +//********************************************************* +// +// 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. +// +//********************************************************* + +// A constant buffer that stores the model transform. +cbuffer SRMeshConstantBuffer : register(b0) +{ + float4x4 model; +}; + +// 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 +{ + float4 pos : POSITION; + 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 +{ + float4 pos : SV_POSITION; + uint viewId : TEXCOORD1; // SV_InstanceID % 2 +}; + +// Simple shader to do vertex processing on the GPU. +VertexShaderOutput main(VertexShaderInput input) +{ + VertexShaderOutput output; + float4 pos = float4(input.pos.xyz, 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 = pos; + + // 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; +} diff --git a/hostsampleapp/desktop/Content/shaders/hsa_VPRTVertexShader.hlsl b/remote/uwp/Content/shaders/hsa_VPRTVertexShader.hlsl similarity index 96% rename from hostsampleapp/desktop/Content/shaders/hsa_VPRTVertexShader.hlsl rename to remote/uwp/Content/shaders/hsa_VPRTVertexShader.hlsl index 83503bc..3770d3f 100644 --- a/hostsampleapp/desktop/Content/shaders/hsa_VPRTVertexShader.hlsl +++ b/remote/uwp/Content/shaders/hsa_VPRTVertexShader.hlsl @@ -1,72 +1,72 @@ -//********************************************************* -// -// 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. -// -//********************************************************* - -// A constant buffer that stores the model transform. -cbuffer ModelConstantBuffer : register(b0) -{ - float4x4 model; - float4x4 normal; -}; - -// 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 -{ - float3 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 -{ - float4 pos : SV_POSITION; - min16float3 color : COLOR0; - uint idx : TEXCOORD0; - 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]); - - // Write minimum-precision floating-point data. - output.pos = pos; - - // Pass the color through without modification. - output.color = input.color; - - // Set the render target array index. - output.rtvId = idx; - output.idx = idx; - - return output; -} +//********************************************************* +// +// 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. +// +//********************************************************* + +// A constant buffer that stores the model transform. +cbuffer ModelConstantBuffer : register(b0) +{ + float4x4 model; + float4x4 normal; +}; + +// 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 +{ + float3 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 +{ + float4 pos : SV_POSITION; + min16float3 color : COLOR0; + uint idx : TEXCOORD0; + 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]); + + // Write minimum-precision floating-point data. + output.pos = pos; + + // Pass the color through without modification. + output.color = input.color; + + // Set the render target array index. + output.rtvId = idx; + output.idx = idx; + + return output; +} diff --git a/hostsampleapp/uwp/Content/shaders/hsa_VertexShader.hlsl b/remote/uwp/Content/shaders/hsa_VertexShader.hlsl similarity index 97% rename from hostsampleapp/uwp/Content/shaders/hsa_VertexShader.hlsl rename to remote/uwp/Content/shaders/hsa_VertexShader.hlsl index 985257a..11f5f1e 100644 --- a/hostsampleapp/uwp/Content/shaders/hsa_VertexShader.hlsl +++ b/remote/uwp/Content/shaders/hsa_VertexShader.hlsl @@ -1,72 +1,72 @@ -//********************************************************* -// -// 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. -// -//********************************************************* - -// A constant buffer that stores the model transform. -cbuffer ModelConstantBuffer : register(b0) -{ - float4x4 model; - float4x4 normal; -}; - -// 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 -{ - float3 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 -{ - float4 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]); - - // Write minimum-precision floating-point data. - output.pos = pos; - - // Pass the color through without modification. - output.color = input.color; - - // 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; -} +//********************************************************* +// +// 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. +// +//********************************************************* + +// A constant buffer that stores the model transform. +cbuffer ModelConstantBuffer : register(b0) +{ + float4x4 model; + float4x4 normal; +}; + +// 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 +{ + float3 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 +{ + float4 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]); + + // Write minimum-precision floating-point data. + output.pos = pos; + + // Pass the color through without modification. + output.color = input.color; + + // 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; +} diff --git a/remote/uwp/Package.appxmanifest b/remote/uwp/Package.appxmanifest new file mode 100644 index 0000000..1923f24 --- /dev/null +++ b/remote/uwp/Package.appxmanifest @@ -0,0 +1,50 @@ + + + + + + RemotingHostSample + Microsoft Corporation + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/remote/uwp/SampleRemote.sln b/remote/uwp/SampleRemote.sln new file mode 100644 index 0000000..98f1054 --- /dev/null +++ b/remote/uwp/SampleRemote.sln @@ -0,0 +1,32 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29806.167 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleRemote", "SampleRemote.vcxproj", "{C3606530-114C-309C-B0D2-61F999097E21}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + RelWithDebInfo|x64 = RelWithDebInfo|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C3606530-114C-309C-B0D2-61F999097E21}.Debug|x64.ActiveCfg = Debug|x64 + {C3606530-114C-309C-B0D2-61F999097E21}.Debug|x64.Build.0 = Debug|x64 + {C3606530-114C-309C-B0D2-61F999097E21}.Debug|x64.Deploy.0 = Debug|x64 + {C3606530-114C-309C-B0D2-61F999097E21}.Release|x64.ActiveCfg = Release|x64 + {C3606530-114C-309C-B0D2-61F999097E21}.Release|x64.Build.0 = Release|x64 + {C3606530-114C-309C-B0D2-61F999097E21}.Release|x64.Deploy.0 = Release|x64 + {C3606530-114C-309C-B0D2-61F999097E21}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {C3606530-114C-309C-B0D2-61F999097E21}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {C3606530-114C-309C-B0D2-61F999097E21}.RelWithDebInfo|x64.Deploy.0 = RelWithDebInfo|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E8A3A1EC-E636-40D6-9E3D-C22347CC8162} + EndGlobalSection +EndGlobal + diff --git a/hostsampleapp/uwp/HolographicHostSample.vcxproj b/remote/uwp/SampleRemote.vcxproj similarity index 84% rename from hostsampleapp/uwp/HolographicHostSample.vcxproj rename to remote/uwp/SampleRemote.vcxproj index 0259beb..07710d1 100644 --- a/hostsampleapp/uwp/HolographicHostSample.vcxproj +++ b/remote/uwp/SampleRemote.vcxproj @@ -1,361 +1,368 @@ - - - - - Debug - x64 - - - Release - x64 - - - RelWithDebInfo - x64 - - - - {8933B2A2-C780-3CC9-8B26-0CCB3E806E54} - Windows Store - en-US - 10.0 - 14.0 - true - 10.0.18362.0 - 10.0.17134.0 - Win32Proj - x64 - HolographicHostSample - NoUpgrade - - - - Application - Unicode - v141 - - - Application - Unicode - v141 - - - Application - Unicode - v141 - - - - - - - - - - - - - <_ProjectFileVersion>10.0.20506.1 - src\hostsampleapp\Debug\ - HolographicHostSample.dir\Debug\ - HolographicHostSample - .exe - true - true - src\hostsampleapp\Release\ - HolographicHostSample.dir\Release\ - HolographicHostSample - .exe - false - true - src\hostsampleapp\RelWithDebInfo\ - HolographicHostSample.dir\RelWithDebInfo\ - HolographicHostSample - .exe - true - true - - - - .;%(AdditionalIncludeDirectories) - %(AdditionalOptions) /await - $(VCIDEInstallDir)vcpackages;$(WindowsSDK_UnionMetadataPath);$(UniversalCRTSdkDir)UnionMetadata - Debug/ - CompileAsCpp - false - ProgramDatabase - 4503;4311;4456;4458;4459;4499 - Sync - true - Disabled - stdcpp17 - true - Disabled - NotUsing - MultiThreadedDebugDLL - true - true - false - Level3 - WIN32;_WINDOWS;UNICODE;_UNICODE;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="Debug";%(PreprocessorDefinitions) - $(IntDir) - - - WIN32;_DEBUG;_WINDOWS;UNICODE;_UNICODE;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"Debug\";%(PreprocessorDefinitions) - .;%(AdditionalIncludeDirectories) - - - .;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - d2d1.lib;d3d11.lib;dxgi.lib;dwrite.lib;windowscodecs.lib;pathcch.lib;Mswsock.lib;mfreadwrite.lib;Mfplat.lib;mfuuid.lib;ntdll.lib;Secur32.lib;crypt32.lib;secur32.lib;avrt.lib;WindowsApp.lib;%(AdditionalDependencies) - %(AdditionalLibraryDirectories) - %(AdditionalOptions) /machine:x64 - false - true - false - %(IgnoreSpecificDefaultLibraries) - src/hostsampleapp/Debug/HolographicHostSample.lib - false - src/hostsampleapp/Debug/HolographicHostSample.pdb - Windows - - - false - - - - - .;%(AdditionalIncludeDirectories) - %(AdditionalOptions) /await - $(VCIDEInstallDir)vcpackages;$(WindowsSDK_UnionMetadataPath);$(UniversalCRTSdkDir)UnionMetadata - Release/ - CompileAsCpp - false - Guard - ProgramDatabase - 4503;4311;4456;4458;4459;4499 - Sync - true - AnySuitable - stdcpp17 - true - MaxSpeed - NotUsing - MultiThreadedDLL - true - true - false - Level3 - WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="Release";%(PreprocessorDefinitions) - $(IntDir) - - - WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"Release\";%(PreprocessorDefinitions) - .;%(AdditionalIncludeDirectories) - - - .;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - d2d1.lib;d3d11.lib;dxgi.lib;dwrite.lib;windowscodecs.lib;pathcch.lib;Mswsock.lib;mfreadwrite.lib;Mfplat.lib;mfuuid.lib;ntdll.lib;Secur32.lib;crypt32.lib;secur32.lib;avrt.lib;WindowsApp.lib;%(AdditionalDependencies) - %(AdditionalLibraryDirectories) - %(AdditionalOptions) /machine:x64 - DebugFull - false - %(IgnoreSpecificDefaultLibraries) - src/hostsampleapp/Release/HolographicHostSample.lib - src/hostsampleapp/Release/HolographicHostSample.pdb - Windows - - - false - - - - - .;%(AdditionalIncludeDirectories) - %(AdditionalOptions) /await - $(VCIDEInstallDir)vcpackages;$(WindowsSDK_UnionMetadataPath);$(UniversalCRTSdkDir)UnionMetadata - RelWithDebInfo/ - CompileAsCpp - false - ProgramDatabase - 4503;4311;4456;4458;4459;4499 - Sync - true - OnlyExplicitInline - stdcpp17 - true - MaxSpeed - NotUsing - MultiThreadedDLL - true - true - false - Level3 - WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="RelWithDebInfo";%(PreprocessorDefinitions) - $(IntDir) - - - WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"RelWithDebInfo\";%(PreprocessorDefinitions) - .;%(AdditionalIncludeDirectories) - - - .;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - d2d1.lib;d3d11.lib;dxgi.lib;dwrite.lib;windowscodecs.lib;pathcch.lib;Mswsock.lib;mfreadwrite.lib;Mfplat.lib;mfuuid.lib;ntdll.lib;Secur32.lib;crypt32.lib;secur32.lib;avrt.lib;WindowsApp.lib;%(AdditionalDependencies) - %(AdditionalLibraryDirectories) - %(AdditionalOptions) /machine:x64 - false - true - false - %(IgnoreSpecificDefaultLibraries) - src/hostsampleapp/RelWithDebInfo/HolographicHostSample.lib - false - src/hostsampleapp/RelWithDebInfo/HolographicHostSample.pdb - Windows - - - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Assets\%(FileName)%(Extension) - true - true - true - - - Assets\%(FileName)%(Extension) - true - true - true - - - Assets\%(FileName)%(Extension) - true - true - true - - - Assets\%(FileName)%(Extension) - true - true - true - - - Assets\%(FileName)%(Extension) - true - true - true - - - Assets\%(FileName)%(Extension) - true - true - true - - - Assets\%(FileName)%(Extension) - true - true - true - - - - Vertex - main - 5.0 - - - Vertex - main - 5.0 - - - Vertex - main - 5.0 - - - Pixel - main - 5.0 - - - Pixel - main - 5.0 - - - Geometry - main - 5.0 - - - Geometry - main - 5.0 - - - .\%(FileName)%(Extension) - true - true - true - PreserveNewest - - - + + + + + x64 + + + + Debug + x64 + + + Release + x64 + + + RelWithDebInfo + x64 + + + + {C3606530-114C-309C-B0D2-61F999097E21} + Windows Store + en-US + 10.0 + 14.0 + true + 10.0.18362.0 + 10.0.17134.0 + Win32Proj + x64 + SampleRemote + NoUpgrade + + + + Application + Unicode + v142 + + + Application + Unicode + v142 + + + Application + Unicode + v142 + + + + + + + + + + + + <_ProjectFileVersion>10.0.20506.1 + src\remote\Holographic\Debug\ + SampleRemote.dir\Debug\ + SampleRemote + .exe + true + true + src\remote\Holographic\Release\ + SampleRemote.dir\Release\ + SampleRemote + .exe + false + true + src\remote\Holographic\RelWithDebInfo\ + SampleRemote.dir\RelWithDebInfo\ + SampleRemote + .exe + true + true + + + + .;%(AdditionalIncludeDirectories) + %(AdditionalOptions) /await + $(VCIDEInstallDir)vcpackages;$(WindowsSDK_UnionMetadataPath);$(UniversalCRTSdkDir)UnionMetadata + $(IntDir) + CompileAsCpp + false + ProgramDatabase + 4503 + Sync + true + Disabled + stdcpp17 + true + Disabled + NotUsing + MultiThreadedDebugDLL + true + true + false + Level3 + WIN32;_WINDOWS;UNICODE;_UNICODE;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="Debug";%(PreprocessorDefinitions) + $(IntDir) + + + WIN32;_DEBUG;_WINDOWS;UNICODE;_UNICODE;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"Debug\";%(PreprocessorDefinitions) + .;%(AdditionalIncludeDirectories) + + + .;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + d2d1.lib;d3d11.lib;dxgi.lib;dwrite.lib;windowscodecs.lib;pathcch.lib;Mswsock.lib;mfreadwrite.lib;Mfplat.lib;mfuuid.lib;ntdll.lib;Secur32.lib;crypt32.lib;secur32.lib;avrt.lib;WindowsApp.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + %(AdditionalOptions) /machine:x64 + false + true + false + %(IgnoreSpecificDefaultLibraries) + src/remote/Holographic/Debug/SampleRemote.lib + false + src/remote/Holographic/Debug/SampleRemote.pdb + Windows + + + false + + + + + .;%(AdditionalIncludeDirectories) + %(AdditionalOptions) /await + $(VCIDEInstallDir)vcpackages;$(WindowsSDK_UnionMetadataPath);$(UniversalCRTSdkDir)UnionMetadata + $(IntDir) + CompileAsCpp + false + Guard + ProgramDatabase + 4503 + Sync + true + AnySuitable + stdcpp17 + true + MaxSpeed + NotUsing + MultiThreadedDLL + true + true + false + Level3 + WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="Release";%(PreprocessorDefinitions) + $(IntDir) + + + WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"Release\";%(PreprocessorDefinitions) + .;%(AdditionalIncludeDirectories) + + + .;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + d2d1.lib;d3d11.lib;dxgi.lib;dwrite.lib;windowscodecs.lib;pathcch.lib;Mswsock.lib;mfreadwrite.lib;Mfplat.lib;mfuuid.lib;ntdll.lib;Secur32.lib;crypt32.lib;secur32.lib;avrt.lib;WindowsApp.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + %(AdditionalOptions) /machine:x64 + DebugFull + false + %(IgnoreSpecificDefaultLibraries) + src/remote/Holographic/Release/SampleRemote.lib + src/remote/Holographic/Release/SampleRemote.pdb + Windows + + + false + + + + + .;%(AdditionalIncludeDirectories) + %(AdditionalOptions) /await + $(VCIDEInstallDir)vcpackages;$(WindowsSDK_UnionMetadataPath);$(UniversalCRTSdkDir)UnionMetadata + $(IntDir) + CompileAsCpp + false + ProgramDatabase + 4503 + Sync + true + OnlyExplicitInline + stdcpp17 + true + MaxSpeed + NotUsing + MultiThreadedDLL + true + true + false + Level3 + WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR="RelWithDebInfo";%(PreprocessorDefinitions) + $(IntDir) + + + WIN32;_WINDOWS;UNICODE;_UNICODE;NDEBUG;ALLOW_INSECURE_RANDOM_DEVICE=1;_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING;RDBUILD_PLATFORM_DEFINED;RDBUILD_PLATFORM_WINDOWS;RDBUILD_PLATFORM_WINDOWS_WINRT;RDBUILD_ARCHITECTURE_DEFINED;RDBUILD_ARCH_INTEL;RDBUILD_ARCH_INTEL_X64;RDBUILD_DEFAULT_CALL=;RDBUILD_FEATURE_OPENSSL=0;_SCL_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN=1;WINVER=0x0A00;_WIN32_WINNT=0x0A00;NTDDI_VERSION=0x0A000007;CMAKE_INTDIR=\"RelWithDebInfo\";%(PreprocessorDefinitions) + .;%(AdditionalIncludeDirectories) + + + .;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + d2d1.lib;d3d11.lib;dxgi.lib;dwrite.lib;windowscodecs.lib;pathcch.lib;Mswsock.lib;mfreadwrite.lib;Mfplat.lib;mfuuid.lib;ntdll.lib;Secur32.lib;crypt32.lib;secur32.lib;avrt.lib;WindowsApp.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + %(AdditionalOptions) /machine:x64 + false + true + false + %(IgnoreSpecificDefaultLibraries) + src/remote/Holographic/RelWithDebInfo/SampleRemote.lib + false + src/remote/Holographic/RelWithDebInfo/SampleRemote.pdb + Windows + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Assets\%(FileName)%(Extension) + true + true + true + + + Assets\%(FileName)%(Extension) + true + true + true + + + Assets\%(FileName)%(Extension) + true + true + true + + + Assets\%(FileName)%(Extension) + true + true + true + + + Assets\%(FileName)%(Extension) + true + true + true + + + Assets\%(FileName)%(Extension) + true + true + true + + + Assets\%(FileName)%(Extension) + true + true + true + + + + Vertex + main + 5.0 + + + Vertex + main + 5.0 + + + Vertex + main + 5.0 + + + Pixel + main + 5.0 + + + Pixel + main + 5.0 + + + Geometry + main + 5.0 + + + Geometry + main + 5.0 + + + .\%(FileName)%(Extension) + true + true + true + PreserveNewest + + + + + + + \ No newline at end of file diff --git a/hostsampleapp/desktop/SampleHostMain.cpp b/remote/uwp/SampleRemoteMain.cpp similarity index 59% rename from hostsampleapp/desktop/SampleHostMain.cpp rename to remote/uwp/SampleRemoteMain.cpp index 3f084d9..f1b681d 100644 --- a/hostsampleapp/desktop/SampleHostMain.cpp +++ b/remote/uwp/SampleRemoteMain.cpp @@ -1,894 +1,1152 @@ -//********************************************************* -// -// 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 "SampleHostMain.h" - -#include "Common\DbgLog.h" -#include "Common\DirectXHelper.h" -#include "Common\Speech.h" - -#include - -#include - -#include -#include - -#include -#include - - -using namespace concurrency; - -using namespace std::chrono_literals; - -using namespace winrt::Microsoft::Holographic::AppRemoting; -using namespace winrt::Windows::Foundation::Numerics; -using namespace winrt::Windows::Graphics::Holographic; -using namespace winrt::Windows::Perception::People; -using namespace winrt::Windows::Perception::Spatial; -using namespace winrt::Windows::UI::Input; - - -namespace -{ - const wchar_t* StreamerConnectionStateToString(ConnectionState state) - { - switch (state) - { - case ConnectionState::Disconnected: - return L"Disconnected"; - - case ConnectionState::Connecting: - return L"Connecting"; - - case ConnectionState::Connected: - return L"Connected"; - } - - return L"Unknown"; - } -} // namespace - - -SampleHostMain::SampleHostMain(std::weak_ptr window) - : m_window(window) -{ - m_deviceResources = std::make_shared(); - m_deviceResources->RegisterDeviceNotify(this); -} - -SampleHostMain::~SampleHostMain() -{ - ShutdownRemoteContext(); - - m_deviceResources->RegisterDeviceNotify(nullptr); - UnregisterHolographicEventHandlers(); -} - -HolographicFrame SampleHostMain::Update() -{ - auto timeDelta = std::chrono::high_resolution_clock::now() - m_windowTitleUpdateTime; - if (timeDelta >= 1s) - { - WindowUpdateTitle(); - - m_windowTitleUpdateTime = std::chrono::high_resolution_clock::now(); - m_framesPerSecond = 0; - } - - if (!m_holographicSpace) - { - return nullptr; - } - - // NOTE: DXHelper::DeviceResources::Present does not wait for the frame to finish. - // Instead we wait here before we do the call to CreateNextFrame on the HolographicSpace. - // We do this to avoid that PeekMessage causes frame delta time spikes, say if we wait - // after PeekMessage WaitForNextFrameReady will compensate any time spend in PeekMessage. - m_holographicSpace.WaitForNextFrameReady(); - - HolographicFrame holographicFrame = m_holographicSpace.CreateNextFrame(); - 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); - - SpatialCoordinateSystem coordinateSystem = nullptr; - { - coordinateSystem = m_referenceFrame.CoordinateSystem(); - } - - // Check for new input state since the last frame. - Spatial::SpatialTappedEventArgs tapped = m_spatialInputHandler->CheckForTapped(); - if (tapped) - { - Spatial::SpatialPointerPose pointerPose = tapped.TryGetPointerPose(coordinateSystem); - - // When the Tapped spatial input event is received, the sample hologram will be repositioned two meters in front of the user. - m_spinningCubeRenderer->PositionHologram(pointerPose); - - } - else - { - static float3 initialCubePosition = float3::zero(); - - auto manipulationStarted = m_spatialInputHandler->CheckForManipulationStarted(); - if (manipulationStarted) - { - initialCubePosition = m_spinningCubeRenderer->GetPosition(); - m_spinningCubeRenderer->Pause(); - } - else - { - auto manipulationUpdated = m_spatialInputHandler->CheckForManipulationUpdated(); - if (manipulationUpdated) - { - auto delta = manipulationUpdated.TryGetCumulativeDelta(coordinateSystem); - if (delta) - { - m_spinningCubeRenderer->SetPosition(initialCubePosition + delta.Translation()); - } - } - else - { - switch (m_spatialInputHandler->CheckForManipulationResult()) - { - case SpatialInputHandler::ManipulationResult::Canceled: - m_spinningCubeRenderer->SetPosition(initialCubePosition); - case SpatialInputHandler::ManipulationResult::Completed: - m_spinningCubeRenderer->Unpause(); - break; - } - } - } - } - - std::chrono::duration timeSinceStart = std::chrono::high_resolution_clock::now() - m_startTime; - m_spinningCubeRenderer->Update(timeSinceStart.count()); - - if (m_spatialSurfaceMeshRenderer != nullptr) - { - m_spatialSurfaceMeshRenderer->Update(coordinateSystem); - } - m_spatialInputRenderer->Update(prediction.Timestamp(), coordinateSystem); - m_qrCodeRenderer->Update(*m_perceptionDeviceHandler.get(), coordinateSystem); - - // We complete the frame update by using information about our content positioning to set the focus point. - for (auto cameraPose : prediction.CameraPoses()) - { - try - { - HolographicCameraRenderingParameters renderingParameters = holographicFrame.GetRenderingParameters(cameraPose); - - // Set the focus point for image stabilization to the center of the sample hologram. - // NOTE: A focus point can be set for every HolographicFrame. If a focus point is set on a HolographicFrame, - // it will get transmitted to the player and will get set during the PlayerContext::BlitRemoteFrame() call. - renderingParameters.SetFocusPoint(coordinateSystem, m_spinningCubeRenderer->GetPosition()); - } - catch (winrt::hresult_error&) - { - } - } - -#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE - timeDelta = std::chrono::high_resolution_clock::now() - m_customDataChannelSendTime; - if (timeDelta > 5s) - { - m_customDataChannelSendTime = std::chrono::high_resolution_clock::now(); - - // Send ping every couple of frames if we have a custom data channel. - std::lock_guard lock(m_customDataChannelLock); - if (m_customDataChannel) - { - uint8_t data = 1; - m_customDataChannel.SendData( - winrt::array_view(reinterpret_cast(&data), reinterpret_cast(&data + 1)), - true); - OutputDebugString(TEXT("Ping Sent.\n")); - } - } -#endif - - return holographicFrame; -} - -void SampleHostMain::Render(HolographicFrame holographicFrame) -{ - bool atLeastOneCameraRendered = false; - - m_deviceResources->UseHolographicCameraResources([this, holographicFrame, &atLeastOneCameraRendered]( - std::map>& cameraResourceMap) { - holographicFrame.UpdateCurrentPrediction(); - HolographicFramePrediction prediction = holographicFrame.CurrentPrediction(); - - SpatialCoordinateSystem coordinateSystem = nullptr; - { - coordinateSystem = m_referenceFrame.CoordinateSystem(); - } - - for (auto cameraPose : prediction.CameraPoses()) - { - try - { - DXHelper::CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get(); - - if (pCameraResources == nullptr) - { - continue; - } - - m_deviceResources->UseD3DDeviceContext([&](ID3D11DeviceContext3* context) { - // Clear the back buffer view. - context->ClearRenderTargetView(pCameraResources->GetBackBufferRenderTargetView(), DirectX::Colors::Transparent); - context->ClearDepthStencilView( - pCameraResources->GetDepthStencilView(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); - - // 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, coordinateSystem); - - // Set up the camera buffer. - bool cameraActive = pCameraResources->AttachViewProjectionBuffer(m_deviceResources); - - // Only render world-locked content when positional tracking is active. - if (cameraActive) - { - // Set the render target, and set the depth target drawing buffer. - ID3D11RenderTargetView* const targets[1] = {pCameraResources->GetBackBufferRenderTargetView()}; - context->OMSetRenderTargets(1, targets, pCameraResources->GetDepthStencilView()); - - // Render the scene objects. - m_spinningCubeRenderer->Render(pCameraResources->IsRenderingStereoscopic()); - if (m_spatialSurfaceMeshRenderer != nullptr) - { - m_spatialSurfaceMeshRenderer->Render(pCameraResources->IsRenderingStereoscopic()); - } - m_spatialInputRenderer->Render(pCameraResources->IsRenderingStereoscopic()); - m_qrCodeRenderer->Render(pCameraResources->IsRenderingStereoscopic()); - } - }); - - atLeastOneCameraRendered = true; - } - catch (const winrt::hresult_error&) - { - } - } - }); - - if (atLeastOneCameraRendered) - { - m_deviceResources->Present(holographicFrame); - } - - if (m_swapChain == nullptr && m_isInitialized) - { - // A device lost event has occurred. - // Reconnection is necessary because the holographic streamer uses the D3D device. - // The following resources depend on the D3D device: - // * Holographic streamer - // * Renderer - // * Holographic space - // The InitializeRemoteContext() function will call the functions necessary to recreate these resources. - ShutdownRemoteContext(); - InitializeRemoteContextAndConnectOrListen(); - } - - // Determine whether or not to copy to the preview buffer. - bool copyPreview = m_remoteContext == nullptr || m_remoteContext.ConnectionState() != ConnectionState::Connected; - if (copyPreview && m_isInitialized) - { - winrt::com_ptr spDevice; - spDevice.copy_from(GetDeviceResources()->GetD3DDevice()); - - winrt::com_ptr spBackBuffer; - winrt::check_hresult(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), spBackBuffer.put_void())); - - // 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. - winrt::com_ptr spRenderTargetView; - winrt::check_hresult(spDevice->CreateRenderTargetView(spBackBuffer.get(), nullptr, spRenderTargetView.put())); - - GetDeviceResources()->UseD3DDeviceContext( - [&](auto context) { context->ClearRenderTargetView(spRenderTargetView.get(), DirectX::Colors::CornflowerBlue); }); - - WindowPresentSwapChain(); - } - - m_framesPerSecond++; -} - -void SampleHostMain::SetHostOptions(bool listen, const std::wstring& hostname, uint32_t port) -{ - m_listen = listen; - m_hostname = hostname; - m_port = port; -} - -void SampleHostMain::OnKeyPress(char key) -{ - switch (key) - { - case ' ': - InitializeRemoteContextAndConnectOrListen(); - break; - - case 'd': - ShutdownRemoteContext(); - break; - - case 'p': - m_showPreview = !m_showPreview; - break; - - case 'l': - LoadPosition(); - break; - - case 's': - SavePosition(); - break; - - - case 'c': - m_spinningCubeRenderer->TogglePauseState(); - break; - } - - WindowUpdateTitle(); -} - -void SampleHostMain::OnResize(int width, int height) -{ - std::lock_guard _lg(m_deviceLock); - - if (width != m_width || height != m_height) - { - m_width = width; - m_height = height; - - if (m_swapChain) - { - winrt::check_hresult(m_swapChain->ResizeBuffers(2, m_width, m_height, DXGI_FORMAT_B8G8R8A8_UNORM, 0)); - } - } -} - -void SampleHostMain::OnRecognizedSpeech(const winrt::hstring& recognizedText) -{ - bool changedColor = false; - DirectX::XMFLOAT4 color = {1, 1, 1, 1}; - - if (recognizedText == L"Red") - { - color = {1, 0, 0, 1}; - changedColor = true; - } - else if (recognizedText == L"Blue") - { - color = {0, 0, 1, 1}; - changedColor = true; - } - else if (recognizedText == L"Green") - { - color = {0, 1, 0, 1}; - changedColor = true; - } - else if (recognizedText == L"Default") - { - color = {1, 1, 1, 1}; - changedColor = true; - } - else if (recognizedText == L"Aquamarine") - { - color = {0, 1, 1, 1}; - changedColor = true; - } - else if (recognizedText == L"Load position") - { - LoadPosition(); - } - else if (recognizedText == L"Save position") - { - SavePosition(); - } - - if (changedColor && m_spinningCubeRenderer) - { - m_spinningCubeRenderer->SetColorFilter(color); - } -} - -void SampleHostMain::InitializeRemoteContextAndConnectOrListen() -{ - if (!m_remoteContext) - { - // Create the RemoteContext - // IMPORTANT: This must be done before creating the HolographicSpace (or any other call to the Holographic API). - CreateRemoteContext(m_remoteContext, 20000, false, PreferredVideoCodec::Default); - - // Create the HolographicSpace - CreateHolographicSpaceAndDeviceResources(); - - if (auto remoteSpeech = m_remoteContext.GetRemoteSpeech()) - { - Speech::InitializeSpeechAsync(remoteSpeech, m_onRecognizedSpeechRevoker, weak_from_this()); - } - - winrt::com_ptr device; - device.copy_from(GetDeviceResources()->GetD3DDevice()); - WindowCreateSwapChain(device); - - DXGI_ADAPTER_DESC2 dxgiAdapterDesc; - if (SUCCEEDED(GetDeviceResources()->GetDXGIAdapter()->GetDesc2(&dxgiAdapterDesc)) && - (dxgiAdapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)) - { - DebugLog(L"Software video adapter is not supported for holographic streamer.\n"); - m_remoteContext = nullptr; - return; - } - - winrt::weak_ref remoteContextWeakRef = m_remoteContext; - - m_onConnectedEventRevoker = m_remoteContext.OnConnected(winrt::auto_revoke, [this, remoteContextWeakRef]() { - if (auto remoteContext = remoteContextWeakRef.get()) - { - WindowUpdateTitle(); - remoteContext.CreateDataChannel(0, DataChannelPriority::Low); - } - }); - - m_onDisconnectedEventRevoker = - m_remoteContext.OnDisconnected(winrt::auto_revoke, [this, remoteContextWeakRef](ConnectionFailureReason failureReason) { - if (auto remoteContext = remoteContextWeakRef.get()) - { - DebugLog(L"Disconnected with reason %d", failureReason); - WindowUpdateTitle(); - - // Reconnect if this is a transient failure. - if (failureReason == ConnectionFailureReason::HandshakeUnreachable || - failureReason == ConnectionFailureReason::TransportUnreachable || - failureReason == ConnectionFailureReason::ConnectionLost) - { - DebugLog(L"Reconnecting..."); - - ConnectOrListen(); - } - // Failure reason None indicates a normal disconnect. - else if (failureReason != ConnectionFailureReason::None) - { - DebugLog(L"Disconnected with unrecoverable error, not attempting to reconnect."); - } - } - }); - - m_onSendFrameEventRevoker = m_remoteContext.OnSendFrame( - winrt::auto_revoke, [this](const winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface& texture) { - if (m_showPreview) - { - winrt::com_ptr spDevice; - spDevice.copy_from(GetDeviceResources()->GetD3DDevice()); - - winrt::com_ptr spBackBuffer; - winrt::check_hresult(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), spBackBuffer.put_void())); - - winrt::com_ptr texturePtr; - { - winrt::com_ptr resource; - winrt::com_ptr<::IInspectable> inspectable = texture.as<::IInspectable>(); - winrt::com_ptr dxgiInterfaceAccess; - winrt::check_hresult(inspectable->QueryInterface(__uuidof(dxgiInterfaceAccess), dxgiInterfaceAccess.put_void())); - winrt::check_hresult(dxgiInterfaceAccess->GetInterface(__uuidof(resource), resource.put_void())); - resource.as(texturePtr); - } - - GetDeviceResources()->UseD3DDeviceContext([&](auto context) { - context->CopySubresourceRegion( - spBackBuffer.get(), // dest - 0, // dest subresource - 0, - 0, - 0, // dest x, y, z - texturePtr.get(), // source - 0, // source subresource - nullptr); // source box, null means the entire resource - }); - - WindowPresentSwapChain(); - } - }); - -#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE - m_onDataChannelCreatedEventRevoker = - m_remoteContext.OnDataChannelCreated(winrt::auto_revoke, [this](const IDataChannel& dataChannel, uint8_t channelId) { - std::lock_guard lock(m_customDataChannelLock); - m_customDataChannel = dataChannel; - - m_customChannelDataReceivedEventRevoker = m_customDataChannel.OnDataReceived( - winrt::auto_revoke, [this](winrt::array_view dataView) { OnCustomDataChannelDataReceived(); }); - - m_customChannelClosedEventRevoker = - m_customDataChannel.OnClosed(winrt::auto_revoke, [this]() { OnCustomDataChannelClosed(); }); - }); -#endif - - ConnectOrListen(); - } -} - -void SampleHostMain::CreateHolographicSpaceAndDeviceResources() -{ - UnregisterHolographicEventHandlers(); - - m_holographicSpace = HolographicSpace::CreateForCoreWindow(nullptr); - - m_deviceResources->SetHolographicSpace(m_holographicSpace); - - m_spinningCubeRenderer = std::make_unique(m_deviceResources); - - // Uncomment the below line to render spatial surfaces - // m_spatialSurfaceMeshRenderer = std::make_unique(m_deviceResources); - - m_spatialInputRenderer = std::make_unique(m_deviceResources); - m_spatialInputHandler = std::make_shared(); - - m_qrCodeRenderer = std::make_unique(m_deviceResources); - - m_perceptionDeviceHandler = std::make_shared(); - m_perceptionDeviceHandler->Start(); - - - m_locator = SpatialLocator::GetDefault(); - - // Be able to respond to changes in the positional tracking state. - m_locatabilityChangedToken = m_locator.LocatabilityChanged({this, &SampleHostMain::OnLocatabilityChanged}); - - m_cameraAddedToken = m_holographicSpace.CameraAdded({this, &SampleHostMain::OnCameraAdded}); - m_cameraRemovedToken = m_holographicSpace.CameraRemoved({this, &SampleHostMain::OnCameraRemoved}); - - { - m_referenceFrame = m_locator.CreateStationaryFrameOfReferenceAtCurrentLocation(float3::zero(), quaternion(0, 0, 0, 1), 0.0); - } - - m_isInitialized = true; -} - -void SampleHostMain::ConnectOrListen() -{ - // Try to establish a connection. - try - { - m_remoteContext.Disconnect(); - - // Request access to eyes pose data on every connection/listen attempt. - RequestEyesPoseAccess(); - - if (m_port == 0) - { - m_port = 8265; - } - - if (m_listen) - { - if (m_hostname.empty()) - { - m_hostname = L"0.0.0.0"; - } - m_remoteContext.Listen(m_hostname, m_port, m_port + 1); - } - else - { - if (m_hostname.empty()) - { - m_hostname = L"127.0.0.1"; - } - m_remoteContext.Connect(m_hostname, m_port); - } - } - catch (winrt::hresult_error& e) - { - if (m_listen) - { - DebugLog(L"Listen failed with hr = 0x%08X", e.code()); - } - else - { - DebugLog(L"Connect failed with hr = 0x%08X", e.code()); - } - } -} - -void SampleHostMain::LoadPosition() -{ - auto storeRequest = SpatialAnchorManager::RequestStoreAsync(); - storeRequest.Completed([this](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { - if (result.Status() != winrt::Windows::Foundation::AsyncStatus::Completed) - { - return; - } - - const SpatialAnchorStore& store = result.GetResults(); - if (store) - { - auto anchors = store.GetAllSavedAnchors(); - if (anchors.HasKey(L"position")) - { - auto position = anchors.Lookup(L"position"); - auto positionToOrigin = position.CoordinateSystem().TryGetTransformTo(m_referenceFrame.CoordinateSystem()); - if (positionToOrigin) - { - const float3 res = transform(float3::zero(), positionToOrigin.Value()); - m_spinningCubeRenderer->SetPosition(res); - OutputDebugStringW(L"Loaded cube position from SpatialAnchorStore.\n"); - } - } - } - }); -} - -void SampleHostMain::SavePosition() -{ - auto position = SpatialAnchor::TryCreateRelativeTo(m_referenceFrame.CoordinateSystem(), m_spinningCubeRenderer->GetPosition()); - - auto storeRequest = SpatialAnchorManager::RequestStoreAsync(); - storeRequest.Completed([position](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { - if (result.Status() != winrt::Windows::Foundation::AsyncStatus::Completed) - { - return; - } - - const SpatialAnchorStore& store = result.GetResults(); - if (store) - { - store.Clear(); - if (store.TrySave(L"position", position)) - { - OutputDebugStringW(L"Saved cube position to SpatialAnchorStore.\n"); - } - } - }); -} - - -void SampleHostMain::RequestEyesPoseAccess() -{ - try - { - auto asyncOpertation = winrt::Windows::Perception::People::EyesPose::RequestAccessAsync(); - asyncOpertation.Completed( - [this](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { - winrt::Windows::UI::Input::GazeInputAccessStatus status = result.GetResults(); - switch (status) - { - case winrt::Windows::UI::Input::GazeInputAccessStatus::Unspecified: - OutputDebugStringA("ParseGazeInputResponseData Unspecified\n"); - break; - case winrt::Windows::UI::Input::GazeInputAccessStatus::Allowed: - OutputDebugStringA("ParseGazeInputResponseData Allowed\n"); - break; - case winrt::Windows::UI::Input::GazeInputAccessStatus::DeniedByUser: - OutputDebugStringA("ParseGazeInputResponseData DeniedByUser\n"); - break; - case winrt::Windows::UI::Input::GazeInputAccessStatus::DeniedBySystem: - OutputDebugStringA("ParseGazeInputResponseData DeniedBySystem\n"); - break; - default: - break; - } - }); - } - catch (winrt::hresult_error&) - { - } -} - -void SampleHostMain::UnregisterHolographicEventHandlers() -{ - if (m_holographicSpace != nullptr) - { - m_holographicSpace.CameraAdded(m_cameraAddedToken); - m_holographicSpace.CameraRemoved(m_cameraRemovedToken); - } - - if (m_locator != nullptr) - { - m_locator.LocatabilityChanged(m_locatabilityChangedToken); - } -} - -void SampleHostMain::ShutdownRemoteContext() -{ - if (m_remoteContext != nullptr) - { - m_onConnectedEventRevoker.revoke(); - m_onDisconnectedEventRevoker.revoke(); - m_onSendFrameEventRevoker.revoke(); - m_onDataChannelCreatedEventRevoker.revoke(); - -#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE - { - std::lock_guard lock(m_customDataChannelLock); - m_customChannelDataReceivedEventRevoker.revoke(); - m_customChannelClosedEventRevoker.revoke(); - m_customDataChannel = nullptr; - } -#endif - - m_remoteContext.Close(); - m_remoteContext = nullptr; - } -} - -void SampleHostMain::OnDeviceLost() -{ - m_spinningCubeRenderer->ReleaseDeviceDependentResources(); - m_spatialInputRenderer->ReleaseDeviceDependentResources(); - m_qrCodeRenderer->ReleaseDeviceDependentResources(); - - if (m_spatialSurfaceMeshRenderer) - { - m_spatialSurfaceMeshRenderer->ReleaseDeviceDependentResources(); - } -} - -void SampleHostMain::OnDeviceRestored() -{ - m_spinningCubeRenderer->CreateDeviceDependentResources(); - m_spatialInputRenderer->CreateDeviceDependentResources(); - m_qrCodeRenderer->CreateDeviceDependentResources(); - - if (m_spatialSurfaceMeshRenderer) - { - m_spatialSurfaceMeshRenderer->CreateDeviceDependentResources(); - } -} - -void SampleHostMain::OnCameraAdded(const HolographicSpace& sender, const HolographicSpaceCameraAddedEventArgs& args) -{ - winrt::Windows::Foundation::Deferral deferral = args.GetDeferral(); - auto holographicCamera = args.Camera(); - create_task([this, deferral, holographicCamera]() { - m_deviceResources->AddHolographicCamera(holographicCamera); - - deferral.Complete(); - }); -} - -void SampleHostMain::OnCameraRemoved(const HolographicSpace& sender, const HolographicSpaceCameraRemovedEventArgs& args) -{ - m_deviceResources->RemoveHolographicCamera(args.Camera()); -} - -void SampleHostMain::OnLocatabilityChanged(const SpatialLocator& sender, const winrt::Windows::Foundation::IInspectable& args) -{ - const wchar_t* locatability = L""; - switch (sender.Locatability()) - { - case SpatialLocatability::Unavailable: - locatability = L"Unavailable"; - break; - - case SpatialLocatability::PositionalTrackingActivating: - locatability = L"PositionalTrackingActivating"; - break; - - case SpatialLocatability::OrientationOnly: - locatability = L"OrientationOnly"; - break; - - case SpatialLocatability::PositionalTrackingInhibited: - locatability = L"PositionalTrackingInhibited"; - break; - - case SpatialLocatability::PositionalTrackingActive: - locatability = L"PositionalTrackingActive"; - break; - } - - winrt::hstring message = L"Positional tracking is " + winrt::to_hstring(locatability) + L".\n"; - OutputDebugStringW(message.data()); -} - -void SampleHostMain::WindowCreateSwapChain(const winrt::com_ptr& device) -{ - std::lock_guard _lg(m_deviceLock); - - DXGI_SWAP_CHAIN_DESC1 desc = {0}; - desc.Width = m_width; - desc.Height = m_height; - desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - desc.Stereo = false; - desc.SampleDesc.Count = 1; // Don't use multi-sampling. - desc.SampleDesc.Quality = 0; - desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.BufferCount = 2; // Double buffered - desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; - desc.Flags = 0; - desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; - desc.Scaling = DXGI_SCALING_STRETCH; - - m_swapChain = nullptr; - - if (auto window = m_window.lock()) - { - m_swapChain = window->CreateSwapChain(device, &desc); - } -} - -void SampleHostMain::WindowPresentSwapChain() -{ - HRESULT hr = m_swapChain->Present(0, 0); - - if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) - { - // The D3D device is lost. - // This should be handled after the frame is complete. - m_swapChain = nullptr; - } - else - { - winrt::check_hresult(hr); - } -} - -void SampleHostMain::WindowUpdateTitle() -{ - std::wstring title = TITLE_TEXT; - std::wstring separator = TITLE_SEPARATOR; - - uint32_t fps = min(120, m_framesPerSecond); - title += separator + std::to_wstring(fps) + L" fps"; - - // Title | {ip} | {State} [| Press Space to Connect] [| Preview Disabled (p toggles)] - title += separator + m_hostname; - { - if (m_remoteContext) - { - auto connectionState = m_remoteContext.ConnectionState(); - title += separator + (m_isInitialized ? StreamerConnectionStateToString(connectionState) : L"Initializing"); - title += separator + ((connectionState == ConnectionState::Disconnected) ? TITLE_CONNECT_TEXT : TITLE_DISCONNECT_TEXT); - } - else - { - title += separator + TITLE_CONNECT_TEXT; - } - title += separator + (m_showPreview ? TITLE_DISABLE_PREVIEW_TEXT : TITLE_ENABLE_PREVIEW_TEXT); - } - - if (auto window = m_window.lock()) - { - window->SetWindowTitle(title); - } -} - -#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE -void SampleHostMain::OnCustomDataChannelDataReceived() -{ - // TODO: React on data received via the custom data channel here. -} - -void SampleHostMain::OnCustomDataChannelClosed() -{ - std::lock_guard lock(m_customDataChannelLock); - if (m_customDataChannel) - { - m_customChannelDataReceivedEventRevoker.revoke(); - m_customChannelClosedEventRevoker.revoke(); - m_customDataChannel = nullptr; - } -} -#endif +//********************************************************* +// +// 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 "SampleRemoteMain.h" + +#include "Common\DbgLog.h" +#include "Common\DirectXHelper.h" +#include "Common\Speech.h" + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +using namespace concurrency; + +using namespace std::chrono_literals; + +using namespace winrt::Microsoft::Holographic::AppRemoting; +using namespace winrt::Windows::Foundation::Numerics; +using namespace winrt::Windows::Graphics::Holographic; +using namespace winrt::Windows::Graphics::DirectX; +using namespace winrt::Windows::Perception::People; +using namespace winrt::Windows::Perception::Spatial; +using namespace winrt::Windows::UI::Input; +using namespace winrt::Windows::Security::Authorization::AppCapabilityAccess; + +namespace +{ + const wchar_t* StreamerConnectionStateToString(ConnectionState state, bool disconnectPending) + { + switch (state) + { + case ConnectionState::Disconnected: + return L"Disconnected"; + + case ConnectionState::Connecting: + return L"Connecting"; + + case ConnectionState::Connected: + return disconnectPending ? L"Disconnecting" : L"Connected"; + } + + return L"Unknown"; + } +} // namespace + +SampleRemoteMain::SampleRemoteMain(std::weak_ptr window) + : m_window(window) +{ + m_deviceResources = std::make_shared(); + m_deviceResources->RegisterDeviceNotify(this); + + m_canCommitDirect3D11DepthBuffer = winrt::Windows::Foundation::Metadata::ApiInformation::IsMethodPresent( + L"Windows.Graphics.Holographic.HolographicCameraRenderingParameters", L"CommitDirect3D11DepthBuffer"); +} + +SampleRemoteMain::~SampleRemoteMain() +{ + ShutdownRemoteContext(); + + m_deviceResources->RegisterDeviceNotify(nullptr); + UnregisterHolographicEventHandlers(); +} + +HolographicFrame SampleRemoteMain::Update() +{ + auto timeDelta = std::chrono::high_resolution_clock::now() - m_windowTitleUpdateTime; + if (timeDelta >= 1s) + { + WindowUpdateTitle(); + + m_windowTitleUpdateTime = std::chrono::high_resolution_clock::now(); + m_framesPerSecond = 0; + } + + if (!m_holographicSpace) + { + return nullptr; + } + + // NOTE: DXHelper::DeviceResources::Present does not wait for the frame to finish. + // Instead we wait here before we do the call to CreateNextFrame on the HolographicSpace. + // We do this to avoid that PeekMessage causes frame delta time spikes, say if we wait + // after PeekMessage WaitForNextFrameReady will compensate any time spend in PeekMessage. + m_holographicSpace.WaitForNextFrameReady(); + + HolographicFrame holographicFrame = m_holographicSpace.CreateNextFrame(); + 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); + + SpatialCoordinateSystem coordinateSystem = nullptr; + { + coordinateSystem = m_referenceFrame.CoordinateSystem(); + } + + // Check for new input state since the last frame. + Spatial::SpatialTappedEventArgs tapped = m_spatialInputHandler->CheckForTapped(); + if (tapped) + { + Spatial::SpatialPointerPose pointerPose = tapped.TryGetPointerPose(coordinateSystem); + + // When the Tapped spatial input event is received, the sample hologram will be repositioned two meters in front of the user. + m_spinningCubeRenderer->PositionHologram(pointerPose); + } + else + { + static float3 initialCubePosition = float3::zero(); + + auto manipulationStarted = m_spatialInputHandler->CheckForManipulationStarted(); + if (manipulationStarted) + { + initialCubePosition = m_spinningCubeRenderer->GetPosition(); + m_spinningCubeRenderer->Pause(); + } + else + { + auto manipulationUpdated = m_spatialInputHandler->CheckForManipulationUpdated(); + if (manipulationUpdated) + { + auto delta = manipulationUpdated.TryGetCumulativeDelta(coordinateSystem); + if (delta) + { + m_spinningCubeRenderer->SetPosition(initialCubePosition + delta.Translation()); + } + } + else + { + switch (m_spatialInputHandler->CheckForManipulationResult()) + { + case SpatialInputHandler::ManipulationResult::Canceled: + m_spinningCubeRenderer->SetPosition(initialCubePosition); + case SpatialInputHandler::ManipulationResult::Completed: + m_spinningCubeRenderer->Unpause(); + break; + } + } + } + } + + std::chrono::duration timeSinceStart = std::chrono::high_resolution_clock::now() - m_startTime; + m_spinningCubeRenderer->Update(timeSinceStart.count(), prediction.Timestamp(), coordinateSystem); + + if (m_spatialSurfaceMeshRenderer != nullptr) + { + m_spatialSurfaceMeshRenderer->Update(prediction.Timestamp(), coordinateSystem); + } + m_spatialInputRenderer->Update(prediction.Timestamp(), coordinateSystem); + if (m_perceptionDeviceHandler) + { + m_qrCodeRenderer->Update(*m_perceptionDeviceHandler, coordinateSystem); + } + + // We complete the frame update by using information about our content positioning to set the focus point. + if (!m_canCommitDirect3D11DepthBuffer || !m_commitDirect3D11DepthBuffer) + { + for (auto cameraPose : prediction.CameraPoses()) + { + try + { + HolographicCameraRenderingParameters renderingParameters = holographicFrame.GetRenderingParameters(cameraPose); + + // Set the focus point for image stabilization to the center of the sample hologram. + // NOTE: A focus point can be set for every HolographicFrame. If a focus point is set on a HolographicFrame, + // it will get transmitted to the player and will get set during the PlayerContext::BlitRemoteFrame() call. + renderingParameters.SetFocusPoint(coordinateSystem, m_spinningCubeRenderer->GetPosition()); + } + catch (winrt::hresult_error&) + { + } + } + } + +#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE + timeDelta = std::chrono::high_resolution_clock::now() - m_customDataChannelSendTime; + if (timeDelta > 5s) + { + m_customDataChannelSendTime = std::chrono::high_resolution_clock::now(); + + // Send ping every couple of frames if we have a custom data channel. + std::lock_guard lock(m_customDataChannelLock); + if (m_customDataChannel) + { + // Try to get send queue size. The send queue size returns the size of data, that has not been send yet, in bytes. + // A big number might indicate that more data is queued to send than the amount of data, that is actually sent. + // If possible skip sending data in this case, to help the queue getting smaller again. + uint32_t sendQueueSize = m_customDataChannel.SendQueueSize(); + + // Only send the packet if the send queue is smaller than 1MiB + if (sendQueueSize < 1 * 1024 * 1024) + { + uint8_t data = 1; + + try + { + m_customDataChannel.SendData( + winrt::array_view( + reinterpret_cast(&data), reinterpret_cast(&data + 1)), + true); + OutputDebugString(TEXT("Request Sent.\n")); + } + catch (...) + { + // SendData might throw if channel is closed, but we did not get or process the async closed event yet. + } + } + } + } +#endif + + return holographicFrame; +} + +void SampleRemoteMain::Render(HolographicFrame holographicFrame) +{ + bool atLeastOneCameraRendered = false; + + m_deviceResources->UseHolographicCameraResources([this, holographicFrame, &atLeastOneCameraRendered]( + std::map>& cameraResourceMap) { + holographicFrame.UpdateCurrentPrediction(); + HolographicFramePrediction prediction = holographicFrame.CurrentPrediction(); + + SpatialCoordinateSystem coordinateSystem = nullptr; + { + coordinateSystem = m_referenceFrame.CoordinateSystem(); + } + + for (auto cameraPose : prediction.CameraPoses()) + { + try + { + DXHelper::CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get(); + + if (pCameraResources == nullptr || pCameraResources->GetBackBufferRenderTargetView() == nullptr) + { + continue; + } + + m_deviceResources->UseD3DDeviceContext([&](ID3D11DeviceContext3* context) { + // Clear the back buffer view. + context->ClearRenderTargetView(pCameraResources->GetBackBufferRenderTargetView(), DirectX::Colors::Transparent); + context->ClearDepthStencilView( + pCameraResources->GetDepthStencilView(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); + + // 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, coordinateSystem); + + // Set up the camera buffer. + bool cameraActive = pCameraResources->AttachViewProjectionBuffer(m_deviceResources); + + // Only render world-locked content when positional tracking is active. + if (cameraActive) + { + // Set the render target, and set the depth target drawing buffer. + ID3D11RenderTargetView* const targets[1] = {pCameraResources->GetBackBufferRenderTargetView()}; + context->OMSetRenderTargets(1, targets, pCameraResources->GetDepthStencilView()); + + // Render the scene objects. + m_spinningCubeRenderer->Render(pCameraResources->IsRenderingStereoscopic()); + if (m_spatialSurfaceMeshRenderer != nullptr) + { + m_spatialSurfaceMeshRenderer->Render(pCameraResources->IsRenderingStereoscopic()); + } + m_spatialInputRenderer->Render(pCameraResources->IsRenderingStereoscopic()); + m_qrCodeRenderer->Render(pCameraResources->IsRenderingStereoscopic()); + + // Commit depth buffer if available and enabled. + if (m_canCommitDirect3D11DepthBuffer && m_commitDirect3D11DepthBuffer) + { + auto interopSurface = pCameraResources->GetDepthStencilTextureInteropObject(); + HolographicCameraRenderingParameters renderingParameters = holographicFrame.GetRenderingParameters(cameraPose); + renderingParameters.CommitDirect3D11DepthBuffer(interopSurface); + } + } + }); + + atLeastOneCameraRendered = true; + } + catch (const winrt::hresult_error&) + { + } + } + }); + + if (atLeastOneCameraRendered) + { + m_deviceResources->Present(holographicFrame); + } + + if (!m_isStandalone) + { + if (m_swapChain == nullptr && m_isInitialized) + { + // A device lost event has occurred. + // Reconnection is necessary because the holographic streamer uses the D3D device. + // The following resources depend on the D3D device: + // * Holographic streamer + // * Renderer + // * Holographic space + // The InitializeRemoteContext() function will call the functions necessary to recreate these resources. + ShutdownRemoteContext(); + InitializeRemoteContextAndConnectOrListen(); + } + + // Determine whether or not to copy to the preview buffer. + bool copyPreview; + { + std::lock_guard remoteContextLock(m_remoteContextAccess); + copyPreview = m_remoteContext == nullptr || m_remoteContext.ConnectionState() != ConnectionState::Connected; + } + if (copyPreview && m_isInitialized) + { + winrt::com_ptr spDevice; + spDevice.copy_from(GetDeviceResources()->GetD3DDevice()); + + winrt::com_ptr spBackBuffer; + winrt::check_hresult(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), spBackBuffer.put_void())); + + // 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. + winrt::com_ptr spRenderTargetView; + winrt::check_hresult(spDevice->CreateRenderTargetView(spBackBuffer.get(), nullptr, spRenderTargetView.put())); + + GetDeviceResources()->UseD3DDeviceContext( + [&](auto context) { context->ClearRenderTargetView(spRenderTargetView.get(), DirectX::Colors::CornflowerBlue); }); + + WindowPresentSwapChain(); + } + } + + m_framesPerSecond++; +} + +void SampleRemoteMain::ConfigureRemoting( + bool listen, const std::wstring& hostname, uint16_t port, uint16_t transportPort, bool ephemeralPort) +{ + if (!m_isInitialized) + { + m_listen = listen; + m_hostname = hostname; + m_port = port; + m_transportPort = transportPort; + m_ephemeralPort = ephemeralPort; + } +} + +void SampleRemoteMain::InitializeStandalone() +{ + if (!m_isInitialized) + { + m_isStandalone = true; + CreateHolographicSpaceAndDeviceResources(); + } +} + +void SampleRemoteMain::OnKeyPress(char key) +{ + switch (key) + { + case ' ': + InitializeRemoteContextAndConnectOrListen(); + break; + + case 'd': + { + std::lock_guard remoteContextLock(m_remoteContextAccess); + if (m_remoteContext && m_remoteContext.ConnectionState() != ConnectionState::Disconnected) + { + m_disconnectPending = true; + m_remoteContext.Disconnect(); + } + } + break; + + case 'p': + m_showPreview = !m_showPreview; + break; + + case 'l': + LoadPosition(); + break; + + case 's': + SavePosition(); + break; + + case 'e': + ExportPosition(); + break; + + case 'x': + m_commitDirect3D11DepthBuffer = !m_commitDirect3D11DepthBuffer; + break; + + case 'c': + m_spinningCubeRenderer->TogglePauseState(); + break; + } + + WindowUpdateTitle(); +} + +void SampleRemoteMain::OnResize(int width, int height) +{ + std::lock_guard _lg(m_deviceLock); + + if (width != m_width || height != m_height) + { + m_width = width; + m_height = height; + + if (m_swapChain) + { + winrt::check_hresult(m_swapChain->ResizeBuffers(2, m_width, m_height, DXGI_FORMAT_B8G8R8A8_UNORM, 0)); + } + } +} + +void SampleRemoteMain::OnRecognizedSpeech(const winrt::hstring& recognizedText) +{ + bool changedColor = false; + DirectX::XMFLOAT4 color = {1, 1, 1, 1}; + + if (recognizedText == L"Red") + { + color = {1, 0, 0, 1}; + changedColor = true; + } + else if (recognizedText == L"Blue") + { + color = {0, 0, 1, 1}; + changedColor = true; + } + else if (recognizedText == L"Green") + { + color = {0, 1, 0, 1}; + changedColor = true; + } + else if (recognizedText == L"Default") + { + color = {1, 1, 1, 1}; + changedColor = true; + } + else if (recognizedText == L"Aquamarine") + { + color = {0, 1, 1, 1}; + changedColor = true; + } + else if (recognizedText == L"Load position") + { + LoadPosition(); + } + else if (recognizedText == L"Save position") + { + SavePosition(); + } + + if (changedColor && m_spinningCubeRenderer) + { + m_spinningCubeRenderer->SetColorFilter(color); + } +} + +void SampleRemoteMain::InitializeRemoteContextAndConnectOrListen() +{ + std::lock_guard remoteContextLock(m_remoteContextAccess); + + if (!m_remoteContext && !m_isStandalone) + { + // Create the RemoteContext + // IMPORTANT: This must be done before creating the HolographicSpace (or any other call to the Holographic API). + CreateRemoteContext(m_remoteContext, 20000, true, PreferredVideoCodec::Any); + + // Configure for half-resolution depth. + m_remoteContext.ConfigureDepthVideoStream(DepthBufferStreamResolution::Half_Resolution); + + // Create the HolographicSpace + CreateHolographicSpaceAndDeviceResources(); + + if (auto remoteSpeech = m_remoteContext.GetRemoteSpeech()) + { + Speech::InitializeSpeechAsync(remoteSpeech, m_onRecognizedSpeechRevoker, weak_from_this()); + } + + winrt::com_ptr device; + device.copy_from(GetDeviceResources()->GetD3DDevice()); + WindowCreateSwapChain(device); + + DXGI_ADAPTER_DESC2 dxgiAdapterDesc; + if (SUCCEEDED(GetDeviceResources()->GetDXGIAdapter()->GetDesc2(&dxgiAdapterDesc)) && + (dxgiAdapterDesc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)) + { + DebugLog(L"Software video adapter is not supported for holographic streamer.\n"); + m_remoteContext = nullptr; + return; + } + + winrt::weak_ref remoteContextWeakRef = m_remoteContext; + + m_onConnectedEventRevoker = m_remoteContext.OnConnected(winrt::auto_revoke, [this, remoteContextWeakRef]() { + if (auto remoteContext = remoteContextWeakRef.get()) + { + WindowUpdateTitle(); + remoteContext.CreateDataChannel(0, DataChannelPriority::Low); + } + + // The spatial surface renderer needs to get recreated on every connect, because its SpatialSurfaceObserver stops working on + // disconnect. Uncomment the below line to render spatial surfaces + // m_spatialSurfaceMeshRenderer = std::make_unique(m_deviceResources); + }); + + m_onDisconnectedEventRevoker = + m_remoteContext.OnDisconnected(winrt::auto_revoke, [this, remoteContextWeakRef](ConnectionFailureReason failureReason) { + if (auto remoteContext = remoteContextWeakRef.get()) + { + OnDisconnected(failureReason); + } + + m_spatialSurfaceMeshRenderer = nullptr; + }); + + m_onSendFrameEventRevoker = m_remoteContext.OnSendFrame( + winrt::auto_revoke, [this](const winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface& texture) { + if (m_showPreview) + { + winrt::com_ptr spDevice; + spDevice.copy_from(GetDeviceResources()->GetD3DDevice()); + + winrt::com_ptr spBackBuffer; + winrt::check_hresult(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), spBackBuffer.put_void())); + + winrt::com_ptr texturePtr; + { + winrt::com_ptr resource; + winrt::com_ptr<::IInspectable> inspectable = texture.as<::IInspectable>(); + winrt::com_ptr dxgiInterfaceAccess; + winrt::check_hresult(inspectable->QueryInterface(__uuidof(dxgiInterfaceAccess), dxgiInterfaceAccess.put_void())); + winrt::check_hresult(dxgiInterfaceAccess->GetInterface(__uuidof(resource), resource.put_void())); + resource.as(texturePtr); + } + + // Get source/dest dimensions and adjust copy rect and destination position to avoid D3D errors + D3D11_TEXTURE2D_DESC backBufferDesc, textureDesc; + spBackBuffer->GetDesc(&backBufferDesc); + texturePtr->GetDesc(&textureDesc); + + UINT destX = 0, destY = 0; + D3D11_BOX srcBox{0, 0, 0, textureDesc.Width, textureDesc.Height, 1}; + + if (backBufferDesc.Width < textureDesc.Width) + { + // Target (BackBuffer) narrower than source (Texture) + srcBox.left = (textureDesc.Width - backBufferDesc.Width) / 2; + srcBox.right = srcBox.left + backBufferDesc.Width; + } + else if (backBufferDesc.Width > textureDesc.Width) + { + // Target (BackBuffer) wider than source (Texture) + destX = (backBufferDesc.Width - textureDesc.Width) / 2; + } + + if (backBufferDesc.Height < textureDesc.Height) + { + // Target (BackBuffer) shorter than source (Texture) + srcBox.top = (textureDesc.Height - backBufferDesc.Height) / 2; + srcBox.bottom = srcBox.top + backBufferDesc.Height; + } + else if (backBufferDesc.Height > textureDesc.Height) + { + // Target (BackBuffer) taller than source (Texture) + destY = (backBufferDesc.Height - textureDesc.Height) / 2; + } + + // Copy texture to back buffer + GetDeviceResources()->UseD3DDeviceContext([&](auto context) { + context->CopySubresourceRegion( + spBackBuffer.get(), // dest + 0, // dest subresource + destX, + destY, + 0, // dest x, y, z + texturePtr.get(), // source + 0, // source subresource + &srcBox); // source box, null means the entire resource + }); + + WindowPresentSwapChain(); + } + }); + +#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE + m_onDataChannelCreatedEventRevoker = + m_remoteContext.OnDataChannelCreated(winrt::auto_revoke, [this](const IDataChannel& dataChannel, uint8_t channelId) { + std::lock_guard lock(m_customDataChannelLock); + m_customDataChannel = dataChannel.as(); + + m_customChannelDataReceivedEventRevoker = m_customDataChannel.OnDataReceived( + winrt::auto_revoke, [this](winrt::array_view dataView) { OnCustomDataChannelDataReceived(); }); + + m_customChannelClosedEventRevoker = + m_customDataChannel.OnClosed(winrt::auto_revoke, [this]() { OnCustomDataChannelClosed(); }); + }); +#endif + + ConnectOrListen(); + } +} + +void SampleRemoteMain::CreateHolographicSpaceAndDeviceResources() +{ + UnregisterHolographicEventHandlers(); + + if (auto window = m_window.lock()) + { + m_holographicSpace = window->CreateHolographicSpace(); + m_interactionManager = window->CreateInteractionManager(); + } + + m_deviceResources->SetHolographicSpace(m_holographicSpace); + + m_spatialInputRenderer = std::make_shared(m_deviceResources, m_interactionManager); + m_spatialInputHandler = std::make_shared(m_interactionManager); + + { + m_spinningCubeRenderer = std::make_unique(m_deviceResources); + } + + m_qrCodeRenderer = std::make_unique(m_deviceResources); + + CreatePerceptionDeviceHandler(); + + m_locator = SpatialLocator::GetDefault(); + + // Be able to respond to changes in the positional tracking state. + m_locatabilityChangedToken = m_locator.LocatabilityChanged({this, &SampleRemoteMain::OnLocatabilityChanged}); + + m_cameraAddedToken = m_holographicSpace.CameraAdded({this, &SampleRemoteMain::OnCameraAdded}); + m_cameraRemovedToken = m_holographicSpace.CameraRemoved({this, &SampleRemoteMain::OnCameraRemoved}); + + { + m_referenceFrame = m_locator.CreateStationaryFrameOfReferenceAtCurrentLocation(float3::zero(), quaternion(0, 0, 0, 1), 0.0); + } + + m_isInitialized = true; +} + +void SampleRemoteMain::ConnectOrListen() +{ + std::lock_guard remoteContextLock(m_remoteContextAccess); + + if (!m_remoteContext || m_remoteContext.ConnectionState() != ConnectionState::Disconnected) + { + return; + } + + // Try to establish a connection. + try + { + // Request access to eyes pose data on every connection/listen attempt. + RequestEyesPoseAccess(); + + if (m_ephemeralPort) + { + m_port = 0; + } + else if (m_port == 0) + { + m_port = 8265; + } + + if (m_listen) + { + if (m_ephemeralPort) + { + m_transportPort = 0; + } + else if (m_transportPort == 0) + { + m_transportPort = m_port + 1; + } + + if (m_hostname.empty()) + { + m_hostname = L"0.0.0.0"; + } + m_remoteContext.Listen(m_hostname, m_port, m_transportPort); + } + else + { + if (m_hostname.empty()) + { + m_hostname = L"127.0.0.1"; + } + m_remoteContext.Connect(m_hostname, m_port); + } + } + catch (winrt::hresult_error& e) + { + if (m_listen) + { + DebugLog(L"Listen failed with hr = 0x%08X", e.code()); + } + else + { + DebugLog(L"Connect failed with hr = 0x%08X", e.code()); + } + } +} + +void SampleRemoteMain::LoadPosition() +{ + auto storeRequest = SpatialAnchorManager::RequestStoreAsync(); + storeRequest.Completed([this](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { + if (result.Status() != winrt::Windows::Foundation::AsyncStatus::Completed) + { + return; + } + + const SpatialAnchorStore& store = result.GetResults(); + if (store) + { + auto anchors = store.GetAllSavedAnchors(); + if (anchors.HasKey(L"position")) + { + auto position = anchors.Lookup(L"position"); + auto positionToOrigin = position.CoordinateSystem().TryGetTransformTo(m_referenceFrame.CoordinateSystem()); + if (positionToOrigin) + { + const float3 res = transform(float3::zero(), positionToOrigin.Value()); + m_spinningCubeRenderer->SetPosition(res); + OutputDebugStringW(L"Loaded cube position from SpatialAnchorStore.\n"); + } + } + } + }); +} + +void SampleRemoteMain::SavePosition() +{ + auto position = SpatialAnchor::TryCreateRelativeTo(m_referenceFrame.CoordinateSystem(), m_spinningCubeRenderer->GetPosition()); + + auto storeRequest = SpatialAnchorManager::RequestStoreAsync(); + storeRequest.Completed([position](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { + if (result.Status() != winrt::Windows::Foundation::AsyncStatus::Completed) + { + return; + } + + const SpatialAnchorStore& store = result.GetResults(); + if (store) + { + store.Clear(); + if (store.TrySave(L"position", position)) + { + OutputDebugStringW(L"Saved cube position to SpatialAnchorStore.\n"); + } + } + }); +} + +winrt::fire_and_forget SampleRemoteMain::ExportPosition() +{ + const auto purpose = winrt::Windows::Perception::Spatial::SpatialAnchorExportPurpose::Sharing; + + auto position = SpatialAnchor::TryCreateRelativeTo(m_referenceFrame.CoordinateSystem(), m_spinningCubeRenderer->GetPosition()); + + co_await winrt::resume_background(); + + try + { + using namespace winrt::Windows::Storage::Streams; + + auto status = SpatialAnchorExporter::RequestAccessAsync().get(); + if (status != SpatialPerceptionAccessStatus::Allowed) + { + co_return; + } + + auto exporter = SpatialAnchorExporter::GetDefault(); + auto sufficient = exporter.GetAnchorExportSufficiencyAsync(position, purpose).get(); + + if (!sufficient.IsMinimallySufficient()) + { + OutputDebugStringW(L"\r\nNot enough data for the anchor to export. Try again later."); + co_return; + } + + { + InMemoryRandomAccessStream stream = InMemoryRandomAccessStream(); + bool result = exporter.TryExportAnchorAsync(position, purpose, stream.GetOutputStreamAt(0)).get(); + + uint64_t size = stream.Size(); + if (size > UINT32_MAX) + { + co_return; + } + + std::vector data; + data.resize(size); + + DataReader reader(stream); + reader.LoadAsync(static_cast(size)); + reader.ReadBytes(winrt::array_view(data.data(), data.data() + data.size())); + + { + std::wostringstream debugMsg; + debugMsg << "\r\nSuccessfully exported anchor. Size is " << size << " bytes."; + OutputDebugStringW(debugMsg.str().c_str()); + } + } + } + catch (...) + { + } +} + +void SampleRemoteMain::RequestEyesPoseAccess() +{ + try + { + auto asyncOpertation = winrt::Windows::Perception::People::EyesPose::RequestAccessAsync(); + asyncOpertation.Completed( + [this](winrt::Windows::Foundation::IAsyncOperation result, auto asyncStatus) { + winrt::Windows::UI::Input::GazeInputAccessStatus status = result.GetResults(); + switch (status) + { + case winrt::Windows::UI::Input::GazeInputAccessStatus::Unspecified: + OutputDebugStringA("ParseGazeInputResponseData Unspecified\n"); + break; + case winrt::Windows::UI::Input::GazeInputAccessStatus::Allowed: + OutputDebugStringA("ParseGazeInputResponseData Allowed\n"); + break; + case winrt::Windows::UI::Input::GazeInputAccessStatus::DeniedByUser: + OutputDebugStringA("ParseGazeInputResponseData DeniedByUser\n"); + break; + case winrt::Windows::UI::Input::GazeInputAccessStatus::DeniedBySystem: + OutputDebugStringA("ParseGazeInputResponseData DeniedBySystem\n"); + break; + default: + break; + } + }); + } + catch (winrt::hresult_error&) + { + } +} + +winrt::fire_and_forget SampleRemoteMain::CreatePerceptionDeviceHandler() +{ + AppCapabilityAccessStatus status; + if (m_isStandalone) + { + if (!winrt::Windows::Foundation::Metadata::ApiInformation::IsTypePresent( + L"Windows.Security.Authorization.AppCapabilityAccess.AppCapability")) + { + return; + } + + AppCapability webcamCapability = AppCapability::Create(L"webcam"); + if (!webcamCapability) + { + return; + } + auto webcamRequest = webcamCapability.RequestAccessAsync(); + status = webcamRequest.get(); + } + else + { + status = AppCapabilityAccessStatus::Allowed; + } + + auto weakThis = weak_from_this(); + co_await winrt::resume_background(); + + // Create the perception device if we have web cam access in standalone mode. + // Create the perception device if we do not use the standalone mode. In this case, the decision is made on the player side, whereby the + // assumption is that the access is allowed. + if (status == AppCapabilityAccessStatus::Allowed) + { + if (auto strongThis = weakThis.lock()) + { + auto perceptionDeviceHandler = std::make_shared(); + perceptionDeviceHandler->Start(); + + // Do not use the PerceptionDeviceHandler before initialization has been completed. + m_perceptionDeviceHandler = perceptionDeviceHandler; + } + } +} + +void SampleRemoteMain::UnregisterHolographicEventHandlers() +{ + if (m_holographicSpace != nullptr) + { + m_holographicSpace.CameraAdded(m_cameraAddedToken); + m_holographicSpace.CameraRemoved(m_cameraRemovedToken); + } + + if (m_locator != nullptr) + { + m_locator.LocatabilityChanged(m_locatabilityChangedToken); + } +} + +void SampleRemoteMain::ShutdownRemoteContext() +{ + std::lock_guard remoteContextLock(m_remoteContextAccess); + + if (m_remoteContext != nullptr) + { + m_onConnectedEventRevoker.revoke(); + m_onSendFrameEventRevoker.revoke(); + m_onDataChannelCreatedEventRevoker.revoke(); + +#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE + { + std::lock_guard lock(m_customDataChannelLock); + m_customChannelDataReceivedEventRevoker.revoke(); + m_customChannelClosedEventRevoker.revoke(); + m_customDataChannel = nullptr; + } +#endif + + m_remoteContext.Close(); + m_remoteContext = nullptr; + } +} + +void SampleRemoteMain::OnDeviceLost() +{ + m_spinningCubeRenderer->ReleaseDeviceDependentResources(); + m_spatialInputRenderer->ReleaseDeviceDependentResources(); + m_qrCodeRenderer->ReleaseDeviceDependentResources(); + + if (m_spatialSurfaceMeshRenderer) + { + m_spatialSurfaceMeshRenderer->ReleaseDeviceDependentResources(); + } +} + +void SampleRemoteMain::OnDeviceRestored() +{ + m_spinningCubeRenderer->CreateDeviceDependentResources(); + m_spatialInputRenderer->CreateDeviceDependentResources(); + m_qrCodeRenderer->CreateDeviceDependentResources(); + + if (m_spatialSurfaceMeshRenderer) + { + m_spatialSurfaceMeshRenderer->CreateDeviceDependentResources(); + } +} + +void SampleRemoteMain::OnCameraAdded(const HolographicSpace& sender, const HolographicSpaceCameraAddedEventArgs& args) +{ + winrt::Windows::Foundation::Deferral deferral = args.GetDeferral(); + auto holographicCamera = args.Camera(); + + HolographicViewConfiguration viewConfig = holographicCamera.ViewConfiguration(); + viewConfig.PixelFormat(DirectXPixelFormat::B8G8R8A8UIntNormalized); + + create_task([this, deferral, holographicCamera]() { + m_deviceResources->AddHolographicCamera(holographicCamera); + + deferral.Complete(); + }); +} + +void SampleRemoteMain::OnCameraRemoved(const HolographicSpace& sender, const HolographicSpaceCameraRemovedEventArgs& args) +{ + m_deviceResources->RemoveHolographicCamera(args.Camera()); +} + +void SampleRemoteMain::OnLocatabilityChanged(const SpatialLocator& sender, const winrt::Windows::Foundation::IInspectable& args) +{ + const wchar_t* locatability = L""; + switch (sender.Locatability()) + { + case SpatialLocatability::Unavailable: + locatability = L"Unavailable"; + break; + + case SpatialLocatability::PositionalTrackingActivating: + locatability = L"PositionalTrackingActivating"; + break; + + case SpatialLocatability::OrientationOnly: + locatability = L"OrientationOnly"; + break; + + case SpatialLocatability::PositionalTrackingInhibited: + locatability = L"PositionalTrackingInhibited"; + break; + + case SpatialLocatability::PositionalTrackingActive: + locatability = L"PositionalTrackingActive"; + break; + } + + winrt::hstring message = L"Positional tracking is " + winrt::to_hstring(locatability) + L".\n"; + OutputDebugStringW(message.data()); +} + +void SampleRemoteMain::OnDisconnected(winrt::Microsoft::Holographic::AppRemoting::ConnectionFailureReason failureReason) +{ + DebugLog(L"Disconnected with reason %d", failureReason); + + { + std::lock_guard remoteContextLock(m_remoteContextAccess); + m_disconnectPending = false; + } + + // Reconnect if this is a transient failure. + if (failureReason == ConnectionFailureReason::DisconnectRequest || failureReason == ConnectionFailureReason::PeerDisconnectRequest) + { + ShutdownRemoteContext(); + } + else if ( + failureReason == ConnectionFailureReason::HandshakeUnreachable || failureReason == ConnectionFailureReason::TransportUnreachable || + failureReason == ConnectionFailureReason::ConnectionLost) + { + DebugLog(L"Reconnecting..."); + ConnectOrListen(); + } + // Failure reason None indicates a normal disconnect. + else if (failureReason != ConnectionFailureReason::None) + { + DebugLog(L"Disconnected with unrecoverable error, not attempting to reconnect."); + ShutdownRemoteContext(); + } + + WindowUpdateTitle(); +} + +void SampleRemoteMain::WindowCreateSwapChain(const winrt::com_ptr& device) +{ + std::lock_guard _lg(m_deviceLock); + + DXGI_SWAP_CHAIN_DESC1 desc = {0}; + desc.Width = m_width; + desc.Height = m_height; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.Stereo = false; + desc.SampleDesc.Count = 1; // Don't use multi-sampling. + desc.SampleDesc.Quality = 0; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.BufferCount = 2; // Double buffered + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + desc.Flags = 0; + desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + desc.Scaling = DXGI_SCALING_STRETCH; + + m_swapChain = nullptr; + + if (auto window = m_window.lock()) + { + m_swapChain = window->CreateSwapChain(device, &desc); + } +} + +void SampleRemoteMain::WindowPresentSwapChain() +{ + HRESULT hr = m_swapChain->Present(0, 0); + + if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) + { + // The D3D device is lost. + // This should be handled after the frame is complete. + m_swapChain = nullptr; + } + else + { + winrt::check_hresult(hr); + } +} + +void SampleRemoteMain::WindowUpdateTitle() +{ + std::wstring title = TITLE_TEXT; + std::wstring separator = TITLE_SEPARATOR; + + uint32_t fps = min(120, m_framesPerSecond); + title += separator + std::to_wstring(fps) + L" fps"; + + // Title | {ip} | {State} [| Press Space to Connect] [| Preview Disabled (p toggles)] + title += separator + m_hostname; + { + std::lock_guard remoteContextLock(m_remoteContextAccess); + if (m_remoteContext) + { + auto connectionState = m_remoteContext.ConnectionState(); + title += + separator + (m_isInitialized ? StreamerConnectionStateToString(connectionState, m_disconnectPending) : L"Initializing"); + title += separator + ((connectionState == ConnectionState::Disconnected) ? TITLE_CONNECT_TEXT : TITLE_DISCONNECT_TEXT); + } + else if (!m_isStandalone) + { + title += separator + TITLE_CONNECT_TEXT; + } + + if (!m_isStandalone) + { + title += separator + (m_showPreview ? TITLE_DISABLE_PREVIEW_TEXT : TITLE_ENABLE_PREVIEW_TEXT); + } + } + + if (auto window = m_window.lock()) + { + window->SetWindowTitle(title); + } +} + +#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE +void SampleRemoteMain::OnCustomDataChannelDataReceived() +{ + // TODO: React on data received via the custom data channel here. + OutputDebugString(TEXT("Response Received.\n")); +} + +void SampleRemoteMain::OnCustomDataChannelClosed() +{ + std::lock_guard lock(m_customDataChannelLock); + if (m_customDataChannel) + { + m_customChannelDataReceivedEventRevoker.revoke(); + m_customChannelClosedEventRevoker.revoke(); + m_customDataChannel = nullptr; + } +} +#endif diff --git a/hostsampleapp/uwp/SampleHostMain.h b/remote/uwp/SampleRemoteMain.h similarity index 76% rename from hostsampleapp/uwp/SampleHostMain.h rename to remote/uwp/SampleRemoteMain.h index 71ef0a1..e34afce 100644 --- a/hostsampleapp/uwp/SampleHostMain.h +++ b/remote/uwp/SampleRemoteMain.h @@ -1,211 +1,240 @@ -//********************************************************* -// -// 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 "Common/DeviceResources.h" - -#include "Content/PerceptionDeviceHandler.h" -#include "Content/QRCodeRenderer.h" -#include "Content/SpatialInputHandler.h" -#include "Content/SpatialInputRenderer.h" -#include "Content/SpatialSurfaceMeshRenderer.h" -#include "Content/SpinningCubeRenderer.h" - -#include - -#include - - -#define INITIAL_WINDOW_WIDTH 1280 -#define INITIAL_WINDOW_HEIGHT 720 - -#define TITLE_TEXT L"Remoting Host Sample" -#define TITLE_SEPARATOR L" | " -#define TITLE_CONNECT_TEXT L"Press Space To Connect" -#define TITLE_DISCONNECT_TEXT L"Press D to Disconnect" -#define TITLE_ENABLE_PREVIEW_TEXT L"Preview Disabled (press P to enable)" -#define TITLE_DISABLE_PREVIEW_TEXT L"Preview Enabled (press P to disable)" - - -class SampleHostMain : public std::enable_shared_from_this, public DXHelper::IDeviceNotify -{ -public: - struct IWindow - { - virtual winrt::com_ptr - CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) = 0; - - virtual void SetWindowTitle(std::wstring title) = 0; - }; - - - -public: - SampleHostMain(std::weak_ptr window); - ~SampleHostMain(); - - // Creates a HolographicFrame and updates the content. - winrt::Windows::Graphics::Holographic::HolographicFrame Update(); - - // Renders the current frame to each holographic camera and presents it. - void Render(winrt::Windows::Graphics::Holographic::HolographicFrame holographicFrame); - - const std::shared_ptr& GetDeviceResources() - { - return m_deviceResources; - } - - void SetHostOptions(bool listen, const std::wstring& hostname, uint32_t port); - - // Responds to key presses. - void OnKeyPress(char key); - - // Responds to window changing its size. - void OnResize(int width, int height); - - // Responds to speech recognition results. - void OnRecognizedSpeech(const winrt::hstring& recognizedText); - - // IDeviceNotify methods - virtual void OnDeviceLost(); - virtual void OnDeviceRestored(); - -private: - // Initializes the RemoteContext and starts connecting or listening to the currently set network address - void InitializeRemoteContextAndConnectOrListen(); - - // Initializes the HolographicSpace and creates graphics device dependent resources - void CreateHolographicSpaceAndDeviceResources(); - - // Connects to or listens on the currently set network address - void ConnectOrListen(); - - // Loads the currently saved position of the spinning cube. - void LoadPosition(); - - // Saves the position of the spinning cube. - void SavePosition(); - - - // Request access for eyes pose data. - void RequestEyesPoseAccess(); - - // Clears event registration state. Used when changing to a new HolographicSpace - // and when tearing down SampleHostMain. - void UnregisterHolographicEventHandlers(); - - // Shuts down the RemoteContext (which will also disconnect, if currently connected) - void ShutdownRemoteContext(); - - // Creates a SwapChain for the host window - void WindowCreateSwapChain(const winrt::com_ptr& device); - - // Presents the SwapChain of the host window - void WindowPresentSwapChain(); - - // Updates the title of the host window - void WindowUpdateTitle(); - - // Asynchronously creates resources for new holographic cameras. - void OnCameraAdded( - const winrt::Windows::Graphics::Holographic::HolographicSpace& sender, - const winrt::Windows::Graphics::Holographic::HolographicSpaceCameraAddedEventArgs& args); - - // Synchronously releases resources for holographic cameras that are no longer - // attached to the system. - void OnCameraRemoved( - const winrt::Windows::Graphics::Holographic::HolographicSpace& sender, - const winrt::Windows::Graphics::Holographic::HolographicSpaceCameraRemovedEventArgs& args); - - // Used to notify the app when the positional tracking state changes. - void OnLocatabilityChanged( - const winrt::Windows::Perception::Spatial::SpatialLocator& sender, const winrt::Windows::Foundation::IInspectable& args); - -#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE - void OnCustomDataChannelDataReceived(); - void OnCustomDataChannelClosed(); -#endif - -private: - bool m_isInitialized = false; - - std::chrono::high_resolution_clock::time_point m_startTime = std::chrono::high_resolution_clock::now(); - - // RemoteContext used to connect with a Holographic Remoting player and display rendered frames - winrt::Microsoft::Holographic::AppRemoting::RemoteContext m_remoteContext = nullptr; - - // Represents the holographic space around the user. - winrt::Windows::Graphics::Holographic::HolographicSpace m_holographicSpace = nullptr; - - // Cached pointer to device resources. - std::shared_ptr m_deviceResources; - - // SpatialLocator that is attached to the primary camera. - winrt::Windows::Perception::Spatial::SpatialLocator m_locator = nullptr; - - // A reference frame that is positioned in the world. - winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference m_referenceFrame = nullptr; - - // Renders a colorful holographic cube that's 20 centimeters wide. This sample content - // is used to demonstrate world-locked rendering. - std::unique_ptr m_spinningCubeRenderer; - - // Renders the surface observed in the user's surroundings. - std::unique_ptr m_spatialSurfaceMeshRenderer; - - // Listens for the Pressed spatial input event. - std::shared_ptr m_spatialInputHandler; - std::unique_ptr m_spatialInputRenderer; - - // Handles perception root objects and their events/updates - std::shared_ptr m_perceptionDeviceHandler; - std::unique_ptr m_qrCodeRenderer; - - // Event registration tokens. - winrt::event_token m_cameraAddedToken; - winrt::event_token m_cameraRemovedToken; - winrt::event_token m_locatabilityChangedToken; - - // Event registration revokers - winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnConnected_revoker m_onConnectedEventRevoker; - winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnDisconnected_revoker m_onDisconnectedEventRevoker; - winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnSendFrame_revoker m_onSendFrameEventRevoker; - winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnDataChannelCreated_revoker m_onDataChannelCreatedEventRevoker; - winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker m_onRecognizedSpeechRevoker; - - // Host options - std::wstring m_hostname; - uint32_t m_port{0}; - bool m_showPreview = true; - bool m_listen{false}; - - // Host window related variables - std::weak_ptr m_window; - int m_width = INITIAL_WINDOW_WIDTH; - int m_height = INITIAL_WINDOW_HEIGHT; - - std::chrono::high_resolution_clock::time_point m_windowTitleUpdateTime; - uint32_t m_framesPerSecond = 0; - - std::recursive_mutex m_deviceLock; - winrt::com_ptr m_swapChain; - winrt::com_ptr m_spTexture; - -#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE - std::recursive_mutex m_customDataChannelLock; - winrt::Microsoft::Holographic::AppRemoting::IDataChannel m_customDataChannel = nullptr; - winrt::Microsoft::Holographic::AppRemoting::IDataChannel::OnDataReceived_revoker m_customChannelDataReceivedEventRevoker; - winrt::Microsoft::Holographic::AppRemoting::IDataChannel::OnClosed_revoker m_customChannelClosedEventRevoker; - std::chrono::high_resolution_clock::time_point m_customDataChannelSendTime = std::chrono::high_resolution_clock::now(); -#endif - -}; +//********************************************************* +// +// 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 "Common/DeviceResources.h" + +#include "Content/PerceptionDeviceHandler.h" +#include "Content/QRCodeRenderer.h" +#include "Content/SpatialInputHandler.h" +#include "Content/SpatialInputRenderer.h" +#include "Content/SpatialSurfaceMeshRenderer.h" +#include "Content/SpinningCubeRenderer.h" + +#include + +#include + +#define INITIAL_WINDOW_WIDTH 1280 +#define INITIAL_WINDOW_HEIGHT 720 + +#define TITLE_TEXT L"Remoting Host Sample" +#define TITLE_SEPARATOR L" | " +#define TITLE_CONNECT_TEXT L"Press Space To Connect" +#define TITLE_DISCONNECT_TEXT L"Press D to Disconnect" +#define TITLE_ENABLE_PREVIEW_TEXT L"Preview Disabled (press P to enable)" +#define TITLE_DISABLE_PREVIEW_TEXT L"Preview Enabled (press P to disable)" + +// #define ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE + +class SampleRemoteMain : public std::enable_shared_from_this, public DXHelper::IDeviceNotify +{ +public: + struct IWindow + { + virtual winrt::com_ptr + CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) = 0; + + virtual winrt::Windows::Graphics::Holographic::HolographicSpace CreateHolographicSpace() = 0; + + virtual winrt::Windows::UI::Input::Spatial::SpatialInteractionManager CreateInteractionManager() = 0; + + virtual void SetWindowTitle(std::wstring title) = 0; + }; + +public: + SampleRemoteMain(std::weak_ptr window); + ~SampleRemoteMain(); + + // Creates a HolographicFrame and updates the content. + winrt::Windows::Graphics::Holographic::HolographicFrame Update(); + + // Renders the current frame to each holographic camera and presents it. + void Render(winrt::Windows::Graphics::Holographic::HolographicFrame holographicFrame); + + const std::shared_ptr& GetDeviceResources() + { + return m_deviceResources; + } + + // Initialize SampleRemoteMain for remote rendering targeting a HolographicRemotingPlayer. + void + ConfigureRemoting(bool listen, const std::wstring& hostname, uint16_t port, uint16_t transportPort = 0, bool ephemeralPort = false); + + // Initialize SampleRemoteMain for local rendering targeting HoloLens or Windows Mixed Reality headsets. + void InitializeStandalone(); + + // Responds to key presses. + void OnKeyPress(char key); + + // Responds to window changing its size. + void OnResize(int width, int height); + + // Responds to speech recognition results. + void OnRecognizedSpeech(const winrt::hstring& recognizedText); + + // IDeviceNotify methods + virtual void OnDeviceLost(); + virtual void OnDeviceRestored(); + + // Initializes the RemoteContext and starts connecting or listening to the currently set network address + void InitializeRemoteContextAndConnectOrListen(); + +private: + // Initializes the HolographicSpace and creates graphics device dependent resources + void CreateHolographicSpaceAndDeviceResources(); + + // Connects to or listens on the currently set network address + void ConnectOrListen(); + + // Loads the currently saved position of the spinning cube. + void LoadPosition(); + + // Saves the position of the spinning cube. + void SavePosition(); + + // Exports a test anchor via SpatialAnchorExporter. + winrt::fire_and_forget ExportPosition(); + + // Request access for eyes pose data. + void RequestEyesPoseAccess(); + + // Create the perception device handler which is required for qr code tracking. + winrt::fire_and_forget CreatePerceptionDeviceHandler(); + + // Clears event registration state. Used when changing to a new HolographicSpace + // and when tearing down SampleRemoteMain. + void UnregisterHolographicEventHandlers(); + + // Shuts down the RemoteContext (which will also disconnect, if currently connected) + void ShutdownRemoteContext(); + + // Creates a SwapChain for the host window + void WindowCreateSwapChain(const winrt::com_ptr& device); + + // Presents the SwapChain of the host window + void WindowPresentSwapChain(); + + // Updates the title of the host window + void WindowUpdateTitle(); + + // Asynchronously creates resources for new holographic cameras. + void OnCameraAdded( + const winrt::Windows::Graphics::Holographic::HolographicSpace& sender, + const winrt::Windows::Graphics::Holographic::HolographicSpaceCameraAddedEventArgs& args); + + // Synchronously releases resources for holographic cameras that are no longer + // attached to the system. + void OnCameraRemoved( + const winrt::Windows::Graphics::Holographic::HolographicSpace& sender, + const winrt::Windows::Graphics::Holographic::HolographicSpaceCameraRemovedEventArgs& args); + + // Used to notify the app when the positional tracking state changes. + void OnLocatabilityChanged( + const winrt::Windows::Perception::Spatial::SpatialLocator& sender, const winrt::Windows::Foundation::IInspectable& args); + + void OnDisconnected(winrt::Microsoft::Holographic::AppRemoting::ConnectionFailureReason failureReason); + +#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE + void OnCustomDataChannelDataReceived(); + void OnCustomDataChannelClosed(); +#endif + +private: + bool m_isInitialized = false; + + std::chrono::high_resolution_clock::time_point m_startTime = std::chrono::high_resolution_clock::now(); + + // Lock to serialize remote context operations and event handlers + std::recursive_mutex m_remoteContextAccess; + + // RemoteContext used to connect with a Holographic Remoting player and display rendered frames + winrt::Microsoft::Holographic::AppRemoting::RemoteContext m_remoteContext = nullptr; + + // Whether a disconnect is currently pending. + bool m_disconnectPending{false}; + + // Represents the holographic space around the user. + winrt::Windows::Graphics::Holographic::HolographicSpace m_holographicSpace = nullptr; + + // The interaction manager provides an event that informs the app when spatial interactions are detected. + winrt::Windows::UI::Input::Spatial::SpatialInteractionManager m_interactionManager = nullptr; + + // Cached pointer to device resources. + std::shared_ptr m_deviceResources; + + // SpatialLocator that is attached to the primary camera. + winrt::Windows::Perception::Spatial::SpatialLocator m_locator = nullptr; + + // A reference frame that is positioned in the world. + winrt::Windows::Perception::Spatial::SpatialStationaryFrameOfReference m_referenceFrame = nullptr; + + // Renders a colorful holographic cube that's 20 centimeters wide. This sample content + // is used to demonstrate world-locked rendering. + std::unique_ptr m_spinningCubeRenderer; + + // Renders the surface observed in the user's surroundings. + std::unique_ptr m_spatialSurfaceMeshRenderer; + + // Listens for the Pressed spatial input event. + std::shared_ptr m_spatialInputHandler; + std::shared_ptr m_spatialInputRenderer; + + // Handles perception root objects and their events/updates + std::shared_ptr m_perceptionDeviceHandler; + std::unique_ptr m_qrCodeRenderer; + + // Event registration tokens. + winrt::event_token m_cameraAddedToken; + winrt::event_token m_cameraRemovedToken; + winrt::event_token m_locatabilityChangedToken; + + // Event registration revokers + winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnConnected_revoker m_onConnectedEventRevoker; + winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnDisconnected_revoker m_onDisconnectedEventRevoker; + winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnSendFrame_revoker m_onSendFrameEventRevoker; + winrt::Microsoft::Holographic::AppRemoting::IRemoteContext::OnDataChannelCreated_revoker m_onDataChannelCreatedEventRevoker; + winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker m_onRecognizedSpeechRevoker; + + // Host options + std::wstring m_hostname; + uint16_t m_port{0}; + uint16_t m_transportPort{0}; + bool m_ephemeralPort = false; + bool m_showPreview = true; + bool m_listen{false}; + + // Host window related variables + std::weak_ptr m_window; + int m_width = INITIAL_WINDOW_WIDTH; + int m_height = INITIAL_WINDOW_HEIGHT; + + std::chrono::high_resolution_clock::time_point m_windowTitleUpdateTime; + uint32_t m_framesPerSecond = 0; + + std::recursive_mutex m_deviceLock; + winrt::com_ptr m_swapChain; + winrt::com_ptr m_spTexture; + + bool m_canCommitDirect3D11DepthBuffer = false; + bool m_commitDirect3D11DepthBuffer = true; + + bool m_isStandalone = false; + +#ifdef ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE + std::recursive_mutex m_customDataChannelLock; + winrt::Microsoft::Holographic::AppRemoting::IDataChannel2 m_customDataChannel = nullptr; + winrt::Microsoft::Holographic::AppRemoting::IDataChannel2::OnDataReceived_revoker m_customChannelDataReceivedEventRevoker; + winrt::Microsoft::Holographic::AppRemoting::IDataChannel2::OnClosed_revoker m_customChannelClosedEventRevoker; + std::chrono::high_resolution_clock::time_point m_customDataChannelSendTime = std::chrono::high_resolution_clock::now(); +#endif +}; diff --git a/hostsampleapp/desktop/SampleHostWindowUWP.cpp b/remote/uwp/SampleRemoteWindowUWP.cpp similarity index 67% rename from hostsampleapp/desktop/SampleHostWindowUWP.cpp rename to remote/uwp/SampleRemoteWindowUWP.cpp index 012b059..0f1c8e7 100644 --- a/hostsampleapp/desktop/SampleHostWindowUWP.cpp +++ b/remote/uwp/SampleRemoteWindowUWP.cpp @@ -1,301 +1,323 @@ -//********************************************************* -// -// 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 "SampleHostWindowUWP.h" - -#include "Common\DbgLog.h" -#include "Common\Speech.h" - -#include -#include - -#include - -#include - -#include -#include -#include - -#define INITIAL_WINDOW_WIDTH 1280 -#define INITIAL_WINDOW_HEIGHT 720 - -#define TITLE_SEPARATOR L" | " - -using namespace winrt::Windows::ApplicationModel; -using namespace winrt::Windows::ApplicationModel::Activation; -using namespace winrt::Windows::ApplicationModel::Core; -using namespace winrt::Windows::Graphics::Display; -using namespace winrt::Microsoft::Holographic::AppRemoting; -using namespace winrt::Windows::UI::Core; -using namespace winrt::Windows::UI::ViewManagement; - - -// The main function is only used to initialize our IFrameworkView class. -int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) -{ - winrt::init_apartment(); - CoreApplication::Run(winrt::make()); -} - -SampleHostWindowUWP::SampleHostWindowUWP() -{ - ApplicationView::PreferredLaunchViewSize(winrt::Windows::Foundation::Size(INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT)); -} - -// The first method called when the IFrameworkView is being created. -void SampleHostWindowUWP::Initialize(const CoreApplicationView& applicationView) -{ - CoreApplication::Suspending({this, &SampleHostWindowUWP::OnSuspending}); - CoreApplication::Resuming({this, &SampleHostWindowUWP::OnResuming}); - - applicationView.Activated({this, &SampleHostWindowUWP::OnViewActivated}); - - m_main = std::make_shared(weak_from_this()); -} - -// Called when the CoreWindow object is created (or re-created). -void SampleHostWindowUWP::SetWindow(const CoreWindow& window) -{ - m_window = window; - - window.SizeChanged({this, &SampleHostWindowUWP::OnWindowSizeChanged}); - window.VisibilityChanged({this, &SampleHostWindowUWP::OnVisibilityChanged}); - window.Closed({this, &SampleHostWindowUWP::OnWindowClosed}); - window.KeyDown({this, &SampleHostWindowUWP::OnKeyDown}); -} - -// Initializes scene resources, or loads a previously saved app state. -void SampleHostWindowUWP::Load(const winrt::hstring& entryPoint) -{ -} - -// This method is called after the window becomes active. -void SampleHostWindowUWP::Run() -{ - CoreWindow window = CoreWindow::GetForCurrentThread(); - window.Activate(); - - while (!m_windowClosed) - { - if (m_windowVisible) - { - CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent); - - if (m_main) - { - if (const HolographicFrame& holographicFrame = m_main->Update()) - { - m_main->Render(holographicFrame); - } - } - } - else - { - CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending); - } - } -} - -// Required for IFrameworkView. -// 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. -void SampleHostWindowUWP::Uninitialize() -{ -} - - -winrt::com_ptr - SampleHostWindowUWP::CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) -{ - winrt::com_ptr dxgiDevice; - device.as(dxgiDevice); - - winrt::com_ptr dxgiAdapter; - winrt::check_hresult(dxgiDevice->GetAdapter(dxgiAdapter.put())); - - winrt::com_ptr dxgiFactory; - winrt::check_hresult(dxgiAdapter->GetParent(__uuidof(dxgiFactory), dxgiFactory.put_void())); - - winrt::com_ptr swapChain; - winrt::check_hresult(dxgiFactory->CreateSwapChainForCoreWindow( - device.get(), static_cast<::IUnknown*>(winrt::get_abi(m_window)), desc, nullptr, swapChain.put())); - - return swapChain; -} - -void SampleHostWindowUWP::SetWindowTitle(std::wstring title) -{ - auto dispatcher = winrt::Windows::ApplicationModel::Core::CoreApplication::MainView().CoreWindow().Dispatcher(); - - auto doSetWindowTitle = [title]() { - try - { - if (auto view = winrt::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()) - { - view.Title(winrt::to_hstring(title.c_str())); - } - } - catch (const winrt::hresult_error&) - { - } - }; - - if (dispatcher.HasThreadAccess()) - { - doSetWindowTitle(); - } - else - { - dispatcher.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, doSetWindowTitle); - } -} - -// Application lifecycle event handlers. - -void SampleHostWindowUWP::OnSuspending(const winrt::Windows::Foundation::IInspectable& sender, const SuspendingEventArgs& args) -{ -} - -void SampleHostWindowUWP::OnResuming( - const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& 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. - - // Insert your code here. -} - -// Window event handlers. - -void SampleHostWindowUWP::OnWindowSizeChanged( - const winrt::Windows::Foundation::IInspectable& sender, const WindowSizeChangedEventArgs& args) -{ - winrt::Windows::Foundation::Size size = args.Size(); - m_main->OnResize(static_cast(size.Width + 0.5f), static_cast(size.Height + 0.5f)); -} - -void SampleHostWindowUWP::OnVisibilityChanged( - const winrt::Windows::Foundation::IInspectable& sender, const VisibilityChangedEventArgs& args) -{ - m_windowVisible = args.Visible(); -} - -void SampleHostWindowUWP::OnWindowClosed(const CoreWindow& window, const CoreWindowEventArgs& args) -{ - m_windowClosed = true; -} - -void SampleHostWindowUWP::OnKeyDown(const CoreWindow& window, const KeyEventArgs& args) -{ - int32_t key = static_cast(args.VirtualKey()); - if (key >= 0 && key <= 0xFF) - { - m_main->OnKeyPress(static_cast(tolower(key))); - } -} - -void SampleHostWindowUWP::OnViewActivated(CoreApplicationView const& sender, IActivatedEventArgs const& activationArgs) -{ - using namespace winrt::Windows::ApplicationModel; - using namespace Activation; - using namespace Core; - - std::wstring host = L"127.0.0.1"; - int32_t port = 8265; - - if (activationArgs != nullptr) - { - ActivationKind activationKind = activationArgs.Kind(); - if (activationKind == Activation::ActivationKind::Launch) - { - LaunchActivatedEventArgs launchArgs = activationArgs.as(); - - std::vector args; - std::wistringstream stream(std::wstring(launchArgs.Arguments())); - std::copy( - std::istream_iterator(stream), - std::istream_iterator(), - std::back_inserter(args)); - - for (const std::wstring& arg : args) - { - if (arg.size() == 0) - continue; - - size_t colonPos = arg.find(L':'); - if (colonPos != std::wstring::npos) - { - std::wstring portStr = arg.substr(colonPos + 1); - - host = arg.substr(0, colonPos); - port = std::wcstol(portStr.c_str(), nullptr, 10); - } - else - { - host = arg.c_str(); - } - } - } - } - - // check for invalid port numbers - if (port < 0 || port > 65535) - { - port = 0; - } - - m_ipAddress = host; - m_port = port; - - m_main->SetHostOptions(false, m_ipAddress, m_port); - - // Run() won't start until the CoreWindow is activated. - sender.CoreWindow().Activate(); -} - -SampleHostWindowUWPView::SampleHostWindowUWPView() -{ - m_window = std::make_shared(); -} - -winrt::Windows::ApplicationModel::Core::IFrameworkView SampleHostWindowUWPView::CreateView() -{ - return *this; -} - -void SampleHostWindowUWPView::Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView& applicationView) -{ - m_window->Initialize(applicationView); -} - -void SampleHostWindowUWPView::SetWindow(const winrt::Windows::UI::Core::CoreWindow& window) -{ - m_window->SetWindow(window); -} - -void SampleHostWindowUWPView::Load(const winrt::hstring& entryPoint) -{ - m_window->Load(entryPoint); -} - -void SampleHostWindowUWPView::Run() -{ - m_window->Run(); -} - -void SampleHostWindowUWPView::Uninitialize() -{ - m_window->Uninitialize(); -} +//********************************************************* +// +// 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 "SampleRemoteWindowUWP.h" + +#include "Common\DbgLog.h" +#include "Common\Speech.h" + +#include +#include + +#include + +#include + +#include +#include +#include + +#define INITIAL_WINDOW_WIDTH 1280 +#define INITIAL_WINDOW_HEIGHT 720 + +#define TITLE_SEPARATOR L" | " + +using namespace winrt::Windows::ApplicationModel; +using namespace winrt::Windows::ApplicationModel::Activation; +using namespace winrt::Windows::ApplicationModel::Core; +using namespace winrt::Windows::Graphics::Display; +using namespace winrt::Microsoft::Holographic::AppRemoting; +using namespace winrt::Windows::UI::Core; +using namespace winrt::Windows::UI::ViewManagement; + +// The main function is only used to initialize our IFrameworkView class. +int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) +{ + winrt::init_apartment(); + CoreApplication::Run(winrt::make()); +} + +SampleRemoteWindowUWP::SampleRemoteWindowUWP() +{ + ApplicationView::PreferredLaunchViewSize(winrt::Windows::Foundation::Size(INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT)); +} + +// The first method called when the IFrameworkView is being created. +void SampleRemoteWindowUWP::Initialize(const CoreApplicationView& applicationView) +{ + CoreApplication::Suspending({this, &SampleRemoteWindowUWP::OnSuspending}); + CoreApplication::Resuming({this, &SampleRemoteWindowUWP::OnResuming}); + + applicationView.Activated({this, &SampleRemoteWindowUWP::OnViewActivated}); + + m_main = std::make_shared(weak_from_this()); +} + +// Called when the CoreWindow object is created (or re-created). +void SampleRemoteWindowUWP::SetWindow(const CoreWindow& window) +{ + m_window = window; + + window.SizeChanged({this, &SampleRemoteWindowUWP::OnWindowSizeChanged}); + window.VisibilityChanged({this, &SampleRemoteWindowUWP::OnVisibilityChanged}); + window.Closed({this, &SampleRemoteWindowUWP::OnWindowClosed}); + window.KeyDown({this, &SampleRemoteWindowUWP::OnKeyDown}); +} + +// Initializes scene resources, or loads a previously saved app state. +void SampleRemoteWindowUWP::Load(const winrt::hstring& entryPoint) +{ +} + +// This method is called after the window becomes active. +void SampleRemoteWindowUWP::Run() +{ + CoreWindow window = CoreWindow::GetForCurrentThread(); + window.Activate(); + + while (!m_windowClosed) + { + if (m_windowVisible) + { + CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent); + + if (m_main) + { + if (const HolographicFrame& holographicFrame = m_main->Update()) + { + m_main->Render(holographicFrame); + } + } + } + else + { + CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending); + } + } +} + +// Required for IFrameworkView. +// 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. +void SampleRemoteWindowUWP::Uninitialize() +{ +} + +winrt::com_ptr + SampleRemoteWindowUWP::CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) +{ + winrt::com_ptr dxgiDevice; + device.as(dxgiDevice); + + winrt::com_ptr dxgiAdapter; + winrt::check_hresult(dxgiDevice->GetAdapter(dxgiAdapter.put())); + + winrt::com_ptr dxgiFactory; + winrt::check_hresult(dxgiAdapter->GetParent(__uuidof(dxgiFactory), dxgiFactory.put_void())); + + winrt::com_ptr swapChain; + winrt::check_hresult(dxgiFactory->CreateSwapChainForCoreWindow( + device.get(), static_cast<::IUnknown*>(winrt::get_abi(m_window)), desc, nullptr, swapChain.put())); + + return swapChain; +} + +winrt::Windows::Graphics::Holographic::HolographicSpace SampleRemoteWindowUWP::CreateHolographicSpace() +{ + return HolographicSpace::CreateForCoreWindow(m_window); +} + +winrt::Windows::UI::Input::Spatial::SpatialInteractionManager SampleRemoteWindowUWP::CreateInteractionManager() +{ + return winrt::Windows::UI::Input::Spatial::SpatialInteractionManager::GetForCurrentView(); +} + +void SampleRemoteWindowUWP::SetWindowTitle(std::wstring title) +{ + auto dispatcher = winrt::Windows::ApplicationModel::Core::CoreApplication::MainView().CoreWindow().Dispatcher(); + + auto doSetWindowTitle = [title]() { + try + { + if (auto view = winrt::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView()) + { + view.Title(winrt::to_hstring(title.c_str())); + } + } + catch (const winrt::hresult_error&) + { + } + }; + + if (dispatcher.HasThreadAccess()) + { + doSetWindowTitle(); + } + else + { + dispatcher.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, doSetWindowTitle); + } +} + +// Application lifecycle event handlers. + +void SampleRemoteWindowUWP::OnSuspending(const winrt::Windows::Foundation::IInspectable& sender, const SuspendingEventArgs& args) +{ +} + +void SampleRemoteWindowUWP::OnResuming( + const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& 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. + + // Insert your code here. +} + +// Window event handlers. + +void SampleRemoteWindowUWP::OnWindowSizeChanged( + const winrt::Windows::Foundation::IInspectable& sender, const WindowSizeChangedEventArgs& args) +{ + winrt::Windows::Foundation::Size size = args.Size(); + m_main->OnResize(static_cast(size.Width + 0.5f), static_cast(size.Height + 0.5f)); +} + +void SampleRemoteWindowUWP::OnVisibilityChanged( + const winrt::Windows::Foundation::IInspectable& sender, const VisibilityChangedEventArgs& args) +{ + m_windowVisible = args.Visible(); +} + +void SampleRemoteWindowUWP::OnWindowClosed(const CoreWindow& window, const CoreWindowEventArgs& args) +{ + m_windowClosed = true; +} + +void SampleRemoteWindowUWP::OnKeyDown(const CoreWindow& window, const KeyEventArgs& args) +{ + int32_t key = static_cast(args.VirtualKey()); + if (key >= 0 && key <= 0xFF) + { + m_main->OnKeyPress(static_cast(tolower(key))); + } +} + +void SampleRemoteWindowUWP::OnViewActivated(CoreApplicationView const& sender, IActivatedEventArgs const& activationArgs) +{ + using namespace winrt::Windows::ApplicationModel; + using namespace Activation; + using namespace Core; + + std::wstring host = L"127.0.0.1"; + int32_t port = 8265; + bool isStandalone = false; + + if (activationArgs != nullptr) + { + ActivationKind activationKind = activationArgs.Kind(); + if (activationKind == Activation::ActivationKind::Launch) + { + LaunchActivatedEventArgs launchArgs = activationArgs.as(); + + std::vector args; + std::wistringstream stream(std::wstring(launchArgs.Arguments())); + std::copy( + std::istream_iterator(stream), + std::istream_iterator(), + std::back_inserter(args)); + + for (const std::wstring& arg : args) + { + if (arg.size() == 0) + continue; + + if (arg == L"-standalone") + { + isStandalone = true; + continue; + } + + size_t colonPos = arg.find(L':'); + if (colonPos != std::wstring::npos) + { + std::wstring portStr = arg.substr(colonPos + 1); + + host = arg.substr(0, colonPos); + port = std::wcstol(portStr.c_str(), nullptr, 10); + } + else + { + host = arg.c_str(); + } + } + } + } + + if (!isStandalone) + { + // check for invalid port numbers + if (port < 0 || port > 65535) + { + port = 0; + } + + m_ipAddress = host; + m_port = port; + + m_main->ConfigureRemoting(false, m_ipAddress, m_port); + } + else + { + m_main->InitializeStandalone(); + } + + // Run() won't start until the CoreWindow is activated. + sender.CoreWindow().Activate(); +} + +SampleRemoteWindowUWPView::SampleRemoteWindowUWPView() +{ + m_window = std::make_shared(); +} + +winrt::Windows::ApplicationModel::Core::IFrameworkView SampleRemoteWindowUWPView::CreateView() +{ + return *this; +} + +void SampleRemoteWindowUWPView::Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView& applicationView) +{ + m_window->Initialize(applicationView); +} + +void SampleRemoteWindowUWPView::SetWindow(const winrt::Windows::UI::Core::CoreWindow& window) +{ + m_window->SetWindow(window); +} + +void SampleRemoteWindowUWPView::Load(const winrt::hstring& entryPoint) +{ + m_window->Load(entryPoint); +} + +void SampleRemoteWindowUWPView::Run() +{ + m_window->Run(); +} + +void SampleRemoteWindowUWPView::Uninitialize() +{ + m_window->Uninitialize(); +} diff --git a/hostsampleapp/uwp/SampleHostWindowUWP.h b/remote/uwp/SampleRemoteWindowUWP.h similarity index 77% rename from hostsampleapp/uwp/SampleHostWindowUWP.h rename to remote/uwp/SampleRemoteWindowUWP.h index b214178..5f4ec3b 100644 --- a/hostsampleapp/uwp/SampleHostWindowUWP.h +++ b/remote/uwp/SampleRemoteWindowUWP.h @@ -1,89 +1,92 @@ -//********************************************************* -// -// 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 "SampleHostMain.h" - -#include "Common\DeviceResources.h" - -#include -#include - - -// Main entry point for our app. Connects the app with the Windows shell and handles application lifecycle events. -class SampleHostWindowUWP : public std::enable_shared_from_this, public SampleHostMain::IWindow -{ -public: - SampleHostWindowUWP(); - - // IFrameworkView methods - virtual void Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView& applicationView); - virtual void SetWindow(const winrt::Windows::UI::Core::CoreWindow& window); - virtual void Load(const winrt::hstring& entryPoint); - virtual void Run(); - virtual void Uninitialize(); - - // SampleHostMain::IWindow methods. - virtual winrt::com_ptr - CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) override; - - virtual void SetWindowTitle(std::wstring title) override; - -protected: - // Application lifecycle event handlers. - void OnSuspending( - const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::ApplicationModel::SuspendingEventArgs& args); - void OnResuming(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); - - // Activation handling - void OnViewActivated( - winrt::Windows::ApplicationModel::Core::CoreApplicationView const& sender, - winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs const& args); - - // Window event handlers. - void OnWindowSizeChanged( - const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Core::WindowSizeChangedEventArgs& args); - void OnVisibilityChanged( - const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Core::VisibilityChangedEventArgs& args); - void OnWindowClosed(const winrt::Windows::UI::Core::CoreWindow& window, const winrt::Windows::UI::Core::CoreWindowEventArgs& args); - void OnKeyDown(const winrt::Windows::UI::Core::CoreWindow& window, const winrt::Windows::UI::Core::KeyEventArgs& args); - -private: - winrt::Windows::UI::Core::CoreWindow m_window = nullptr; - std::shared_ptr m_main; - std::wstring m_ipAddress; - int32_t m_port = 8265; - bool m_windowClosed = false; - bool m_windowVisible = true; -}; - -class SampleHostWindowUWPView : public winrt::implements< - SampleHostWindowUWPView, - winrt::Windows::ApplicationModel::Core::IFrameworkViewSource, - winrt::Windows::ApplicationModel::Core::IFrameworkView> -{ -public: - SampleHostWindowUWPView(); - - // IFrameworkViewSource methods. - winrt::Windows::ApplicationModel::Core::IFrameworkView CreateView(); - - // IFrameworkView methods. - virtual void Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView& applicationView); - virtual void SetWindow(const winrt::Windows::UI::Core::CoreWindow& window); - virtual void Load(const winrt::hstring& entryPoint); - virtual void Run(); - virtual void Uninitialize(); - -private: - std::shared_ptr m_window; -}; +//********************************************************* +// +// 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 "SampleRemoteMain.h" + +#include "Common\DeviceResources.h" + +#include +#include + +// Main entry point for our app. Connects the app with the Windows shell and handles application lifecycle events. +class SampleRemoteWindowUWP : public std::enable_shared_from_this, public SampleRemoteMain::IWindow +{ +public: + SampleRemoteWindowUWP(); + + // IFrameworkView methods + virtual void Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView& applicationView); + virtual void SetWindow(const winrt::Windows::UI::Core::CoreWindow& window); + virtual void Load(const winrt::hstring& entryPoint); + virtual void Run(); + virtual void Uninitialize(); + + // SampleRemoteMain::IWindow methods. + virtual winrt::com_ptr + CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) override; + + virtual winrt::Windows::Graphics::Holographic::HolographicSpace CreateHolographicSpace() override; + + virtual winrt::Windows::UI::Input::Spatial::SpatialInteractionManager CreateInteractionManager() override; + + virtual void SetWindowTitle(std::wstring title) override; + +protected: + // Application lifecycle event handlers. + void OnSuspending( + const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::ApplicationModel::SuspendingEventArgs& args); + void OnResuming(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args); + + // Activation handling + void OnViewActivated( + winrt::Windows::ApplicationModel::Core::CoreApplicationView const& sender, + winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs const& args); + + // Window event handlers. + void OnWindowSizeChanged( + const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Core::WindowSizeChangedEventArgs& args); + void OnVisibilityChanged( + const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::UI::Core::VisibilityChangedEventArgs& args); + void OnWindowClosed(const winrt::Windows::UI::Core::CoreWindow& window, const winrt::Windows::UI::Core::CoreWindowEventArgs& args); + void OnKeyDown(const winrt::Windows::UI::Core::CoreWindow& window, const winrt::Windows::UI::Core::KeyEventArgs& args); + +private: + winrt::Windows::UI::Core::CoreWindow m_window = nullptr; + std::shared_ptr m_main; + std::wstring m_ipAddress; + int32_t m_port = 8265; + bool m_windowClosed = false; + bool m_windowVisible = true; +}; + +class SampleRemoteWindowUWPView : public winrt::implements< + SampleRemoteWindowUWPView, + winrt::Windows::ApplicationModel::Core::IFrameworkViewSource, + winrt::Windows::ApplicationModel::Core::IFrameworkView> +{ +public: + SampleRemoteWindowUWPView(); + + // IFrameworkViewSource methods. + winrt::Windows::ApplicationModel::Core::IFrameworkView CreateView(); + + // IFrameworkView methods. + virtual void Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView& applicationView); + virtual void SetWindow(const winrt::Windows::UI::Core::CoreWindow& window); + virtual void Load(const winrt::hstring& entryPoint); + virtual void Run(); + virtual void Uninitialize(); + +private: + std::shared_ptr m_window; +}; diff --git a/remote/uwp/SampleRemoteWindowWin32.cpp b/remote/uwp/SampleRemoteWindowWin32.cpp new file mode 100644 index 0000000..80ea18e --- /dev/null +++ b/remote/uwp/SampleRemoteWindowWin32.cpp @@ -0,0 +1,363 @@ +//********************************************************* +// +// 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 +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#define WINDOWCLASSNAME L"SampleRemoteWindowWin32Class" + +LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static SampleRemoteWindowWin32* s_sampleHostWindow; + + LRESULT result = 0; + + switch (msg) + { + case WM_CREATE: + { + CREATESTRUCT* cs = reinterpret_cast(lParam); + s_sampleHostWindow = reinterpret_cast(cs->lpCreateParams); + + RECT clientRect; + GetClientRect(hWnd, &clientRect); + + s_sampleHostWindow->OnResize(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top); + result = 0; + } + break; + case WM_WINDOWPOSCHANGED: + { + auto windowPos = reinterpret_cast(lParam); + if ((windowPos->flags & SWP_NOSIZE) == 0) + { + RECT clientRect; + GetClientRect(hWnd, &clientRect); + + s_sampleHostWindow->OnResize(clientRect.right - clientRect.left, clientRect.bottom - clientRect.top); + } + result = 0; + } + break; + case WM_DESTROY: + { + s_sampleHostWindow = nullptr; + result = 0; + PostQuitMessage(0); + } + break; + case WM_CLOSE: + { + DestroyWindow(hWnd); + result = 0; + } + break; + case WM_CHAR: + { + const int key = tolower(static_cast(wParam)); + s_sampleHostWindow->OnKeyPress(static_cast(key)); + } + break; + default: + result = DefWindowProc(hWnd, msg, wParam, lParam); + break; + } + + return result; +} + +namespace +{ + std::wstring SplitHostnameAndPortString(const std::wstring& address, uint16_t& port) + { + static std::basic_regex addressMatcher(L"(?:(\\[.*\\])|([^:]*))(?:[:](\\d+))?"); + std::match_results results; + if (std::regex_match(address, results, addressMatcher)) + { + if (results[3].matched) + { + std::wstring portStr = results[3].str(); + port = static_cast(std::wcstol(portStr.c_str(), nullptr, 10)); + } + + return (results[1].matched) ? results[1].str() : results[2].str(); + } + else + { + return address; + } + } +} // namespace + +void SampleRemoteWindowWin32::Initialize() +{ + m_main = std::make_shared(weak_from_this()); +} + +void SampleRemoteWindowWin32::InitializeHwnd(HWND hWnd) +{ + m_hWnd = hWnd; +} + +void SampleRemoteWindowWin32::ConfigureRemoting( + bool listen, const std::wstring& hostname, uint16_t port, uint16_t transportPort, bool ephemeralPort) +{ + m_main->ConfigureRemoting(listen, hostname, port, transportPort, ephemeralPort); +} + +void SampleRemoteWindowWin32::Connect() +{ + m_main->InitializeRemoteContextAndConnectOrListen(); +} + +void SampleRemoteWindowWin32::InitializeStandalone() +{ + m_main->InitializeStandalone(); +} + +void SampleRemoteWindowWin32::Tick() +{ + if (const HolographicFrame& holographicFrame = m_main->Update()) + { + m_main->Render(holographicFrame); + } +} + +void SampleRemoteWindowWin32::OnKeyPress(char key) +{ + m_main->OnKeyPress(key); +} + +void SampleRemoteWindowWin32::OnResize(int width, int height) +{ + m_main->OnResize(width, height); +} + +winrt::com_ptr + SampleRemoteWindowWin32::CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) +{ + winrt::com_ptr dxgiDevice; + device.as(dxgiDevice); + + winrt::com_ptr dxgiAdapter; + winrt::check_hresult(dxgiDevice->GetAdapter(dxgiAdapter.put())); + + winrt::com_ptr dxgiFactory; + winrt::check_hresult(dxgiAdapter->GetParent(__uuidof(IDXGIFactory2), dxgiFactory.put_void())); + + winrt::check_hresult(dxgiFactory->MakeWindowAssociation(m_hWnd, DXGI_MWA_NO_ALT_ENTER)); + + winrt::com_ptr swapChain = nullptr; + winrt::check_hresult(dxgiFactory->CreateSwapChainForHwnd(device.get(), m_hWnd, desc, nullptr, nullptr, swapChain.put())); + + return swapChain; +} + +void SampleRemoteWindowWin32::SetWindowTitle(std::wstring title) +{ + if (m_hWnd) + { + if (!SetWindowTextW(m_hWnd, title.c_str())) + { + winrt::check_hresult(HRESULT_FROM_WIN32(GetLastError())); + } + } +} + +winrt::Windows::Graphics::Holographic::HolographicSpace SampleRemoteWindowWin32::CreateHolographicSpace() +{ + // Use WinRT factory to create the holographic space. + // See https://docs.microsoft.com/en-us/windows/win32/api/holographicspaceinterop/ + winrt::com_ptr holographicSpaceInterop = + winrt::get_activation_factory(); + + winrt::com_ptr spHolographicSpace; + winrt::check_hresult(holographicSpaceInterop->CreateForWindow( + m_hWnd, __uuidof(ABI::Windows::Graphics::Holographic::IHolographicSpace), winrt::put_abi(spHolographicSpace))); + + return spHolographicSpace.as(); +} + +winrt::Windows::UI::Input::Spatial::SpatialInteractionManager SampleRemoteWindowWin32::CreateInteractionManager() +{ + using namespace winrt::Windows::UI::Input::Spatial; + + // Use WinRT factory to create the spatial interaction manager. + // See https://docs.microsoft.com/en-us/windows/win32/api/spatialinteractionmanagerinterop/ + winrt::com_ptr spatialInteractionManagerInterop = + winrt::get_activation_factory(); + + winrt::com_ptr spSpatialInteractionManager; + winrt::check_hresult(spatialInteractionManagerInterop->GetForWindow( + m_hWnd, __uuidof(ABI::Windows::UI::Input::Spatial::ISpatialInteractionManager), winrt::put_abi(spSpatialInteractionManager))); + + return spSpatialInteractionManager.as(); +} + +int main(Platform::Array ^ args) +{ + winrt::init_apartment(); + + bool listen{false}; + std::wstring host; + uint16_t port{0}; + uint16_t transportPort{0}; + bool isStandalone = false; + bool noUserWait = false; + bool useEphemeralPort = false; + + for (unsigned int i = 1; i < args->Length; ++i) + { + if (args[i]->Length() == 0) + continue; + + std::wstring arg = args[i]->Data(); + if (arg[0] == '-') + { + std::wstring param = arg.substr(1); + std::transform(param.begin(), param.end(), param.begin(), ::tolower); + + if (param == L"listen") + { + listen = true; + continue; + } + + if (param == L"standalone") + { + isStandalone = true; + continue; + } + + if (param == L"nouserwait") + { + noUserWait = true; + continue; + } + + if (param == L"ephemeralport") + { + useEphemeralPort = true; + continue; + } + + if (param == L"transportport") + { + if (args->Length > i + 1) + { + std::wstring transportPortStr = args[i + 1]->Data(); + transportPort = std::stoi(transportPortStr); + i++; + } + continue; + } + } + + host = SplitHostnameAndPortString(arg, port); + } + + std::shared_ptr sampleHostWindow = std::make_shared(); + sampleHostWindow->Initialize(); + + WNDCLASSEXW wcex = {}; + wcex.cbSize = sizeof(wcex); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = wndProc; + wcex.hInstance = 0; + wcex.hIcon = LoadIcon(0, IDI_APPLICATION); + wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); + wcex.hbrBackground = static_cast(GetStockObject(NULL_BRUSH)); + wcex.lpszClassName = WINDOWCLASSNAME; + RegisterClassExW(&wcex); + + RECT rc = {0, 0, INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT}; + AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW, FALSE, 0); + + std::wstring windowName = TITLE_TEXT; + + HWND hWnd = CreateWindowW( + WINDOWCLASSNAME, + windowName.c_str(), + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + rc.right - rc.left, + rc.bottom - rc.top, + nullptr, + nullptr, + 0, + sampleHostWindow.get()); + + RECT clientRect; + GetClientRect(hWnd, &clientRect); + + sampleHostWindow->InitializeHwnd(hWnd); + + if (!isStandalone) + { + sampleHostWindow->ConfigureRemoting(listen, host, port, transportPort, useEphemeralPort); + if (noUserWait) + { + sampleHostWindow->Connect(); + } + } + else + { + sampleHostWindow->InitializeStandalone(); + } + + ShowWindow(hWnd, SW_SHOWNORMAL); + bool quit = false; + while (!quit) + { + MSG msg = {0}; + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + quit = true; + } + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else + { + try + { + sampleHostWindow->Tick(); + } + catch (...) + { + // Unhandeled exception during tick, exit program + return 1; + } + } + } + + return 0; +} diff --git a/hostsampleapp/uwp/SampleHostWindowWin32.h b/remote/uwp/SampleRemoteWindowWin32.h similarity index 57% rename from hostsampleapp/uwp/SampleHostWindowWin32.h rename to remote/uwp/SampleRemoteWindowWin32.h index 9eb4bde..ef7cb42 100644 --- a/hostsampleapp/uwp/SampleHostWindowWin32.h +++ b/remote/uwp/SampleRemoteWindowWin32.h @@ -1,41 +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. -// -//********************************************************* - -#pragma once - -//#include - -#include "SampleHostMain.h" - -// #define ENABLE_CUSTOM_DATA_CHANNEL_SAMPLE - -class SampleHostWindowWin32 : public std::enable_shared_from_this, public SampleHostMain::IWindow -{ -public: - void Initialize(bool listen, const std::wstring& host, uint32_t port); - - void InitializeHwnd(HWND hWnd); - - void Tick(); - - void OnKeyPress(char key); - void OnResize(int width, int height); - - virtual winrt::com_ptr - CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) override; - - virtual void SetWindowTitle(std::wstring title) override; - -private: - HWND m_hWnd = 0; - - std::shared_ptr m_main; -}; +//********************************************************* +// +// 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 + +class SampleRemoteWindowWin32 : public std::enable_shared_from_this, public SampleRemoteMain::IWindow +{ +public: + void Initialize(); + + void InitializeHwnd(HWND hWnd); + + void ConfigureRemoting(bool listen, const std::wstring& hostname, uint16_t port, uint16_t transportPort, bool ephemeralPort); + void Connect(); + + void InitializeStandalone(); + + void Tick(); + + void OnKeyPress(char key); + void OnResize(int width, int height); + + virtual winrt::com_ptr + CreateSwapChain(const winrt::com_ptr& device, const DXGI_SWAP_CHAIN_DESC1* desc) override; + + virtual winrt::Windows::Graphics::Holographic::HolographicSpace CreateHolographicSpace() override; + + virtual winrt::Windows::UI::Input::Spatial::SpatialInteractionManager CreateInteractionManager() override; + + virtual void SetWindowTitle(std::wstring title) override; + +private: + HWND m_hWnd = 0; + + std::shared_ptr m_main; +}; diff --git a/hostsampleapp/uwp/SpeechGrammar.xml b/remote/uwp/SpeechGrammar.xml similarity index 96% rename from hostsampleapp/uwp/SpeechGrammar.xml rename to remote/uwp/SpeechGrammar.xml index f45638c..49f4f4c 100644 --- a/hostsampleapp/uwp/SpeechGrammar.xml +++ b/remote/uwp/SpeechGrammar.xml @@ -1,11 +1,11 @@ - - - - - - - Load position - Save position - - + + + + + + + Load position + Save position + + \ No newline at end of file diff --git a/remote/uwp/packages.config b/remote/uwp/packages.config new file mode 100644 index 0000000..4e4f68f --- /dev/null +++ b/remote/uwp/packages.config @@ -0,0 +1,5 @@ + + + + + diff --git a/hostsampleapp/desktop/pch.cpp b/remote/uwp/pch.cpp similarity index 97% rename from hostsampleapp/desktop/pch.cpp rename to remote/uwp/pch.cpp index 5149ada..3ca571e 100644 --- a/hostsampleapp/desktop/pch.cpp +++ b/remote/uwp/pch.cpp @@ -1,12 +1,12 @@ -//********************************************************* -// -// 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" +//********************************************************* +// +// 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" diff --git a/hostsampleapp/desktop/pch.h b/remote/uwp/pch.h similarity index 96% rename from hostsampleapp/desktop/pch.h rename to remote/uwp/pch.h index 7b76575..5eb544d 100644 --- a/hostsampleapp/desktop/pch.h +++ b/remote/uwp/pch.h @@ -1,21 +1,21 @@ -//********************************************************* -// -// 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 - -#include -#include - -#include - -#include +//********************************************************* +// +// 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 + +#include +#include + +#include + +#include