diff --git a/Camera Renderer.sln b/Camera Renderer.sln new file mode 100644 index 0000000..a68adff --- /dev/null +++ b/Camera Renderer.sln @@ -0,0 +1,51 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31702.278 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Camera Renderer CS", "Camera-Renderer_cs\Camera Renderer CS.csproj", "{33A294C7-3146-405C-BCCA-C4E36985D0D7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|ARM = Release|ARM + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Debug|ARM.ActiveCfg = Debug|ARM + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Debug|ARM.Build.0 = Debug|ARM + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Debug|ARM.Deploy.0 = Debug|ARM + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Debug|ARM64.Build.0 = Debug|ARM64 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Debug|x64.ActiveCfg = Debug|x64 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Debug|x64.Build.0 = Debug|x64 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Debug|x64.Deploy.0 = Debug|x64 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Debug|x86.ActiveCfg = Debug|x86 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Debug|x86.Build.0 = Debug|x86 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Debug|x86.Deploy.0 = Debug|x86 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Release|ARM.ActiveCfg = Release|ARM + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Release|ARM.Build.0 = Release|ARM + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Release|ARM.Deploy.0 = Release|ARM + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Release|ARM64.ActiveCfg = Release|ARM64 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Release|ARM64.Build.0 = Release|ARM64 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Release|ARM64.Deploy.0 = Release|ARM64 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Release|x64.ActiveCfg = Release|x64 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Release|x64.Build.0 = Release|x64 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Release|x64.Deploy.0 = Release|x64 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Release|x86.ActiveCfg = Release|x86 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Release|x86.Build.0 = Release|x86 + {33A294C7-3146-405C-BCCA-C4E36985D0D7}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {44D20E12-11F5-4631-9882-CF0DEE92FBED} + EndGlobalSection +EndGlobal diff --git a/Camera-Renderer_cpp/App.xaml b/Camera-Renderer_cpp/App.xaml new file mode 100644 index 0000000..8feaded --- /dev/null +++ b/Camera-Renderer_cpp/App.xaml @@ -0,0 +1,7 @@ + + + diff --git a/Camera-Renderer_cpp/App.xaml.cpp b/Camera-Renderer_cpp/App.xaml.cpp new file mode 100644 index 0000000..ae855dd --- /dev/null +++ b/Camera-Renderer_cpp/App.xaml.cpp @@ -0,0 +1,125 @@ +// +// App.xaml.cpp +// Implementation of the App class. +// + +#include "pch.h" +#include "DirectXPage.xaml.h" + +using namespace CameraDirect_cpp; + +using namespace Platform; +using namespace Windows::ApplicationModel; +using namespace Windows::ApplicationModel::Activation; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::Storage; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Interop; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Navigation; +/// +/// Initializes the singleton application object. This is the first line of authored code +/// executed, and as such is the logical equivalent of main() or WinMain(). +/// +App::App() +{ + InitializeComponent(); + Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending); + Resuming += ref new EventHandler(this, &App::OnResuming); +} + +/// +/// Invoked when the application is launched normally by the end user. Other entry points +/// will be used when the application is launched to open a specific file, to display +/// search results, and so forth. +/// +/// Details about the launch request and process. +void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e) +{ +#if _DEBUG + if (IsDebuggerPresent()) + { + DebugSettings->EnableFrameRateCounter = true; + } +#endif + + auto rootFrame = dynamic_cast(Window::Current->Content); + + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == nullptr) + { + // Create a Frame to act as the navigation context and associate it with + // a SuspensionManager key + rootFrame = ref new Frame(); + + rootFrame->NavigationFailed += ref new Windows::UI::Xaml::Navigation::NavigationFailedEventHandler(this, &App::OnNavigationFailed); + + // Place the frame in the current Window + Window::Current->Content = rootFrame; + } + + if (rootFrame->Content == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + rootFrame->Navigate(TypeName(DirectXPage::typeid), e->Arguments); + } + + if (m_directXPage == nullptr) + { + m_directXPage = dynamic_cast(rootFrame->Content); + } + + if (e->PreviousExecutionState == ApplicationExecutionState::Terminated) + { + m_directXPage->LoadInternalState(ApplicationData::Current->LocalSettings->Values); + } + + // Ensure the current window is active + Window::Current->Activate(); +} +/// +/// Invoked when application execution is being suspended. Application state is saved +/// without knowing whether the application will be terminated or resumed with the contents +/// of memory still intact. +/// +/// The source of the suspend request. +/// Details about the suspend request. +void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e) +{ + (void) sender; // Unused parameter + (void) e; // Unused parameter + + m_directXPage->SaveInternalState(ApplicationData::Current->LocalSettings->Values); +} + +/// +/// Invoked when application execution is being resumed. +/// +/// The source of the resume request. +/// Details about the resume request. +void App::OnResuming(Object ^sender, Object ^args) +{ + (void) sender; // Unused parameter + (void) args; // Unused parameter + + m_directXPage->LoadInternalState(ApplicationData::Current->LocalSettings->Values); +} + +/// +/// Invoked when Navigation to a certain page fails +/// +/// The Frame which failed navigation +/// Details about the navigation failure +void App::OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e) +{ + throw ref new FailureException("Failed to load Page " + e->SourcePageType.Name); +} + diff --git a/Camera-Renderer_cpp/App.xaml.h b/Camera-Renderer_cpp/App.xaml.h new file mode 100644 index 0000000..0672c22 --- /dev/null +++ b/Camera-Renderer_cpp/App.xaml.h @@ -0,0 +1,28 @@ +// +// App.xaml.h +// Declaration of the App class. +// + +#pragma once + +#include "App.g.h" +#include "DirectXPage.xaml.h" + +namespace CameraDirect_cpp +{ + /// + /// Provides application-specific behavior to supplement the default Application class. + /// + ref class App sealed + { + public: + App(); + virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e) override; + + private: + void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e); + void OnResuming(Platform::Object ^sender, Platform::Object ^args); + void OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e); + DirectXPage^ m_directXPage; + }; +} diff --git a/Camera-Renderer_cpp/Assets/LockScreenLogo.scale-200.png b/Camera-Renderer_cpp/Assets/LockScreenLogo.scale-200.png new file mode 100644 index 0000000..735f57a Binary files /dev/null and b/Camera-Renderer_cpp/Assets/LockScreenLogo.scale-200.png differ diff --git a/Camera-Renderer_cpp/Assets/SplashScreen.scale-200.png b/Camera-Renderer_cpp/Assets/SplashScreen.scale-200.png new file mode 100644 index 0000000..023e7f1 Binary files /dev/null and b/Camera-Renderer_cpp/Assets/SplashScreen.scale-200.png differ diff --git a/Camera-Renderer_cpp/Assets/Square150x150Logo.scale-200.png b/Camera-Renderer_cpp/Assets/Square150x150Logo.scale-200.png new file mode 100644 index 0000000..af49fec Binary files /dev/null and b/Camera-Renderer_cpp/Assets/Square150x150Logo.scale-200.png differ diff --git a/Camera-Renderer_cpp/Assets/Square44x44Logo.scale-200.png b/Camera-Renderer_cpp/Assets/Square44x44Logo.scale-200.png new file mode 100644 index 0000000..ce342a2 Binary files /dev/null and b/Camera-Renderer_cpp/Assets/Square44x44Logo.scale-200.png differ diff --git a/Camera-Renderer_cpp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/Camera-Renderer_cpp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png new file mode 100644 index 0000000..f6c02ce Binary files /dev/null and b/Camera-Renderer_cpp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ diff --git a/Camera-Renderer_cpp/Assets/StoreLogo.png b/Camera-Renderer_cpp/Assets/StoreLogo.png new file mode 100644 index 0000000..7385b56 Binary files /dev/null and b/Camera-Renderer_cpp/Assets/StoreLogo.png differ diff --git a/Camera-Renderer_cpp/Assets/Wide310x150Logo.scale-200.png b/Camera-Renderer_cpp/Assets/Wide310x150Logo.scale-200.png new file mode 100644 index 0000000..288995b Binary files /dev/null and b/Camera-Renderer_cpp/Assets/Wide310x150Logo.scale-200.png differ diff --git a/Camera-Renderer_cpp/CameraDirect_cpp.vcxproj b/Camera-Renderer_cpp/CameraDirect_cpp.vcxproj new file mode 100644 index 0000000..73bbeb8 --- /dev/null +++ b/Camera-Renderer_cpp/CameraDirect_cpp.vcxproj @@ -0,0 +1,319 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + Debug + ARM + + + Release + ARM + + + Debug + ARM64 + + + Release + ARM64 + + + + {e764711a-933e-4e87-a081-2c24b25f7699} + DirectXXamlApp + CameraDirect_cpp + en-US + 14.0 + true + Windows Store + 10.0.19041.0 + 10.0.17763.0 + 10.0 + false + + + + Application + true + v142 + + + Application + true + v142 + + + Application + true + v142 + true + + + Application + true + v142 + + + Application + false + true + v142 + true + + + Application + false + true + v142 + true + + + Application + false + true + v142 + true + + + Application + false + true + v142 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm; $(VCInstallDir)\lib\arm + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + _DEBUG;%(PreprocessorDefinitions) + + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm; $(VCInstallDir)\lib\arm + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + NDEBUG;%(PreprocessorDefinitions) + + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm64; $(VCInstallDir)\lib\arm64 + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + _DEBUG;%(PreprocessorDefinitions) + + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\arm64; $(VCInstallDir)\lib\arm64 + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + NDEBUG;%(PreprocessorDefinitions) + + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store; $(VCInstallDir)\lib + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + _DEBUG;%(PreprocessorDefinitions) + + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store; $(VCInstallDir)\lib + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + NDEBUG;%(PreprocessorDefinitions) + + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\amd64; $(VCInstallDir)\lib\amd64 + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + _DEBUG;%(PreprocessorDefinitions) + + + + + d2d1.lib; d3d11.lib; dxgi.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies) + %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store\amd64; $(VCInstallDir)\lib\amd64 + + + pch.h + $(IntDir)pch.pch + $(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4453;28204 + NDEBUG;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + App.xaml + + + + + DirectXPage.xaml + + + + + + + + + + + App.xaml + + + + + DirectXPage.xaml + + + + + Create + Create + Create + Create + Create + Create + Create + Create + + + + + Designer + + + + + Pixel + + + Vertex + + + + + Designer + + + Designer + + + + + + + + + diff --git a/Camera-Renderer_cpp/CameraDirect_cpp.vcxproj.filters b/Camera-Renderer_cpp/CameraDirect_cpp.vcxproj.filters new file mode 100644 index 0000000..5b6d723 --- /dev/null +++ b/Camera-Renderer_cpp/CameraDirect_cpp.vcxproj.filters @@ -0,0 +1,66 @@ + + + + + e764711a-933e-4e87-a081-2c24b25f7699 + + + 9a29d315-3729-42f1-8e9a-441e0ca09644 + bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png + + + e15b4174-702d-4f9c-b6c9-a413728a0086 + + + Common + + + Common + + + Common + + + Common + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Content + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + \ No newline at end of file diff --git a/Camera-Renderer_cpp/CameraDirect_cppMain.cpp b/Camera-Renderer_cpp/CameraDirect_cppMain.cpp new file mode 100644 index 0000000..9f551a7 --- /dev/null +++ b/Camera-Renderer_cpp/CameraDirect_cppMain.cpp @@ -0,0 +1,141 @@ +#include "pch.h" +#include "CameraDirect_cppMain.h" +#include "Common\DirectXHelper.h" + +using namespace CameraDirect_cpp; +using namespace Windows::Foundation; +using namespace Windows::System::Threading; +using namespace Concurrency; + +// Loads and initializes application assets when the application is loaded. +CameraDirect_cppMain::CameraDirect_cppMain(const std::shared_ptr& deviceResources) : + m_deviceResources(deviceResources), m_pointerLocationX(0.0f) +{ + // Register to be notified if the Device is lost or recreated + m_deviceResources->RegisterDeviceNotify(this); + + // TODO: Replace this with your app's content initialization. + m_sceneRenderer = std::unique_ptr(new Sample3DSceneRenderer(m_deviceResources)); + + m_fpsTextRenderer = std::unique_ptr(new SampleFpsTextRenderer(m_deviceResources)); + + // TODO: Change the timer settings if you want something other than the default variable timestep mode. + // e.g. for 60 FPS fixed timestep update logic, call: + /* + m_timer.SetFixedTimeStep(true); + m_timer.SetTargetElapsedSeconds(1.0 / 60); + */ +} + +CameraDirect_cppMain::~CameraDirect_cppMain() +{ + // Deregister device notification + m_deviceResources->RegisterDeviceNotify(nullptr); +} + +// Updates application state when the window size changes (e.g. device orientation change) +void CameraDirect_cppMain::CreateWindowSizeDependentResources() +{ + // TODO: Replace this with the size-dependent initialization of your app's content. + m_sceneRenderer->CreateWindowSizeDependentResources(); +} + +void CameraDirect_cppMain::StartRenderLoop() +{ + // If the animation render loop is already running then do not start another thread. + if (m_renderLoopWorker != nullptr && m_renderLoopWorker->Status == AsyncStatus::Started) + { + return; + } + + // Create a task that will be run on a background thread. + auto workItemHandler = ref new WorkItemHandler([this](IAsyncAction ^ action) + { + // Calculate the updated frame and render once per vertical blanking interval. + while (action->Status == AsyncStatus::Started) + { + critical_section::scoped_lock lock(m_criticalSection); + Update(); + if (Render()) + { + m_deviceResources->Present(); + } + } + }); + + // Run task on a dedicated high priority background thread. + m_renderLoopWorker = ThreadPool::RunAsync(workItemHandler, WorkItemPriority::High, WorkItemOptions::TimeSliced); +} + +void CameraDirect_cppMain::StopRenderLoop() +{ + m_renderLoopWorker->Cancel(); +} + +// Updates the application state once per frame. +void CameraDirect_cppMain::Update() +{ + ProcessInput(); + + // Update scene objects. + m_timer.Tick([&]() + { + // TODO: Replace this with your app's content update functions. + m_sceneRenderer->Update(m_timer); + m_fpsTextRenderer->Update(m_timer); + }); +} + +// Process all input from the user before updating game state +void CameraDirect_cppMain::ProcessInput() +{ + // TODO: Add per frame input handling here. + m_sceneRenderer->TrackingUpdate(m_pointerLocationX); +} + +// Renders the current frame according to the current application state. +// Returns true if the frame was rendered and is ready to be displayed. +bool CameraDirect_cppMain::Render() +{ + // Don't try to render anything before the first Update. + if (m_timer.GetFrameCount() == 0) + { + return false; + } + + auto context = m_deviceResources->GetD3DDeviceContext(); + + // Reset the viewport to target the whole screen. + auto viewport = m_deviceResources->GetScreenViewport(); + context->RSSetViewports(1, &viewport); + + // Reset render targets to the screen. + ID3D11RenderTargetView *const targets[1] = { m_deviceResources->GetBackBufferRenderTargetView() }; + context->OMSetRenderTargets(1, targets, m_deviceResources->GetDepthStencilView()); + + // Clear the back buffer and depth stencil view. + context->ClearRenderTargetView(m_deviceResources->GetBackBufferRenderTargetView(), DirectX::Colors::CornflowerBlue); + context->ClearDepthStencilView(m_deviceResources->GetDepthStencilView(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); + + // Render the scene objects. + // TODO: Replace this with your app's content rendering functions. + m_sceneRenderer->Render(); + m_fpsTextRenderer->Render(); + + return true; +} + +// Notifies renderers that device resources need to be released. +void CameraDirect_cppMain::OnDeviceLost() +{ + m_sceneRenderer->ReleaseDeviceDependentResources(); + m_fpsTextRenderer->ReleaseDeviceDependentResources(); +} + +// Notifies renderers that device resources may now be recreated. +void CameraDirect_cppMain::OnDeviceRestored() +{ + m_sceneRenderer->CreateDeviceDependentResources(); + m_fpsTextRenderer->CreateDeviceDependentResources(); + CreateWindowSizeDependentResources(); +} diff --git a/Camera-Renderer_cpp/CameraDirect_cppMain.h b/Camera-Renderer_cpp/CameraDirect_cppMain.h new file mode 100644 index 0000000..6f95fdd --- /dev/null +++ b/Camera-Renderer_cpp/CameraDirect_cppMain.h @@ -0,0 +1,50 @@ +#pragma once + +#include "Common\StepTimer.h" +#include "Common\DeviceResources.h" +#include "Content\Sample3DSceneRenderer.h" +#include "Content\SampleFpsTextRenderer.h" + +// Renders Direct2D and 3D content on the screen. +namespace CameraDirect_cpp +{ + class CameraDirect_cppMain : public DX::IDeviceNotify + { + public: + CameraDirect_cppMain(const std::shared_ptr& deviceResources); + ~CameraDirect_cppMain(); + void CreateWindowSizeDependentResources(); + void StartTracking() { m_sceneRenderer->StartTracking(); } + void TrackingUpdate(float positionX) { m_pointerLocationX = positionX; } + void StopTracking() { m_sceneRenderer->StopTracking(); } + bool IsTracking() { return m_sceneRenderer->IsTracking(); } + void StartRenderLoop(); + void StopRenderLoop(); + Concurrency::critical_section& GetCriticalSection() { return m_criticalSection; } + + // IDeviceNotify + virtual void OnDeviceLost(); + virtual void OnDeviceRestored(); + + private: + void ProcessInput(); + void Update(); + bool Render(); + + // Cached pointer to device resources. + std::shared_ptr m_deviceResources; + + // TODO: Replace with your own content renderers. + std::unique_ptr m_sceneRenderer; + std::unique_ptr m_fpsTextRenderer; + + Windows::Foundation::IAsyncAction^ m_renderLoopWorker; + Concurrency::critical_section m_criticalSection; + + // Rendering loop timer. + DX::StepTimer m_timer; + + // Track current input pointer position. + float m_pointerLocationX; + }; +} \ No newline at end of file diff --git a/Camera-Renderer_cpp/Common/DeviceResources.cpp b/Camera-Renderer_cpp/Common/DeviceResources.cpp new file mode 100644 index 0000000..9831248 --- /dev/null +++ b/Camera-Renderer_cpp/Common/DeviceResources.cpp @@ -0,0 +1,748 @@ +#include "pch.h" +#include "DeviceResources.h" +#include "DirectXHelper.h" +#include + +using namespace D2D1; +using namespace DirectX; +using namespace Microsoft::WRL; +using namespace Windows::Foundation; +using namespace Windows::Graphics::Display; +using namespace Windows::UI::Core; +using namespace Windows::UI::Xaml::Controls; +using namespace Platform; + +namespace DisplayMetrics +{ + // High resolution displays can require a lot of GPU and battery power to render. + // High resolution phones, for example, may suffer from poor battery life if + // games attempt to render at 60 frames per second at full fidelity. + // The decision to render at full fidelity across all platforms and form factors + // should be deliberate. + static const bool SupportHighResolutions = false; + + // The default thresholds that define a "high resolution" display. If the thresholds + // are exceeded and SupportHighResolutions is false, the dimensions will be scaled + // by 50%. + static const float DpiThreshold = 192.0f; // 200% of standard desktop display. + static const float WidthThreshold = 1920.0f; // 1080p width. + static const float HeightThreshold = 1080.0f; // 1080p height. +}; + +// Constants used to calculate screen rotations. +namespace ScreenRotation +{ + // 0-degree Z-rotation + static const XMFLOAT4X4 Rotation0( + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); + + // 90-degree Z-rotation + static const XMFLOAT4X4 Rotation90( + 0.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); + + // 180-degree Z-rotation + static const XMFLOAT4X4 Rotation180( + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); + + // 270-degree Z-rotation + static const XMFLOAT4X4 Rotation270( + 0.0f, -1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); +}; + +// Constructor for DeviceResources. +DX::DeviceResources::DeviceResources() : + m_screenViewport(), + m_d3dFeatureLevel(D3D_FEATURE_LEVEL_9_1), + m_d3dRenderTargetSize(), + m_outputSize(), + m_logicalSize(), + m_nativeOrientation(DisplayOrientations::None), + m_currentOrientation(DisplayOrientations::None), + m_dpi(-1.0f), + m_effectiveDpi(-1.0f), + m_compositionScaleX(1.0f), + m_compositionScaleY(1.0f), + m_deviceNotify(nullptr) +{ + CreateDeviceIndependentResources(); + CreateDeviceResources(); +} + +// Configures resources that don't depend on the Direct3D device. +void DX::DeviceResources::CreateDeviceIndependentResources() +{ + // Initialize Direct2D resources. + D2D1_FACTORY_OPTIONS options; + ZeroMemory(&options, sizeof(D2D1_FACTORY_OPTIONS)); + +#if defined(_DEBUG) + // If the project is in a debug build, enable Direct2D debugging via SDK Layers. + options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; +#endif + + // Initialize the Direct2D Factory. + DX::ThrowIfFailed( + D2D1CreateFactory( + D2D1_FACTORY_TYPE_SINGLE_THREADED, + __uuidof(ID2D1Factory3), + &options, + &m_d2dFactory + ) + ); + + // Initialize the DirectWrite Factory. + DX::ThrowIfFailed( + DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory3), + &m_dwriteFactory + ) + ); + + // Initialize the Windows Imaging Component (WIC) Factory. + DX::ThrowIfFailed( + CoCreateInstance( + CLSID_WICImagingFactory2, + nullptr, + CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&m_wicFactory) + ) + ); +} + +// Configures the Direct3D device, and stores handles to it and the device context. +void DX::DeviceResources::CreateDeviceResources() +{ + // This flag adds support for surfaces with a different color channel ordering + // than the API default. It is required for compatibility with Direct2D. + UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + +#if defined(_DEBUG) + if (DX::SdkLayersAvailable()) + { + // If the project is in a debug build, enable debugging via SDK Layers with this flag. + creationFlags |= D3D11_CREATE_DEVICE_DEBUG; + } +#endif + + // This array defines the set of DirectX hardware feature levels this app will support. + // Note the ordering should be preserved. + // Don't forget to declare your application's minimum required feature level in its + // description. All applications are assumed to support 9.1 unless otherwise stated. + 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, + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1 + }; + + // Create the Direct3D 11 API device object and a corresponding context. + ComPtr device; + ComPtr context; + + HRESULT hr = D3D11CreateDevice( + nullptr, // Specify nullptr to use the default adapter. + D3D_DRIVER_TYPE_HARDWARE, // Create a device using the hardware graphics driver. + 0, // Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE. + creationFlags, // Set debug and Direct2D compatibility flags. + featureLevels, // List of feature levels this app can support. + ARRAYSIZE(featureLevels), // Size of the list above. + D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Microsoft Store apps. + &device, // Returns the Direct3D device created. + &m_d3dFeatureLevel, // Returns feature level of device created. + &context // Returns the device immediate context. + ); + + if (FAILED(hr)) + { + // If the initialization fails, fall back to the WARP device. + // For more information on WARP, see: + // https://go.microsoft.com/fwlink/?LinkId=286690 + DX::ThrowIfFailed( + D3D11CreateDevice( + nullptr, + D3D_DRIVER_TYPE_WARP, // Create a WARP device instead of a hardware device. + 0, + creationFlags, + featureLevels, + ARRAYSIZE(featureLevels), + D3D11_SDK_VERSION, + &device, + &m_d3dFeatureLevel, + &context + ) + ); + } + + // Store pointers to the Direct3D 11.3 API device and immediate context. + DX::ThrowIfFailed( + device.As(&m_d3dDevice) + ); + + DX::ThrowIfFailed( + context.As(&m_d3dContext) + ); + + // Create the Direct2D device object and a corresponding context. + ComPtr dxgiDevice; + DX::ThrowIfFailed( + m_d3dDevice.As(&dxgiDevice) + ); + + DX::ThrowIfFailed( + m_d2dFactory->CreateDevice(dxgiDevice.Get(), &m_d2dDevice) + ); + + DX::ThrowIfFailed( + m_d2dDevice->CreateDeviceContext( + D2D1_DEVICE_CONTEXT_OPTIONS_NONE, + &m_d2dContext + ) + ); +} + +// These resources need to be recreated every time the window size is changed. +void DX::DeviceResources::CreateWindowSizeDependentResources() +{ + // Clear the previous window size specific context. + ID3D11RenderTargetView* nullViews[] = {nullptr}; + m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr); + m_d3dRenderTargetView = nullptr; + m_d2dContext->SetTarget(nullptr); + m_d2dTargetBitmap = nullptr; + m_d3dDepthStencilView = nullptr; + m_d3dContext->Flush1(D3D11_CONTEXT_TYPE_ALL, nullptr); + + UpdateRenderTargetSize(); + + // The width and height of the swap chain must be based on the window's + // natively-oriented width and height. If the window is not in the native + // orientation, the dimensions must be reversed. + DXGI_MODE_ROTATION displayRotation = ComputeDisplayRotation(); + + bool swapDimensions = displayRotation == DXGI_MODE_ROTATION_ROTATE90 || displayRotation == DXGI_MODE_ROTATION_ROTATE270; + m_d3dRenderTargetSize.Width = swapDimensions ? m_outputSize.Height : m_outputSize.Width; + m_d3dRenderTargetSize.Height = swapDimensions ? m_outputSize.Width : m_outputSize.Height; + + if (m_swapChain != nullptr) + { + // If the swap chain already exists, resize it. + HRESULT hr = m_swapChain->ResizeBuffers( + 2, // Double-buffered swap chain. + lround(m_d3dRenderTargetSize.Width), + lround(m_d3dRenderTargetSize.Height), + DXGI_FORMAT_B8G8R8A8_UNORM, + 0 + ); + + if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) + { + // If the device was removed for any reason, a new device and swap chain will need to be created. + HandleDeviceLost(); + + // Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method + // and correctly set up the new device. + return; + } + else + { + DX::ThrowIfFailed(hr); + } + } + else + { + // Otherwise, create a new one using the same adapter as the existing Direct3D device. + DXGI_SCALING scaling = DisplayMetrics::SupportHighResolutions ? DXGI_SCALING_NONE : DXGI_SCALING_STRETCH; + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0}; + + swapChainDesc.Width = lround(m_d3dRenderTargetSize.Width); // Match the size of the window. + swapChainDesc.Height = lround(m_d3dRenderTargetSize.Height); + swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format. + swapChainDesc.Stereo = false; + swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling. + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency. + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Microsoft Store apps must use _FLIP_ SwapEffects. + swapChainDesc.Flags = 0; + swapChainDesc.Scaling = scaling; + swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + + // This sequence obtains the DXGI factory that was used to create the Direct3D device above. + ComPtr dxgiDevice; + DX::ThrowIfFailed( + m_d3dDevice.As(&dxgiDevice) + ); + + ComPtr dxgiAdapter; + DX::ThrowIfFailed( + dxgiDevice->GetAdapter(&dxgiAdapter) + ); + + ComPtr dxgiFactory; + DX::ThrowIfFailed( + dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory)) + ); + + // When using XAML interop, the swap chain must be created for composition. + ComPtr swapChain; + DX::ThrowIfFailed( + dxgiFactory->CreateSwapChainForComposition( + m_d3dDevice.Get(), + &swapChainDesc, + nullptr, + &swapChain + ) + ); + + DX::ThrowIfFailed( + swapChain.As(&m_swapChain) + ); + + // Associate swap chain with SwapChainPanel + // UI changes will need to be dispatched back to the UI thread + m_swapChainPanel->Dispatcher->RunAsync(CoreDispatcherPriority::High, ref new DispatchedHandler([=]() + { + // Get backing native interface for SwapChainPanel + ComPtr panelNative; + DX::ThrowIfFailed( + reinterpret_cast(m_swapChainPanel)->QueryInterface(IID_PPV_ARGS(&panelNative)) + ); + + DX::ThrowIfFailed( + panelNative->SetSwapChain(m_swapChain.Get()) + ); + }, CallbackContext::Any)); + + // Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and + // ensures that the application will only render after each VSync, minimizing power consumption. + DX::ThrowIfFailed( + dxgiDevice->SetMaximumFrameLatency(1) + ); + } + + // Set the proper orientation for the swap chain, and generate 2D and + // 3D matrix transformations for rendering to the rotated swap chain. + // Note the rotation angle for the 2D and 3D transforms are different. + // This is due to the difference in coordinate spaces. Additionally, + // the 3D matrix is specified explicitly to avoid rounding errors. + + switch (displayRotation) + { + case DXGI_MODE_ROTATION_IDENTITY: + m_orientationTransform2D = Matrix3x2F::Identity(); + m_orientationTransform3D = ScreenRotation::Rotation0; + break; + + case DXGI_MODE_ROTATION_ROTATE90: + m_orientationTransform2D = + Matrix3x2F::Rotation(90.0f) * + Matrix3x2F::Translation(m_logicalSize.Height, 0.0f); + m_orientationTransform3D = ScreenRotation::Rotation270; + break; + + case DXGI_MODE_ROTATION_ROTATE180: + m_orientationTransform2D = + Matrix3x2F::Rotation(180.0f) * + Matrix3x2F::Translation(m_logicalSize.Width, m_logicalSize.Height); + m_orientationTransform3D = ScreenRotation::Rotation180; + break; + + case DXGI_MODE_ROTATION_ROTATE270: + m_orientationTransform2D = + Matrix3x2F::Rotation(270.0f) * + Matrix3x2F::Translation(0.0f, m_logicalSize.Width); + m_orientationTransform3D = ScreenRotation::Rotation90; + break; + + default: + throw ref new FailureException(); + } + + DX::ThrowIfFailed( + m_swapChain->SetRotation(displayRotation) + ); + + // Setup inverse scale on the swap chain + DXGI_MATRIX_3X2_F inverseScale = { 0 }; + inverseScale._11 = 1.0f / m_effectiveCompositionScaleX; + inverseScale._22 = 1.0f / m_effectiveCompositionScaleY; + ComPtr spSwapChain2; + DX::ThrowIfFailed( + m_swapChain.As(&spSwapChain2) + ); + + DX::ThrowIfFailed( + spSwapChain2->SetMatrixTransform(&inverseScale) + ); + + // Create a render target view of the swap chain back buffer. + ComPtr backBuffer; + DX::ThrowIfFailed( + m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer)) + ); + + DX::ThrowIfFailed( + m_d3dDevice->CreateRenderTargetView1( + backBuffer.Get(), + nullptr, + &m_d3dRenderTargetView + ) + ); + + // Create a depth stencil view for use with 3D rendering if needed. + CD3D11_TEXTURE2D_DESC1 depthStencilDesc( + DXGI_FORMAT_D24_UNORM_S8_UINT, + lround(m_d3dRenderTargetSize.Width), + lround(m_d3dRenderTargetSize.Height), + 1, // This depth stencil view has only one texture. + 1, // Use a single mipmap level. + D3D11_BIND_DEPTH_STENCIL + ); + + ComPtr depthStencil; + DX::ThrowIfFailed( + m_d3dDevice->CreateTexture2D1( + &depthStencilDesc, + nullptr, + &depthStencil + ) + ); + + CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D); + DX::ThrowIfFailed( + m_d3dDevice->CreateDepthStencilView( + depthStencil.Get(), + &depthStencilViewDesc, + &m_d3dDepthStencilView + ) + ); + + // Set the 3D rendering viewport to target the entire window. + m_screenViewport = CD3D11_VIEWPORT( + 0.0f, + 0.0f, + m_d3dRenderTargetSize.Width, + m_d3dRenderTargetSize.Height + ); + + m_d3dContext->RSSetViewports(1, &m_screenViewport); + + // Create a Direct2D target bitmap associated with the + // swap chain back buffer and set it as the current target. + D2D1_BITMAP_PROPERTIES1 bitmapProperties = + D2D1::BitmapProperties1( + D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), + m_dpi, + m_dpi + ); + + ComPtr dxgiBackBuffer; + DX::ThrowIfFailed( + m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer)) + ); + + DX::ThrowIfFailed( + m_d2dContext->CreateBitmapFromDxgiSurface( + dxgiBackBuffer.Get(), + &bitmapProperties, + &m_d2dTargetBitmap + ) + ); + + m_d2dContext->SetTarget(m_d2dTargetBitmap.Get()); + m_d2dContext->SetDpi(m_effectiveDpi, m_effectiveDpi); + + // Grayscale text anti-aliasing is recommended for all Microsoft Store apps. + m_d2dContext->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE); +} + +// Determine the dimensions of the render target and whether it will be scaled down. +void DX::DeviceResources::UpdateRenderTargetSize() +{ + m_effectiveDpi = m_dpi; + m_effectiveCompositionScaleX = m_compositionScaleX; + m_effectiveCompositionScaleY = m_compositionScaleY; + + // To improve battery life on high resolution devices, render to a smaller render target + // and allow the GPU to scale the output when it is presented. + if (!DisplayMetrics::SupportHighResolutions && m_dpi > DisplayMetrics::DpiThreshold) + { + float width = DX::ConvertDipsToPixels(m_logicalSize.Width, m_dpi); + float height = DX::ConvertDipsToPixels(m_logicalSize.Height, m_dpi); + + // When the device is in portrait orientation, height > width. Compare the + // larger dimension against the width threshold and the smaller dimension + // against the height threshold. + if (max(width, height) > DisplayMetrics::WidthThreshold && min(width, height) > DisplayMetrics::HeightThreshold) + { + // To scale the app we change the effective DPI. Logical size does not change. + m_effectiveDpi /= 2.0f; + m_effectiveCompositionScaleX /= 2.0f; + m_effectiveCompositionScaleY /= 2.0f; + } + } + + // Calculate the necessary render target size in pixels. + m_outputSize.Width = DX::ConvertDipsToPixels(m_logicalSize.Width, m_effectiveDpi); + m_outputSize.Height = DX::ConvertDipsToPixels(m_logicalSize.Height, m_effectiveDpi); + + // Prevent zero size DirectX content from being created. + m_outputSize.Width = max(m_outputSize.Width, 1); + m_outputSize.Height = max(m_outputSize.Height, 1); +} + +// This method is called when the XAML control is created (or re-created). +void DX::DeviceResources::SetSwapChainPanel(SwapChainPanel^ panel) +{ + DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView(); + + m_swapChainPanel = panel; + m_logicalSize = Windows::Foundation::Size(static_cast(panel->ActualWidth), static_cast(panel->ActualHeight)); + m_nativeOrientation = currentDisplayInformation->NativeOrientation; + m_currentOrientation = currentDisplayInformation->CurrentOrientation; + m_compositionScaleX = panel->CompositionScaleX; + m_compositionScaleY = panel->CompositionScaleY; + m_dpi = currentDisplayInformation->LogicalDpi; + m_d2dContext->SetDpi(m_dpi, m_dpi); + + CreateWindowSizeDependentResources(); +} + +// This method is called in the event handler for the SizeChanged event. +void DX::DeviceResources::SetLogicalSize(Windows::Foundation::Size logicalSize) +{ + if (m_logicalSize != logicalSize) + { + m_logicalSize = logicalSize; + CreateWindowSizeDependentResources(); + } +} + +// This method is called in the event handler for the DpiChanged event. +void DX::DeviceResources::SetDpi(float dpi) +{ + if (dpi != m_dpi) + { + m_dpi = dpi; + m_d2dContext->SetDpi(m_dpi, m_dpi); + CreateWindowSizeDependentResources(); + } +} + +// This method is called in the event handler for the OrientationChanged event. +void DX::DeviceResources::SetCurrentOrientation(DisplayOrientations currentOrientation) +{ + if (m_currentOrientation != currentOrientation) + { + m_currentOrientation = currentOrientation; + CreateWindowSizeDependentResources(); + } +} + +// This method is called in the event handler for the CompositionScaleChanged event. +void DX::DeviceResources::SetCompositionScale(float compositionScaleX, float compositionScaleY) +{ + if (m_compositionScaleX != compositionScaleX || + m_compositionScaleY != compositionScaleY) + { + m_compositionScaleX = compositionScaleX; + m_compositionScaleY = compositionScaleY; + CreateWindowSizeDependentResources(); + } +} + +// This method is called in the event handler for the DisplayContentsInvalidated event. +void DX::DeviceResources::ValidateDevice() +{ + // The D3D Device is no longer valid if the default adapter changed since the device + // was created or if the device has been removed. + + // First, get the information for the default adapter from when the device was created. + + ComPtr dxgiDevice; + DX::ThrowIfFailed(m_d3dDevice.As(&dxgiDevice)); + + ComPtr deviceAdapter; + DX::ThrowIfFailed(dxgiDevice->GetAdapter(&deviceAdapter)); + + ComPtr deviceFactory; + DX::ThrowIfFailed(deviceAdapter->GetParent(IID_PPV_ARGS(&deviceFactory))); + + ComPtr previousDefaultAdapter; + DX::ThrowIfFailed(deviceFactory->EnumAdapters1(0, &previousDefaultAdapter)); + + DXGI_ADAPTER_DESC1 previousDesc; + DX::ThrowIfFailed(previousDefaultAdapter->GetDesc1(&previousDesc)); + + // Next, get the information for the current default adapter. + + ComPtr currentFactory; + DX::ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(¤tFactory))); + + ComPtr currentDefaultAdapter; + DX::ThrowIfFailed(currentFactory->EnumAdapters1(0, ¤tDefaultAdapter)); + + DXGI_ADAPTER_DESC1 currentDesc; + DX::ThrowIfFailed(currentDefaultAdapter->GetDesc1(¤tDesc)); + + // If the adapter LUIDs don't match, or if the device reports that it has been removed, + // a new D3D device must be created. + + if (previousDesc.AdapterLuid.LowPart != currentDesc.AdapterLuid.LowPart || + previousDesc.AdapterLuid.HighPart != currentDesc.AdapterLuid.HighPart || + FAILED(m_d3dDevice->GetDeviceRemovedReason())) + { + // Release references to resources related to the old device. + dxgiDevice = nullptr; + deviceAdapter = nullptr; + deviceFactory = nullptr; + previousDefaultAdapter = nullptr; + + // Create a new device and swap chain. + HandleDeviceLost(); + } +} + +// Recreate all device resources and set them back to the current state. +void DX::DeviceResources::HandleDeviceLost() +{ + m_swapChain = nullptr; + + if (m_deviceNotify != nullptr) + { + m_deviceNotify->OnDeviceLost(); + } + + CreateDeviceResources(); + m_d2dContext->SetDpi(m_dpi, m_dpi); + CreateWindowSizeDependentResources(); + + if (m_deviceNotify != nullptr) + { + m_deviceNotify->OnDeviceRestored(); + } +} + +// Register our DeviceNotify to be informed on device lost and creation. +void DX::DeviceResources::RegisterDeviceNotify(DX::IDeviceNotify* deviceNotify) +{ + m_deviceNotify = deviceNotify; +} + +// Call this method when the app suspends. It provides a hint to the driver that the app +// is entering an idle state and that temporary buffers can be reclaimed for use by other apps. +void DX::DeviceResources::Trim() +{ + ComPtr dxgiDevice; + m_d3dDevice.As(&dxgiDevice); + + dxgiDevice->Trim(); +} + +// Present the contents of the swap chain to the screen. +void DX::DeviceResources::Present() +{ + // The first argument instructs DXGI to block until VSync, putting the application + // to sleep until the next VSync. This ensures we don't waste any cycles rendering + // frames that will never be displayed to the screen. + DXGI_PRESENT_PARAMETERS parameters = { 0 }; + HRESULT hr = m_swapChain->Present1(1, 0, ¶meters); + + // Discard the contents of the render target. + // This is a valid operation only when the existing contents will be entirely + // overwritten. If dirty or scroll rects are used, this call should be modified. + m_d3dContext->DiscardView1(m_d3dRenderTargetView.Get(), nullptr, 0); + + // Discard the contents of the depth stencil. + m_d3dContext->DiscardView1(m_d3dDepthStencilView.Get(), nullptr, 0); + + // If the device was removed either by a disconnection or a driver upgrade, we + // must recreate all device resources. + if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) + { + HandleDeviceLost(); + } + else + { + DX::ThrowIfFailed(hr); + } +} + +// This method determines the rotation between the display device's native orientation and the +// current display orientation. +DXGI_MODE_ROTATION DX::DeviceResources::ComputeDisplayRotation() +{ + DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED; + + // Note: NativeOrientation can only be Landscape or Portrait even though + // the DisplayOrientations enum has other values. + switch (m_nativeOrientation) + { + case DisplayOrientations::Landscape: + switch (m_currentOrientation) + { + case DisplayOrientations::Landscape: + rotation = DXGI_MODE_ROTATION_IDENTITY; + break; + + case DisplayOrientations::Portrait: + rotation = DXGI_MODE_ROTATION_ROTATE270; + break; + + case DisplayOrientations::LandscapeFlipped: + rotation = DXGI_MODE_ROTATION_ROTATE180; + break; + + case DisplayOrientations::PortraitFlipped: + rotation = DXGI_MODE_ROTATION_ROTATE90; + break; + } + break; + + case DisplayOrientations::Portrait: + switch (m_currentOrientation) + { + case DisplayOrientations::Landscape: + rotation = DXGI_MODE_ROTATION_ROTATE90; + break; + + case DisplayOrientations::Portrait: + rotation = DXGI_MODE_ROTATION_IDENTITY; + break; + + case DisplayOrientations::LandscapeFlipped: + rotation = DXGI_MODE_ROTATION_ROTATE270; + break; + + case DisplayOrientations::PortraitFlipped: + rotation = DXGI_MODE_ROTATION_ROTATE180; + break; + } + break; + } + return rotation; +} \ No newline at end of file diff --git a/Camera-Renderer_cpp/Common/DeviceResources.h b/Camera-Renderer_cpp/Common/DeviceResources.h new file mode 100644 index 0000000..00d84e7 --- /dev/null +++ b/Camera-Renderer_cpp/Common/DeviceResources.h @@ -0,0 +1,107 @@ +#pragma once + +namespace DX +{ + // Provides an interface for an application that owns DeviceResources to be notified of the device being lost or created. + interface IDeviceNotify + { + virtual void OnDeviceLost() = 0; + virtual void OnDeviceRestored() = 0; + }; + + // Controls all the DirectX device resources. + class DeviceResources + { + public: + DeviceResources(); + void SetSwapChainPanel(Windows::UI::Xaml::Controls::SwapChainPanel^ panel); + void SetLogicalSize(Windows::Foundation::Size logicalSize); + void SetCurrentOrientation(Windows::Graphics::Display::DisplayOrientations currentOrientation); + void SetDpi(float dpi); + void SetCompositionScale(float compositionScaleX, float compositionScaleY); + void ValidateDevice(); + void HandleDeviceLost(); + void RegisterDeviceNotify(IDeviceNotify* deviceNotify); + void Trim(); + void Present(); + + // The size of the render target, in pixels. + Windows::Foundation::Size GetOutputSize() const { return m_outputSize; } + + // The size of the render target, in dips. + Windows::Foundation::Size GetLogicalSize() const { return m_logicalSize; } + float GetDpi() const { return m_effectiveDpi; } + + // D3D Accessors. + ID3D11Device3* GetD3DDevice() const { return m_d3dDevice.Get(); } + ID3D11DeviceContext3* GetD3DDeviceContext() const { return m_d3dContext.Get(); } + IDXGISwapChain3* GetSwapChain() const { return m_swapChain.Get(); } + D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const { return m_d3dFeatureLevel; } + ID3D11RenderTargetView1* GetBackBufferRenderTargetView() const { return m_d3dRenderTargetView.Get(); } + ID3D11DepthStencilView* GetDepthStencilView() const { return m_d3dDepthStencilView.Get(); } + D3D11_VIEWPORT GetScreenViewport() const { return m_screenViewport; } + DirectX::XMFLOAT4X4 GetOrientationTransform3D() const { return m_orientationTransform3D; } + + // D2D Accessors. + ID2D1Factory3* GetD2DFactory() const { return m_d2dFactory.Get(); } + ID2D1Device2* GetD2DDevice() const { return m_d2dDevice.Get(); } + ID2D1DeviceContext2* GetD2DDeviceContext() const { return m_d2dContext.Get(); } + ID2D1Bitmap1* GetD2DTargetBitmap() const { return m_d2dTargetBitmap.Get(); } + IDWriteFactory3* GetDWriteFactory() const { return m_dwriteFactory.Get(); } + IWICImagingFactory2* GetWicImagingFactory() const { return m_wicFactory.Get(); } + D2D1::Matrix3x2F GetOrientationTransform2D() const { return m_orientationTransform2D; } + + private: + void CreateDeviceIndependentResources(); + void CreateDeviceResources(); + void CreateWindowSizeDependentResources(); + void UpdateRenderTargetSize(); + DXGI_MODE_ROTATION ComputeDisplayRotation(); + + // Direct3D objects. + Microsoft::WRL::ComPtr m_d3dDevice; + Microsoft::WRL::ComPtr m_d3dContext; + Microsoft::WRL::ComPtr m_swapChain; + + // Direct3D rendering objects. Required for 3D. + Microsoft::WRL::ComPtr m_d3dRenderTargetView; + Microsoft::WRL::ComPtr m_d3dDepthStencilView; + D3D11_VIEWPORT m_screenViewport; + + // Direct2D drawing components. + Microsoft::WRL::ComPtr m_d2dFactory; + Microsoft::WRL::ComPtr m_d2dDevice; + Microsoft::WRL::ComPtr m_d2dContext; + Microsoft::WRL::ComPtr m_d2dTargetBitmap; + + // DirectWrite drawing components. + Microsoft::WRL::ComPtr m_dwriteFactory; + Microsoft::WRL::ComPtr m_wicFactory; + + // Cached reference to the XAML panel. + Windows::UI::Xaml::Controls::SwapChainPanel^ m_swapChainPanel; + + // Cached device properties. + D3D_FEATURE_LEVEL m_d3dFeatureLevel; + Windows::Foundation::Size m_d3dRenderTargetSize; + Windows::Foundation::Size m_outputSize; + Windows::Foundation::Size m_logicalSize; + Windows::Graphics::Display::DisplayOrientations m_nativeOrientation; + Windows::Graphics::Display::DisplayOrientations m_currentOrientation; + float m_dpi; + float m_compositionScaleX; + float m_compositionScaleY; + + // Variables that take into account whether the app supports high resolution screens or not. + float m_effectiveDpi; + float m_effectiveCompositionScaleX; + float m_effectiveCompositionScaleY; + + // Transforms used for display orientation. + D2D1::Matrix3x2F m_orientationTransform2D; + DirectX::XMFLOAT4X4 m_orientationTransform3D; + + // The IDeviceNotify can be held directly as it owns the DeviceResources. + IDeviceNotify* m_deviceNotify; + }; +} \ No newline at end of file diff --git a/Camera-Renderer_cpp/Common/DirectXHelper.h b/Camera-Renderer_cpp/Common/DirectXHelper.h new file mode 100644 index 0000000..4434b08 --- /dev/null +++ b/Camera-Renderer_cpp/Common/DirectXHelper.h @@ -0,0 +1,63 @@ +#pragma once + +#include // For create_task + +namespace DX +{ + inline void ThrowIfFailed(HRESULT hr) + { + if (FAILED(hr)) + { + // Set a breakpoint on this line to catch Win32 API errors. + throw Platform::Exception::CreateException(hr); + } + } + + // Function that reads from a binary file asynchronously. + inline Concurrency::task> ReadDataAsync(const std::wstring& filename) + { + using namespace Windows::Storage; + using namespace Concurrency; + + auto folder = Windows::ApplicationModel::Package::Current->InstalledLocation; + + return create_task(folder->GetFileAsync(Platform::StringReference(filename.c_str()))).then([] (StorageFile^ file) + { + return FileIO::ReadBufferAsync(file); + }).then([] (Streams::IBuffer^ fileBuffer) -> std::vector + { + std::vector returnBuffer; + returnBuffer.resize(fileBuffer->Length); + Streams::DataReader::FromBuffer(fileBuffer)->ReadBytes(Platform::ArrayReference(returnBuffer.data(), fileBuffer->Length)); + 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 Microsoft Store apps. + nullptr, // No need to keep the D3D device reference. + nullptr, // No need to know the feature level. + nullptr // No need to keep the D3D device context reference. + ); + + return SUCCEEDED(hr); + } +#endif +} diff --git a/Camera-Renderer_cpp/Common/StepTimer.h b/Camera-Renderer_cpp/Common/StepTimer.h new file mode 100644 index 0000000..286710c --- /dev/null +++ b/Camera-Renderer_cpp/Common/StepTimer.h @@ -0,0 +1,183 @@ +#pragma once + +#include + +namespace DX +{ + // Helper class for animation and simulation timing. + class StepTimer + { + public: + StepTimer() : + m_elapsedTicks(0), + m_totalTicks(0), + m_leftOverTicks(0), + m_frameCount(0), + m_framesPerSecond(0), + m_framesThisSecond(0), + m_qpcSecondCounter(0), + m_isFixedTimeStep(false), + m_targetElapsedTicks(TicksPerSecond / 60) + { + if (!QueryPerformanceFrequency(&m_qpcFrequency)) + { + throw ref new Platform::FailureException(); + } + + if (!QueryPerformanceCounter(&m_qpcLastTime)) + { + throw ref new Platform::FailureException(); + } + + // Initialize max delta to 1/10 of a second. + m_qpcMaxDelta = m_qpcFrequency.QuadPart / 10; + } + + // Get elapsed time since the previous Update call. + uint64 GetElapsedTicks() const { return m_elapsedTicks; } + double GetElapsedSeconds() const { return TicksToSeconds(m_elapsedTicks); } + + // Get total time since the start of the program. + uint64 GetTotalTicks() const { return m_totalTicks; } + double GetTotalSeconds() const { return TicksToSeconds(m_totalTicks); } + + // Get total number of updates since start of the program. + uint32 GetFrameCount() const { return m_frameCount; } + + // Get the current framerate. + uint32 GetFramesPerSecond() const { return m_framesPerSecond; } + + // Set whether to use fixed or variable timestep mode. + void SetFixedTimeStep(bool isFixedTimestep) { m_isFixedTimeStep = isFixedTimestep; } + + // Set how often to call Update when in fixed timestep mode. + void SetTargetElapsedTicks(uint64 targetElapsed) { m_targetElapsedTicks = targetElapsed; } + void SetTargetElapsedSeconds(double targetElapsed) { m_targetElapsedTicks = SecondsToTicks(targetElapsed); } + + // Integer format represents time using 10,000,000 ticks per second. + static const uint64 TicksPerSecond = 10000000; + + static double TicksToSeconds(uint64 ticks) { return static_cast(ticks) / TicksPerSecond; } + static uint64 SecondsToTicks(double seconds) { return static_cast(seconds * TicksPerSecond); } + + // After an intentional timing discontinuity (for instance a blocking IO operation) + // call this to avoid having the fixed timestep logic attempt a set of catch-up + // Update calls. + + void ResetElapsedTime() + { + if (!QueryPerformanceCounter(&m_qpcLastTime)) + { + throw ref new Platform::FailureException(); + } + + m_leftOverTicks = 0; + m_framesPerSecond = 0; + m_framesThisSecond = 0; + m_qpcSecondCounter = 0; + } + + // Update timer state, calling the specified Update function the appropriate number of times. + template + void Tick(const TUpdate& update) + { + // Query the current time. + LARGE_INTEGER currentTime; + + if (!QueryPerformanceCounter(¤tTime)) + { + throw ref new Platform::FailureException(); + } + + uint64 timeDelta = currentTime.QuadPart - m_qpcLastTime.QuadPart; + + m_qpcLastTime = currentTime; + m_qpcSecondCounter += timeDelta; + + // Clamp excessively large time deltas (e.g. after paused in the debugger). + if (timeDelta > m_qpcMaxDelta) + { + timeDelta = m_qpcMaxDelta; + } + + // Convert QPC units into a canonical tick format. This cannot overflow due to the previous clamp. + timeDelta *= TicksPerSecond; + timeDelta /= m_qpcFrequency.QuadPart; + + uint32 lastFrameCount = m_frameCount; + + if (m_isFixedTimeStep) + { + // Fixed timestep update logic + + // If the app is running very close to the target elapsed time (within 1/4 of a millisecond) just clamp + // the clock to exactly match the target value. This prevents tiny and irrelevant errors + // from accumulating over time. Without this clamping, a game that requested a 60 fps + // fixed update, running with vsync enabled on a 59.94 NTSC display, would eventually + // accumulate enough tiny errors that it would drop a frame. It is better to just round + // small deviations down to zero to leave things running smoothly. + + if (abs(static_cast(timeDelta - m_targetElapsedTicks)) < TicksPerSecond / 4000) + { + timeDelta = m_targetElapsedTicks; + } + + m_leftOverTicks += timeDelta; + + while (m_leftOverTicks >= m_targetElapsedTicks) + { + m_elapsedTicks = m_targetElapsedTicks; + m_totalTicks += m_targetElapsedTicks; + m_leftOverTicks -= m_targetElapsedTicks; + m_frameCount++; + + update(); + } + } + else + { + // Variable timestep update logic. + m_elapsedTicks = timeDelta; + m_totalTicks += timeDelta; + m_leftOverTicks = 0; + m_frameCount++; + + update(); + } + + // Track the current framerate. + if (m_frameCount != lastFrameCount) + { + m_framesThisSecond++; + } + + if (m_qpcSecondCounter >= static_cast(m_qpcFrequency.QuadPart)) + { + m_framesPerSecond = m_framesThisSecond; + m_framesThisSecond = 0; + m_qpcSecondCounter %= m_qpcFrequency.QuadPart; + } + } + + private: + // Source timing data uses QPC units. + LARGE_INTEGER m_qpcFrequency; + LARGE_INTEGER m_qpcLastTime; + uint64 m_qpcMaxDelta; + + // Derived timing data uses a canonical tick format. + uint64 m_elapsedTicks; + uint64 m_totalTicks; + uint64 m_leftOverTicks; + + // Members for tracking the framerate. + uint32 m_frameCount; + uint32 m_framesPerSecond; + uint32 m_framesThisSecond; + uint64 m_qpcSecondCounter; + + // Members for configuring fixed timestep mode. + bool m_isFixedTimeStep; + uint64 m_targetElapsedTicks; + }; +} diff --git a/Camera-Renderer_cpp/Content/Sample3DSceneRenderer.cpp b/Camera-Renderer_cpp/Content/Sample3DSceneRenderer.cpp new file mode 100644 index 0000000..7ad5abf --- /dev/null +++ b/Camera-Renderer_cpp/Content/Sample3DSceneRenderer.cpp @@ -0,0 +1,324 @@ +#include "pch.h" +#include "Sample3DSceneRenderer.h" + +#include "..\Common\DirectXHelper.h" + +using namespace CameraDirect_cpp; + +using namespace DirectX; +using namespace Windows::Foundation; + +// Loads vertex and pixel shaders from files and instantiates the cube geometry. +Sample3DSceneRenderer::Sample3DSceneRenderer(const std::shared_ptr& deviceResources) : + m_loadingComplete(false), + m_degreesPerSecond(45), + m_indexCount(0), + m_tracking(false), + m_deviceResources(deviceResources) +{ + CreateDeviceDependentResources(); + CreateWindowSizeDependentResources(); +} + +// Initializes view parameters when the window size changes. +void Sample3DSceneRenderer::CreateWindowSizeDependentResources() +{ + Size outputSize = m_deviceResources->GetOutputSize(); + float aspectRatio = outputSize.Width / outputSize.Height; + float fovAngleY = 70.0f * XM_PI / 180.0f; + + // This is a simple example of change that can be made when the app is in + // portrait or snapped view. + if (aspectRatio < 1.0f) + { + fovAngleY *= 2.0f; + } + + // Note that the OrientationTransform3D matrix is post-multiplied here + // in order to correctly orient the scene to match the display orientation. + // This post-multiplication step is required for any draw calls that are + // made to the swap chain render target. For draw calls to other targets, + // this transform should not be applied. + + // This sample makes use of a right-handed coordinate system using row-major matrices. + XMMATRIX perspectiveMatrix = XMMatrixPerspectiveFovRH( + fovAngleY, + aspectRatio, + 0.01f, + 100.0f + ); + + XMFLOAT4X4 orientation = m_deviceResources->GetOrientationTransform3D(); + + XMMATRIX orientationMatrix = XMLoadFloat4x4(&orientation); + + XMStoreFloat4x4( + &m_constantBufferData.projection, + XMMatrixTranspose(perspectiveMatrix * orientationMatrix) + ); + + // Eye is at (0,0.7,1.5), looking at point (0,-0.1,0) with the up-vector along the y-axis. + static const XMVECTORF32 eye = { 0.0f, 0.7f, 1.5f, 0.0f }; + static const XMVECTORF32 at = { 0.0f, -0.1f, 0.0f, 0.0f }; + static const XMVECTORF32 up = { 0.0f, 1.0f, 0.0f, 0.0f }; + + XMStoreFloat4x4(&m_constantBufferData.view, XMMatrixTranspose(XMMatrixLookAtRH(eye, at, up))); +} + +// Called once per frame, rotates the cube and calculates the model and view matrices. +void Sample3DSceneRenderer::Update(DX::StepTimer const& timer) +{ + if (!m_tracking) + { + // Convert degrees to radians, then convert seconds to rotation angle + float radiansPerSecond = XMConvertToRadians(m_degreesPerSecond); + double totalRotation = timer.GetTotalSeconds() * radiansPerSecond; + float radians = static_cast(fmod(totalRotation, XM_2PI)); + + Rotate(radians); + } +} + +// Rotate the 3D cube model a set amount of radians. +void Sample3DSceneRenderer::Rotate(float radians) +{ + // Prepare to pass the updated model matrix to the shader + XMStoreFloat4x4(&m_constantBufferData.model, XMMatrixTranspose(XMMatrixRotationY(radians))); +} + +void Sample3DSceneRenderer::StartTracking() +{ + m_tracking = true; +} + +// When tracking, the 3D cube can be rotated around its Y axis by tracking pointer position relative to the output screen width. +void Sample3DSceneRenderer::TrackingUpdate(float positionX) +{ + if (m_tracking) + { + float radians = XM_2PI * 2.0f * positionX / m_deviceResources->GetOutputSize().Width; + Rotate(radians); + } +} + +void Sample3DSceneRenderer::StopTracking() +{ + m_tracking = false; +} + +// Renders one frame using the vertex and pixel shaders. +void Sample3DSceneRenderer::Render() +{ + // Loading is asynchronous. Only draw geometry after it's loaded. + if (!m_loadingComplete) + { + return; + } + + auto context = m_deviceResources->GetD3DDeviceContext(); + + // Prepare the constant buffer to send it to the graphics device. + context->UpdateSubresource1( + m_constantBuffer.Get(), + 0, + NULL, + &m_constantBufferData, + 0, + 0, + 0 + ); + + // Each vertex is one instance of the VertexPositionColor struct. + UINT stride = sizeof(VertexPositionColor); + UINT offset = 0; + context->IASetVertexBuffers( + 0, + 1, + m_vertexBuffer.GetAddressOf(), + &stride, + &offset + ); + + context->IASetIndexBuffer( + m_indexBuffer.Get(), + DXGI_FORMAT_R16_UINT, // Each index is one 16-bit unsigned integer (short). + 0 + ); + + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + context->IASetInputLayout(m_inputLayout.Get()); + + // Attach our vertex shader. + context->VSSetShader( + m_vertexShader.Get(), + nullptr, + 0 + ); + + // Send the constant buffer to the graphics device. + context->VSSetConstantBuffers1( + 0, + 1, + m_constantBuffer.GetAddressOf(), + nullptr, + nullptr + ); + + // Attach our pixel shader. + context->PSSetShader( + m_pixelShader.Get(), + nullptr, + 0 + ); + + // Draw the objects. + context->DrawIndexed( + m_indexCount, + 0, + 0 + ); +} + +void Sample3DSceneRenderer::CreateDeviceDependentResources() +{ + // Load shaders asynchronously. + auto loadVSTask = DX::ReadDataAsync(L"SampleVertexShader.cso"); + auto loadPSTask = DX::ReadDataAsync(L"SamplePixelShader.cso"); + + // After the vertex shader file is loaded, create the shader and input layout. + auto createVSTask = loadVSTask.then([this](const std::vector& fileData) { + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateVertexShader( + &fileData[0], + fileData.size(), + nullptr, + &m_vertexShader + ) + ); + + static const D3D11_INPUT_ELEMENT_DESC vertexDesc [] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateInputLayout( + vertexDesc, + ARRAYSIZE(vertexDesc), + &fileData[0], + fileData.size(), + &m_inputLayout + ) + ); + }); + + // After the pixel shader file is loaded, create the shader and constant buffer. + auto createPSTask = loadPSTask.then([this](const std::vector& fileData) { + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreatePixelShader( + &fileData[0], + fileData.size(), + nullptr, + &m_pixelShader + ) + ); + + CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelViewProjectionConstantBuffer) , D3D11_BIND_CONSTANT_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &constantBufferDesc, + nullptr, + &m_constantBuffer + ) + ); + }); + + // Once both shaders are loaded, create the mesh. + auto createCubeTask = (createPSTask && createVSTask).then([this] () { + + // Load mesh vertices. Each vertex has a position and a color. + static const VertexPositionColor cubeVertices[] = + { + {XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT3(0.0f, 0.0f, 0.0f)}, + {XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT3(0.0f, 0.0f, 1.0f)}, + {XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT3(0.0f, 1.0f, 0.0f)}, + {XMFLOAT3(-0.5f, 0.5f, 0.5f), XMFLOAT3(0.0f, 1.0f, 1.0f)}, + {XMFLOAT3( 0.5f, -0.5f, -0.5f), XMFLOAT3(1.0f, 0.0f, 0.0f)}, + {XMFLOAT3( 0.5f, -0.5f, 0.5f), XMFLOAT3(1.0f, 0.0f, 1.0f)}, + {XMFLOAT3( 0.5f, 0.5f, -0.5f), XMFLOAT3(1.0f, 1.0f, 0.0f)}, + {XMFLOAT3( 0.5f, 0.5f, 0.5f), XMFLOAT3(1.0f, 1.0f, 1.0f)}, + }; + + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = cubeVertices; + vertexBufferData.SysMemPitch = 0; + vertexBufferData.SysMemSlicePitch = 0; + CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &vertexBufferDesc, + &vertexBufferData, + &m_vertexBuffer + ) + ); + + // Load mesh indices. Each trio of indices represents + // a triangle to be rendered on the screen. + // For example: 0,2,1 means that the vertices with indexes + // 0, 2 and 1 from the vertex buffer compose the + // first triangle of this mesh. + static const unsigned short cubeIndices [] = + { + 0,2,1, // -x + 1,2,3, + + 4,5,6, // +x + 5,7,6, + + 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; + CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER); + DX::ThrowIfFailed( + m_deviceResources->GetD3DDevice()->CreateBuffer( + &indexBufferDesc, + &indexBufferData, + &m_indexBuffer + ) + ); + }); + + // Once the cube is loaded, the object is ready to be rendered. + createCubeTask.then([this] () { + m_loadingComplete = true; + }); +} + +void Sample3DSceneRenderer::ReleaseDeviceDependentResources() +{ + m_loadingComplete = false; + m_vertexShader.Reset(); + m_inputLayout.Reset(); + m_pixelShader.Reset(); + m_constantBuffer.Reset(); + m_vertexBuffer.Reset(); + m_indexBuffer.Reset(); +} \ No newline at end of file diff --git a/Camera-Renderer_cpp/Content/Sample3DSceneRenderer.h b/Camera-Renderer_cpp/Content/Sample3DSceneRenderer.h new file mode 100644 index 0000000..aae2e32 --- /dev/null +++ b/Camera-Renderer_cpp/Content/Sample3DSceneRenderer.h @@ -0,0 +1,50 @@ +#pragma once + +#include "..\Common\DeviceResources.h" +#include "ShaderStructures.h" +#include "..\Common\StepTimer.h" + +namespace CameraDirect_cpp +{ + // This sample renderer instantiates a basic rendering pipeline. + class Sample3DSceneRenderer + { + public: + Sample3DSceneRenderer(const std::shared_ptr& deviceResources); + void CreateDeviceDependentResources(); + void CreateWindowSizeDependentResources(); + void ReleaseDeviceDependentResources(); + void Update(DX::StepTimer const& timer); + void Render(); + void StartTracking(); + void TrackingUpdate(float positionX); + void StopTracking(); + bool IsTracking() { return m_tracking; } + + + private: + void Rotate(float radians); + + private: + // Cached pointer to device resources. + std::shared_ptr m_deviceResources; + + // Direct3D resources for cube geometry. + Microsoft::WRL::ComPtr m_inputLayout; + Microsoft::WRL::ComPtr m_vertexBuffer; + Microsoft::WRL::ComPtr m_indexBuffer; + Microsoft::WRL::ComPtr m_vertexShader; + Microsoft::WRL::ComPtr m_pixelShader; + Microsoft::WRL::ComPtr m_constantBuffer; + + // System resources for cube geometry. + ModelViewProjectionConstantBuffer m_constantBufferData; + uint32 m_indexCount; + + // Variables used with the rendering loop. + bool m_loadingComplete; + float m_degreesPerSecond; + bool m_tracking; + }; +} + diff --git a/Camera-Renderer_cpp/Content/SampleFpsTextRenderer.cpp b/Camera-Renderer_cpp/Content/SampleFpsTextRenderer.cpp new file mode 100644 index 0000000..751158e --- /dev/null +++ b/Camera-Renderer_cpp/Content/SampleFpsTextRenderer.cpp @@ -0,0 +1,122 @@ +#include "pch.h" +#include "SampleFpsTextRenderer.h" + +#include "Common/DirectXHelper.h" + +using namespace CameraDirect_cpp; +using namespace Microsoft::WRL; + +// Initializes D2D resources used for text rendering. +SampleFpsTextRenderer::SampleFpsTextRenderer(const std::shared_ptr& deviceResources) : + m_text(L""), + m_deviceResources(deviceResources) +{ + ZeroMemory(&m_textMetrics, sizeof(DWRITE_TEXT_METRICS)); + + // Create device independent resources + ComPtr textFormat; + DX::ThrowIfFailed( + m_deviceResources->GetDWriteFactory()->CreateTextFormat( + L"Segoe UI", + nullptr, + DWRITE_FONT_WEIGHT_LIGHT, + DWRITE_FONT_STYLE_NORMAL, + DWRITE_FONT_STRETCH_NORMAL, + 32.0f, + L"en-US", + &textFormat + ) + ); + + DX::ThrowIfFailed( + textFormat.As(&m_textFormat) + ); + + DX::ThrowIfFailed( + m_textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR) + ); + + DX::ThrowIfFailed( + m_deviceResources->GetD2DFactory()->CreateDrawingStateBlock(&m_stateBlock) + ); + + CreateDeviceDependentResources(); +} + +// Updates the text to be displayed. +void SampleFpsTextRenderer::Update(DX::StepTimer const& timer) +{ + // Update display text. + uint32 fps = timer.GetFramesPerSecond(); + + m_text = (fps > 0) ? std::to_wstring(fps) + L" FPS" : L" - FPS"; + + ComPtr textLayout; + DX::ThrowIfFailed( + m_deviceResources->GetDWriteFactory()->CreateTextLayout( + m_text.c_str(), + (uint32) m_text.length(), + m_textFormat.Get(), + 240.0f, // Max width of the input text. + 50.0f, // Max height of the input text. + &textLayout + ) + ); + + DX::ThrowIfFailed( + textLayout.As(&m_textLayout) + ); + + DX::ThrowIfFailed( + m_textLayout->GetMetrics(&m_textMetrics) + ); +} + +// Renders a frame to the screen. +void SampleFpsTextRenderer::Render() +{ + ID2D1DeviceContext* context = m_deviceResources->GetD2DDeviceContext(); + Windows::Foundation::Size logicalSize = m_deviceResources->GetLogicalSize(); + + context->SaveDrawingState(m_stateBlock.Get()); + context->BeginDraw(); + + // Position on the bottom right corner + D2D1::Matrix3x2F screenTranslation = D2D1::Matrix3x2F::Translation( + logicalSize.Width - m_textMetrics.layoutWidth, + logicalSize.Height - m_textMetrics.height + ); + + context->SetTransform(screenTranslation * m_deviceResources->GetOrientationTransform2D()); + + DX::ThrowIfFailed( + m_textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING) + ); + + context->DrawTextLayout( + D2D1::Point2F(0.f, 0.f), + m_textLayout.Get(), + m_whiteBrush.Get() + ); + + // Ignore D2DERR_RECREATE_TARGET here. This error indicates that the device + // is lost. It will be handled during the next call to Present. + HRESULT hr = context->EndDraw(); + if (hr != D2DERR_RECREATE_TARGET) + { + DX::ThrowIfFailed(hr); + } + + context->RestoreDrawingState(m_stateBlock.Get()); +} + +void SampleFpsTextRenderer::CreateDeviceDependentResources() +{ + DX::ThrowIfFailed( + m_deviceResources->GetD2DDeviceContext()->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), &m_whiteBrush) + ); +} +void SampleFpsTextRenderer::ReleaseDeviceDependentResources() +{ + m_whiteBrush.Reset(); +} \ No newline at end of file diff --git a/Camera-Renderer_cpp/Content/SampleFpsTextRenderer.h b/Camera-Renderer_cpp/Content/SampleFpsTextRenderer.h new file mode 100644 index 0000000..5115a15 --- /dev/null +++ b/Camera-Renderer_cpp/Content/SampleFpsTextRenderer.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include "..\Common\DeviceResources.h" +#include "..\Common\StepTimer.h" + +namespace CameraDirect_cpp +{ + // Renders the current FPS value in the bottom right corner of the screen using Direct2D and DirectWrite. + class SampleFpsTextRenderer + { + public: + SampleFpsTextRenderer(const std::shared_ptr& deviceResources); + void CreateDeviceDependentResources(); + void ReleaseDeviceDependentResources(); + void Update(DX::StepTimer const& timer); + void Render(); + + private: + // Cached pointer to device resources. + std::shared_ptr m_deviceResources; + + // Resources related to text rendering. + std::wstring m_text; + DWRITE_TEXT_METRICS m_textMetrics; + Microsoft::WRL::ComPtr m_whiteBrush; + Microsoft::WRL::ComPtr m_stateBlock; + Microsoft::WRL::ComPtr m_textLayout; + Microsoft::WRL::ComPtr m_textFormat; + }; +} \ No newline at end of file diff --git a/Camera-Renderer_cpp/Content/SamplePixelShader.hlsl b/Camera-Renderer_cpp/Content/SamplePixelShader.hlsl new file mode 100644 index 0000000..c7282d6 --- /dev/null +++ b/Camera-Renderer_cpp/Content/SamplePixelShader.hlsl @@ -0,0 +1,10 @@ +struct PixelShaderInput +{ + float4 pos : SV_POSITION; + float3 color : COLOR0; +}; + +float4 main(PixelShaderInput input) : SV_TARGET +{ + return float4(input.color, 1.0f); +} diff --git a/Camera-Renderer_cpp/Content/SampleVertexShader.hlsl b/Camera-Renderer_cpp/Content/SampleVertexShader.hlsl new file mode 100644 index 0000000..faab260 --- /dev/null +++ b/Camera-Renderer_cpp/Content/SampleVertexShader.hlsl @@ -0,0 +1,33 @@ +cbuffer ModelViewProjectionConstantBuffer : register(b0) +{ + matrix model; + matrix view; + matrix projection; +}; + +struct VertexShaderInput +{ + float3 pos : POSITION; + float3 color : COLOR0; +}; + +struct PixelShaderInput +{ + float4 pos : SV_POSITION; + float3 color : COLOR0; +}; + +PixelShaderInput main(VertexShaderInput input) +{ + PixelShaderInput output; + float4 pos = float4(input.pos, 1.0f); + + pos = mul(pos, model); + pos = mul(pos, view); + pos = mul(pos, projection); + output.pos = pos; + + output.color = input.color; + + return output; +} diff --git a/Camera-Renderer_cpp/Content/ShaderStructures.h b/Camera-Renderer_cpp/Content/ShaderStructures.h new file mode 100644 index 0000000..87b7585 --- /dev/null +++ b/Camera-Renderer_cpp/Content/ShaderStructures.h @@ -0,0 +1,19 @@ +#pragma once + +namespace CameraDirect_cpp +{ + // Constant buffer used to send MVP matrices to the vertex shader. + struct ModelViewProjectionConstantBuffer + { + DirectX::XMFLOAT4X4 model; + DirectX::XMFLOAT4X4 view; + DirectX::XMFLOAT4X4 projection; + }; + + // Used to send per-vertex data to the vertex shader. + struct VertexPositionColor + { + DirectX::XMFLOAT3 pos; + DirectX::XMFLOAT3 color; + }; +} \ No newline at end of file diff --git a/Camera-Renderer_cpp/DirectXPage.xaml b/Camera-Renderer_cpp/DirectXPage.xaml new file mode 100644 index 0000000..b10f3dc --- /dev/null +++ b/Camera-Renderer_cpp/DirectXPage.xaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + +