diff --git a/Kits/ATGTK/imgui/imgui_atg.cpp b/Kits/ATGTK/imgui/imgui_atg.cpp index 1a075d1c..8be554e4 100644 --- a/Kits/ATGTK/imgui/imgui_atg.cpp +++ b/Kits/ATGTK/imgui/imgui_atg.cpp @@ -551,11 +551,13 @@ namespace ImGuiAtg { "Triangle", ControllerGlyph::BtnTriangle }, // Xbox D-Pad - { "DPad", ControllerGlyph::DPad }, - { "DPadUp", ControllerGlyph::DPadUp }, - { "DPadDown", ControllerGlyph::DPadDown }, - { "DPadLeft", ControllerGlyph::DPadLeft }, - { "DPadRight", ControllerGlyph::DPadRight }, + { "DPad", ControllerGlyph::DPad }, + { "DPadUp", ControllerGlyph::DPadUp }, + { "DPadDown", ControllerGlyph::DPadDown }, + { "DPadLeft", ControllerGlyph::DPadLeft }, + { "DPadRight", ControllerGlyph::DPadRight }, + { "DPadUpDown", ControllerGlyph::DPadUpDown }, + { "DPadLeftRight", ControllerGlyph::DPadLeftRight }, // Generic D-Pad { "Up", ControllerGlyph::Up }, @@ -1059,7 +1061,9 @@ namespace ImGuiAtg void DrawLogPanel(float height, bool wrap) { + ImGuiAtg::BeginNavigationGroup("Log"); DrawLogContent(GetState(), "Log", height, wrap); + ImGuiAtg::EndNavigationGroup(); } void ClearLog() diff --git a/Kits/ATGTK/imgui/imgui_atg.h b/Kits/ATGTK/imgui/imgui_atg.h index 9137b368..54109df6 100644 --- a/Kits/ATGTK/imgui/imgui_atg.h +++ b/Kits/ATGTK/imgui/imgui_atg.h @@ -177,6 +177,8 @@ namespace ImGuiAtg DPadDown = 0x227D, DPadLeft = 0x227A, DPadRight = 0x227C, + DPadUpDown = 0x227F, + DPadLeftRight = 0x227E, // D-Pad (generic) Up = 0x219F, diff --git a/Kits/OpenSource/imgui/imconfig.h b/Kits/OpenSource/imgui/imconfig.h index 51552e50..d6cfdb97 100644 --- a/Kits/OpenSource/imgui/imconfig.h +++ b/Kits/OpenSource/imgui/imconfig.h @@ -46,7 +46,7 @@ //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) -//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. +//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). //#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded font (ProggyClean.ttf), remove ~9.5 KB from output binary. AddFontDefault() will assert. //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available diff --git a/Samples/System/Gamepad/DeviceResources.cpp b/Samples/System/Gamepad/DeviceResources.cpp deleted file mode 100644 index f7084157..00000000 --- a/Samples/System/Gamepad/DeviceResources.cpp +++ /dev/null @@ -1,862 +0,0 @@ -// -// DeviceResources.cpp - A wrapper for the Direct3D 12/12.X device and swapchain -// - -#include "pch.h" -#include "DeviceResources.h" - -using namespace DirectX; -using namespace DX; - -using Microsoft::WRL::ComPtr; - -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wcovered-switch-default" -#pragma clang diagnostic ignored "-Wswitch-enum" -#endif - -#pragma warning(disable : 4061) - -#ifdef _GAMING_DESKTOP -namespace -{ - inline DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt) noexcept - { - switch (fmt) - { - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: return DXGI_FORMAT_R8G8B8A8_UNORM; - case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8A8_UNORM; - case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8X8_UNORM; - default: return fmt; - } - } -} -#endif - -// Constructor for DeviceResources. -DeviceResources::DeviceResources( - DXGI_FORMAT backBufferFormat, - DXGI_FORMAT depthBufferFormat, - UINT backBufferCount, - unsigned int flags) noexcept(false) : - m_backBufferIndex(0), - m_fenceValues{}, -#ifdef _GAMING_XBOX - m_framePipelineToken{}, -#endif - m_rtvDescriptorSize(0), - m_screenViewport{}, - m_scissorRect{}, - m_backBufferFormat(backBufferFormat), - m_depthBufferFormat(depthBufferFormat), - m_backBufferCount(backBufferCount), - m_clearColor{}, - m_window(nullptr), - m_d3dFeatureLevel(D3D_FEATURE_LEVEL_11_0), - m_outputSize{ 0, 0, 1, 1 }, - m_options(flags), - m_deviceNotify(nullptr) -{ - if (backBufferCount < 2 || backBufferCount > MAX_BACK_BUFFER_COUNT) - { - throw std::out_of_range("invalid backBufferCount"); - } -} - -// Destructor for DeviceResources. -DeviceResources::~DeviceResources() -{ - // Ensure that the GPU is no longer referencing resources that are about to be destroyed. - WaitForGpu(); - -#ifdef _GAMING_XBOX - // Ensure we present a blank screen before cleaning up resources. - if (m_commandQueue) - { - std::ignore = m_commandQueue->PresentX(0, nullptr, nullptr); - } -#endif -} - -// Configures the Direct3D device, and stores handles to it and the device context. -void DeviceResources::CreateDeviceResources() -{ -#ifdef _GAMING_XBOX - - // Create the DX12 API device object. - D3D12XBOX_CREATE_DEVICE_PARAMETERS params = {}; - params.Version = D3D12_SDK_VERSION; - -#if defined(_DEBUG) - // Enable the debug layer. - params.ProcessDebugFlags = D3D12_PROCESS_DEBUG_FLAG_DEBUG_LAYER_ENABLED; -#elif defined(PROFILE) - // Enable the instrumented driver. - params.ProcessDebugFlags = D3D12XBOX_PROCESS_DEBUG_FLAG_INSTRUMENTED; -#endif - - params.GraphicsCommandQueueRingSizeBytes = static_cast(D3D12XBOX_DEFAULT_SIZE_BYTES); - params.DisableGeometryShaderAllocations = (m_options & c_GeometryShaders) ? FALSE : TRUE; - params.DisableTessellationShaderAllocations = (m_options & c_TessellationShaders) ? FALSE : TRUE; - -#ifdef _GAMING_XBOX_SCARLETT - params.DisableDXR = (m_options & c_EnableDXR) ? FALSE : TRUE; - params.CreateDeviceFlags = D3D12XBOX_CREATE_DEVICE_FLAG_NONE; - -#if (_GRDK_VER >= 0x585D070E /* GXDK Edition 221000 */) - if (m_options & c_AmplificationShaders) - { - params.AmplificationShaderIndirectArgsBufferSize = static_cast(D3D12XBOX_DEFAULT_SIZE_BYTES); - params.AmplificationShaderPayloadBufferSize = static_cast(D3D12XBOX_DEFAULT_SIZE_BYTES); - } -#endif -#else // _GAMING_XBOX_XBOXONE - m_options &= ~(c_AmplificationShaders | c_EnableDXR); -#endif - - HRESULT hr = D3D12XboxCreateDevice( - nullptr, - ¶ms, - IID_GRAPHICS_PPV_ARGS(m_d3dDevice.ReleaseAndGetAddressOf())); -#ifdef _DEBUG - if (hr == D3D12_ERROR_DRIVER_VERSION_MISMATCH) - { -#ifdef _GAMING_XBOX_SCARLETT - OutputDebugStringA("ERROR: Running a d3d12_xs.lib (Xbox Series X|S) linked binary on an Xbox One is not supported\n"); -#else - OutputDebugStringA("ERROR: Running a d3d12_x.lib (Xbox One) linked binary on a Xbox Series X|S in 'Scarlett' mode is not supported\n"); -#endif - } -#endif - ThrowIfFailed(hr); - - m_d3dDevice->SetName(L"DeviceResources"); - - m_d3dFeatureLevel = D3D_FEATURE_LEVEL_12_0; - -#else // _GAMING_DESKTOP - - DWORD dxgiFactoryFlags = 0; - -#if defined(_DEBUG) - // Enable the debug layer (requires the Graphics Tools "optional feature"). - // - // NOTE: Enabling the debug layer after device creation will invalidate the active device. - { - ComPtr debugController; - if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(debugController.GetAddressOf())))) - { - debugController->EnableDebugLayer(); - } - else - { - OutputDebugStringA("WARNING: Direct3D Debug Device is not available\n"); - } - - ComPtr dxgiInfoQueue; - if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(dxgiInfoQueue.GetAddressOf())))) - { - dxgiFactoryFlags = DXGI_CREATE_FACTORY_DEBUG; - - dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true); - dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true); - - DXGI_INFO_QUEUE_MESSAGE_ID hide[] = - { - 80 /* IDXGISwapChain::GetContainingOutput: The swapchain's adapter does not control the output on which the swapchain's window resides. */, - }; - DXGI_INFO_QUEUE_FILTER filter = {}; - filter.DenyList.NumIDs = static_cast(std::size(hide)); - filter.DenyList.pIDList = hide; - dxgiInfoQueue->AddStorageFilterEntries(DXGI_DEBUG_DXGI, &filter); - } - } -#endif - - ThrowIfFailed(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf()))); - - ComPtr adapter; - GetAdapter(adapter.GetAddressOf()); - - // Create the DX12 API device object. - HRESULT hr = D3D12CreateDevice( - adapter.Get(), - D3D_FEATURE_LEVEL_11_0, - IID_PPV_ARGS(m_d3dDevice.ReleaseAndGetAddressOf()) - ); - ThrowIfFailed(hr); - - m_d3dDevice->SetName(L"DeviceResources"); - -#ifndef NDEBUG - // Configure debug device (if active). - ComPtr d3dInfoQueue; - if (SUCCEEDED(m_d3dDevice.As(&d3dInfoQueue))) - { -#ifdef _DEBUG - d3dInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true); - d3dInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true); -#endif - D3D12_MESSAGE_ID hide[] = - { - D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE, - D3D12_MESSAGE_ID_UNMAP_INVALID_NULLRANGE, - // Workarounds for debug layer issues on hybrid-graphics systems - D3D12_MESSAGE_ID_EXECUTECOMMANDLISTS_WRONGSWAPCHAINBUFFERREFERENCE, - D3D12_MESSAGE_ID_RESOURCE_BARRIER_MISMATCHING_COMMAND_LIST_TYPE, - }; - D3D12_INFO_QUEUE_FILTER filter = {}; - filter.DenyList.NumIDs = static_cast(std::size(hide)); - filter.DenyList.pIDList = hide; - d3dInfoQueue->AddStorageFilterEntries(&filter); - } -#endif - - // Determine maximum supported feature level for this device - static const D3D_FEATURE_LEVEL s_featureLevels[] = - { -#if defined(NTDDI_WIN10_FE) && (NTDDI_VERSION >= NTDDI_WIN10_FE) - D3D_FEATURE_LEVEL_12_2, -#endif - D3D_FEATURE_LEVEL_12_1, - D3D_FEATURE_LEVEL_12_0, - D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0, - }; - - D3D12_FEATURE_DATA_FEATURE_LEVELS featLevels = - { - static_cast(std::size(s_featureLevels)), s_featureLevels, D3D_FEATURE_LEVEL_11_0 - }; - - hr = m_d3dDevice->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &featLevels, sizeof(featLevels)); - if (SUCCEEDED(hr)) - { - m_d3dFeatureLevel = featLevels.MaxSupportedFeatureLevel; - } - else - { - m_d3dFeatureLevel = D3D_FEATURE_LEVEL_11_0; - } - - // Check device options. - if (m_options & c_AmplificationShaders) - { - D3D12_FEATURE_DATA_D3D12_OPTIONS7 devopt = {}; - if (FAILED(m_d3dDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &devopt, sizeof(devopt)))) - { - devopt = {}; - } - if (devopt.MeshShaderTier == D3D12_MESH_SHADER_TIER_NOT_SUPPORTED) - { - m_options &= ~c_AmplificationShaders; - } - } - - if (m_options & c_EnableDXR) - { - D3D12_FEATURE_DATA_D3D12_OPTIONS5 devopt = {}; - if (FAILED(m_d3dDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &devopt, sizeof(devopt)))) - { - devopt = {}; - } - if (devopt.RaytracingTier == D3D12_RAYTRACING_TIER_NOT_SUPPORTED) - { - m_options &= ~c_EnableDXR; - } - } - -#endif - - // Create the command queue. - D3D12_COMMAND_QUEUE_DESC queueDesc = {}; - queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - - ThrowIfFailed(m_d3dDevice->CreateCommandQueue(&queueDesc, IID_GRAPHICS_PPV_ARGS(m_commandQueue.ReleaseAndGetAddressOf()))); - - m_commandQueue->SetName(L"DeviceResources"); - - // Create descriptor heaps for render target views and depth stencil views. - D3D12_DESCRIPTOR_HEAP_DESC rtvDescriptorHeapDesc = {}; - rtvDescriptorHeapDesc.NumDescriptors = m_backBufferCount; - rtvDescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; - - ThrowIfFailed(m_d3dDevice->CreateDescriptorHeap(&rtvDescriptorHeapDesc, IID_GRAPHICS_PPV_ARGS(m_rtvDescriptorHeap.ReleaseAndGetAddressOf()))); - - m_rtvDescriptorHeap->SetName(L"DeviceResources"); - - m_rtvDescriptorSize = m_d3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); - - if (m_depthBufferFormat != DXGI_FORMAT_UNKNOWN) - { - D3D12_DESCRIPTOR_HEAP_DESC dsvDescriptorHeapDesc = {}; - dsvDescriptorHeapDesc.NumDescriptors = 1; - dsvDescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; - - ThrowIfFailed(m_d3dDevice->CreateDescriptorHeap(&dsvDescriptorHeapDesc, IID_GRAPHICS_PPV_ARGS(m_dsvDescriptorHeap.ReleaseAndGetAddressOf()))); - - m_dsvDescriptorHeap->SetName(L"DeviceResources"); - } - - // Create a command allocator for each back buffer that will be rendered to. - for (UINT n = 0; n < m_backBufferCount; n++) - { - ThrowIfFailed(m_d3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_GRAPHICS_PPV_ARGS(m_commandAllocators[n].ReleaseAndGetAddressOf()))); - - wchar_t name[25] = {}; - swprintf_s(name, L"Render target %u", n); - m_commandAllocators[n]->SetName(name); - } - - // Create a command list for recording graphics commands. - ThrowIfFailed(m_d3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[0].Get(), nullptr, IID_GRAPHICS_PPV_ARGS(m_commandList.ReleaseAndGetAddressOf()))); - ThrowIfFailed(m_commandList->Close()); - - m_commandList->SetName(L"DeviceResources"); - - // Create a fence for tracking GPU execution progress. - ThrowIfFailed(m_d3dDevice->CreateFence(m_fenceValues[m_backBufferIndex], D3D12_FENCE_FLAG_NONE, IID_GRAPHICS_PPV_ARGS(m_fence.ReleaseAndGetAddressOf()))); - m_fenceValues[m_backBufferIndex]++; - - m_fence->SetName(L"DeviceResources"); - - m_fenceEvent.Attach(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE)); - if (!m_fenceEvent.IsValid()) - { - throw std::system_error(std::error_code(static_cast(GetLastError()), std::system_category()), "CreateEventEx"); - } - -#ifdef _GAMING_XBOX - RegisterFrameEvents(); -#endif -} - -// These resources need to be recreated every time the window size is changed. -void DeviceResources::CreateWindowSizeDependentResources() -{ - if (!m_window) - { - throw std::logic_error("Call SetWindow with a valid Win32 window handle"); - } - - // Wait until all previous GPU work is complete. - WaitForGpu(); - -#ifdef _GAMING_XBOX - // Ensure we present a blank screen before cleaning up resources. - ThrowIfFailed(m_commandQueue->PresentX(0, nullptr, nullptr)); -#endif - - // Release resources that are tied to the swap chain and update fence values. - for (UINT n = 0; n < m_backBufferCount; n++) - { - m_renderTargets[n].Reset(); - m_fenceValues[n] = m_fenceValues[m_backBufferIndex]; - } - - // Determine the render target size in pixels. - const UINT backBufferWidth = std::max(static_cast(m_outputSize.right - m_outputSize.left), 1u); - const UINT backBufferHeight = std::max(static_cast(m_outputSize.bottom - m_outputSize.top), 1u); - -#ifdef _GAMING_XBOX - - // Obtain the back buffers for this window which will be the final render targets - // and create render target views for each of them. - const CD3DX12_HEAP_PROPERTIES swapChainHeapProperties(D3D12_HEAP_TYPE_DEFAULT); - - D3D12_RESOURCE_DESC swapChainBufferDesc = CD3DX12_RESOURCE_DESC::Tex2D( - m_backBufferFormat, - backBufferWidth, - backBufferHeight, - 1, // This resource has only one texture. - 1 // Use a single mipmap level. - ); - swapChainBufferDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; - - const CD3DX12_CLEAR_VALUE swapChainOptimizedClearValue(m_backBufferFormat, m_clearColor); - - for (UINT n = 0; n < m_backBufferCount; n++) - { - ThrowIfFailed(m_d3dDevice->CreateCommittedResource( - &swapChainHeapProperties, - D3D12_HEAP_FLAG_ALLOW_DISPLAY, - &swapChainBufferDesc, - D3D12_RESOURCE_STATE_PRESENT, - &swapChainOptimizedClearValue, - IID_GRAPHICS_PPV_ARGS(m_renderTargets[n].GetAddressOf()))); - - wchar_t name[25] = {}; - swprintf_s(name, L"Render target %u", n); - m_renderTargets[n]->SetName(name); - - D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; - rtvDesc.Format = m_backBufferFormat; - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; - - const CD3DX12_CPU_DESCRIPTOR_HANDLE rtvDescriptor( - m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), - static_cast(n), m_rtvDescriptorSize); - m_d3dDevice->CreateRenderTargetView(m_renderTargets[n].Get(), &rtvDesc, rtvDescriptor); - } - - // Reset the index to the current back buffer. - m_backBufferIndex = 0; - -#else // _GAMING_DESKTOP - - const DXGI_FORMAT backBufferFormat = NoSRGB(m_backBufferFormat); - - // If the swap chain already exists, resize it, otherwise create one. - if (m_swapChain) - { - // If the swap chain already exists, resize it. - HRESULT hr = m_swapChain->ResizeBuffers( - m_backBufferCount, - backBufferWidth, - backBufferHeight, - backBufferFormat, - 0 - ); - - if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) - { -#ifdef _DEBUG - char buff[64] = {}; - sprintf_s(buff, "Device Lost on ResizeBuffers: Reason code 0x%08X\n", - static_cast((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr)); - OutputDebugStringA(buff); -#endif - // 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 - { - ThrowIfFailed(hr); - } - } - else - { - // Create a descriptor for the swap chain. - DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; - swapChainDesc.Width = backBufferWidth; - swapChainDesc.Height = backBufferHeight; - swapChainDesc.Format = backBufferFormat; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapChainDesc.BufferCount = m_backBufferCount; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.Scaling = DXGI_SCALING_STRETCH; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; - - DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsSwapChainDesc = {}; - fsSwapChainDesc.Windowed = TRUE; - - // Create a swap chain for the window. - ComPtr swapChain; - ThrowIfFailed(m_dxgiFactory->CreateSwapChainForHwnd( - m_commandQueue.Get(), - m_window, - &swapChainDesc, - &fsSwapChainDesc, - nullptr, - swapChain.GetAddressOf() - )); - - ThrowIfFailed(swapChain.As(&m_swapChain)); - - // This class does not support exclusive full-screen mode and prevents DXGI from responding to the ALT+ENTER shortcut - ThrowIfFailed(m_dxgiFactory->MakeWindowAssociation(m_window, DXGI_MWA_NO_ALT_ENTER)); - } - - // Obtain the back buffers for this window which will be the final render targets - // and create render target views for each of them. - for (UINT n = 0; n < m_backBufferCount; n++) - { - ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(m_renderTargets[n].GetAddressOf()))); - - wchar_t name[25] = {}; - swprintf_s(name, L"Render target %u", n); - m_renderTargets[n]->SetName(name); - - D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; - rtvDesc.Format = m_backBufferFormat; - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; - - const CD3DX12_CPU_DESCRIPTOR_HANDLE rtvDescriptor( - m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), - static_cast(n), m_rtvDescriptorSize); - m_d3dDevice->CreateRenderTargetView(m_renderTargets[n].Get(), &rtvDesc, rtvDescriptor); - } - - // Reset the index to the current back buffer. - m_backBufferIndex = m_swapChain->GetCurrentBackBufferIndex(); - -#endif - - if (m_depthBufferFormat != DXGI_FORMAT_UNKNOWN) - { - // Allocate a 2-D surface as the depth/stencil buffer and create a depth/stencil view - // on this surface. - const CD3DX12_HEAP_PROPERTIES depthHeapProperties(D3D12_HEAP_TYPE_DEFAULT); - - D3D12_RESOURCE_DESC depthStencilDesc = CD3DX12_RESOURCE_DESC::Tex2D( - m_depthBufferFormat, - backBufferWidth, - backBufferHeight, - 1, // Use a single array entry. - 1 // Use a single mipmap level. - ); - depthStencilDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; - - const CD3DX12_CLEAR_VALUE depthOptimizedClearValue(m_depthBufferFormat, (m_options & c_ReverseDepth) ? 0.0f : 1.0f, 0u); - - ThrowIfFailed(m_d3dDevice->CreateCommittedResource( - &depthHeapProperties, - D3D12_HEAP_FLAG_NONE, - &depthStencilDesc, - D3D12_RESOURCE_STATE_DEPTH_WRITE, - &depthOptimizedClearValue, - IID_GRAPHICS_PPV_ARGS(m_depthStencil.ReleaseAndGetAddressOf()) - )); - - m_depthStencil->SetName(L"Depth stencil"); - - D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; - dsvDesc.Format = m_depthBufferFormat; - dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; - - m_d3dDevice->CreateDepthStencilView(m_depthStencil.Get(), &dsvDesc, m_dsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart()); - } - - // Set the 3D rendering viewport and scissor rectangle to target the entire window. - m_screenViewport.TopLeftX = m_screenViewport.TopLeftY = 0.f; - m_screenViewport.Width = static_cast(backBufferWidth); - m_screenViewport.Height = static_cast(backBufferHeight); - m_screenViewport.MinDepth = D3D12_MIN_DEPTH; - m_screenViewport.MaxDepth = D3D12_MAX_DEPTH; - - m_scissorRect.left = m_scissorRect.top = 0; - m_scissorRect.right = static_cast(backBufferWidth); - m_scissorRect.bottom = static_cast(backBufferHeight); -} - -// This method is called when the Win32 window is created (or re-created). -void DeviceResources::SetWindow(HWND window, int width, int height) noexcept -{ - m_window = window; - - m_outputSize.left = m_outputSize.top = 0; - m_outputSize.right = width; - m_outputSize.bottom = height; -} - -// This method is called when the Win32 window changes size. -bool DeviceResources::WindowSizeChanged(int width, int height) -{ - if (!m_window) - return false; - - RECT newRc; - newRc.left = newRc.top = 0; - newRc.right = width; - newRc.bottom = height; - if (newRc.right == m_outputSize.right && newRc.bottom == m_outputSize.bottom) - { - return false; - } - - m_outputSize = newRc; - CreateWindowSizeDependentResources(); - return true; -} - -// Recreate all device resources and set them back to the current state. -void DeviceResources::HandleDeviceLost() -{ -#ifdef _GAMING_DESKTOP - if (m_deviceNotify) - { - m_deviceNotify->OnDeviceLost(); - } - - for (UINT n = 0; n < m_backBufferCount; n++) - { - m_commandAllocators[n].Reset(); - m_renderTargets[n].Reset(); - } - - m_depthStencil.Reset(); - m_commandQueue.Reset(); - m_commandList.Reset(); - m_fence.Reset(); - m_rtvDescriptorHeap.Reset(); - m_dsvDescriptorHeap.Reset(); - m_swapChain.Reset(); - m_d3dDevice.Reset(); - m_dxgiFactory.Reset(); - -#ifdef _DEBUG - { - ComPtr dxgiDebug; - if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug)))) - { - dxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_IGNORE_INTERNAL)); - } - } -#endif - - CreateDeviceResources(); - CreateWindowSizeDependentResources(); - - if (m_deviceNotify) - { - m_deviceNotify->OnDeviceRestored(); - } -#endif -} - -// Prepare the command list and render target for rendering. -void DeviceResources::Prepare(D3D12_RESOURCE_STATES beforeState, D3D12_RESOURCE_STATES afterState) -{ - // Reset command list and allocator. - ThrowIfFailed(m_commandAllocators[m_backBufferIndex]->Reset()); - ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_backBufferIndex].Get(), nullptr)); - - if (beforeState != afterState) - { - // Transition the render target into the correct state to allow for drawing into it. - const D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition( - m_renderTargets[m_backBufferIndex].Get(), - beforeState, afterState); - m_commandList->ResourceBarrier(1, &barrier); - } -} - -// Present the contents of the swap chain to the screen. -void DeviceResources::Present(D3D12_RESOURCE_STATES beforeState) -{ - if (beforeState != D3D12_RESOURCE_STATE_PRESENT) - { - // Transition the render target to the state that allows it to be presented to the display. - const D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition( - m_renderTargets[m_backBufferIndex].Get(), - beforeState, D3D12_RESOURCE_STATE_PRESENT); - m_commandList->ResourceBarrier(1, &barrier); - } - - // Send the command list off to the GPU for processing. - ThrowIfFailed(m_commandList->Close()); - m_commandQueue->ExecuteCommandLists(1, CommandListCast(m_commandList.GetAddressOf())); - -#ifdef _GAMING_XBOX - - // Present the backbuffer using the PresentX API. - D3D12XBOX_PRESENT_PLANE_PARAMETERS planeParameters = {}; - planeParameters.Token = m_framePipelineToken; - planeParameters.ResourceCount = 1; - planeParameters.ppResources = m_renderTargets[m_backBufferIndex].GetAddressOf(); - - ThrowIfFailed( - m_commandQueue->PresentX(1, &planeParameters, nullptr) - ); - - // Xbox apps do not need to handle DXGI_ERROR_DEVICE_REMOVED or DXGI_ERROR_DEVICE_RESET. - - // Update the back buffer index. - const UINT64 currentFenceValue = m_fenceValues[m_backBufferIndex]; - m_backBufferIndex = (m_backBufferIndex + 1) % m_backBufferCount; - m_fenceValues[m_backBufferIndex] = currentFenceValue; - -#else // _GAMING_DESKTOP - - // 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. - HRESULT hr = m_swapChain->Present(1, 0); - - // If the device was reset we must completely reinitialize the renderer. - if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) - { -#ifdef _DEBUG - char buff[64] = {}; - sprintf_s(buff, "Device Lost on Present: Reason code 0x%08X\n", - static_cast((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr)); - OutputDebugStringA(buff); -#endif - HandleDeviceLost(); - } - else - { - ThrowIfFailed(hr); - } - - MoveToNextFrame(); -#endif -} - -// Handle GPU suspend/resume -void DeviceResources::Suspend() -{ -#ifdef _GAMING_XBOX - m_commandQueue->SuspendX(0); -#endif -} - -void DeviceResources::Resume() -{ -#ifdef _GAMING_XBOX - m_commandQueue->ResumeX(); - - RegisterFrameEvents(); -#endif -} - -// Wait for pending GPU work to complete. -void DeviceResources::WaitForGpu() noexcept -{ - if (m_commandQueue && m_fence && m_fenceEvent.IsValid()) - { - // Schedule a Signal command in the GPU queue. - const UINT64 fenceValue = m_fenceValues[m_backBufferIndex]; - if (SUCCEEDED(m_commandQueue->Signal(m_fence.Get(), fenceValue))) - { - // Wait until the Signal has been processed. - if (SUCCEEDED(m_fence->SetEventOnCompletion(fenceValue, m_fenceEvent.Get()))) - { - std::ignore = WaitForSingleObjectEx(m_fenceEvent.Get(), INFINITE, FALSE); - - // Increment the fence value for the current frame. - m_fenceValues[m_backBufferIndex]++; - } - } - } -} - -#ifdef _GAMING_XBOX -// For PresentX rendering, we should wait for the origin event just before processing input. -void DeviceResources::WaitForOrigin() -{ - // Wait until frame start is signaled - m_framePipelineToken = D3D12XBOX_FRAME_PIPELINE_TOKEN_NULL; - ThrowIfFailed(m_d3dDevice->WaitFrameEventX( - D3D12XBOX_FRAME_EVENT_ORIGIN, - INFINITE, - nullptr, - D3D12XBOX_WAIT_FRAME_EVENT_FLAG_NONE, - &m_framePipelineToken)); -} - -// Set frame interval and register for frame events -void DeviceResources::RegisterFrameEvents() -{ - // First, retrieve the underlying DXGI device from the D3D device. - ComPtr dxgiDevice; - ThrowIfFailed(m_d3dDevice.As(&dxgiDevice)); - - // Identify the physical adapter (GPU or card) this device is running on. - ComPtr dxgiAdapter; - ThrowIfFailed(dxgiDevice->GetAdapter(dxgiAdapter.GetAddressOf())); - - // Retrieve the outputs for the adapter. - ComPtr dxgiOutput; - ThrowIfFailed(dxgiAdapter->EnumOutputs(0, dxgiOutput.GetAddressOf())); - - // Set frame interval and register for frame events - ThrowIfFailed(m_d3dDevice->SetFrameIntervalX( - dxgiOutput.Get(), - D3D12XBOX_FRAME_INTERVAL_60_HZ, - m_backBufferCount - 1u /* Allow n-1 frames of latency */, - D3D12XBOX_FRAME_INTERVAL_FLAG_NONE)); - - ThrowIfFailed(m_d3dDevice->ScheduleFrameEventX( - D3D12XBOX_FRAME_EVENT_ORIGIN, - 0U, - nullptr, - D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE)); -} - -#else // _GAMING_DESKTOP - -// Prepare to render the next frame. -void DeviceResources::MoveToNextFrame() -{ - // Schedule a Signal command in the queue. - const UINT64 currentFenceValue = m_fenceValues[m_backBufferIndex]; - ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), currentFenceValue)); - - // Update the back buffer index. - m_backBufferIndex = m_swapChain->GetCurrentBackBufferIndex(); - - // If the next frame is not ready to be rendered yet, wait until it is ready. - if (m_fence->GetCompletedValue() < m_fenceValues[m_backBufferIndex]) - { - ThrowIfFailed(m_fence->SetEventOnCompletion(m_fenceValues[m_backBufferIndex], m_fenceEvent.Get())); - std::ignore = WaitForSingleObjectEx(m_fenceEvent.Get(), INFINITE, FALSE); - } - - // Set the fence value for the next frame. - m_fenceValues[m_backBufferIndex] = currentFenceValue + 1; -} - -// This method acquires the first available hardware adapter that supports Direct3D 12. -// If no such adapter can be found, try WARP. Otherwise throw an exception. -void DeviceResources::GetAdapter(IDXGIAdapter1** ppAdapter) -{ - *ppAdapter = nullptr; - - ComPtr adapter; - for (UINT adapterIndex = 0; - SUCCEEDED(m_dxgiFactory->EnumAdapterByGpuPreference( - adapterIndex, - DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, - IID_PPV_ARGS(adapter.ReleaseAndGetAddressOf()))); - adapterIndex++) - { - DXGI_ADAPTER_DESC1 desc; - ThrowIfFailed(adapter->GetDesc1(&desc)); - - if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) - { - // Don't select the Basic Render Driver adapter. - continue; - } - - // Check to see if the adapter supports Direct3D 12, but don't create the actual device yet. - if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), nullptr))) - { -#ifdef _DEBUG - wchar_t buff[256] = {}; - swprintf_s(buff, L"Direct3D Adapter (%u): VID:%04X, PID:%04X - %ls\n", adapterIndex, desc.VendorId, desc.DeviceId, desc.Description); - OutputDebugStringW(buff); -#endif - break; - } - } - -#if !defined(NDEBUG) - if (!adapter) - { - // Try WARP12 instead - if (FAILED(m_dxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(adapter.ReleaseAndGetAddressOf())))) - { - throw std::runtime_error("WARP12 not available. Enable the 'Graphics Tools' optional feature"); - } - - OutputDebugStringA("Direct3D Adapter - WARP12\n"); - } -#endif - - if (!adapter) - { - throw std::runtime_error("No Direct3D 12 device found"); - } - - *ppAdapter = adapter.Detach(); -} -#endif diff --git a/Samples/System/Gamepad/DeviceResources.h b/Samples/System/Gamepad/DeviceResources.h deleted file mode 100644 index 590f30db..00000000 --- a/Samples/System/Gamepad/DeviceResources.h +++ /dev/null @@ -1,153 +0,0 @@ -// -// DeviceResources.h - A wrapper for the Direct3D 12/12.X device and swapchain -// - -#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; - - protected: - ~IDeviceNotify() = default; - }; - - // Controls all the DirectX device resources. - class DeviceResources - { - public: - static constexpr unsigned int c_ReverseDepth = 0x1; - static constexpr unsigned int c_GeometryShaders = 0x2; - static constexpr unsigned int c_TessellationShaders = 0x4; - static constexpr unsigned int c_AmplificationShaders = 0x8; - static constexpr unsigned int c_EnableDXR = 0x10; - - DeviceResources(DXGI_FORMAT backBufferFormat = DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT depthBufferFormat = DXGI_FORMAT_D32_FLOAT, - UINT backBufferCount = 2, - unsigned int flags = 0) noexcept(false); - ~DeviceResources(); - - DeviceResources(DeviceResources&&) = default; - DeviceResources& operator= (DeviceResources&&) = default; - - DeviceResources(DeviceResources const&) = delete; - DeviceResources& operator= (DeviceResources const&) = delete; - - void CreateDeviceResources(); - void CreateWindowSizeDependentResources(); - void SetWindow(HWND window, int width, int height) noexcept; - bool WindowSizeChanged(int width, int height); - void HandleDeviceLost(); - void RegisterDeviceNotify(IDeviceNotify* deviceNotify) noexcept { m_deviceNotify = deviceNotify; } - void Prepare(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_PRESENT, - D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_RENDER_TARGET); - void Present(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_RENDER_TARGET); - void Suspend(); - void Resume(); - void WaitForGpu() noexcept; -#ifdef _GAMING_XBOX - void WaitForOrigin(); -#endif - - // Direct3D Properties. - void SetClearColor(_In_reads_(4) const float* rgba) noexcept { memcpy(m_clearColor, rgba, sizeof(m_clearColor)); } - - // Device Accessors. - RECT GetOutputSize() const noexcept { return m_outputSize; } - - // Direct3D Accessors. - auto GetD3DDevice() const noexcept { return m_d3dDevice.Get(); } -#ifdef _GAMING_DESKTOP - auto GetSwapChain() const noexcept { return m_swapChain.Get(); } - auto GetDXGIFactory() const noexcept { return m_dxgiFactory.Get(); } -#endif - HWND GetWindow() const noexcept { return m_window; } - D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const noexcept { return m_d3dFeatureLevel; } - ID3D12Resource* GetRenderTarget() const noexcept { return m_renderTargets[m_backBufferIndex].Get(); } - ID3D12Resource* GetDepthStencil() const noexcept { return m_depthStencil.Get(); } - ID3D12CommandQueue* GetCommandQueue() const noexcept { return m_commandQueue.Get(); } - ID3D12CommandAllocator* GetCommandAllocator() const noexcept { return m_commandAllocators[m_backBufferIndex].Get(); } - auto GetCommandList() const noexcept { return m_commandList.Get(); } - DXGI_FORMAT GetBackBufferFormat() const noexcept { return m_backBufferFormat; } - DXGI_FORMAT GetDepthBufferFormat() const noexcept { return m_depthBufferFormat; } - D3D12_VIEWPORT GetScreenViewport() const noexcept { return m_screenViewport; } - D3D12_RECT GetScissorRect() const noexcept { return m_scissorRect; } - UINT GetCurrentFrameIndex() const noexcept { return m_backBufferIndex; } - UINT GetBackBufferCount() const noexcept { return m_backBufferCount; } - unsigned int GetDeviceOptions() const noexcept { return m_options; } - - CD3DX12_CPU_DESCRIPTOR_HANDLE GetRenderTargetView() const noexcept - { - return CD3DX12_CPU_DESCRIPTOR_HANDLE( - m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), - static_cast(m_backBufferIndex), m_rtvDescriptorSize); - } - CD3DX12_CPU_DESCRIPTOR_HANDLE GetDepthStencilView() const noexcept - { - return CD3DX12_CPU_DESCRIPTOR_HANDLE(m_dsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart()); - } - - private: -#ifdef _GAMING_XBOX - void RegisterFrameEvents(); -#else - void MoveToNextFrame(); - void GetAdapter(IDXGIAdapter1** ppAdapter); -#endif - - static constexpr size_t MAX_BACK_BUFFER_COUNT = 3; - - UINT m_backBufferIndex; - - // Direct3D objects. - Microsoft::WRL::ComPtr m_d3dDevice; - Microsoft::WRL::ComPtr m_commandList; - Microsoft::WRL::ComPtr m_commandQueue; - Microsoft::WRL::ComPtr m_commandAllocators[MAX_BACK_BUFFER_COUNT]; - - // Swap chain objects. -#ifdef _GAMING_DESKTOP - Microsoft::WRL::ComPtr m_dxgiFactory; - Microsoft::WRL::ComPtr m_swapChain; -#endif - Microsoft::WRL::ComPtr m_renderTargets[MAX_BACK_BUFFER_COUNT]; - Microsoft::WRL::ComPtr m_depthStencil; - - // Presentation fence objects. - Microsoft::WRL::ComPtr m_fence; - UINT64 m_fenceValues[MAX_BACK_BUFFER_COUNT]; - Microsoft::WRL::Wrappers::Event m_fenceEvent; -#ifdef _GAMING_XBOX - D3D12XBOX_FRAME_PIPELINE_TOKEN m_framePipelineToken; -#endif - - // Direct3D rendering objects. - Microsoft::WRL::ComPtr m_rtvDescriptorHeap; - Microsoft::WRL::ComPtr m_dsvDescriptorHeap; - UINT m_rtvDescriptorSize; - D3D12_VIEWPORT m_screenViewport; - D3D12_RECT m_scissorRect; - - // Direct3D properties. - DXGI_FORMAT m_backBufferFormat; - DXGI_FORMAT m_depthBufferFormat; - UINT m_backBufferCount; - float m_clearColor[4]; - - // Cached device properties. - HWND m_window; - D3D_FEATURE_LEVEL m_d3dFeatureLevel; - RECT m_outputSize; - - // DeviceResources options (see flags above) - unsigned int m_options; - - // The IDeviceNotify can be held directly as it owns the DeviceResources. - IDeviceNotify* m_deviceNotify; - }; -} diff --git a/Samples/System/Gamepad/Gamepad.cpp b/Samples/System/Gamepad/Gamepad.cpp index 5515827c..c181e4c7 100644 --- a/Samples/System/Gamepad/Gamepad.cpp +++ b/Samples/System/Gamepad/Gamepad.cpp @@ -1,6 +1,8 @@ //-------------------------------------------------------------------------------------- // Gamepad.cpp // +// GameInput initialization, device callbacks, and frame orchestration. +// // Advanced Technology Group (ATG) // Copyright (C) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- @@ -8,503 +10,587 @@ #include "pch.h" #include "Gamepad.h" -#include "ATGColors.h" -#include "ControllerFont.h" -#include "FindMedia.h" - -extern void ExitSample() noexcept; - -using namespace DirectX; -using namespace DirectX::SimpleMath; - using Microsoft::WRL::ComPtr; -Sample::Sample() noexcept(false) : - m_frame(0), - m_deviceString{}, - m_leftTrigger(0), - m_rightTrigger(0), - m_leftStickX(0), - m_leftStickY(0), - m_rightStickX(0), - m_rightStickY(0), - m_accelX(0), - m_accelY(0), - m_accelZ(0), - m_angularX(0), - m_angularY(0), - m_angularZ(0), - m_orientationX(0), - m_orientationY(0), - m_orientationZ(0), - m_orientationW(0) +//-------------------------------------------------------------------------------------- +// Initialize GameInput and register callbacks. +//-------------------------------------------------------------------------------------- +void Sample::Initialize(HWND hWnd, ImGuiAtg::DeviceContext* deviceContext) { - // Renders only 2D, so no need for a depth buffer. - m_deviceResources = std::make_unique(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN); - m_deviceResources->SetClearColor(ATG::Colors::Background); -} + m_hWnd = hWnd; -Sample::~Sample() -{ - if (m_deviceResources) + HRESULT hr = GameInputCreate(&m_gameInput); + + if (FAILED(hr)) { - m_deviceResources->WaitForGpu(); + wchar_t buff[256] = {}; +#ifdef _GAMING_XBOX + swprintf_s(buff, + L"GameInput creation failed with error: %08X\n\n", + static_cast(hr)); + OutputDebugStringW(buff); +#else + swprintf_s(buff, + L"GameInput creation failed with error: %08X\n\n" + L"Verify that the GameInput runtime has been installed that is included with\n" + L"the redist in the NuGet package or via 'winget install Microsoft.GameInput'", + static_cast(hr)); + MessageBoxW(hWnd, buff, L"Gamepad", MB_ICONERROR | MB_OK); +#endif + PostQuitMessage(1); + return; } -} -// Initialize the Direct3D resources required to run. -void Sample::Initialize(HWND window, int width, int height) -{ - m_deviceResources->SetWindow(window, width, height); + ImGuiAtg::Log("GameInput created successfully\n"); - m_deviceResources->CreateDeviceResources(); - CreateDeviceDependentResources(); + QueryPerformanceFrequency(reinterpret_cast(&m_perfFrequency)); - m_deviceResources->CreateWindowSizeDependentResources(); - CreateWindowSizeDependentResources(); + if (deviceContext) + { + InitializeModelRenderer(deviceContext); + } - HRESULT hr = GameInputCreate(&m_gameInput); + // Blocking enumeration reports already-connected matching devices before returning. + hr = m_gameInput->RegisterDeviceCallback( + nullptr, + GameInputKindGamepad | GameInputKindSensors, + GameInputDeviceAnyStatus, + GameInputBlockingEnumeration, + this, + OnDeviceChanged, + &m_deviceCallbackToken); -#ifdef _GAMING_XBOX - DX::ThrowIfFailed(hr); -#else - extern LPCWSTR g_szAppName; + if (FAILED(hr)) + { + ImGuiAtg::Log("Failed to register device callback: %08X\n", static_cast(hr)); + } + + // Guide and Share are system buttons, not GameInputGamepadState buttons. + hr = m_gameInput->RegisterSystemButtonCallback( + nullptr, + GameInputSystemButtonGuide | GameInputSystemButtonShare, + this, + OnSystemButtonChanged, + &m_systemButtonCallbackToken); if (FAILED(hr)) { - wchar_t buff[256] = {}; - swprintf_s(buff, - L"GameInput creation failed with error: %08X\n\nVerify that GameInputRedist.msi has been installed as noted in the README.", - static_cast(hr)); - _Analysis_assume_nullterminated_(g_szAppName); - std::ignore = MessageBoxW(window, buff, g_szAppName, MB_ICONERROR | MB_OK); - ExitSample(); + ImGuiAtg::Log("Failed to register system button callback: %08X\n", static_cast(hr)); } -#endif + + InitializeHaptics(); } -#pragma region Frame Update -// Executes basic render loop. -void Sample::Tick() +//-------------------------------------------------------------------------------------- +// Track device connection and status changes. +// +// GameInput device pointers have stable identity. GetDeviceInfo returns data valid for +// the lifetime of the device. +//-------------------------------------------------------------------------------------- +void CALLBACK Sample::OnDeviceChanged( + GameInputCallbackToken /*token*/, + void* context, + IGameInputDevice* device, + uint64_t /*timestamp*/, + GameInputDeviceStatus currentStatus, + GameInputDeviceStatus previousStatus) noexcept { - PIXBeginEvent(PIX_COLOR_DEFAULT, L"Frame %llu", m_frame); + auto* sample = static_cast(context); -#ifdef _GAMING_XBOX - m_deviceResources->WaitForOrigin(); -#endif + const GameInputDeviceInfo* info = nullptr; + HRESULT infoResult = device->GetDeviceInfo(&info); - m_timer.Tick([&]() + bool wasConnected = (previousStatus & GameInputDeviceConnected) != 0; + bool isConnected = (currentStatus & GameInputDeviceConnected) != 0; + bool hapticsReady = (currentStatus & GameInputDeviceHapticInfoReady) && !(previousStatus & GameInputDeviceHapticInfoReady); + + std::lock_guard lock(sample->m_gamepadsMutex); + + if (wasConnected && !isConnected) { - Update(m_timer); - }); + if (SUCCEEDED(infoResult)) + { + ImGuiAtg::Log("Disconnected: %s (VID: %04X, PID: %04X) prev=0x%08X cur=0x%08X\n", + GetDeviceDisplayName(info), info->vendorId, info->productId, static_cast(previousStatus), static_cast(currentStatus)); + } + else + { + ImGuiAtg::Log("Failed to get disconnected device info: %08X\n", static_cast(infoResult)); + } - Render(); + for (auto it = sample->m_gamepads.begin(); it != sample->m_gamepads.end(); ++it) + { + if (it->device.Get() == device) + { + sample->m_gamepads.erase(it); + break; + } + } - PIXEndEvent(); - m_frame++; -} + return; + } -// Updates the world. -void Sample::Update(DX::StepTimer const&) -{ - PIXBeginEvent(PIX_COLOR_DEFAULT, L"Update"); + if (FAILED(infoResult)) + { + ImGuiAtg::Log("Failed to get device info: %08X\n", static_cast(infoResult)); + return; + } - // request Gamepad and Sensor input in readings - if (FAILED(m_gameInput->GetCurrentReading(GameInputKindGamepad | GameInputKindSensors, nullptr, &m_reading))) + if (isConnected && !wasConnected) { - // Failure indicates no gamepad is connected - m_buttonString.clear(); + ImGuiAtg::Log("Connected: %s (VID: %04X, PID: %04X) prev=0x%08X cur=0x%08X\n", + GetDeviceDisplayName(info), info->vendorId, info->productId, static_cast(previousStatus), static_cast(currentStatus)); + + GamepadDevice newDevice = {}; + newDevice.device = device; + newDevice.deviceInfo = info; + + sample->m_gamepads.push_back(std::move(newDevice)); + sample->m_selectedGamepad = static_cast(sample->m_gamepads.size() - 1); } - else + + if (hapticsReady) { - ComPtr device; - m_reading->GetDevice(&device); + // Haptic information may become ready after connection. + ImGuiAtg::Log("Haptics ready: %s (VID: %04X, PID: %04X) prev=0x%08X cur=0x%08X\n", + GetDeviceDisplayName(info), info->vendorId, info->productId, static_cast(previousStatus), static_cast(currentStatus)); + } +} - int currentDevice = -1; +//-------------------------------------------------------------------------------------- +// Track Guide and Share button state. +// +// Guide and Share require RegisterSystemButtonCallback. Guide delivery also depends +// on the configured focus policy. +//-------------------------------------------------------------------------------------- +void CALLBACK Sample::OnSystemButtonChanged( + GameInputCallbackToken /*token*/, + void* context, + IGameInputDevice* device, + uint64_t /*timestamp*/, + GameInputSystemButtons currentButtons, + GameInputSystemButtons /*previousButtons*/) noexcept +{ + auto* sample = static_cast(context); - for (size_t i = 0; i< m_devices.size(); i++) + std::lock_guard lock(sample->m_gamepadsMutex); + + for (auto& gamepad : sample->m_gamepads) + { + if (gamepad.device.Get() == device) { - // GameInput device objects are singletons, and their lifetime is the same as the process. - // The API guarantees that IGameInputDevice instances can be directly compared for equality. - if (m_devices[i].Get() == device.Get()) - { - currentDevice = static_cast(i); - break; - } + gamepad.systemButtons = currentButtons; + break; } + } +} + +//-------------------------------------------------------------------------------------- +// Update readings, vibration, and model orientation. +//-------------------------------------------------------------------------------------- +void Sample::Update() +{ + if (!m_gameInput) + return; + + std::lock_guard lock(m_gamepadsMutex); - if (currentDevice == -1) + for (auto& gamepad : m_gamepads) + { + // Callback mode updates state on the GameInput worker thread. + if (!m_useCallbackMode) { - currentDevice = static_cast(m_devices.size()); - m_devices.emplace_back(device); + PollGamepadReading(gamepad); } - swprintf(m_deviceString, 19, L"Gamepad index: %d", currentDevice); - - GameInputGamepadState state = {}; + UpdateVibration(gamepad); + } - if (m_reading->GetGamepadState(&state)) + // render the 3D model for the visible tab + if (m_selectedGamepad >= 0 && m_selectedGamepad < static_cast(m_gamepads.size())) + { + auto& gamepad = m_gamepads[static_cast(m_selectedGamepad)]; + if (gamepad.hasSensorsState) { - m_buttonString = L"Buttons pressed: "; + RenderModel(gamepad.sensorsState); + } + } +} - int exitComboPressed = 0; +//-------------------------------------------------------------------------------------- +// Draw the sample UI. +//-------------------------------------------------------------------------------------- +void Sample::Draw() +{ + HandleSampleInput(); - if (state.buttons & GameInputGamepadDPadUp) - { - m_buttonString += L"[DPad]Up "; - } + ImGuiAtg::BeginFullscreenLayout(); - if (state.buttons & GameInputGamepadDPadDown) - { - m_buttonString += L"[DPad]Down "; - } + float footerH = ImGuiAtg::GetFooterHeight(); + ImGui::BeginChild("##SplitArea", ImVec2(0, ImGui::GetContentRegionAvail().y - footerH)); - if (state.buttons & GameInputGamepadDPadRight) - { - m_buttonString += L"[DPad]Right "; - } + ImGuiAtg::BeginSplitH("##LogSplit", 200.0f); - if (state.buttons & GameInputGamepadDPadLeft) - { - m_buttonString += L"[DPad]Left "; - } + if (ImGui::IsWindowAppearing()) + { + ImGui::SetWindowFocus(); + } - if (state.buttons & GameInputGamepadA) - { - m_buttonString += L"[A] "; - } + // Focus policy controls foreground/background input and system-button routing. +#ifndef _GAMING_XBOX + if (ImGui::CollapsingHeader("Focus Policy and Reading Mode", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + { + ImGuiAtg::BeginNavigationGroup("FocusPolicy"); - if (state.buttons & GameInputGamepadB) - { - m_buttonString += L"[B] "; - } + bool changed = false; + changed |= DrawFocusPolicyCheckbox("ExclusiveForegroundInput", GameInputExclusiveForegroundInput); + changed |= DrawFocusPolicyCheckbox("ExclusiveForegroundGuideButton", GameInputExclusiveForegroundGuideButton); + changed |= DrawFocusPolicyCheckbox("ExclusiveForegroundShareButton", GameInputExclusiveForegroundShareButton); + changed |= DrawFocusPolicyCheckbox("EnableBackgroundInput", GameInputEnableBackgroundInput); + changed |= DrawFocusPolicyCheckbox("EnableBackgroundGuideButton", GameInputEnableBackgroundGuideButton); + changed |= DrawFocusPolicyCheckbox("EnableBackgroundShareButton", GameInputEnableBackgroundShareButton); - if (state.buttons & GameInputGamepadX) - { - m_buttonString += L"[X] "; - } + if (changed && m_gameInput) + { + m_gameInput->SetFocusPolicy(m_focusPolicy); + ImGuiAtg::Log("Focus policy changed to: 0x%04X\n", static_cast(m_focusPolicy)); + } - if (state.buttons & GameInputGamepadY) - { - m_buttonString += L"[Y] "; - } + ImGuiAtg::EndNavigationGroup(); + } +#endif - if (state.buttons & GameInputGamepadLeftShoulder) - { - m_buttonString += L"[LB] "; - exitComboPressed += 1; - } + // Switch between polling and callback-driven readings. + { + ImGui::AlignTextToFramePadding(); + ImGui::Text("Reading Mode:"); + ImGui::SameLine(); - if (state.buttons & GameInputGamepadRightShoulder) - { - m_buttonString += L"[RB] "; - exitComboPressed += 1; - } + ImGuiAtg::BeginNavigationGroup("ReadingMode"); - if (state.buttons & GameInputGamepadLeftThumbstick) + if (ImGui::RadioButton("Polling", !m_useCallbackMode)) + { + if (m_useCallbackMode) { - m_buttonString += L"[LThumb] "; + UnregisterReadingCallbacks(); + m_useCallbackMode = false; + ImGuiAtg::Log("Switched to polling mode\n"); } + } - if (state.buttons & GameInputGamepadRightThumbstick) - { - m_buttonString += L"[RThumb] "; - } + ImGui::SameLine(); - if (state.buttons & GameInputGamepadMenu) + if (ImGui::RadioButton("Callback", m_useCallbackMode)) + { + if (!m_useCallbackMode) { - m_buttonString += L"[Menu] "; - exitComboPressed += 1; + if (RegisterReadingCallbacks()) + { + m_useCallbackMode = true; + ImGuiAtg::Log("Switched to callback mode\n"); + } } + } - if (state.buttons & GameInputGamepadView) - { - m_buttonString += L"[View] "; - exitComboPressed += 1; - } + ImGuiAtg::EndNavigationGroup(); + } - m_leftTrigger = state.leftTrigger; - m_rightTrigger = state.rightTrigger; - m_leftStickX = state.leftThumbstickX; - m_leftStickY = state.leftThumbstickY; - m_rightStickX = state.rightThumbstickX; - m_rightStickY = state.rightThumbstickY; + { + std::lock_guard lock(m_gamepadsMutex); - if (exitComboPressed == 4) - ExitSample(); + if (m_gamepads.empty()) + { + ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "No gamepad connected."); + ImGui::TextWrapped("Connect a gamepad to see input readings."); } - - // get current sensor state for display. Note that not all gamepads have sensors, - // so this may fail even if a gamepad is connected. - GameInputSensorsState sensorsState = {}; - if (m_reading->GetSensorsState(&sensorsState)) + else { - m_accelX = sensorsState.accelerationInGX; - m_accelY = sensorsState.accelerationInGY; - m_accelZ = sensorsState.accelerationInGZ; - - m_angularX = sensorsState.angularVelocityInRadPerSecX; - m_angularY = sensorsState.angularVelocityInRadPerSecY; - m_angularZ = sensorsState.angularVelocityInRadPerSecZ; - - m_orientationX = sensorsState.orientationX; - m_orientationY = sensorsState.orientationY; - m_orientationZ = sensorsState.orientationZ; - m_orientationW = sensorsState.orientationW; + if (ImGui::BeginTabBar("GamepadTabs")) + { + for (size_t i = 0; i < m_gamepads.size(); i++) + { + auto& gamepad = m_gamepads[i]; + + ImGui::PushID(static_cast(i)); + ImGuiTabItemFlags tabFlags = (m_requestedGamepadTab == static_cast(i)) + ? ImGuiTabItemFlags_SetSelected + : ImGuiTabItemFlags_None; + if (ImGui::BeginTabItem(GetDeviceDisplayName(gamepad.deviceInfo), nullptr, tabFlags)) + { + m_selectedGamepad = static_cast(i); + + float availWidth = ImGui::GetContentRegionAvail().x; + float spacing = ImGui::GetStyle().ItemSpacing.x; + float colWidth = (availWidth - spacing * 2) / 3.0f; + float colHeight = ImGui::GetContentRegionAvail().y - ImGuiAtg::Scaled(30); + + ImGui::BeginChild("LeftCol", ImVec2(colWidth, colHeight), ImGuiChildFlags_None); + DrawDeviceInfoSection(gamepad); + ImGui::Spacing(); + DrawButtonsSection(gamepad); + ImGui::Spacing(); + DrawAnalogSection(gamepad.gamepadState); + ImGui::EndChild(); + + ImGui::SameLine(); + + ImGui::BeginChild("CenterCol", ImVec2(colWidth, colHeight), ImGuiChildFlags_None); + DrawSensorsSection(gamepad); + ImGui::Spacing(); + DrawModelSection(gamepad); + ImGui::EndChild(); + + ImGui::SameLine(); + + ImGui::BeginChild("RightCol", ImVec2(colWidth, colHeight), ImGuiChildFlags_None); + DrawVibrationSection(gamepad); + ImGui::Spacing(); + DrawHapticsSection(gamepad); + ImGui::EndChild(); + + ImGui::EndTabItem(); + } + ImGui::PopID(); + } + + ImGui::EndTabBar(); + m_requestedGamepadTab = -1; + } } } - PIXEndEvent(); -} -#pragma endregion - -#pragma region Frame Render -// Draws the scene. -void Sample::Render() -{ - // Don't try to render anything before the first Update. - if (m_timer.GetFrameCount() == 0) - { - return; - } - - // Prepare the command list to render a new frame. - m_deviceResources->Prepare(); - Clear(); - - auto commandList = m_deviceResources->GetCommandList(); - PIXBeginEvent(commandList, PIX_COLOR_DEFAULT, L"Render"); + ImGuiAtg::SplitNext(); + ImGuiAtg::DrawLogPanel(0); + ImGuiAtg::EndSplit(); - auto const fullscreen = m_deviceResources->GetOutputSize(); + ImGui::EndChild(); - auto const safeRect = Viewport::ComputeTitleSafeArea(UINT(fullscreen.right - fullscreen.left), UINT(fullscreen.bottom - fullscreen.top)); + ImGuiAtg::BeginFooter(); + if (ImGuiAtg::FooterItem("[F3] / [LB]+[RB]+[X] Toggle Gamepad Nav")) + ToggleGamepadNavigation(); - auto heap = m_resourceDescriptors->Heap(); - commandList->SetDescriptorHeaps(1, &heap); + ImGuiAtg::FooterItem("[LB]+[RB]+[DPadUpDown] Prev/Next Item", false); + ImGuiAtg::FooterItem("[LB]+[RB]+[DPadLeftRight] Prev/Next Tab", false); - m_batch->Begin(commandList); + ImGuiAtg::EndFooter(); - m_batch->Draw(m_resourceDescriptors->GetGpuHandle(Descriptors::Background), XMUINT2(1920, 1080), fullscreen); - - wchar_t tempString[256] = {}; - XMFLOAT2 pos(float(safeRect.left), float(safeRect.top)); - - m_font->DrawString(m_batch.get(), m_deviceString, pos, ATG::Colors::OffWhite); - pos.y += m_font->GetLineSpacing() * 1.5f; + ImGuiAtg::EndFullscreenLayout(); +} - if (!m_buttonString.empty()) +//-------------------------------------------------------------------------------------- +// Display properties returned by GetDeviceInfo. +//-------------------------------------------------------------------------------------- +void Sample::DrawDeviceInfoSection(const GamepadDevice& gamepad) +{ + if (ImGui::CollapsingHeader("Device Info", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) { - DX::DrawControllerString(m_batch.get(), m_font.get(), m_ctrlFont.get(), m_buttonString.c_str(), pos); - pos.y += m_font->GetLineSpacing() * 1.5f; - - swprintf(tempString, 255, L"[LT] %1.3f", m_leftTrigger); - DX::DrawControllerString(m_batch.get(), m_font.get(), m_ctrlFont.get(), tempString, pos); - pos.y += m_font->GetLineSpacing() * 1.5f; + if (ImGui::BeginTable("DeviceInfo", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) + { + ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed, ImGuiAtg::Scaled(180)); + ImGui::TableSetupColumn("Value"); - swprintf(tempString, 255, L"[RT] %1.3f", m_rightTrigger); - DX::DrawControllerString(m_batch.get(), m_font.get(), m_ctrlFont.get(), tempString, pos); - pos.y += m_font->GetLineSpacing() * 1.5f; + ImGuiAtg::DrawNameValueTable("Name", "%s", GetDeviceDisplayName(gamepad.deviceInfo)); + ImGuiAtg::DrawNameValueTable("VID / PID", "%04X / %04X", gamepad.deviceInfo->vendorId, gamepad.deviceInfo->productId); - swprintf(tempString, 255, L"[LThumb] X: %1.3f Y: %1.3f", m_leftStickX, m_leftStickY); - DX::DrawControllerString(m_batch.get(), m_font.get(), m_ctrlFont.get(), tempString, pos); - pos.y += m_font->GetLineSpacing() * 1.5f; + const char* familyStr = "Unknown"; + switch (gamepad.deviceInfo->deviceFamily) + { + case GameInputFamilyVirtual: + familyStr = "Virtual"; + break; + case GameInputFamilyXboxOne: + familyStr = "Xbox One"; + break; + case GameInputFamilyXbox360: + familyStr = "Xbox 360"; + break; + case GameInputFamilyHid: + familyStr = "HID"; + break; + case GameInputFamilyI8042: + familyStr = "I8042"; + break; + case GameInputFamilyAggregate: + familyStr = "Aggregate"; + break; + case GameInputFamilyUnknown: + break; + } + ImGuiAtg::DrawNameValueTable("Device Family", "%s", familyStr); - swprintf(tempString, 255, L"[RThumb] X: %1.3f Y: %1.3f", m_rightStickX, m_rightStickY); - DX::DrawControllerString(m_batch.get(), m_font.get(), m_ctrlFont.get(), tempString, pos); - pos.y += m_font->GetLineSpacing() * 5.0f; + std::string supportedInputText = GameInputKindToString(gamepad.deviceInfo->supportedInput); + ImGuiAtg::DrawNameValueTable("Supported Input", "%s", supportedInputText.c_str()); + ImGuiAtg::DrawNameValueTable("Last Reading Timestamp", "%llu \xc2\xb5s", gamepad.readingTimestamp); -#ifdef _GAMING_XBOX - pos.x = 1430; -#else - pos.x = 930; +#ifndef _GAMING_XBOX + ImGuiAtg::DrawNameValueTable("PnP Path", "%s", gamepad.deviceInfo->pnpPath); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::TextUnformatted(gamepad.deviceInfo->pnpPath); + ImGui::EndTooltip(); + } #endif - pos.y = (float)safeRect.top; - m_font->DrawString(m_batch.get(), "Acceleration", pos, Colors::Green); - pos.y += m_font->GetLineSpacing(); - - swprintf(tempString, 255, L" X: %1.2f\n Y: %1.2f\n Z: %1.2f", m_accelX, m_accelY, m_accelZ); - DX::DrawControllerString(m_batch.get(), m_font.get(), m_ctrlFont.get(), tempString, pos); - pos.y += m_font->GetLineSpacing() * 3.0f; - - m_font->DrawString(m_batch.get(), "Angular Velocity", pos, Colors::Green); - pos.y += m_font->GetLineSpacing(); - - swprintf(tempString, 255, L" X: %1.2f\n Y: %1.2f\n Z: %1.2f", m_angularX, m_angularY, m_angularZ); - DX::DrawControllerString(m_batch.get(), m_font.get(), m_ctrlFont.get(), tempString, pos); - pos.y += m_font->GetLineSpacing() * 3.0f; + ImGui::EndTable(); + } + } +} - m_font->DrawString(m_batch.get(), "Orientation", pos, Colors::Green); - pos.y += m_font->GetLineSpacing(); +//-------------------------------------------------------------------------------------- +// Stop output and unregister callbacks. +//-------------------------------------------------------------------------------------- +void Sample::Shutdown() +{ + UnregisterReadingCallbacks(); - swprintf(tempString, 255, L" X: %1.2f\n Y: %1.2f\n Z: %1.2f", m_orientationX, m_orientationY, m_orientationZ); - DX::DrawControllerString(m_batch.get(), m_font.get(), m_ctrlFont.get(), tempString, pos); - } - else + if (m_hapticsManager) { - m_font->DrawString(m_batch.get(), L"No controller connected", pos, ATG::Colors::Orange); + m_hapticsManager->StopAllDevices(); + m_hapticsManager.reset(); } - DX::DrawControllerString(m_batch.get(), - m_smallFont.get(), m_ctrlFont.get(), - L"[RB]+[LB]+[View]+[Menu] Exit", - XMFLOAT2(float(safeRect.left), float(safeRect.bottom) - m_font->GetLineSpacing()), - ATG::Colors::LightGrey); + StopVibration(); - m_batch->End(); + if (m_gameInput && m_deviceCallbackToken) + { + m_gameInput->UnregisterCallback(m_deviceCallbackToken); + m_deviceCallbackToken = 0; + } - PIXEndEvent(commandList); + if (m_gameInput && m_systemButtonCallbackToken) + { + m_gameInput->UnregisterCallback(m_systemButtonCallbackToken); + m_systemButtonCallbackToken = 0; + } - // Show the new frame. - PIXBeginEvent(PIX_COLOR_DEFAULT, L"Present"); - m_deviceResources->Present(); - m_graphicsMemory->Commit(m_deviceResources->GetCommandQueue()); - PIXEndEvent(); + m_gamepads.clear(); + m_gameInput.Reset(); } -// Helper method to clear the back buffers. -void Sample::Clear() +#ifdef _GAMING_XBOX +//-------------------------------------------------------------------------------------- +// Xbox suspend and resume. +//-------------------------------------------------------------------------------------- +void Sample::Suspend(ImGuiAtg::DeviceContext* deviceContext) { - auto commandList = m_deviceResources->GetCommandList(); - PIXBeginEvent(commandList, PIX_COLOR_DEFAULT, L"Clear"); - - // Clear the views. - auto const rtvDescriptor = m_deviceResources->GetRenderTargetView(); - - commandList->OMSetRenderTargets(1, &rtvDescriptor, FALSE, nullptr); - commandList->ClearRenderTargetView(rtvDescriptor, ATG::Colors::Background, 0, nullptr); - - // Set the viewport and scissor rect. - auto const viewport = m_deviceResources->GetScreenViewport(); - auto const scissorRect = m_deviceResources->GetScissorRect(); - commandList->RSSetViewports(1, &viewport); - commandList->RSSetScissorRects(1, &scissorRect); + StopVibration(); - PIXEndEvent(commandList); + if (deviceContext) + { + deviceContext->Suspend(); + } } -#pragma endregion -#pragma region Message Handlers -// Message handlers -void Sample::OnSuspending() +void Sample::Resume(ImGuiAtg::DeviceContext* deviceContext) { - m_deviceResources->Suspend(); + if (deviceContext) + { + deviceContext->Resume(); + } } +#endif -void Sample::OnResuming() +//-------------------------------------------------------------------------------------- +// Sample input helpers. +//-------------------------------------------------------------------------------------- +void Sample::ToggleGamepadNavigation() { - m_deviceResources->Resume(); - m_timer.ResetElapsedTime(); + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags ^= ImGuiConfigFlags_NavEnableGamepad; } -void Sample::OnWindowMoved() +void Sample::HandleSampleInput() { - auto const r = m_deviceResources->GetOutputSize(); - m_deviceResources->WindowSizeChanged(r.right, r.bottom); -} + const bool gamepadChord = ImGui::IsKeyDown(ImGuiKey_GamepadL1) + && ImGui::IsKeyDown(ImGuiKey_GamepadR1); -void Sample::OnWindowSizeChanged(int width, int height) -{ - if (!m_deviceResources->WindowSizeChanged(width, height)) - return; + if ((!ImGui::GetIO().WantTextInput && ImGui::IsKeyPressed(ImGuiKey_F3, false)) || + (gamepadChord && + ImGui::IsKeyPressed(ImGuiKey_GamepadFaceLeft, false))) + { + ToggleGamepadNavigation(); + } - CreateWindowSizeDependentResources(); + int tabOffset = 0; + if (gamepadChord && ImGui::IsKeyPressed(ImGuiKey_GamepadDpadLeft, false)) + { + tabOffset = -1; + } + else if (gamepadChord && ImGui::IsKeyPressed(ImGuiKey_GamepadDpadRight, false)) + { + tabOffset = 1; + } + + if (tabOffset != 0) + { + std::lock_guard lock(m_gamepadsMutex); + if (m_gamepads.size() > 1) + { + const int gamepadCount = static_cast(m_gamepads.size()); + m_requestedGamepadTab = (m_selectedGamepad + tabOffset + gamepadCount) % gamepadCount; + } + } } -// Properties -void Sample::GetDefaultSize(int& width, int& height) const noexcept +const char* Sample::GetDeviceDisplayName(const GameInputDeviceInfo* deviceInfo) { - width = 1280; - height = 720; + return deviceInfo->displayName[0] != '\0' ? deviceInfo->displayName : "Xbox Gamepad"; } -#pragma endregion -#pragma region Direct3D Resources -// These are the resources that depend on the device. -void Sample::CreateDeviceDependentResources() +bool Sample::DrawFocusPolicyCheckbox(const char* label, GameInputFocusPolicy flag) { - auto device = m_deviceResources->GetD3DDevice(); + const float rightEdge = ImGui::GetWindowPos().x + ImGui::GetWindowWidth() - ImGui::GetStyle().WindowPadding.x; + const float width = ImGui::CalcTextSize(label).x + ImGuiAtg::Scaled(30); + if (ImGui::GetItemRectMax().x + ImGui::GetStyle().ItemSpacing.x + width < rightEdge) + ImGui::SameLine(); -#ifdef _GAMING_DESKTOP - D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = { D3D_SHADER_MODEL_6_0 }; - if (FAILED(device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shaderModel, sizeof(shaderModel))) - || (shaderModel.HighestShaderModel < D3D_SHADER_MODEL_6_0)) + bool enabled = (m_focusPolicy & flag) != 0; + if (ImGui::Checkbox(label, &enabled)) { - throw std::runtime_error("Shader Model 6.0 is not supported!"); + if (enabled) + m_focusPolicy = static_cast(m_focusPolicy | flag); + else + m_focusPolicy = static_cast(m_focusPolicy & ~flag); + return true; } -#endif - - m_graphicsMemory = std::make_unique(device); - - m_resourceDescriptors = std::make_unique(device, Descriptors::Count); - - const RenderTargetState rtState(m_deviceResources->GetBackBufferFormat(), - m_deviceResources->GetDepthBufferFormat()); - - ResourceUploadBatch upload(device); - upload.Begin(); + return false; +} +std::string Sample::GameInputKindToString(GameInputKind kind) +{ + std::string result; + auto append = [&](GameInputKind flag, const char* name) { - const SpriteBatchPipelineStateDescription pd( - rtState, - &CommonStates::AlphaBlend); - - m_batch = std::make_unique(device, upload, pd); - } - - wchar_t strFilePath[MAX_PATH] = {}; - DX::FindMediaFile(strFilePath, MAX_PATH, L"SegoeUI_24.spritefont"); - m_font = std::make_unique(device, upload, - strFilePath, - m_resourceDescriptors->GetCpuHandle(Descriptors::PrintFont), - m_resourceDescriptors->GetGpuHandle(Descriptors::PrintFont)); - - DX::FindMediaFile(strFilePath, MAX_PATH, L"SegoeUI_18.spritefont"); - m_smallFont = std::make_unique(device, upload, - strFilePath, - m_resourceDescriptors->GetCpuHandle(Descriptors::TextFont), - m_resourceDescriptors->GetGpuHandle(Descriptors::TextFont)); - - DX::FindMediaFile(strFilePath, MAX_PATH, L"XboxOneControllerLegendSmall.spritefont"); - m_ctrlFont = std::make_unique(device, upload, - strFilePath, - m_resourceDescriptors->GetCpuHandle(Descriptors::ControllerFont), - m_resourceDescriptors->GetGpuHandle(Descriptors::ControllerFont)); - - DX::FindMediaFile(strFilePath, MAX_PATH, L"gamepad.dds"); - DX::ThrowIfFailed(CreateDDSTextureFromFile(device, upload, strFilePath, - m_background.ReleaseAndGetAddressOf())); - - auto finish = upload.End(m_deviceResources->GetCommandQueue()); - finish.wait(); + if (kind & flag) + { + if (!result.empty()) + result += " | "; + result += name; + } + }; - m_deviceResources->WaitForGpu(); + append(GameInputKindGamepad, "Gamepad"); + append(GameInputKindKeyboard, "Keyboard"); + append(GameInputKindMouse, "Mouse"); + append(GameInputKindArcadeStick, "ArcadeStick"); + append(GameInputKindFlightStick, "FlightStick"); + append(GameInputKindRacingWheel, "RacingWheel"); + append(GameInputKindSensors, "Sensors"); - CreateShaderResourceView(device, m_background.Get(), - m_resourceDescriptors->GetCpuHandle(Descriptors::Background)); + return result.empty() ? "Unknown" : result; } -// Allocate all memory resources that change on a window SizeChanged event. -void Sample::CreateWindowSizeDependentResources() +void Sample::Activated() { - auto const vp = m_deviceResources->GetScreenViewport(); - m_batch->SetViewport(vp); } -void Sample::OnDeviceLost() +void Sample::Deactivated() { - m_font.reset(); - m_smallFont.reset(); - m_ctrlFont.reset(); - m_batch.reset(); - m_resourceDescriptors.reset(); - m_graphicsMemory.reset(); } -void Sample::OnDeviceRestored() +LRESULT Sample::WndProcHandler(HWND /*hWnd*/, UINT /*msg*/, WPARAM /*wParam*/, LPARAM /*lParam*/) { - CreateDeviceDependentResources(); - - CreateWindowSizeDependentResources(); + return 0; } -#pragma endregion + diff --git a/Samples/System/Gamepad/Gamepad.h b/Samples/System/Gamepad/Gamepad.h index 8ce44943..e155d55c 100644 --- a/Samples/System/Gamepad/Gamepad.h +++ b/Samples/System/Gamepad/Gamepad.h @@ -1,112 +1,140 @@ //-------------------------------------------------------------------------------------- // Gamepad.h // +// GameInput gamepad sample state and interface. +// // Advanced Technology Group (ATG) // Copyright (C) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- #pragma once -#include "DeviceResources.h" -#include "StepTimer.h" - -#include -#if GAMEINPUT_API_VERSION == 1 -using namespace GameInput::v1; -#elif GAMEINPUT_API_VERSION == 2 -using namespace GameInput::v2; -#elif GAMEINPUT_API_VERSION == 3 -using namespace GameInput::v3; -#endif +#include "GamepadHaptics.h" +#include "GamepadVibration.h" +#include "HapticsManager/HapticsManager.h" -// A basic sample implementation that creates a D3D12 device and -// provides a render loop. -class Sample final : public DX::IDeviceNotify +//-------------------------------------------------------------------------------------- +// State associated with one connected gamepad. GameInput device pointers have stable +// identity and can be compared directly. +//-------------------------------------------------------------------------------------- +struct GamepadDevice { -public: + Microsoft::WRL::ComPtr device; - Sample() noexcept(false); - ~Sample(); + // Valid for the lifetime of device. + const GameInputDeviceInfo* deviceInfo = nullptr; - Sample(Sample&&) = default; - Sample& operator= (Sample&&) = default; + GameInputGamepadState gamepadState = {}; // Buttons, triggers, thumbsticks + GameInputSensorsState sensorsState = {}; // Accelerometer, gyroscope, orientation + uint64_t readingTimestamp = 0; // Microseconds (from IGameInputReading::GetTimestamp) + bool hasGamepadState = false; + bool hasSensorsState = false; - Sample(Sample const&) = delete; - Sample& operator= (Sample const&) = delete; + // Guide/Share state from RegisterSystemButtonCallback. + GameInputSystemButtons systemButtons = {}; - // Initialization and management - void Initialize(HWND window, int width, int height); - - // Basic render loop - void Tick(); + size_t selectedMediaIndex = 0; + VibrationEffectState vibEffect; +}; - // IDeviceNotify - void OnDeviceLost() override; - void OnDeviceRestored() override; +//-------------------------------------------------------------------------------------- +// Sample class +//-------------------------------------------------------------------------------------- +class Sample +{ +public: + Sample() = default; + ~Sample() = default; - // Messages - void OnActivated() {} - void OnDeactivated() {} - void OnSuspending(); - void OnResuming(); - void OnWindowMoved(); - void OnWindowSizeChanged(int width, int height); + Sample(Sample const&) = delete; + Sample& operator= (Sample const&) = delete; - // Properties - void GetDefaultSize(int& width, int& height) const noexcept; + void Initialize(HWND hWnd, ImGuiAtg::DeviceContext* deviceContext); + void Update(); + void Draw(); + void Shutdown(); + void Activated(); + void Deactivated(); + LRESULT WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +#ifdef _GAMING_XBOX + // PLM suspend/resume handling for Xbox console + void Suspend(ImGuiAtg::DeviceContext* deviceContext); + void Resume(ImGuiAtg::DeviceContext* deviceContext); +#endif private: + // Gamepad.cpp + void DrawDeviceInfoSection(const GamepadDevice& gamepad); + bool DrawFocusPolicyCheckbox(const char* label, GameInputFocusPolicy flag); + static std::string GameInputKindToString(GameInputKind kind); + static const char* GetDeviceDisplayName(const GameInputDeviceInfo* deviceInfo); + void ToggleGamepadNavigation(); + void HandleSampleInput(); + + static void CALLBACK OnDeviceChanged( + GameInputCallbackToken token, + void* context, + IGameInputDevice* device, + uint64_t timestamp, + GameInputDeviceStatus currentStatus, + GameInputDeviceStatus previousStatus) noexcept; + + static void CALLBACK OnSystemButtonChanged( + GameInputCallbackToken token, + void* context, + IGameInputDevice* device, + uint64_t timestamp, + GameInputSystemButtons currentButtons, + GameInputSystemButtons previousButtons) noexcept; + + Microsoft::WRL::ComPtr m_gameInput; // Main GameInput interface + GameInputCallbackToken m_deviceCallbackToken = 0; // Token for device callback + GameInputCallbackToken m_systemButtonCallbackToken = 0; // Token for Guide/Share callback + std::mutex m_gamepadsMutex; // Synchronization for m_gamepads + std::vector m_gamepads; // All tracked gamepads + int m_selectedGamepad = 0; // Currently viewed tab + int m_requestedGamepadTab = -1; // Tab selected by a gamepad shortcut + GameInputFocusPolicy m_focusPolicy = GameInputDefaultFocusPolicy; + + // GamepadReadings.cpp + void PollGamepadReading(GamepadDevice& gamepad); + static void CALLBACK OnReadingChanged( + GameInputCallbackToken token, + void* context, + IGameInputReading* reading) noexcept; + bool RegisterReadingCallbacks(); + void UnregisterReadingCallbacks(); + void DrawButtonsSection(const GamepadDevice& gamepad); + void DrawAnalogSection(const GameInputGamepadState& state); + void DrawSensorsSection(const GamepadDevice& gamepad); + + GameInputCallbackToken m_readingCallbackToken = 0; // Token for reading callback + bool m_useCallbackMode = false; // false = polling, true = callback-driven + + // GamepadVibration.cpp + void InitializeVibrationEffect(GamepadDevice& gamepad); + void UpdateVibration(GamepadDevice& gamepad); + void StopVibration(); + void DrawVibrationSection(GamepadDevice& gamepad); + + uint64_t m_perfFrequency = 0; // QueryPerformanceFrequency result + + // GamepadHaptics.cpp + void InitializeHaptics(); + void DrawHapticsSection(GamepadDevice& gamepad); +#ifndef _GAMING_XBOX + std::wstring OpenFileDialog(const wchar_t* filter); +#endif + + std::unique_ptr m_hapticsManager; // Manages haptic audio endpoints + std::vector m_mediaList; // Available WAV effects + HWND m_hWnd = nullptr; + + // GamepadModel.cpp + void InitializeModelRenderer(ImGuiAtg::DeviceContext* deviceContext); + void RenderModel(const GameInputSensorsState& sensors); + void DrawModelSection(const GamepadDevice& gamepad); - void Update(DX::StepTimer const& timer); - void Render(); - - void Clear(); - - void CreateDeviceDependentResources(); - void CreateWindowSizeDependentResources(); - - // Device resources. - std::unique_ptr m_deviceResources; - - // Rendering loop timer. - uint64_t m_frame; - DX::StepTimer m_timer; - - //Gamepad states - Microsoft::WRL::ComPtr m_gameInput; - Microsoft::WRL::ComPtr m_reading; - std::vector> m_devices; - - wchar_t m_deviceString[20]; - std::wstring m_buttonString; - double m_leftTrigger; - double m_rightTrigger; - double m_leftStickX; - double m_leftStickY; - double m_rightStickX; - double m_rightStickY; - float m_accelX, m_accelY, m_accelZ; - float m_angularX, m_angularY, m_angularZ; - float m_orientationX, m_orientationY, m_orientationZ, m_orientationW; - - // DirectXTK objects. - std::unique_ptr m_graphicsMemory; - std::unique_ptr m_resourceDescriptors; - - // UI - std::unique_ptr m_batch; - std::unique_ptr m_font; - std::unique_ptr m_smallFont; - std::unique_ptr m_ctrlFont; - - Microsoft::WRL::ComPtr m_background; - - enum Descriptors : size_t - { - PrintFont, - TextFont, - ControllerFont, - Background, - Count, - }; + ImGuiAtg::ModelViewer m_modelViewer; }; diff --git a/Samples/System/Gamepad/Gamepad.sln b/Samples/System/Gamepad/Gamepad.sln index 1b9ed82e..ba469092 100644 --- a/Samples/System/Gamepad/Gamepad.sln +++ b/Samples/System/Gamepad/Gamepad.sln @@ -1,7 +1,6 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 15.0.28010.2036 +VisualStudioVersion = 17.14.36203.30 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Gamepad", "Gamepad.vcxproj", "{898A2E23-EC32-4E00-9E12-B55D6CA52AB7}" EndProject diff --git a/Samples/System/Gamepad/Gamepad.vcxproj b/Samples/System/Gamepad/Gamepad.vcxproj index 8b37d01e..f79bbb8f 100644 --- a/Samples/System/Gamepad/Gamepad.vcxproj +++ b/Samples/System/Gamepad/Gamepad.vcxproj @@ -55,6 +55,7 @@ {898A2E23-EC32-4E00-9E12-B55D6CA52AB7} en-US Win32Proj + true 17.0 Native @@ -287,7 +288,7 @@ $(GDKCrossPlatformPath)windows\lib\ARM64;$(LibraryPath) false - + false @@ -301,7 +302,7 @@ Use pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) + $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;..\..\..\Kits\OpenSource\imgui;%(AdditionalIncludeDirectories) MaxSpeed @@ -309,8 +310,10 @@ Level4 true true + stdcpp17 true - 5204;5204 + /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) + 5204;%(DisableSpecificWarnings) 6.0 @@ -327,7 +330,7 @@ Use pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) + $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;..\..\..\Kits\OpenSource\imgui;%(AdditionalIncludeDirectories) @@ -337,8 +340,10 @@ Level4 true true + stdcpp17 true - 5204;5204 + /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) + 5204;%(DisableSpecificWarnings) 6.0 @@ -355,7 +360,7 @@ Use pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) + $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;..\..\..\Kits\OpenSource\imgui;%(AdditionalIncludeDirectories) MaxSpeed @@ -363,8 +368,10 @@ Level4 true true + stdcpp17 true - 5204;5204 + /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) + 5204;%(DisableSpecificWarnings) 6.0 @@ -381,7 +388,7 @@ Use pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) + $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;..\..\..\Kits\OpenSource\imgui;%(AdditionalIncludeDirectories) @@ -391,8 +398,10 @@ Level4 true true + stdcpp17 true - 5204;5204 + /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) + 5204;%(DisableSpecificWarnings) 6.0 @@ -408,14 +417,16 @@ pch.h Use false - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) + $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;..\..\..\Kits\OpenSource\imgui;%(AdditionalIncludeDirectories) Level4 Disabled _DEBUG;%(PreprocessorDefinitions) + stdcpp17 true - 5204;5204 + /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) + 5204;%(DisableSpecificWarnings) 6.0 @@ -431,7 +442,7 @@ pch.h Use false - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) + $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;..\..\..\Kits\OpenSource\imgui;%(AdditionalIncludeDirectories) @@ -439,8 +450,10 @@ Level4 Disabled _DEBUG;%(PreprocessorDefinitions) + stdcpp17 true - 5204;5204 + /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) + 5204;%(DisableSpecificWarnings) 6.0 @@ -464,7 +477,7 @@ Use pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) + $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;..\..\..\Kits\OpenSource\imgui;%(AdditionalIncludeDirectories) _GAMING_DESKTOP;_WINDOWS;WIN32;_DEBUG;%(PreprocessorDefinitions) Fast /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) @@ -472,7 +485,7 @@ Level4 stdcpp17 true - 5204;5204 + 5204;%(DisableSpecificWarnings) 6.0 @@ -493,7 +506,7 @@ Use pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) + $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;..\..\..\Kits\OpenSource\imgui;%(AdditionalIncludeDirectories) _GAMING_DESKTOP;_WINDOWS;WIN32;_DEBUG;%(PreprocessorDefinitions) Fast /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) @@ -501,7 +514,7 @@ Level4 stdcpp17 true - 5204;5204 + 5204;%(DisableSpecificWarnings) 6.0 @@ -524,7 +537,7 @@ Use pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) + $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;..\..\..\Kits\OpenSource\imgui;%(AdditionalIncludeDirectories) _GAMING_DESKTOP;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) Fast /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) @@ -534,7 +547,7 @@ Level4 stdcpp17 true - 5204;5204 + 5204;%(DisableSpecificWarnings) 6.0 @@ -557,7 +570,7 @@ Use pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) + $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;..\..\..\Kits\OpenSource\imgui;%(AdditionalIncludeDirectories) _GAMING_DESKTOP;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) Fast /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) @@ -567,7 +580,7 @@ Level4 stdcpp17 true - 5204;5204 + 5204;%(DisableSpecificWarnings) 6.0 @@ -590,7 +603,7 @@ Use pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) + $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;..\..\..\Kits\OpenSource\imgui;%(AdditionalIncludeDirectories) PROFILE;_GAMING_DESKTOP;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) Fast /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) @@ -600,7 +613,7 @@ Level4 stdcpp17 true - 5204;5204 + 5204;%(DisableSpecificWarnings) 6.0 @@ -623,7 +636,7 @@ Use pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) + $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;..\..\..\Kits\OpenSource\imgui;%(AdditionalIncludeDirectories) PROFILE;_GAMING_DESKTOP;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) Fast /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) @@ -633,7 +646,7 @@ Level4 stdcpp17 true - 5204;5204 + 5204;%(DisableSpecificWarnings) 6.0 @@ -642,36 +655,268 @@ - - - + + - - - + + + + + + + + VCR001 + + + 4365 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + 6011;6387;26819;28182;%(DisableSpecificWarnings) + + + NotUsing + 4265;4365;6011;6387;26819;28182;%(DisableSpecificWarnings) + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + 6011;6387;26819;28182;%(DisableSpecificWarnings) + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + 6011;6387;26819;28182;%(DisableSpecificWarnings) + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + 6011;6387;26819;28182;%(DisableSpecificWarnings) + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + 6011;6387;26819;28182;%(DisableSpecificWarnings) + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + NotUsing + - Create - Create - Create + Create Create + Create Create - Create + Create + Create Create - Create Create - Create Create + Create + Create Create @@ -718,44 +963,228 @@ - + + true + Document + media/Haptics/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + + + true + Document + media/Haptics/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + + + true + Document + media/Haptics/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + + + true + Document + media/Haptics/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + + + true + Document + media/Haptics/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + + + true + Document + media/Haptics/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics - + + true + Document + media/Haptics/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics + $(OutDir)/media/Haptics - - true - true - true - true - true - true + + true Document + media/Model/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model - - true - true - true - true - true - true + + true Document + media/Model/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model - - true - true - true - true - true - true + + true + Document + media/Model/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + + + true + Document + media/Model/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + + + true Document + media/Model/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + + true + Document + media/Model/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + + + true + Document + media/Model/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + + + true + Document + media/Model/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + + + true + Document + media/Model/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + + + true + Document + media/Model/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + + + true + Document + media/Model/%(Filename)%(Extension) + $(OutDir) + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + $(OutDir)/media/Model + + + - - - @@ -780,8 +1209,14 @@ - + + + + This project requires the Microsoft GDK with Xbox Extensions to be installed. If you have already installed the GDK, then run Repair to ensure proper integration with Visual Studio. The missing platform is {0}. + + + @@ -790,12 +1225,6 @@ - - - This project requires the Microsoft GDK with Xbox Extensions to be installed. If you have already installed the GDK, then run Repair to ensure proper integration with Visual Studio. The missing platform is {0}. - - - @@ -804,6 +1233,6 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + - + \ No newline at end of file diff --git a/Samples/System/Gamepad/Gamepad.vcxproj.filters b/Samples/System/Gamepad/Gamepad.vcxproj.filters index ad3e79ec..3e156030 100644 --- a/Samples/System/Gamepad/Gamepad.vcxproj.filters +++ b/Samples/System/Gamepad/Gamepad.vcxproj.filters @@ -1,103 +1,318 @@ - + - - AEFBF7B3-C825-439E-86F4-E4AE6393100F + + {d0c8dfa4-19bb-457b-8e2d-15c5b3b861c0} - - A41B0F38-92C1-457C-AB72-94AA7593A1FE - ico;cur;bmp;dds;dlg;fbx;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms + + {cb0fb046-6df5-4057-a3e2-92d0a38f9921} + + + {b89cf65d-98a1-4857-a1fb-1b0ab4f7da11} + + + {83199e07-dff2-4569-83c5-43f08286201e} - 85E16375-51BA-4398-B6C1-7359C2F48746 + {dd386775-11b9-4b4e-98aa-4851f7260408} + + + {e2b45a9b-4b32-4c24-9f94-088331907962} + + + {29aa3a1a-3bc9-4139-be4f-92669d76f012} + + + {5dad6bcb-15ed-4aa4-ae8a-2a82fd8e377c} + + + {456b65ae-1508-42f4-b4e6-94a21b237be1} + + + {32090d51-a68a-4062-82ac-266d5acf98d5} + + + {cefa3d70-7d29-425b-b5f8-4543514645ac} - - - Common - - - Common - - + + + + + + + + ATG Tool Kit - - + + ATG Tool Kit - + + + ImGui\ATG + + + ImGui\ATG + + + ImGui\ATG + + + ImGui\ATG + + + ImGui\ATG + + + ImGui\Backends + + + ImGui\Backends + + + ImGui + + + ImGui + + + ImGui + + + ImGui + + + HapticsManager + + + HapticsManager + + + HapticsManager\Audio + + + HapticsManager\Audio + + + HapticsManager\Audio + + + HapticsManager\Audio + + + + + + + ATG Tool Kit ATG Tool Kit - + ATG Tool Kit - ATG Tool Kit - - ATG Tool Kit + + ImGui\ATG + + + ImGui\ATG + + + ImGui\ATG + + + ImGui\ATG + + + ImGui\ATG + + + ImGui + + + ImGui + + + ImGui + + + ImGui + + + ImGui + + + ImGui + + + ImGui\Backends + + + ImGui\Backends + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + ImGui\Backends\Shaders + + + HapticsManager + + + HapticsManager + + + HapticsManager\Audio + + + HapticsManager\Audio + + + HapticsManager\Audio + + + HapticsManager\Audio + + + HapticsManager\Audio + + + HapticsManager\Audio - - - - Common - - - ATG Tool Kit - - - ATG Tool Kit - - - - - - - - - - - - - - - - - Assets + + Media\Haptics - - Assets + + Media\Haptics - - Assets + + Media\Haptics - - Assets + + Media\Haptics - - Assets + + Media\Haptics + + + Media\Haptics + + + Media\Haptics + + + Media\Model + + + Media\Model + + + Media\Model + + + Media\Model + + + Media\Model + + + Media\Model + + + Media\Model - + + Media\Model + + + Media\Model + + + Media\Model + + + Media\Model + + Assets - + Assets - + Assets - + Assets - + Assets + + + + + + + + \ No newline at end of file diff --git a/Samples/System/Gamepad/GamepadHaptics.cpp b/Samples/System/Gamepad/GamepadHaptics.cpp new file mode 100644 index 00000000..1f91198c --- /dev/null +++ b/Samples/System/Gamepad/GamepadHaptics.cpp @@ -0,0 +1,170 @@ +//-------------------------------------------------------------------------------------- +// GamepadHaptics.cpp +// +// WAV-driven haptic playback through controller audio endpoints. +// +// Advanced Technology Group (ATG) +// Copyright (C) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- + +#include "pch.h" +#include "Gamepad.h" + +#ifndef _GAMING_XBOX +#include +#endif + +//-------------------------------------------------------------------------------------- +// InitializeHaptics -- build the media list and initialize the HapticsManager +// +// HapticsManager registers its own callback for GameInputDeviceHapticInfoReady. +//-------------------------------------------------------------------------------------- +void Sample::InitializeHaptics() +{ + wchar_t exePath[MAX_PATH] = {}; + if (GetModuleFileNameW(nullptr, exePath, MAX_PATH) > 0) + { + std::wstring basePath(exePath); + basePath = basePath.substr(0, basePath.find_last_of(L'\\')); + + auto addMedia = [&](const wchar_t* relPath, const char* title) + { + MediaItem mediaItem; + mediaItem.filename = basePath + L"\\" + relPath; + mediaItem.title = title; + m_mediaList.push_back(std::move(mediaItem)); + }; + + addMedia(L"media\\Haptics\\AhoogaHorn.wav", "Ahooga Horn"); + addMedia(L"media\\Haptics\\car.wav", "Car"); + addMedia(L"media\\Haptics\\fireworks.wav", "Fireworks"); + addMedia(L"media\\Haptics\\gun_shot.wav", "Gun Shot"); + addMedia(L"media\\Haptics\\PenScratch.wav", "Pen Scratch"); + addMedia(L"media\\Haptics\\ShakeEffect.wav", "Shake"); + addMedia(L"media\\Haptics\\TommyGun.wav", "Tommy Gun"); + } + + m_hapticsManager = std::make_unique(); + HRESULT hr = m_hapticsManager->Initialize(m_gameInput.Get()); + if (FAILED(hr)) + { + ImGuiAtg::Log("Failed to initialize HapticsManager: %08X\n", static_cast(hr)); + m_hapticsManager.reset(); + } + else + { + ImGuiAtg::Log("HapticsManager initialized\n"); + } +} + +//-------------------------------------------------------------------------------------- +// DrawHapticsSection -- UI for selecting and playing haptic audio effects +// +// Plays the selected WAV through the device's WASAPI or XAudio2 haptic endpoint. +//-------------------------------------------------------------------------------------- +void Sample::DrawHapticsSection(GamepadDevice& gamepad) +{ + if (ImGui::CollapsingHeader("Haptics", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + { + if (!m_hapticsManager) + { + ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "HapticsManager not initialized."); + return; + } + + const ATG::HapticsDevice* hapticsDevice = m_hapticsManager->GetHapticsDevice(gamepad.device.Get()); + + if (!hapticsDevice) + { + ImGui::TextColored(ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled), "No haptic endpoint found for this device."); + return; + } + + ImGuiAtg::BeginNavigationGroup("Haptics"); + ImGui::TextWrapped("Select a haptic effect to play:"); + ImGui::Spacing(); + + const char* currentTitle = (gamepad.selectedMediaIndex < m_mediaList.size()) + ? m_mediaList[gamepad.selectedMediaIndex].title.c_str() + : "Select..."; + + if (ImGui::BeginCombo("##Haptics", currentTitle)) + { + for (size_t i = 0; i < m_mediaList.size(); i++) + { + bool isSelected = (gamepad.selectedMediaIndex == i); + if (ImGui::Selectable(m_mediaList[i].title.c_str(), isSelected)) + { + gamepad.selectedMediaIndex = i; + } + if (isSelected) + { + ImGui::SetItemDefaultFocus(); + } + } + + ImGui::EndCombo(); + } + +#ifndef _GAMING_XBOX + // The Win32 file dialog is unavailable on Xbox. + ImGui::SameLine(); + if (ImGui::Button("Load WAV...")) + { + std::wstring selectedFile = OpenFileDialog(L"WAV Files (*.wav)\0*.wav\0"); + if (!selectedFile.empty()) + { + MediaItem mediaItem; + mediaItem.filename = selectedFile; + mediaItem.title = DX::WideToUtf8(selectedFile); + m_mediaList.push_back(std::move(mediaItem)); + gamepad.selectedMediaIndex = m_mediaList.size() - 1; + } + } +#endif + + bool hasMedia = gamepad.selectedMediaIndex < m_mediaList.size(); + bool isPlaying = hapticsDevice->IsPlaying(); + + ImGui::BeginDisabled(!hasMedia || isPlaying); + if (ImGui::Button("Play WASAPI")) + { + hapticsDevice->PlayWAVFile(m_mediaList[gamepad.selectedMediaIndex].filename.c_str(), ATG::HapticPlaybackEngine::WASAPI); + ImGuiAtg::Log("Playing via WASAPI: %s\n", m_mediaList[gamepad.selectedMediaIndex].title.c_str()); + } + ImGui::SameLine(); + if (ImGui::Button("Play XAudio2")) + { + hapticsDevice->PlayWAVFile(m_mediaList[gamepad.selectedMediaIndex].filename.c_str(), ATG::HapticPlaybackEngine::XAudio2); + ImGuiAtg::Log("Playing via XAudio2: %s\n", m_mediaList[gamepad.selectedMediaIndex].title.c_str()); + } + ImGui::EndDisabled(); + ImGui::SameLine(); + if (ImGui::Button("Stop##haptics")) + { + hapticsDevice->Stop(); + ImGuiAtg::Log("Haptics stopped\n"); + } + + ImGuiAtg::EndNavigationGroup(); + } +} + +#ifndef _GAMING_XBOX +std::wstring Sample::OpenFileDialog(const wchar_t* filter) +{ + wchar_t filePath[MAX_PATH] = {}; + OPENFILENAMEW openFile = {}; + openFile.lStructSize = sizeof(openFile); + openFile.hwndOwner = m_hWnd; + openFile.lpstrFile = filePath; + openFile.nMaxFile = MAX_PATH; + openFile.lpstrFilter = filter; + openFile.nFilterIndex = 1; + openFile.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + if (GetOpenFileNameW(&openFile)) + return filePath; + return {}; +} +#endif diff --git a/Samples/System/GamepadVibration/pch.cpp b/Samples/System/Gamepad/GamepadHaptics.h similarity index 50% rename from Samples/System/GamepadVibration/pch.cpp rename to Samples/System/Gamepad/GamepadHaptics.h index fb58e703..f4af317c 100644 --- a/Samples/System/GamepadVibration/pch.cpp +++ b/Samples/System/Gamepad/GamepadHaptics.h @@ -1,10 +1,19 @@ //-------------------------------------------------------------------------------------- -// pch.cpp +// GamepadHaptics.h // -// Include the standard header and generate the precompiled header. +// Haptic media item used by the sample. // // Advanced Technology Group (ATG) // Copyright (C) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- -#include "pch.h" +#pragma once + +#include + +// A WAV file available to the haptic playback UI. +struct MediaItem +{ + std::wstring filename; // Full path to WAV file + std::string title; // Display name in the UI +}; diff --git a/Samples/System/Gamepad/GamepadModel.cpp b/Samples/System/Gamepad/GamepadModel.cpp new file mode 100644 index 00000000..f38d1e1e --- /dev/null +++ b/Samples/System/Gamepad/GamepadModel.cpp @@ -0,0 +1,110 @@ +//-------------------------------------------------------------------------------------- +// GamepadModel.cpp +// +// Displays sensor orientation on a 3D controller model. +// +// Advanced Technology Group (ATG) +// Copyright (C) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- + +#include "pch.h" +#include "Gamepad.h" + +using namespace DirectX; + +//-------------------------------------------------------------------------------------- +// Initialize the offscreen model renderer. +//-------------------------------------------------------------------------------------- +void Sample::InitializeModelRenderer(ImGuiAtg::DeviceContext* deviceContext) +{ + m_modelViewer.SetClearColor(0.0f, 0.0f, 0.0f, 0.0f); + m_modelViewer.Initialize(deviceContext, 1280, 1024); + + wchar_t exePath[MAX_PATH] = {}; + GetModuleFileNameW(nullptr, exePath, MAX_PATH); + std::wstring modelDir(exePath); + modelDir = modelDir.substr(0, modelDir.find_last_of(L'\\')) + L"\\media\\Model\\"; + + std::wstring meshPath = modelDir + L"XboxControllerGen3.sdkmesh"; + m_modelViewer.LoadModel(meshPath.c_str(), modelDir.c_str()); +} + +//-------------------------------------------------------------------------------------- +// Convert the sensor quaternion to the model's coordinate system and render it. +//-------------------------------------------------------------------------------------- +void Sample::RenderModel(const GameInputSensorsState& sensors) +{ + if (!m_modelViewer.IsInitialized()) + return; + + XMVECTOR sensorQuat = XMVectorSet( + sensors.orientationX, + sensors.orientationY, + sensors.orientationZ, + sensors.orientationW); + + if (XMVector4Equal(sensorQuat, XMVectorZero())) + sensorQuat = XMQuaternionIdentity(); + + XMMATRIX sensorRot = XMMatrixRotationQuaternion(sensorQuat); + + // Change basis from sensor RH Y-up coordinates to render LH Y-up coordinates. + // Applying M * R * M^T works at every orientation, unlike remapping quaternion + // components directly. + XMMATRIX changeBasis = { + -1, 0, 0, 0, + 0, 0, -1, 0, + 0, -1, 0, 0, + 0, 0, 0, 1 + }; + XMMATRIX changeBasisT = XMMatrixTranspose(changeBasis); + XMMATRIX convertedRot = changeBasis * sensorRot * changeBasisT; + + // Align the model's rest pose with the sensor identity orientation. + XMMATRIX baseRot = XMMatrixRotationX(XM_PI); + + constexpr float modelScale = 0.10f; + XMMATRIX world = XMMatrixScaling(modelScale, modelScale, modelScale) + * baseRot + * convertedRot; + + m_modelViewer.Render(world); +} + +//-------------------------------------------------------------------------------------- +// Display the rendered model. +//-------------------------------------------------------------------------------------- +void Sample::DrawModelSection(const GamepadDevice& gamepad) +{ + if (ImGui::CollapsingHeader("3D Orientation", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + { + if (!(gamepad.deviceInfo->supportedInput & GameInputKindSensors) + || !(gamepad.deviceInfo->sensorsInfo->supportedSensors & GameInputSensorsOrientation)) + { + ImGui::TextColored(ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled), "Orientation sensor not supported by this device."); + return; + } + + if (!m_modelViewer.IsInitialized()) + { + ImGui::TextColored(ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled), "3D renderer not initialized."); + return; + } + + float aspect = static_cast(m_modelViewer.GetRenderer().GetWidth()) + / static_cast(m_modelViewer.GetRenderer().GetHeight()); + ImVec2 avail = ImGui::GetContentRegionAvail(); + float imageWidth = avail.x; + float imageHeight = imageWidth / aspect; + if (imageHeight > avail.y) + { + imageHeight = avail.y; + imageWidth = imageHeight * aspect; + } + float offsetX = (avail.x - imageWidth) * 0.5f; + float offsetY = (avail.y - imageHeight) * 0.5f; + if (offsetX > 0) ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offsetX); + if (offsetY > 0) ImGui::SetCursorPosY(ImGui::GetCursorPosY() + offsetY); + m_modelViewer.DrawImage(imageWidth, imageHeight); + } +} \ No newline at end of file diff --git a/Samples/System/Gamepad/GamepadReadings.cpp b/Samples/System/Gamepad/GamepadReadings.cpp new file mode 100644 index 00000000..e41a30f8 --- /dev/null +++ b/Samples/System/Gamepad/GamepadReadings.cpp @@ -0,0 +1,361 @@ +//-------------------------------------------------------------------------------------- +// GamepadReadings.cpp +// +// Polling and callback-based GameInput reading. +// +// Advanced Technology Group (ATG) +// Copyright (C) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- + +#include "pch.h" +#include "Gamepad.h" + +using Microsoft::WRL::ComPtr; + +namespace +{ + void DrawCenteredText(ImDrawList* drawList, float x, float y, float elementWidth, const char* text, ImU32 color); + void DrawButtonGlyph(const char* fallbackLabel, GameInputLabel label, bool pressed, float glyphSize); + void DrawVerticalTrigger(const char* label, float value, float barWidth, float barHeight); + void DrawThumbstick(const char* label, float x, float y, float stickSize); +} + +//-------------------------------------------------------------------------------------- +// PollGamepadReading - default polling mode when callback mode is not enabled +// +// Passing a device filters GetCurrentReading to that gamepad; nullptr would return the +// latest matching reading from any device. +//-------------------------------------------------------------------------------------- +void Sample::PollGamepadReading(GamepadDevice& gamepad) +{ + ComPtr reading; + + HRESULT hr = m_gameInput->GetCurrentReading( + GameInputKindGamepad | GameInputKindSensors, + gamepad.device.Get(), + &reading); + + if (SUCCEEDED(hr) && reading) + { + gamepad.hasGamepadState = reading->GetGamepadState(&gamepad.gamepadState); + gamepad.hasSensorsState = reading->GetSensorsState(&gamepad.sensorsState); + gamepad.readingTimestamp = reading->GetTimestamp(); + } + else + { + gamepad.hasGamepadState = false; + gamepad.hasSensorsState = false; + } +} + +//-------------------------------------------------------------------------------------- +// Reading Callback Mode - only used when callback mode is enabled +// +// Reading callbacks run on a GameInput worker thread when new input arrives. +//-------------------------------------------------------------------------------------- +void CALLBACK Sample::OnReadingChanged( + GameInputCallbackToken /*token*/, + void* context, + IGameInputReading* reading) noexcept +{ + auto* sample = static_cast(context); + + ComPtr device; + reading->GetDevice(&device); + + std::lock_guard lock(sample->m_gamepadsMutex); + + for (auto& gamepad : sample->m_gamepads) + { + if (gamepad.device.Get() == device.Get()) + { + gamepad.hasGamepadState = reading->GetGamepadState(&gamepad.gamepadState); + gamepad.hasSensorsState = reading->GetSensorsState(&gamepad.sensorsState); + gamepad.readingTimestamp = reading->GetTimestamp(); + break; + } + } +} + +//-------------------------------------------------------------------------------------- +// RegisterReadingCallbacks - switch to callback-driven input +// +// A nullptr device registers one callback for all matching devices. The returned token +// unregisters that single callback. +//-------------------------------------------------------------------------------------- +bool Sample::RegisterReadingCallbacks() +{ + if (!m_gameInput) + return false; + + if (m_readingCallbackToken == 0) + { + HRESULT hr = m_gameInput->RegisterReadingCallback( + nullptr, + GameInputKindGamepad | GameInputKindSensors, + this, + OnReadingChanged, + &m_readingCallbackToken); + + if (FAILED(hr)) + { + ImGuiAtg::Log("Failed to register reading callback: %08X\n", static_cast(hr)); + return false; + } + } + + return true; +} + +//-------------------------------------------------------------------------------------- +// UnregisterReadingCallbacks - switch back to polling mode +// +// UnregisterCallback waits for in-flight callbacks before returning. +//-------------------------------------------------------------------------------------- +void Sample::UnregisterReadingCallbacks() +{ + if (!m_gameInput) + return; + + if (m_readingCallbackToken != 0) + { + m_gameInput->UnregisterCallback(m_readingCallbackToken); + m_readingCallbackToken = 0; + } +} + +//-------------------------------------------------------------------------------------- +// Standard gamepad buttons, paddles, and separately reported system buttons. +//-------------------------------------------------------------------------------------- +void Sample::DrawButtonsSection(const GamepadDevice& gamepad) +{ + const auto& state = gamepad.gamepadState; + const auto* gamepadInfo = gamepad.deviceInfo->gamepadInfo; + + if (gamepadInfo && ImGui::CollapsingHeader("Buttons", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + { + float glyphSize = ImGui::GetFontSize() * 1.5f; + float spacing = ImGuiAtg::Scaled(8); + + DrawButtonGlyph("A", gamepadInfo->aButtonLabel, state.buttons & GameInputGamepadA, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("B", gamepadInfo->bButtonLabel, state.buttons & GameInputGamepadB, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("X", gamepadInfo->xButtonLabel, state.buttons & GameInputGamepadX, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("Y", gamepadInfo->yButtonLabel, state.buttons & GameInputGamepadY, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("DPad Up", gamepadInfo->dpadUpLabel, state.buttons & GameInputGamepadDPadUp, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("DPad Down", gamepadInfo->dpadDownLabel, state.buttons & GameInputGamepadDPadDown, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("DPad Left", gamepadInfo->dpadLeftLabel, state.buttons & GameInputGamepadDPadLeft, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("DPad Right",gamepadInfo->dpadRightLabel, state.buttons & GameInputGamepadDPadRight, glyphSize); + + DrawButtonGlyph("LB", gamepadInfo->leftShoulderButtonLabel, state.buttons & GameInputGamepadLeftShoulder, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("RB", gamepadInfo->rightShoulderButtonLabel, state.buttons & GameInputGamepadRightShoulder, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("LStick", gamepadInfo->leftThumbstickButtonLabel, state.buttons & GameInputGamepadLeftThumbstick, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("RStick", gamepadInfo->rightThumbstickButtonLabel, state.buttons & GameInputGamepadRightThumbstick, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("View", gamepadInfo->viewButtonLabel, state.buttons & GameInputGamepadView, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("Menu", gamepadInfo->menuButtonLabel, state.buttons & GameInputGamepadMenu, glyphSize); ImGui::SameLine(0.0f, spacing); + + if (gamepad.deviceInfo->supportedSystemButtons & GameInputSystemButtonGuide) + { + DrawButtonGlyph("Guide", GameInputLabelGuide, (gamepad.systemButtons & GameInputSystemButtonGuide) != 0, glyphSize); ImGui::SameLine(0.0f, spacing); + } + if (gamepad.deviceInfo->supportedSystemButtons & GameInputSystemButtonShare) + { + DrawButtonGlyph("Share", GameInputLabelShare, (gamepad.systemButtons & GameInputSystemButtonShare) != 0, glyphSize); ImGui::SameLine(0.0f, spacing); + } + + DrawButtonGlyph("PL1", GameInputLabelPaddleLeft1, state.buttons & GameInputGamepadPaddleLeft1, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("PL2", GameInputLabelPaddleLeft2, state.buttons & GameInputGamepadPaddleLeft2, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("PR1", GameInputLabelPaddleRight1, state.buttons & GameInputGamepadPaddleRight1, glyphSize); ImGui::SameLine(0.0f, spacing); + DrawButtonGlyph("PR2", GameInputLabelPaddleRight2, state.buttons & GameInputGamepadPaddleRight2, glyphSize); + } +} + +//-------------------------------------------------------------------------------------- +// Triggers use [0, 1]; thumbstick axes use [-1, 1]. +//-------------------------------------------------------------------------------------- +void Sample::DrawAnalogSection(const GameInputGamepadState& state) +{ + if (ImGui::CollapsingHeader("Analog Inputs", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + { + float stickSize = ImGuiAtg::Scaled(80); + float barWidth = ImGuiAtg::Scaled(24); + float gap = ImGuiAtg::Scaled(42); + + ImGui::Indent(ImGuiAtg::Scaled(12)); + DrawVerticalTrigger("LT", state.leftTrigger, barWidth, stickSize); + ImGui::SameLine(0.0f, gap); + DrawThumbstick("Left Stick", state.leftThumbstickX, state.leftThumbstickY, stickSize); + ImGui::SameLine(0.0f, gap); + DrawThumbstick("Right Stick", state.rightThumbstickX, state.rightThumbstickY, stickSize); + ImGui::SameLine(0.0f, gap); + DrawVerticalTrigger("RT", state.rightTrigger, barWidth, stickSize); + ImGui::Unindent(ImGuiAtg::Scaled(12)); + } +} + +//-------------------------------------------------------------------------------------- +// sensorsInfo is present when supportedInput includes GameInputKindSensors. +//-------------------------------------------------------------------------------------- +void Sample::DrawSensorsSection(const GamepadDevice& gamepad) +{ + if (ImGui::CollapsingHeader("Sensors", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + { + if (!(gamepad.deviceInfo->supportedInput & GameInputKindSensors)) + { + ImGui::TextColored(ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled), "Sensors not supported by this device."); + return; + } + + if (ImGui::BeginTable("Sensors", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) + { + ImGui::TableSetupColumn("Sensor Kind", ImGuiTableColumnFlags_WidthFixed, ImGuiAtg::Scaled(180)); + const float valueColumnWidth = ImGui::CalcTextSize("-23.567").x + ImGuiAtg::Scaled(4); + ImGui::TableSetupColumn("X", ImGuiTableColumnFlags_WidthFixed, valueColumnWidth); + ImGui::TableSetupColumn("Y", ImGuiTableColumnFlags_WidthFixed, valueColumnWidth); + ImGui::TableSetupColumn("Z", ImGuiTableColumnFlags_WidthFixed, valueColumnWidth); + ImGui::TableSetupColumn("W", ImGuiTableColumnFlags_WidthFixed, valueColumnWidth); + ImGui::TableHeadersRow(); + + const auto& state = gamepad.sensorsState; + const auto supportedSensors = gamepad.deviceInfo->sensorsInfo->supportedSensors; + + if (supportedSensors & GameInputSensorsAccelerometer) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("Acceleration (G)"); + ImGui::TableNextColumn(); + ImGui::Text("% 7.3f", state.accelerationInGX); + ImGui::TableNextColumn(); + ImGui::Text("% 7.3f", state.accelerationInGY); + ImGui::TableNextColumn(); + ImGui::Text("% 7.3f", state.accelerationInGZ); + } + + if (supportedSensors & GameInputSensorsGyrometer) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("Gyroscope (rad/s)"); + ImGui::TableNextColumn(); + ImGui::Text("% 7.3f", state.angularVelocityInRadPerSecX); + ImGui::TableNextColumn(); + ImGui::Text("% 7.3f", state.angularVelocityInRadPerSecY); + ImGui::TableNextColumn(); + ImGui::Text("% 7.3f", state.angularVelocityInRadPerSecZ); + } + + if (supportedSensors & GameInputSensorsCompass) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("Heading (degrees)"); + ImGui::TableNextColumn(); + ImGui::Text("% 7.3f", state.headingInDegreesFromMagneticNorth); + } + + if (supportedSensors & GameInputSensorsOrientation) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("Orientation"); + ImGui::TableNextColumn(); + ImGui::Text("% 7.3f", state.orientationX); + ImGui::TableNextColumn(); + ImGui::Text("% 7.3f", state.orientationY); + ImGui::TableNextColumn(); + ImGui::Text("% 7.3f", state.orientationZ); + ImGui::TableNextColumn(); + ImGui::Text("% 7.3f", state.orientationW); + } + + ImGui::EndTable(); + } + } +} + +namespace +{ + void DrawCenteredText(ImDrawList* drawList, float x, float y, float elementWidth, const char* text, ImU32 color) + { + ImVec2 textSize = ImGui::CalcTextSize(text); + drawList->AddText(ImVec2(x + (elementWidth - textSize.x) * 0.5f, y), color, text); + } + + void DrawButtonGlyph(const char* fallbackLabel, GameInputLabel label, bool pressed, float glyphSize) + { + if (pressed) + ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered)); + ImGuiAtg::Glyph(label, glyphSize, fallbackLabel); + if (pressed) + ImGui::PopStyleColor(); + } + + void DrawVerticalTrigger(const char* label, float value, float barWidth, float barHeight) + { + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImDrawList* drawList = ImGui::GetWindowDrawList(); + ImU32 textColor = ImGui::GetColorU32(ImGuiCol_Text); + ImU32 backgroundColor = ImGui::GetColorU32(ImGuiCol_FrameBg); + ImU32 borderColor = ImGui::GetColorU32(ImGuiCol_Border); + ImU32 fillColor = ImGui::GetColorU32(ImGuiCol_SliderGrab); + float lineHeight = ImGui::GetTextLineHeight(); + float padding = ImGuiAtg::Scaled(1); + float gap = ImGuiAtg::Scaled(2); + + drawList->AddRectFilled(pos, ImVec2(pos.x + barWidth, pos.y + barHeight), backgroundColor); + drawList->AddRect(pos, ImVec2(pos.x + barWidth, pos.y + barHeight), borderColor); + + float fillHeight = barHeight * value; + drawList->AddRectFilled( + ImVec2(pos.x + padding, pos.y + barHeight - fillHeight), + ImVec2(pos.x + barWidth - padding, pos.y + barHeight), + fillColor); + + float textY = pos.y + barHeight + gap; + DrawCenteredText(drawList, pos.x, textY, barWidth, label, textColor); + textY += lineHeight; + char valueText[16]; + snprintf(valueText, sizeof(valueText), "%.2f", value); + DrawCenteredText(drawList, pos.x, textY, barWidth, valueText, textColor); + + ImGui::Dummy(ImVec2(barWidth, barHeight + lineHeight * 2 + gap * 2)); + } + + void DrawThumbstick(const char* label, float x, float y, float stickSize) + { + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImVec2 center(pos.x + stickSize * 0.5f, pos.y + stickSize * 0.5f); + ImDrawList* drawList = ImGui::GetWindowDrawList(); + ImU32 textColor = ImGui::GetColorU32(ImGuiCol_Text); + ImU32 backgroundColor = ImGui::GetColorU32(ImGuiCol_FrameBg); + ImU32 borderColor = ImGui::GetColorU32(ImGuiCol_Border); + ImU32 guideColor = ImGui::GetColorU32(ImGuiCol_TextDisabled); + ImU32 dotColor = ImGui::GetColorU32(ImGuiCol_SliderGrab); + float lineHeight = ImGui::GetTextLineHeight(); + float gap = ImGuiAtg::Scaled(2); + + drawList->AddCircleFilled(center, stickSize * 0.5f, backgroundColor); + drawList->AddCircle(center, stickSize * 0.5f, borderColor); + + drawList->AddLine(ImVec2(center.x - stickSize * 0.4f, center.y), + ImVec2(center.x + stickSize * 0.4f, center.y), guideColor); + drawList->AddLine(ImVec2(center.x, center.y - stickSize * 0.4f), + ImVec2(center.x, center.y + stickSize * 0.4f), guideColor); + + ImVec2 dot(center.x + x * stickSize * 0.4f, center.y - y * stickSize * 0.4f); + drawList->AddCircleFilled(dot, ImGuiAtg::Scaled(4), dotColor); + + float textY = pos.y + stickSize + gap; + DrawCenteredText(drawList, pos.x, textY, stickSize, label, textColor); + textY += lineHeight; + char xText[24]; + char yText[24]; + snprintf(xText, sizeof(xText), "X: %5.2f", x); + snprintf(yText, sizeof(yText), "Y: %5.2f", y); + DrawCenteredText(drawList, pos.x, textY, stickSize, xText, textColor); + textY += lineHeight; + DrawCenteredText(drawList, pos.x, textY, stickSize, yText, textColor); + + ImGui::Dummy(ImVec2(stickSize, stickSize + lineHeight * 3 + gap * 2)); + } +} diff --git a/Samples/System/Gamepad/GamepadVibration.cpp b/Samples/System/Gamepad/GamepadVibration.cpp new file mode 100644 index 00000000..b64570ad --- /dev/null +++ b/Samples/System/Gamepad/GamepadVibration.cpp @@ -0,0 +1,331 @@ +//-------------------------------------------------------------------------------------- +// GamepadVibration.cpp +// +// Vibration UI and preset effect implementation. +// +// Advanced Technology Group (ATG) +// Copyright (C) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- + +#include "pch.h" +#include "Gamepad.h" + +//-------------------------------------------------------------------------------------- +// Effect patterns use parallel duration (milliseconds) and motor-level arrays. +//-------------------------------------------------------------------------------------- +namespace +{ + constexpr const char* g_vibrationEffectNames[] = { + "Manual", + "Impulse Test", + "Flat Tire", + "Gun with Recoil", + "Heartbeat", + "Footsteps" + }; + + // Rhythmic bump on the left trigger. + constexpr uint32_t g_flatTireLTDurations[] = { 33, 80, 16 }; + constexpr float g_flatTireLTLevels[] = { 0.8f, 0.0f, 0.0f }; + + // Trigger pulse followed by a full motor kick. + constexpr uint32_t g_gunRecoilLTDurations[] = { 20, 10, 90, 10000 }; + constexpr float g_gunRecoilLTLevels[] = { 1.0f, 0.0f, 0.0f, 0.0f }; + + // Alternating trigger pulses at approximately 60 BPM. + constexpr uint32_t g_heartbeatLTDurations[] = { 25, 200, 25, 10, 745 }; + constexpr float g_heartbeatLTLevels[] = { 0.2f, 0.0f, 0.0f, 0.0f, 0.0f }; + constexpr uint32_t g_heartbeatRTDurations[] = { 25, 200, 25, 10, 745 }; + constexpr float g_heartbeatRTLevels[] = { 0.0f, 0.0f, 0.2f, 0.02f, 0.0f }; + + // Alternating trigger thumps. + constexpr uint32_t g_footstepsLTDurations[] = { 25, 600, 25, 600 }; + constexpr float g_footstepsLTLevels[] = { 0.3f, 0.0f, 0.0f, 0.0f }; + constexpr uint32_t g_footstepsRTDurations[] = { 25, 600, 25, 600 }; + constexpr float g_footstepsRTLevels[] = { 0.0f, 0.0f, 0.3f, 0.0f }; +} + +//-------------------------------------------------------------------------------------- +// Reset effect state and schedule its first step. +//-------------------------------------------------------------------------------------- +void Sample::InitializeVibrationEffect(GamepadDevice& gamepad) +{ + auto& effectState = gamepad.vibEffect; + effectState.leftTriggerIndex = 0; + effectState.rightTriggerIndex = 0; + effectState.rumble = {}; + effectState.gunState = VibrationEffectState::GunState::WaitForRelease; + + uint64_t counter = 0; + QueryPerformanceCounter(reinterpret_cast(&counter)); + + switch (effectState.selectedEffect) + { + case VibrationEffect::FlatTire: + effectState.leftTriggerNextTime = counter + (m_perfFrequency * g_flatTireLTDurations[0]) / 1000; + break; + case VibrationEffect::Heartbeat: + effectState.leftTriggerNextTime = counter + (m_perfFrequency * g_heartbeatLTDurations[0]) / 1000; + effectState.rightTriggerNextTime = counter + (m_perfFrequency * g_heartbeatRTDurations[0]) / 1000; + break; + case VibrationEffect::Footsteps: + effectState.leftTriggerNextTime = counter + (m_perfFrequency * g_footstepsLTDurations[0]) / 1000; + effectState.rightTriggerNextTime = counter + (m_perfFrequency * g_footstepsRTDurations[0]) / 1000; + break; + case VibrationEffect::Manual: + case VibrationEffect::ImpulseTest: + case VibrationEffect::GunWithRecoil: + case VibrationEffect::Count: + default: + break; + } +} + +//-------------------------------------------------------------------------------------- +// Advance the selected effect and apply its rumble values to the device. +// +// Rumble values persist until changed; GameInput handles focus muting. +//-------------------------------------------------------------------------------------- +void Sample::UpdateVibration(GamepadDevice& gamepad) +{ + auto& effectState = gamepad.vibEffect; + + if (gamepad.hasGamepadState) + { + auto& state = gamepad.gamepadState; + uint64_t counter = 0; + QueryPerformanceCounter(reinterpret_cast(&counter)); + + switch (effectState.selectedEffect) + { + case VibrationEffect::Manual: + // Sliders set these values directly. + break; + + case VibrationEffect::ImpulseTest: + // Trigger positions directly drive all four channels. + effectState.rumble.leftTrigger = state.leftTrigger; + effectState.rumble.rightTrigger = state.rightTrigger; + effectState.rumble.lowFrequency = state.leftTrigger; + effectState.rumble.highFrequency = state.rightTrigger; + break; + + case VibrationEffect::FlatTire: + effectState.rumble.leftTrigger = g_flatTireLTLevels[effectState.leftTriggerIndex]; + if (counter > effectState.leftTriggerNextTime) + { + effectState.leftTriggerIndex = (effectState.leftTriggerIndex + 1) % _countof(g_flatTireLTDurations); + effectState.leftTriggerNextTime = counter + (m_perfFrequency * g_flatTireLTDurations[effectState.leftTriggerIndex]) / 1000; + } + break; + + case VibrationEffect::GunWithRecoil: + // Wait for release, wait for press, then play the recoil sequence. + switch (effectState.gunState) + { + case VibrationEffectState::GunState::WaitForRelease: + if (state.leftTrigger <= 1.0f / 255.0f) + effectState.gunState = VibrationEffectState::GunState::WaitForPress; + break; + case VibrationEffectState::GunState::WaitForPress: + if (state.leftTrigger >= 32.0f / 255.0f) + { + effectState.leftTriggerIndex = 0; + effectState.leftTriggerNextTime = counter + (m_perfFrequency * g_gunRecoilLTDurations[0]) / 1000; + effectState.gunState = VibrationEffectState::GunState::Playing; + } + break; + case VibrationEffectState::GunState::Playing: + effectState.rumble.leftTrigger = g_gunRecoilLTLevels[effectState.leftTriggerIndex]; + + // Step 2 adds the recoil kick. + if (effectState.leftTriggerIndex == 2) + { + effectState.rumble.lowFrequency = 1.0f; + effectState.rumble.highFrequency = 1.0f; + } + else + { + effectState.rumble.lowFrequency = 0.0f; + effectState.rumble.highFrequency = 0.0f; + } + + if (effectState.leftTriggerIndex == 3) + { + effectState.leftTriggerIndex = 0; + effectState.gunState = VibrationEffectState::GunState::WaitForRelease; + effectState.rumble.lowFrequency = 0; + effectState.rumble.highFrequency = 0; + effectState.rumble.leftTrigger = 0; + break; + } + + if (counter > effectState.leftTriggerNextTime) + { + effectState.leftTriggerIndex = (effectState.leftTriggerIndex + 1) % _countof(g_gunRecoilLTDurations); + effectState.leftTriggerNextTime = counter + (m_perfFrequency * g_gunRecoilLTDurations[effectState.leftTriggerIndex]) / 1000; + } + break; + } + break; + + case VibrationEffect::Heartbeat: + // Left and right patterns advance independently. + effectState.rumble.leftTrigger = g_heartbeatLTLevels[effectState.leftTriggerIndex]; + effectState.rumble.rightTrigger = g_heartbeatRTLevels[effectState.rightTriggerIndex]; + + if (counter > effectState.leftTriggerNextTime) + { + effectState.leftTriggerIndex = (effectState.leftTriggerIndex + 1) % _countof(g_heartbeatLTDurations); + effectState.leftTriggerNextTime = counter + (m_perfFrequency * g_heartbeatLTDurations[effectState.leftTriggerIndex]) / 1000; + } + if (counter > effectState.rightTriggerNextTime) + { + effectState.rightTriggerIndex = (effectState.rightTriggerIndex + 1) % _countof(g_heartbeatRTDurations); + effectState.rightTriggerNextTime = counter + (m_perfFrequency * g_heartbeatRTDurations[effectState.rightTriggerIndex]) / 1000; + } + break; + + case VibrationEffect::Footsteps: + effectState.rumble.leftTrigger = g_footstepsLTLevels[effectState.leftTriggerIndex]; + effectState.rumble.rightTrigger = g_footstepsRTLevels[effectState.rightTriggerIndex]; + + if (counter > effectState.leftTriggerNextTime) + { + effectState.leftTriggerIndex = (effectState.leftTriggerIndex + 1) % _countof(g_footstepsLTDurations); + effectState.leftTriggerNextTime = counter + (m_perfFrequency * g_footstepsLTDurations[effectState.leftTriggerIndex]) / 1000; + } + if (counter > effectState.rightTriggerNextTime) + { + effectState.rightTriggerIndex = (effectState.rightTriggerIndex + 1) % _countof(g_footstepsRTDurations); + effectState.rightTriggerNextTime = counter + (m_perfFrequency * g_footstepsRTDurations[effectState.rightTriggerIndex]) / 1000; + } + break; + + case VibrationEffect::Count: + default: + break; + } + + int historyIndex = effectState.historyOffset; + effectState.lowFreqHistory[historyIndex] = effectState.rumble.lowFrequency; + effectState.highFreqHistory[historyIndex] = effectState.rumble.highFrequency; + effectState.leftTriggerHistory[historyIndex] = effectState.rumble.leftTrigger; + effectState.rightTriggerHistory[historyIndex] = effectState.rumble.rightTrigger; + effectState.historyOffset = (historyIndex + 1) % VibrationEffectState::HistorySize; + } + + gamepad.device->SetRumbleState(&effectState.rumble); +} + +//-------------------------------------------------------------------------------------- +// Stop vibration on every connected gamepad without changing the selected effects. +//-------------------------------------------------------------------------------------- +void Sample::StopVibration() +{ + std::lock_guard lock(m_gamepadsMutex); + + GameInputRumbleParams stop = {}; + for (auto& gamepad : m_gamepads) + { + gamepad.device->SetRumbleState(&stop); + } +} + +//-------------------------------------------------------------------------------------- +// Vibration effect selection and controls. +//-------------------------------------------------------------------------------------- +void Sample::DrawVibrationSection(GamepadDevice& gamepad) +{ + if (ImGui::CollapsingHeader("Vibration", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf)) + { + if (!gamepad.deviceInfo->supportedRumbleMotors) + { + ImGui::TextWrapped("No rumble motors supported by this device."); + return; + } + + ImGuiAtg::BeginNavigationGroup("Vibration"); + + ImGui::TextWrapped("Select a vibration effect to play:"); + ImGui::Spacing(); + + int effectIndex = static_cast(gamepad.vibEffect.selectedEffect); + if (ImGui::Combo("##Vibration", &effectIndex, g_vibrationEffectNames, static_cast(VibrationEffect::Count))) + { + gamepad.vibEffect.selectedEffect = static_cast(effectIndex); + InitializeVibrationEffect(gamepad); + } + ImGui::SameLine(); + if (ImGui::Button("Stop")) + { + gamepad.vibEffect.selectedEffect = VibrationEffect::Manual; + gamepad.vibEffect.rumble = {}; + } + + ImGui::Spacing(); + float width = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f; + + switch (gamepad.vibEffect.selectedEffect) + { + case VibrationEffect::Manual: + { + ImGui::PushItemWidth(width); + bool hasLowFrequencyMotor = (gamepad.deviceInfo->supportedRumbleMotors & GameInputRumbleLowFrequency) != 0; + bool hasHighFrequencyMotor = (gamepad.deviceInfo->supportedRumbleMotors & GameInputRumbleHighFrequency) != 0; + bool hasLeftTriggerMotor = (gamepad.deviceInfo->supportedRumbleMotors & GameInputRumbleLeftTrigger) != 0; + bool hasRightTriggerMotor = (gamepad.deviceInfo->supportedRumbleMotors & GameInputRumbleRightTrigger) != 0; + + if (hasLowFrequencyMotor) + ImGui::SliderFloat("##lfm", &gamepad.vibEffect.rumble.lowFrequency, 0.0f, 1.0f, "Low Freq Motor %.3f"); + if (hasLowFrequencyMotor && hasHighFrequencyMotor) + ImGui::SameLine(); + if (hasHighFrequencyMotor) + ImGui::SliderFloat("##hfm", &gamepad.vibEffect.rumble.highFrequency, 0.0f, 1.0f, "High Freq Motor %.3f"); + if (hasLeftTriggerMotor) + ImGui::SliderFloat("##ltvib", &gamepad.vibEffect.rumble.leftTrigger, 0.0f, 1.0f, "Left Trigger %.3f"); + if (hasLeftTriggerMotor && hasRightTriggerMotor) + ImGui::SameLine(); + if (hasRightTriggerMotor) + ImGui::SliderFloat("##rtvib", &gamepad.vibEffect.rumble.rightTrigger, 0.0f, 1.0f, "Right Trigger %.3f"); + ImGui::PopItemWidth(); + break; + } + case VibrationEffect::ImpulseTest: + ImGui::TextWrapped("Pull the triggers to feel proportional feedback on both triggers and motors."); + break; + case VibrationEffect::FlatTire: + ImGui::TextWrapped("Simulates a flat tire with a rhythmic bump on the left trigger."); + break; + case VibrationEffect::GunWithRecoil: + ImGui::TextWrapped("Pull the left trigger to fire. Trigger pulse + motor recoil kick."); + break; + case VibrationEffect::Heartbeat: + ImGui::TextWrapped("Alternating left/right trigger pulses simulating a heartbeat (~60 BPM)."); + break; + case VibrationEffect::Footsteps: + ImGui::TextWrapped("Alternating left/right trigger thumps simulating nearby footsteps."); + break; + case VibrationEffect::Count: + default: + break; + } + + ImGui::Spacing(); + float graphHeight = ImGuiAtg::Scaled(30); + int offset = gamepad.vibEffect.historyOffset; + int count = VibrationEffectState::HistorySize; + ImGui::PushStyleVar(ImGuiStyleVar_DisabledAlpha, 1.0f); + ImGui::BeginDisabled(true); + ImGui::PlotLines("##LowFreq", gamepad.vibEffect.lowFreqHistory, count, offset, "Low Frequency", 0.0f, 1.0f, ImVec2(width, graphHeight)); + ImGui::SameLine(); + ImGui::PlotLines("##HighFreq", gamepad.vibEffect.highFreqHistory, count, offset, "High Frequency", 0.0f, 1.0f, ImVec2(width, graphHeight)); + ImGui::PlotLines("##LeftTrig", gamepad.vibEffect.leftTriggerHistory, count, offset, "Left Trigger", 0.0f, 1.0f, ImVec2(width, graphHeight)); + ImGui::SameLine(); + ImGui::PlotLines("##RightTrig", gamepad.vibEffect.rightTriggerHistory, count, offset, "Right Trigger", 0.0f, 1.0f, ImVec2(width, graphHeight)); + ImGui::EndDisabled(); + ImGui::PopStyleVar(); + + ImGuiAtg::EndNavigationGroup(); + } +} diff --git a/Samples/System/Gamepad/GamepadVibration.h b/Samples/System/Gamepad/GamepadVibration.h new file mode 100644 index 00000000..fea1031e --- /dev/null +++ b/Samples/System/Gamepad/GamepadVibration.h @@ -0,0 +1,59 @@ +//-------------------------------------------------------------------------------------- +// GamepadVibration.h +// +// Vibration effect types and per-gamepad effect state. +// +// Advanced Technology Group (ATG) +// Copyright (C) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- + +#pragma once + +#include +#include + +// GameInputRumbleParams has four independent motor channels: +// lowFrequency - left vibration motor (larger, lower pitch), range 0.0-1.0 +// highFrequency - right vibration motor (smaller, higher pitch), range 0.0-1.0 +// leftTrigger - left impulse trigger motor (adaptive trigger), range 0.0-1.0 +// rightTrigger - right impulse trigger motor (adaptive trigger), range 0.0-1.0 +enum class VibrationEffect +{ + Manual = 0, // Direct slider control of all four motors + ImpulseTest, // Trigger position directly drives corresponding motors + FlatTire, // Rhythmic pulse on left trigger (driving over bumps) + GunWithRecoil, // Trigger-activated shot with motor recoil kick + Heartbeat, // Alternating left/right trigger pulses (~60 BPM) + Footsteps, // Alternating left/right trigger thumps + Count +}; + +struct VibrationEffectState +{ + enum class GunState + { + WaitForRelease, + WaitForPress, + Playing + }; + + VibrationEffect selectedEffect = VibrationEffect::Manual; + + uint32_t leftTriggerIndex = 0; + uint32_t rightTriggerIndex = 0; + + uint64_t leftTriggerNextTime = 0; + uint64_t rightTriggerNextTime = 0; + + GunState gunState = GunState::WaitForRelease; + + // Values passed directly to SetRumbleState each frame. + GameInput::v3::GameInputRumbleParams rumble = {}; + + static constexpr int HistorySize = 180; // ~3 seconds at 60fps + float lowFreqHistory[HistorySize] = {}; + float highFreqHistory[HistorySize] = {}; + float leftTriggerHistory[HistorySize] = {}; + float rightTriggerHistory[HistorySize] = {}; + int historyOffset = 0; // Write position in ring buffer +}; diff --git a/Samples/System/Haptics/HapticsManager/Audio/IGenerator.h b/Samples/System/Gamepad/HapticsManager/Audio/IGenerator.h similarity index 100% rename from Samples/System/Haptics/HapticsManager/Audio/IGenerator.h rename to Samples/System/Gamepad/HapticsManager/Audio/IGenerator.h diff --git a/Samples/System/Haptics/HapticsManager/Audio/RenderBuffer.h b/Samples/System/Gamepad/HapticsManager/Audio/RenderBuffer.h similarity index 100% rename from Samples/System/Haptics/HapticsManager/Audio/RenderBuffer.h rename to Samples/System/Gamepad/HapticsManager/Audio/RenderBuffer.h diff --git a/Samples/System/Haptics/HapticsManager/Audio/WASAPIManager.cpp b/Samples/System/Gamepad/HapticsManager/Audio/WASAPIManager.cpp similarity index 100% rename from Samples/System/Haptics/HapticsManager/Audio/WASAPIManager.cpp rename to Samples/System/Gamepad/HapticsManager/Audio/WASAPIManager.cpp diff --git a/Samples/System/Haptics/HapticsManager/Audio/WASAPIManager.h b/Samples/System/Gamepad/HapticsManager/Audio/WASAPIManager.h similarity index 100% rename from Samples/System/Haptics/HapticsManager/Audio/WASAPIManager.h rename to Samples/System/Gamepad/HapticsManager/Audio/WASAPIManager.h diff --git a/Samples/System/Haptics/HapticsManager/Audio/WAVFileReader.cpp b/Samples/System/Gamepad/HapticsManager/Audio/WAVFileReader.cpp similarity index 100% rename from Samples/System/Haptics/HapticsManager/Audio/WAVFileReader.cpp rename to Samples/System/Gamepad/HapticsManager/Audio/WAVFileReader.cpp diff --git a/Samples/System/Haptics/HapticsManager/Audio/WAVFileReader.h b/Samples/System/Gamepad/HapticsManager/Audio/WAVFileReader.h similarity index 100% rename from Samples/System/Haptics/HapticsManager/Audio/WAVFileReader.h rename to Samples/System/Gamepad/HapticsManager/Audio/WAVFileReader.h diff --git a/Samples/System/Haptics/HapticsManager/Audio/WaveSampleGenerator.cpp b/Samples/System/Gamepad/HapticsManager/Audio/WaveSampleGenerator.cpp similarity index 100% rename from Samples/System/Haptics/HapticsManager/Audio/WaveSampleGenerator.cpp rename to Samples/System/Gamepad/HapticsManager/Audio/WaveSampleGenerator.cpp diff --git a/Samples/System/Haptics/HapticsManager/Audio/WaveSampleGenerator.h b/Samples/System/Gamepad/HapticsManager/Audio/WaveSampleGenerator.h similarity index 100% rename from Samples/System/Haptics/HapticsManager/Audio/WaveSampleGenerator.h rename to Samples/System/Gamepad/HapticsManager/Audio/WaveSampleGenerator.h diff --git a/Samples/System/Haptics/HapticsManager/Audio/XAudio2Manager.cpp b/Samples/System/Gamepad/HapticsManager/Audio/XAudio2Manager.cpp similarity index 100% rename from Samples/System/Haptics/HapticsManager/Audio/XAudio2Manager.cpp rename to Samples/System/Gamepad/HapticsManager/Audio/XAudio2Manager.cpp diff --git a/Samples/System/Haptics/HapticsManager/Audio/XAudio2Manager.h b/Samples/System/Gamepad/HapticsManager/Audio/XAudio2Manager.h similarity index 100% rename from Samples/System/Haptics/HapticsManager/Audio/XAudio2Manager.h rename to Samples/System/Gamepad/HapticsManager/Audio/XAudio2Manager.h diff --git a/Samples/System/Haptics/HapticsManager/HapticsDevice.cpp b/Samples/System/Gamepad/HapticsManager/HapticsDevice.cpp similarity index 87% rename from Samples/System/Haptics/HapticsManager/HapticsDevice.cpp rename to Samples/System/Gamepad/HapticsManager/HapticsDevice.cpp index 4462a9f7..250f0faf 100644 --- a/Samples/System/Haptics/HapticsManager/HapticsDevice.cpp +++ b/Samples/System/Gamepad/HapticsManager/HapticsDevice.cpp @@ -9,16 +9,15 @@ namespace ATG { - HRESULT HapticsDevice::Initialize(IGameInputDevice* giDevice, wchar_t* endpoint, uint32_t locationCount, GUID* locations) + HRESULT HapticsDevice::Initialize(IGameInputDevice* gameInputDevice, wchar_t* endpoint, uint32_t locationCount, GUID* locations) { - const GameInputDeviceInfo* di = nullptr; - HRESULT hr = giDevice->GetDeviceInfo(&di); + const GameInputDeviceInfo* deviceInfo = nullptr; + HRESULT hr = gameInputDevice->GetDeviceInfo(&deviceInfo); if (FAILED(hr)) { return hr; } - // create a WASAPI engine for the device m_wasapi = std::make_unique(); hr = m_wasapi->InitializeDevice(endpoint, locationCount, locations); if (FAILED(hr)) @@ -26,7 +25,6 @@ namespace ATG return hr; } - // create an XAudio2 engine for the device m_xaudio = std::make_unique(); hr = m_xaudio->InitializeDevice(endpoint, locationCount, locations); if (FAILED(hr)) diff --git a/Samples/System/Haptics/HapticsManager/HapticsDevice.h b/Samples/System/Gamepad/HapticsManager/HapticsDevice.h similarity index 92% rename from Samples/System/Haptics/HapticsManager/HapticsDevice.h rename to Samples/System/Gamepad/HapticsManager/HapticsDevice.h index 3fe94e87..a7022ffb 100644 --- a/Samples/System/Haptics/HapticsManager/HapticsDevice.h +++ b/Samples/System/Gamepad/HapticsManager/HapticsDevice.h @@ -46,7 +46,7 @@ namespace ATG bool IsPlaying() const { return (m_wasapi && m_wasapi->IsPlaying()) || (m_xaudio && m_xaudio->IsPlaying()); } private: - HRESULT Initialize(IGameInputDevice* giDevice, wchar_t* endpoint, uint32_t locationCount, GUID* locations); + HRESULT Initialize(IGameInputDevice* gameInputDevice, wchar_t* endpoint, uint32_t locationCount, GUID* locations); std::unique_ptr m_wasapi {}; std::unique_ptr m_xaudio {}; diff --git a/Samples/System/Haptics/HapticsManager/HapticsManager.cpp b/Samples/System/Gamepad/HapticsManager/HapticsManager.cpp similarity index 63% rename from Samples/System/Haptics/HapticsManager/HapticsManager.cpp rename to Samples/System/Gamepad/HapticsManager/HapticsManager.cpp index 1a33d430..e0138ac9 100644 --- a/Samples/System/Haptics/HapticsManager/HapticsManager.cpp +++ b/Samples/System/Gamepad/HapticsManager/HapticsManager.cpp @@ -34,53 +34,45 @@ HapticsManager::~HapticsManager() } } -void HapticsManager::DeviceCallback(GameInputCallbackToken, void* context, IGameInputDevice* giDevice, uint64_t, +void HapticsManager::DeviceCallback(GameInputCallbackToken, void* context, IGameInputDevice* gameInputDevice, uint64_t, GameInputDeviceStatus currentStatus, GameInputDeviceStatus previousStatus) noexcept { - HapticsManager* mgr = reinterpret_cast(context); - - const GameInputDeviceInfo* di = nullptr; - if(FAILED(giDevice->GetDeviceInfo(&di))) - { - return; - } + HapticsManager* manager = reinterpret_cast(context); bool wasConnected = (previousStatus & GameInputDeviceConnected) != 0; bool isConnected = (currentStatus & GameInputDeviceConnected) != 0; - // newly connected haptics device, initialize haptics + // Haptic information can become ready after the device connects. if(isConnected && currentStatus & GameInputDeviceStatus::GameInputDeviceHapticInfoReady) { GameInputHapticInfo hapticInfo; - if(FAILED(giDevice->GetHapticInfo(&hapticInfo))) + if(FAILED(gameInputDevice->GetHapticInfo(&hapticInfo))) { return; } - mgr->AddHapticsDevice(giDevice, hapticInfo.audioEndpointId, hapticInfo.locationCount, hapticInfo.locations); + manager->AddHapticsDevice(gameInputDevice, hapticInfo.audioEndpointId, hapticInfo.locationCount, hapticInfo.locations); } - // newly disconnected device, remove from our list - if(wasConnected && !isConnected && mgr->m_devices.find(giDevice) != mgr->m_devices.end()) + if(wasConnected && !isConnected && manager->m_devices.find(gameInputDevice) != manager->m_devices.end()) { - mgr->m_devices.erase(giDevice); + manager->m_devices.erase(gameInputDevice); } } -HRESULT HapticsManager::AddHapticsDevice(IGameInputDevice* giDevice, wchar_t* endpoint, uint32_t locationCount, GUID* locations) +HRESULT HapticsManager::AddHapticsDevice(IGameInputDevice* gameInputDevice, wchar_t* endpoint, uint32_t locationCount, GUID* locations) { - // don't add the same device twice - if (m_devices.find(giDevice) == m_devices.end()) + if (m_devices.find(gameInputDevice) == m_devices.end()) { - HapticsDevice hd; + HapticsDevice hapticsDevice; - HRESULT hr = hd.Initialize(giDevice, endpoint, locationCount, locations); + HRESULT hr = hapticsDevice.Initialize(gameInputDevice, endpoint, locationCount, locations); if (FAILED(hr)) { return hr; } - m_devices[giDevice] = std::move(hd); + m_devices[gameInputDevice] = std::move(hapticsDevice); } return S_OK; @@ -95,3 +87,11 @@ const HapticsDevice* HapticsManager::GetHapticsDevice(IGameInputDevice* device) } return nullptr; } + +void HapticsManager::StopAllDevices() +{ + for (auto& deviceEntry : m_devices) + { + deviceEntry.second.Stop(); + } +} diff --git a/Samples/System/Haptics/HapticsManager/HapticsManager.h b/Samples/System/Gamepad/HapticsManager/HapticsManager.h similarity index 81% rename from Samples/System/Haptics/HapticsManager/HapticsManager.h rename to Samples/System/Gamepad/HapticsManager/HapticsManager.h index b50395f3..fe5fe609 100644 --- a/Samples/System/Haptics/HapticsManager/HapticsManager.h +++ b/Samples/System/Gamepad/HapticsManager/HapticsManager.h @@ -1,5 +1,5 @@ //-------------------------------------------------------------------------------------- -// HapticHelper.h +// HapticsManager.h // // Advanced Technology Group (ATG) // Copyright (C) Microsoft Corporation. All rights reserved. @@ -31,19 +31,18 @@ namespace ATG HapticsManager() = default; ~HapticsManager(); - HapticsManager(HapticsManager&&) = default; - HapticsManager& operator= (HapticsManager&&) = default; - HapticsManager(HapticsManager const&) = delete; HapticsManager& operator= (HapticsManager const&) = delete; + HapticsManager(HapticsManager&&) = delete; + HapticsManager& operator= (HapticsManager&&) = delete; HRESULT Initialize(IGameInput* gameInput); const HapticsDevice* GetHapticsDevice(IGameInputDevice* device); - size_t GetDeviceCount() const { return m_devices.size(); } + void StopAllDevices(); private: static void DeviceCallback(GameInputCallbackToken, void* context, IGameInputDevice* device, uint64_t, GameInputDeviceStatus currentStatus, GameInputDeviceStatus previousStatus) noexcept; - HRESULT AddHapticsDevice(IGameInputDevice* device, wchar_t* endpoint, uint32_t locationCount, GUID* locations); + HRESULT AddHapticsDevice(IGameInputDevice* gameInputDevice, wchar_t* endpoint, uint32_t locationCount, GUID* locations); std::map, HapticsDevice> m_devices {}; Microsoft::WRL::ComPtr m_gameInput = nullptr; diff --git a/Samples/System/Gamepad/Main.cpp b/Samples/System/Gamepad/Main.cpp index 7c6d2ee7..cd670d98 100644 --- a/Samples/System/Gamepad/Main.cpp +++ b/Samples/System/Gamepad/Main.cpp @@ -1,13 +1,14 @@ //-------------------------------------------------------------------------------------- // Main.cpp // -// Entry point for Microsoft Game Development Kit (GDK) +// Window setup and message loop for the Gamepad sample. // // Advanced Technology Group (ATG) // Copyright (C) Microsoft Corporation. All rights reserved. //-------------------------------------------------------------------------------------- #include "pch.h" + #include "Gamepad.h" #include @@ -16,381 +17,323 @@ #include "ATGTelemetry.h" -using namespace DirectX; - -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wcovered-switch-default" -#pragma clang diagnostic ignored "-Wswitch-enum" -#endif - -#pragma warning(disable : 4061) - namespace { - std::unique_ptr g_sample; + static constexpr int c_WindowWidth = 1920; + static constexpr int c_WindowHeight = 1080; + + static std::unique_ptr g_d3dDeviceContext; + static std::unique_ptr g_sample; + #ifdef _GAMING_XBOX HANDLE g_plmSuspendComplete = nullptr; HANDLE g_plmSignalResume = nullptr; #endif } -LPCWSTR g_szAppName = L"Gamepad"; +static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); -LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); -void ExitSample() noexcept; - -int SampleMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) +#ifndef _GAMING_XBOX +static void ToggleFullscreen(HWND hWnd) { - UNREFERENCED_PARAMETER(lpCmdLine); + static bool isFullscreen = false; + static RECT windowRect = {}; - if (!XMVerifyCPUSupport()) + if (isFullscreen) { -#ifdef _DEBUG - OutputDebugStringA("ERROR: This hardware does not support the required instruction set.\n"); -#if defined(_GAMING_XBOX) && defined(__AVX2__) - OutputDebugStringA("This may indicate a Gaming.Xbox.Scarlett.x64 binary is being run on an Xbox One.\n"); -#endif + // Restore windowed mode + SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE); + SetWindowPos(hWnd, HWND_TOP, + windowRect.left, windowRect.top, + windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, + SWP_FRAMECHANGED); + } + else + { + // Switch to borderless fullscreen + GetWindowRect(hWnd, &windowRect); + SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP | WS_VISIBLE); + SetWindowPos(hWnd, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_FRAMECHANGED); + } + isFullscreen = !isFullscreen; +} #endif - return 1; + +// Main code +int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE /*hPrevInstance*/, _In_ LPWSTR /*lpCmdLine*/, _In_ int /*nCmdShow*/) +{ +#ifdef _GAMING_DESKTOP + // Set working directory to exe location + char dir[_MAX_PATH] = {}; + if (GetModuleFileNameA(nullptr, dir, _MAX_PATH) > 0) + { + std::string exe = dir; + exe = exe.substr(0, exe.find_last_of("\\")); + std::ignore = SetCurrentDirectoryA(exe.c_str()); } +#endif HRESULT hr = XGameRuntimeInitialize(); if (FAILED(hr)) { +#ifdef _GAMING_DESKTOP if (hr == E_GAMERUNTIME_DLL_NOT_FOUND || hr == E_GAMERUNTIME_VERSION_MISMATCH) { -#ifdef _GAMING_DESKTOP - std::ignore = MessageBoxW(nullptr, L"Game Runtime is not installed on this system or needs updating.", g_szAppName, MB_ICONERROR | MB_OK); -#endif + std::ignore = MessageBoxW(nullptr, L"Game Runtime is not installed on this system or needs updating.", L"Gamepad", MB_ICONERROR | MB_OK); } +#endif return 1; } #ifdef _GAMING_XBOX - // Default main thread to CPU 0 SetThreadAffinityMask(GetCurrentThread(), 0x1); #endif - g_sample = std::make_unique(); - - // Register class and create window -#ifdef _GAMING_XBOX - PAPPSTATE_REGISTRATION hPLM = {}; + // Create application window +#ifndef _GAMING_XBOX + ImGui_ImplWin32_EnableDpiAwareness(); #endif - { - // Register class - WNDCLASSEXW wcex = {}; - wcex.cbSize = sizeof(WNDCLASSEXW); - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = WndProc; - wcex.hInstance = hInstance; - wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW); - wcex.hbrBackground = reinterpret_cast(COLOR_WINDOW + 1); - wcex.lpszClassName = L"GamepadWindowClass"; - if (!RegisterClassExW(&wcex)) - return 1; - - // Create window + + WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, hInstance, nullptr, nullptr, nullptr, nullptr, L"Gamepad", nullptr }; + RegisterClassExW(&wc); + #ifdef _GAMING_XBOX - RECT rc = { 0, 0, 1920, 1080 }; + int width = 1920; + int height = 1080; #else - int w, h; - g_sample->GetDefaultSize(w, h); - - RECT rc = { 0, 0, static_cast(w), static_cast(h) }; - AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); + int width = c_WindowWidth; + int height = c_WindowHeight; #endif - HWND hwnd = CreateWindowExW(0, L"GamepadWindowClass", g_szAppName, WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, - nullptr, nullptr, hInstance, - g_sample.get()); - if (!hwnd) - return 1; + HWND hWnd = CreateWindowW(wc.lpszClassName, L"Gamepad", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, width, height, nullptr, nullptr, wc.hInstance, nullptr); - ShowWindow(hwnd, nCmdShow); + // Initialize Direct3D + g_d3dDeviceContext = std::make_unique(); + if (!g_d3dDeviceContext->CreateDevice(hWnd, width, height)) + { + UnregisterClassW(wc.lpszClassName, wc.hInstance); + return 1; + } + + // Show the window + ShowWindow(hWnd, SW_SHOWNORMAL); +#ifndef _GAMING_XBOX + UpdateWindow(hWnd); + SetForegroundWindow(hWnd); +#endif - // Sample Usage Telemetry - // - // Disable or remove this code block to opt-out of sample usage telemetry - ATG::SendLaunchTelemetry(); + // Sample Usage Telemetry + // + // Disable or remove this code block to opt-out of sample usage telemetry + ATG::SendLaunchTelemetry(); + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad; // Disable Gamepad Controls (the sample reads the gamepad directly) + io.IniFilename = nullptr; // Disable INI file creation + + // Setup Dear ImGui style + ImGuiAtg::SetAtgStyle(); +#ifndef _GAMING_XBOX + ImGuiAtg::SetDpiScale(hWnd); +#endif - GetClientRect(hwnd, &rc); + // Setup Platform/Renderer backends + ImGui_ImplWin32_Init(hWnd); + g_d3dDeviceContext->DX12_Init(); - g_sample->Initialize(hwnd, rc.right - rc.left, rc.bottom - rc.top); + g_sample = std::make_unique(); + g_sample->Initialize(hWnd, g_d3dDeviceContext.get()); #ifdef _GAMING_XBOX - g_plmSuspendComplete = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE); - g_plmSignalResume = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE); - if (!g_plmSuspendComplete || !g_plmSignalResume) - return 1; + // Setup PLM suspend/resume + PAPPSTATE_REGISTRATION hPLM = {}; + g_plmSuspendComplete = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE); + g_plmSignalResume = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE); - if (RegisterAppStateChangeNotification([](BOOLEAN quiesced, PVOID context) + RegisterAppStateChangeNotification([](BOOLEAN quiesced, PVOID context) + { + if (quiesced) { - if (quiesced) - { - ResetEvent(g_plmSuspendComplete); - ResetEvent(g_plmSignalResume); + ResetEvent(g_plmSuspendComplete); + ResetEvent(g_plmSignalResume); - // To ensure we use the main UI thread to process the notification, we self-post a message - PostMessage(reinterpret_cast(context), WM_USER, 0, 0); + PostMessage(reinterpret_cast(context), WM_USER, 0, 0); - // To defer suspend, you must wait to exit this callback - std::ignore = WaitForSingleObject(g_plmSuspendComplete, INFINITE); - } - else - { - SetEvent(g_plmSignalResume); - } - }, hwnd, &hPLM)) - return 1; + std::ignore = WaitForSingleObject(g_plmSuspendComplete, INFINITE); + } + else + { + SetEvent(g_plmSignalResume); + } + }, hWnd, &hPLM); #endif - } - // Main message loop + // Main loop MSG msg = {}; - OutputDebugStringA("INFO: Sample started.\n"); - while (WM_QUIT != msg.message) + while (msg.message != WM_QUIT) { - if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) + if (PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { - g_sample->Tick(); + g_sample->Update(); + + // Start the Dear ImGui frame + g_d3dDeviceContext->DX12_PreRender(); + ImGui_ImplDX12_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + + ImGuiAtg::HandleStandardInput(); + + // Draw the ImGui controls + g_sample->Draw(); + + // Rendering + ImGui::Render(); + g_d3dDeviceContext->DX12_PostRender(); } } + // Shutdown and cleanup + g_d3dDeviceContext->DX12_Shutdown(); + g_sample->Shutdown(); g_sample.reset(); + ImGui_ImplDX12_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); #ifdef _GAMING_XBOX UnregisterAppStateChangeNotification(hPLM); - - CloseHandle(g_plmSuspendComplete); - CloseHandle(g_plmSignalResume); + if (g_plmSuspendComplete) + { + CloseHandle(g_plmSuspendComplete); + } + if (g_plmSignalResume) + { + CloseHandle(g_plmSignalResume); + } #endif XGameRuntimeUninitialize(); - return static_cast(msg.wParam); + g_d3dDeviceContext.reset(); + DestroyWindow(hWnd); + UnregisterClassW(wc.lpszClassName, wc.hInstance); + + return 0; } -// Entry point -int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - try - { - return SampleMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); - } - catch (const std::exception& e) + // Give the sample first crack at messages before passing them to ImGui or the default proc. + if (g_sample && g_sample->WndProcHandler(hWnd, msg, wParam, lParam)) { - OutputDebugStringA("*** ERROR: Unhandled C++ exception thrown: "); - OutputDebugStringA(e.what()); - OutputDebugStringA(" *** \n"); return 1; } - catch (...) + + if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) { - OutputDebugStringA("*** ERROR: Unknown unhandled C++ exception thrown ***\n"); return 1; } -} -// Windows procedure -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ -#ifdef _GAMING_DESKTOP - static bool s_in_sizemove = false; - static bool s_in_suspend = false; - static bool s_minimized = false; - static bool s_fullscreen = false; -#endif - - auto sample = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); - - switch (message) + switch (msg) { - case WM_CREATE: - if (lParam) - { - auto params = reinterpret_cast(lParam); - SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(params->lpCreateParams)); - } - break; - - case WM_ACTIVATEAPP: - if (sample) - { - if (wParam) +#ifdef _GAMING_XBOX + case WM_USER: + if (g_sample) { - sample->OnActivated(); + g_sample->Suspend(g_d3dDeviceContext.get()); + SetEvent(g_plmSuspendComplete); + std::ignore = WaitForSingleObject(g_plmSignalResume, INFINITE); + g_sample->Resume(g_d3dDeviceContext.get()); } - else + break; +#endif + +#ifndef _GAMING_XBOX + case WM_GETMINMAXINFO: { - sample->OnDeactivated(); + // Enforce a minimum window size on desktop. + auto mmi = reinterpret_cast(lParam); + mmi->ptMinTrackSize.x = 1280; + mmi->ptMinTrackSize.y = 720; } - } - break; - -#ifdef _GAMING_XBOX - case WM_USER: - if (sample) - { - sample->OnSuspending(); - - // Complete deferral - SetEvent(g_plmSuspendComplete); + return 0; - std::ignore = WaitForSingleObject(g_plmSignalResume, INFINITE); - - sample->OnResuming(); - } - break; -#else - case WM_PAINT: - if (s_in_sizemove && sample) - { - sample->Tick(); - } - else - { - PAINTSTRUCT ps; - std::ignore = BeginPaint(hWnd, &ps); - EndPaint(hWnd, &ps); - } - break; - - case WM_MOVE: - if (sample) - { - sample->OnWindowMoved(); - } - break; - - case WM_SIZE: - if (wParam == SIZE_MINIMIZED) - { - if (!s_minimized) + case WM_KEYDOWN: + if (wParam == VK_F11) { - s_minimized = true; - if (!s_in_suspend && sample) - sample->OnSuspending(); - s_in_suspend = true; + ToggleFullscreen(hWnd); + return 0; } - } - else if (s_minimized) - { - s_minimized = false; - if (s_in_suspend && sample) - sample->OnResuming(); - s_in_suspend = false; - } - else if (!s_in_sizemove && sample) - { - sample->OnWindowSizeChanged(LOWORD(lParam), HIWORD(lParam)); - } - break; - - case WM_ENTERSIZEMOVE: - s_in_sizemove = true; - break; - - case WM_EXITSIZEMOVE: - s_in_sizemove = false; - if (sample) - { - RECT rc; - GetClientRect(hWnd, &rc); - - sample->OnWindowSizeChanged(rc.right - rc.left, rc.bottom - rc.top); - } - break; - - case WM_GETMINMAXINFO: - if (lParam) - { - auto info = reinterpret_cast(lParam); - info->ptMinTrackSize.x = 320; - info->ptMinTrackSize.y = 200; - } - break; + break; - case WM_POWERBROADCAST: - switch (wParam) - { - case PBT_APMQUERYSUSPEND: - if (!s_in_suspend && sample) - sample->OnSuspending(); - s_in_suspend = true; - return TRUE; - - case PBT_APMRESUMESUSPEND: - if (!s_minimized) + case WM_SYSKEYDOWN: + if (wParam == VK_RETURN && (lParam & 0x60000000) == 0x20000000) { - if (s_in_suspend && sample) - sample->OnResuming(); - s_in_suspend = false; + ToggleFullscreen(hWnd); + return 0; } - return TRUE; - } - break; + break; - case WM_DESTROY: - PostQuitMessage(0); - break; - - case WM_KEYUP: - if (wParam == VK_ESCAPE) - { - PostQuitMessage(0); - } - break; +#endif - case WM_SYSKEYDOWN: - if (wParam == VK_RETURN && (lParam & 0x60000000) == 0x20000000) - { - // Implements the classic ALT+ENTER fullscreen toggle - if (s_fullscreen) + case WM_ACTIVATEAPP: + if (g_sample) { - SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); - SetWindowLongPtr(hWnd, GWL_EXSTYLE, 0); - - int width = 800; - int height = 600; - if (sample) - sample->GetDefaultSize(width, height); - - ShowWindow(hWnd, SW_SHOWNORMAL); - - SetWindowPos(hWnd, HWND_TOP, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); + if (wParam) + { + g_sample->Activated(); + } + else + { + g_sample->Deactivated(); + } } - else - { - SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP); - SetWindowLongPtr(hWnd, GWL_EXSTYLE, WS_EX_TOPMOST); + break; - SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + case WM_SIZE: + if (g_d3dDeviceContext) + { + g_d3dDeviceContext->DX12_Resize(lParam, wParam); + } + return 0; - ShowWindow(hWnd, SW_SHOWMAXIMIZED); +#ifndef _GAMING_XBOX + case WM_DPICHANGED: + { + auto rect = reinterpret_cast(lParam); + SetWindowPos(hWnd, nullptr, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top, SWP_NOZORDER); + ImGuiAtg::SetDpiScale(hWnd); } + return 0; +#endif - s_fullscreen = !s_fullscreen; - } - break; + case WM_SYSCOMMAND: + if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu + { + return 0; + } + break; - case WM_MENUCHAR: - // A menu is active and the user presses a key that does not correspond - // to any mnemonic or accelerator key. Ignore so we don't produce an error beep. - return MAKELRESULT(0, MNC_CLOSE); -#endif + case WM_DESTROY: + PostQuitMessage(0); + return 0; } - - return DefWindowProc(hWnd, message, wParam, lParam); + return DefWindowProcW(hWnd, msg, wParam, lParam); } -// Exit helper void ExitSample() noexcept { PostQuitMessage(0); diff --git a/Samples/System/Gamepad/MicrosoftGameConfig.mgc b/Samples/System/Gamepad/MicrosoftGameConfig.mgc index 4bc579a9..21f5aa38 100644 --- a/Samples/System/Gamepad/MicrosoftGameConfig.mgc +++ b/Samples/System/Gamepad/MicrosoftGameConfig.mgc @@ -1,11 +1,13 @@ - - + - + + PleaseChangeMe + FFFFFFFF + @@ -14,9 +16,9 @@ -#include -#include - - -namespace DX -{ - // Helper class for animation and simulation timing. - class StepTimer - { - public: - StepTimer() noexcept(false) : - 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 std::exception(); - } - - if (!QueryPerformanceCounter(&m_qpcLastTime)) - { - throw std::exception(); - } - - // Initialize max delta to 1/10 of a second. - m_qpcMaxDelta = static_cast(m_qpcFrequency.QuadPart / 10); - } - - // Get elapsed time since the previous Update call. - uint64_t GetElapsedTicks() const noexcept { return m_elapsedTicks; } - double GetElapsedSeconds() const noexcept { return TicksToSeconds(m_elapsedTicks); } - - // Get total time since the start of the program. - uint64_t GetTotalTicks() const noexcept { return m_totalTicks; } - double GetTotalSeconds() const noexcept { return TicksToSeconds(m_totalTicks); } - - // Get total number of updates since start of the program. - uint32_t GetFrameCount() const noexcept { return m_frameCount; } - - // Get the current framerate. - uint32_t GetFramesPerSecond() const noexcept { return m_framesPerSecond; } - - // Set whether to use fixed or variable timestep mode. - void SetFixedTimeStep(bool isFixedTimestep) noexcept { m_isFixedTimeStep = isFixedTimestep; } - - // Set how often to call Update when in fixed timestep mode. - void SetTargetElapsedTicks(uint64_t targetElapsed) noexcept { m_targetElapsedTicks = targetElapsed; } - void SetTargetElapsedSeconds(double targetElapsed) noexcept { m_targetElapsedTicks = SecondsToTicks(targetElapsed); } - - // Integer format represents time using 10,000,000 ticks per second. - static constexpr uint64_t TicksPerSecond = 10000000; - - static constexpr double TicksToSeconds(uint64_t ticks) noexcept { return static_cast(ticks) / TicksPerSecond; } - static constexpr uint64_t SecondsToTicks(double seconds) noexcept { 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 std::exception(); - } - - 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 std::exception(); - } - - uint64_t timeDelta = static_cast(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 /= static_cast(m_qpcFrequency.QuadPart); - - const uint32_t 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 (static_cast(std::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 %= static_cast(m_qpcFrequency.QuadPart); - } - } - - private: - // Source timing data uses QPC units. - LARGE_INTEGER m_qpcFrequency; - LARGE_INTEGER m_qpcLastTime; - uint64_t m_qpcMaxDelta; - - // Derived timing data uses a canonical tick format. - uint64_t m_elapsedTicks; - uint64_t m_totalTicks; - uint64_t m_leftOverTicks; - - // Members for tracking the framerate. - uint32_t m_frameCount; - uint32_t m_framesPerSecond; - uint32_t m_framesThisSecond; - uint64_t m_qpcSecondCounter; - - // Members for configuring fixed timestep mode. - bool m_isFixedTimeStep; - uint64_t m_targetElapsedTicks; - }; -} diff --git a/Samples/System/Haptics/Media/AhoogaHorn.wav b/Samples/System/Gamepad/media/Haptics/AhoogaHorn.wav similarity index 100% rename from Samples/System/Haptics/Media/AhoogaHorn.wav rename to Samples/System/Gamepad/media/Haptics/AhoogaHorn.wav diff --git a/Samples/System/Haptics/Media/PenScratch.wav b/Samples/System/Gamepad/media/Haptics/PenScratch.wav similarity index 100% rename from Samples/System/Haptics/Media/PenScratch.wav rename to Samples/System/Gamepad/media/Haptics/PenScratch.wav diff --git a/Samples/System/Haptics/Media/ShakeEffect.wav b/Samples/System/Gamepad/media/Haptics/ShakeEffect.wav similarity index 100% rename from Samples/System/Haptics/Media/ShakeEffect.wav rename to Samples/System/Gamepad/media/Haptics/ShakeEffect.wav diff --git a/Samples/System/Haptics/Media/TommyGun.wav b/Samples/System/Gamepad/media/Haptics/TommyGun.wav similarity index 100% rename from Samples/System/Haptics/Media/TommyGun.wav rename to Samples/System/Gamepad/media/Haptics/TommyGun.wav diff --git a/Samples/System/Haptics/Media/car.wav b/Samples/System/Gamepad/media/Haptics/car.wav similarity index 100% rename from Samples/System/Haptics/Media/car.wav rename to Samples/System/Gamepad/media/Haptics/car.wav diff --git a/Samples/System/Haptics/Media/fireworks.wav b/Samples/System/Gamepad/media/Haptics/fireworks.wav similarity index 100% rename from Samples/System/Haptics/Media/fireworks.wav rename to Samples/System/Gamepad/media/Haptics/fireworks.wav diff --git a/Samples/System/Haptics/Media/gun_shot.wav b/Samples/System/Gamepad/media/Haptics/gun_shot.wav similarity index 100% rename from Samples/System/Haptics/Media/gun_shot.wav rename to Samples/System/Gamepad/media/Haptics/gun_shot.wav diff --git a/Samples/System/Gamepad/media/Model/XboxControllerGen3.sdkmesh b/Samples/System/Gamepad/media/Model/XboxControllerGen3.sdkmesh new file mode 100644 index 00000000..eb23043b Binary files /dev/null and b/Samples/System/Gamepad/media/Model/XboxControllerGen3.sdkmesh differ diff --git a/Samples/System/Gamepad/media/Model/colors-on-black.dds b/Samples/System/Gamepad/media/Model/colors-on-black.dds new file mode 100644 index 00000000..ebc5ea14 Binary files /dev/null and b/Samples/System/Gamepad/media/Model/colors-on-black.dds differ diff --git a/Samples/System/Gamepad/media/Model/noise-normal.dds b/Samples/System/Gamepad/media/Model/noise-normal.dds new file mode 100644 index 00000000..e3595c53 Binary files /dev/null and b/Samples/System/Gamepad/media/Model/noise-normal.dds differ diff --git a/Samples/System/Gamepad/media/Model/noise-roughness.dds b/Samples/System/Gamepad/media/Model/noise-roughness.dds new file mode 100644 index 00000000..d591edc8 Binary files /dev/null and b/Samples/System/Gamepad/media/Model/noise-roughness.dds differ diff --git a/Samples/System/Gamepad/media/Model/occ-1.dds b/Samples/System/Gamepad/media/Model/occ-1.dds new file mode 100644 index 00000000..8e794fbd Binary files /dev/null and b/Samples/System/Gamepad/media/Model/occ-1.dds differ diff --git a/Samples/System/Gamepad/media/Model/occ-2.dds b/Samples/System/Gamepad/media/Model/occ-2.dds new file mode 100644 index 00000000..9541ee97 Binary files /dev/null and b/Samples/System/Gamepad/media/Model/occ-2.dds differ diff --git a/Samples/System/Gamepad/media/Model/occ-nexus.dds b/Samples/System/Gamepad/media/Model/occ-nexus.dds new file mode 100644 index 00000000..4bc0134e Binary files /dev/null and b/Samples/System/Gamepad/media/Model/occ-nexus.dds differ diff --git a/Samples/System/Gamepad/media/Model/ports-diffuse.dds b/Samples/System/Gamepad/media/Model/ports-diffuse.dds new file mode 100644 index 00000000..341f248c Binary files /dev/null and b/Samples/System/Gamepad/media/Model/ports-diffuse.dds differ diff --git a/Samples/System/Gamepad/media/Model/ports-metalness.dds b/Samples/System/Gamepad/media/Model/ports-metalness.dds new file mode 100644 index 00000000..3eea9e92 Binary files /dev/null and b/Samples/System/Gamepad/media/Model/ports-metalness.dds differ diff --git a/Samples/System/Gamepad/media/Model/toppers-normals.dds b/Samples/System/Gamepad/media/Model/toppers-normals.dds new file mode 100644 index 00000000..4ff94203 Binary files /dev/null and b/Samples/System/Gamepad/media/Model/toppers-normals.dds differ diff --git a/Samples/System/Gamepad/media/Model/viewmenushare-gray-on-black.dds b/Samples/System/Gamepad/media/Model/viewmenushare-gray-on-black.dds new file mode 100644 index 00000000..eb90c80e Binary files /dev/null and b/Samples/System/Gamepad/media/Model/viewmenushare-gray-on-black.dds differ diff --git a/Samples/System/Gamepad/media/image1.png b/Samples/System/Gamepad/media/image1.png deleted file mode 100644 index 3791445d..00000000 Binary files a/Samples/System/Gamepad/media/image1.png and /dev/null differ diff --git a/Samples/System/Gamepad/media/image3.png b/Samples/System/Gamepad/media/image3.png deleted file mode 100644 index 11b944bf..00000000 Binary files a/Samples/System/Gamepad/media/image3.png and /dev/null differ diff --git a/Samples/System/Gamepad/packages.config b/Samples/System/Gamepad/packages.config index 0c27d7a1..17226255 100644 --- a/Samples/System/Gamepad/packages.config +++ b/Samples/System/Gamepad/packages.config @@ -1,4 +1,4 @@ - + - + \ No newline at end of file diff --git a/Samples/System/Gamepad/pch.h b/Samples/System/Gamepad/pch.h index f6aa84e4..7e09e671 100644 --- a/Samples/System/Gamepad/pch.h +++ b/Samples/System/Gamepad/pch.h @@ -16,10 +16,12 @@ // Use the C++ standard templated min/max #define NOMINMAX -// DirectX apps don't need GDI +// ImGui Desktop needs GDI +#ifdef _GAMING_XBOX #define NODRAWTEXT #define NOGDI #define NOBITMAP +#endif // !_GAMING_XBOX // Include if you need this #define NOMCX @@ -41,11 +43,6 @@ #include -#ifdef _GAMING_DESKTOP -#if _GRDK_EDITION < 251000 -#error The Desktop version of this sample requires the October 2025 GDK or later -#endif -#else #if _GRDK_VER < 0x65F41800 /* GDK Edition 251000 */ #error This sample requires the October 2025 GDK or later #endif @@ -55,7 +52,6 @@ #error ARM64 support requires April 2026 GDK or later #endif #endif -#endif #ifdef _GAMING_XBOX_SCARLETT #include @@ -89,14 +85,24 @@ #include #include #include +#include #include #include #include +#include #include #include #include #include #include +#include + +// GameInput (the Microsoft.GameInput NuGet package overrides the GDK version on all platforms) +#include +#if GAMEINPUT_API_VERSION != 3 +#error This sample requires the GameInput v3 API from Microsoft.GameInput 3.5 or later. +#endif +using namespace GameInput::v3; #ifdef _GAMING_XBOX #include @@ -108,56 +114,31 @@ #include #include -#include +// DirectXTK12 -- used by the 3D controller model viewer (ImGuiAtg::ModelViewer) #include "CommonStates.h" #include "DDSTextureLoader.h" #include "DescriptorHeap.h" #include "DirectXHelpers.h" +#include "Effects.h" #include "GraphicsMemory.h" +#include "Model.h" #include "RenderTargetState.h" #include "ResourceUploadBatch.h" #include "SimpleMath.h" -#include "SpriteBatch.h" -#include "SpriteFont.h" + +#include "StringUtil.h" + +// Dear ImGui + ATG ImGui helpers +#include "imgui.h" +#include "backends/imgui_impl_dx12.h" +#include "backends/imgui_impl_win32.h" +#include "imgui/imgui_atg.h" +#include "imgui/imgui_atg_render_target.h" +#include "imgui/imgui_atg_model_viewer.h" // To opt-out of telemetry uncomment the following line //#define ATG_DISABLE_TELEMETRY -namespace DX -{ - // Helper class for COM exceptions - class com_exception : public std::exception - { - public: - com_exception(HRESULT hr) noexcept : result(hr) {} - - const char* what() const noexcept override - { - static char s_str[64] = {}; - sprintf_s(s_str, "Failure with HRESULT of %08X", static_cast(result)); - return s_str; - } - - private: - HRESULT result; - }; - - // Helper utility converts D3D API failures into exceptions. - inline void ThrowIfFailed(HRESULT hr) - { - if (FAILED(hr)) - { -#ifdef _DEBUG - char str[64] = {}; - sprintf_s(str, "**ERROR** Fatal Error with HRESULT of %08X\n", static_cast(hr)); - OutputDebugStringA(str); - __debugbreak(); -#endif - throw com_exception(hr); - } - } -} - // Enable off by default warnings to improve code conformance #pragma warning(default : 4061 4062 4191 4263 4264 4265 4266 4289 4365 4746 4826 4841 4986 4987 5029 5038 5042) diff --git a/Samples/System/Gamepad/readme.md b/Samples/System/Gamepad/readme.md index 54f03894..95b83f5d 100644 --- a/Samples/System/Gamepad/readme.md +++ b/Samples/System/Gamepad/readme.md @@ -13,71 +13,123 @@ extendedZipContent: target: Kits - path: Media target: Media -description: "This sample demonstrates how to read inputs from a gamepad on Xbox." +description: "This sample demonstrates gamepad input, motion sensor readings, vibration control, and audio-driven haptics using GameInput on Xbox and Windows PC." --- -----> -![](./media/image1.png) - # Gamepad Sample -*This sample is compatible with the Microsoft Game Development Kit (June 2020)* +*This sample is compatible with the Microsoft GDK (October 2025) or later. ARM64 requires the April 2026 GDK or later.* # Description -This sample demonstrates how to read inputs from a gamepad on the Xbox One and PC - -![](./media/image3.png) +This sample demonstrates how to read input from gamepads using the GameInput API on +Xbox Series X|S, Xbox One, and Windows PC (x64 and ARM64). It presents a Dear ImGui +interface (using the repository's `ImGuiAtg` framework) with a tab per connected device, and covers: + +- **Device enumeration** -- automatic detection of gamepad connect/disconnect via device callbacks +- **Multiple gamepad support** -- each connected gamepad gets its own tab +- **Gamepad state reading** -- buttons, analog triggers, and thumbstick axes +- **Visual analog indicators** -- vertical trigger bars and 2D thumbstick crosshairs with live values +- **Sensor/motion data** -- accelerometer, gyroscope, and orientation quaternion (requires a motion-capable controller such as the DualSense) +- **3D controller model** -- real-time orientation visualization driven by sensor data, rendered with DirectXTK12 +- **Vibration control** -- interactive sliders and preset effects for all four rumble motors (low/high frequency and the two impulse triggers) +- **Haptic playback** -- WAV-based haptic feedback via WASAPI and XAudio2 on supported controllers +- **Reading modes** -- toggle between polling (`GetCurrentReading`) and callback-driven (`RegisterReadingCallback`) input +- **Device info** -- display name, vendor/product IDs, supported input kinds, and reading timestamp # Building the sample -- If building for Xbox One, set the active solution platform to `Gaming.Xbox.XboxOne.x64`. - If building for Xbox Series X|S, set the active solution platform to `Gaming.Xbox.Scarlett.x64`. -- If building for PC, set the active solution platform to x64.\ -**NOTE: This requires the [GameInput NuGet package](https://www.nuget.org/packages/Microsoft.GameInput) and its -included redistributable to be installed. Please see -[GameInput on PC](https://learn.microsoft.com/gaming/gdk/_content/gc/input/overviews/input-nuget) for more information.**. +- If building for Xbox One, set the active solution platform to `Gaming.Xbox.XboxOne.x64`. +- If building for PC, set the active solution platform to `x64` or `ARM64`. + +The `Microsoft.GameInput` NuGet package is restored automatically for every platform and +overrides the GameInput version included with the GDK. This sample requires Microsoft.GameInput +3.5 or later and uses the GameInput v3 API. -*For more information, see* __Running samples__, *in the GDK documentation.* +**NOTE:** On PC, the GameInput runtime must be installed. See +[GameInput on PC](https://learn.microsoft.com/gaming/gdk/_content/gc/input/overviews/input-nuget) +for more information. + +*For more information, see* __Running samples__, *in the GDK documentation.* # Running the sample -Ensure the GameInput Redistributable (GameInputRedist.msi) is installed. This installer can be found in the NuGet package, -or it can be installed separately using WinGet via a command prompt with the following command: +On PC, ensure the GameInput runtime is installed. It can be installed from the NuGet package's +redistributable, or via WinGet from a command prompt: `winget install Microsoft.GameInput` +Connect one or more gamepads. The UI displays a tab for each connected device. Press buttons, +move the thumbsticks, and pull the triggers to see live readings and visual indicators. The +**Vibration** section drives the rumble motors, the **Haptics** section plays WAV-based haptic +effects, and the **Sensors** / **3D Orientation** sections display motion data on supported +controllers. + # Using the sample -Press buttons to see them displayed and move the thumbsticks and triggers to see their readings. -Move the controller around to see the motion sensor readings. +Use the on-screen ImGui controls to select the reading mode, configure vibration, and play +haptic effects. Hold LB + RB and press D-pad up/down to move through the currently available +navigation groups. Release LB + RB to navigate within the selected group normally. +Use LB + RB + D-pad left/right to select the previous or next connected-gamepad tab. -# Implementation notes +When multiple gamepads are connected, only the most recently connected gamepad controls +Dear ImGui navigation. Navigation input is not merged across gamepads. If that gamepad +disconnects, navigation falls back to the next most recently connected gamepad. -This sample demonstrates how to use the new GameInput API to read input -from a gamepad, including buttons, thumbsticks, triggers, and motion sensors. +# Controls -# Known Issues/Expectations +| Action | Keyboard & Mouse | Gamepad | +|---|---|---| +| Exit | Alt+F4 | LB + RB + View + Menu | +| Toggle light/dark theme | F2 | LB + RB + Y | +| Toggle gamepad navigation | F3 | LB + RB + X | +| Select previous/next gamepad tab | N/A | LB + RB + D-pad left/right | +| Move between interactive UI groups | N/A | LB + RB + D-pad up/down | +| Toggle fullscreen (PC only) | F11 or Alt+Enter | N/A | -At present, the only motion-enabled controller supported by GameInput is the PlayStation®5 DualSense® controller. - -# Version History +# Implementation notes -- October 2018: Initial GDK release -- February 2020: Updated for changes to GameInput API. -- June 2022: Added support for GameInput on PC (June 2022 GDK or later) -- March 2025: Added support for GameInput v1.x on PC via the - [GameInput NuGet package](https://www.nuget.org/packages/Microsoft.GameInput) -- July 2025: Added support for GameInput v2.x on PC via the - [GameInput NuGet package](https://www.nuget.org/packages/Microsoft.GameInput) -- April 2026: Added motion sensor readings for supported devices +- Uses the **GameInput v3** API from the Microsoft.GameInput 3.5 or later NuGet package on both + PC and Xbox. Device connect/disconnect is handled through + `IGameInput::RegisterDeviceCallback` with `GameInputBlockingEnumeration` so already-connected + devices are reported at startup. +- Gamepad state is read via `IGameInput::GetCurrentReading` (polling) or + `IGameInput::RegisterReadingCallback` (callback mode) with `GameInputKindGamepad | GameInputKindSensors`. +- `GamepadVibration.h` defines the vibration effects and per-gamepad state. + `GamepadVibration.cpp` calculates each preset directly into `GameInputRumbleParams` and applies it + via `IGameInputDevice::SetRumbleState`. The sample sends a zeroed rumble state when the title is + suspended or shut down. +- `GamepadHaptics.h` defines the WAV media item presented by the UI, while `GamepadHaptics.cpp` + handles media selection and playback. The lower-level `HapticsManager` helper wraps XAudio2 and + WASAPI for WAV-to-haptic streaming. +- 3D model rendering uses `ImGuiAtg::ModelViewer`, which renders the controller model into an + offscreen render target oriented by the device's sensor quaternion. +- The Focus Policy section, the custom WAV file picker, and the fullscreen toggle are desktop-only + and are compiled out on Xbox console. + +# Known issues / expectations + +- Motion sensor data (accelerometer, gyroscope, orientation) is currently only available on + controllers that report sensor support, such as the DualSense. +- The 3D controller model requires orientation sensor support; otherwise the section displays an + unsupported message. + +# Update history + +- 07/2026 -- Rewritten. Added a 3D controller model, audio-driven haptics, vibration presets, and ARM64 support. +- 04/2026 -- Added motion sensor readings for supported devices. +- 07/2025 -- Added support for GameInput v2.x on PC via the Microsoft.GameInput NuGet package. +- 03/2025 -- Added support for GameInput v1.x on PC via the Microsoft.GameInput NuGet package. +- 06/2022 -- Added support for GameInput on PC. +- 10/2018 -- Initial GDK release. # Privacy statement -When compiling and running a sample, the file name of the sample -executable will be sent to Microsoft to help track sample usage. To -opt-out of this data collection, you can remove the block of code in -Main.cpp labeled "Sample Usage Telemetry". +When compiling and running a sample, the file name of the sample executable will be sent to +Microsoft to help track sample usage. To opt-out of this data collection, you can remove the +block of code in Main.cpp labeled "Sample Usage Telemetry". -For more information about Microsoft's privacy policies in general, see -the [Microsoft Privacy Statement](https://privacy.microsoft.com/en-us/privacystatement/). +For more information about Microsoft's privacy policies in general, see the +[Microsoft Privacy Statement](https://privacy.microsoft.com/en-us/privacystatement/). diff --git a/Samples/System/Gamepad/readme_ja-jp.md b/Samples/System/Gamepad/readme_ja-jp.md deleted file mode 100644 index 28300fbc..00000000 --- a/Samples/System/Gamepad/readme_ja-jp.md +++ /dev/null @@ -1,45 +0,0 @@ -![](./media/image1.png) - -# Gamepad サンプル - -*このサンプルは Microsoft Game Development Kit (2020 年 6 月) と互換性があります* - -# 説明 - -このサンプルでは、Xbox One のゲームパッドからの入力を読み取る方法を示します。 - -![](./media/image3.png) - -# サンプルのビルド - -Xbox One 開発キットを使用している場合は、アクティブなソリューション プラットフォームを `Gaming.Xbox.XboxOne.x64` に設定します。 - -Xbox Series X|S を使用している場合は、アクティブなソリューション プラットフォームを `Gaming.Xbox.Scarlett.x64` に設定します。 - -PC の場合は、アクティブなソリューション プラットフォームを Gaming.Desktop.x64 に設定します。 **これには 2022 年 6 月以降の GDK が必要です**。 - -*詳細については、* *GDK ドキュメント*の「__サンプルの実行__」を参照してください。 - -# サンプルの使用方法 - -ボタンを押して表示を確認し、サムスティックとトリガーを動かして読み取り値を確認します。 - -# 実装メモ - -このサンプルでは、新しい GameInput API を使用して、サムスティックやトリガーなど、ゲームパッドから入力を読み取る方法を示します。 - -# バージョン履歴 - -- 2018 年 10 月: GDK の初期リリース - -- 2020 年 2 月: GameInput API の変更を更新しました。 - -- 2022 年 6 月: PC での GameInput のサポートを追加しました (2022 年 6 月 以降の GDK) - -# プライバシーにかんするせいめい - -サンプルをコンパイルして実行する場合、サンプルの使用状況を追跡するために、サンプルの実行可能ファイルのファイル名が Microsoft に送信されます。 このデータ コレクションからオプトアウトするには、Main.cpp の "サンプル使用状況テレメトリ" というラベルの付いたコードのブロックを削除します。 - -Microsoft のプライバシー ポリシー全般の詳細については、「[Microsoft のプライバシーに関する声明](https://privacy.microsoft.com/en-us/privacystatement/)」を参照してください。 - - diff --git a/Samples/System/Gamepad/readme_ko-kr.md b/Samples/System/Gamepad/readme_ko-kr.md deleted file mode 100644 index cd656862..00000000 --- a/Samples/System/Gamepad/readme_ko-kr.md +++ /dev/null @@ -1,45 +0,0 @@ -![](./media/image1.png) - -# 게임 패드 샘플 - -*이 샘플은 Microsoft 게임 개발 키트(2020년 6월)와 호환됩니다.* - -# 설명 - -이 샘플에서는 Xbox One 게임 패드에서 입력된 항목을 읽는 방법을 보여 줍니다. - -![](./media/image3.png) - -# 샘플 빌드 - -Xbox One 개발 키트를 사용하는 경우 활성 솔루션 플랫폼을 `Gaming.Xbox.XboxOne.x64`(으)로 설정합니다. - -Xbox Series X|S를 사용하는 경우 활성 솔루션 플랫폼을 `Gaming.Xbox.Scarlett.x64`(으)로 설정합니다. - -PC를 사용하는 경우 활성 솔루션 플랫폼을 Gaming.Desktop.x64로 설정합니다. **이를 위해서는 GDK 2022년 6월 버전 이상이**필요합니다. - -*GDK 설명서의* __샘플 실행__에서 *자세한 내용을 참고하세요.*  - -# 샘플 사용 - -버튼을 눌러 표시되는 것을 확인하고 엄지스틱과 트리거를 이동하여 판독값을 확인합니다. - -# 구현 참고 사항 - -이 샘플에서는 새로운 GameInput API를 사용하여 엄지스틱 및 트리거를 포함한 게임 패드에서 입력을 읽는 방법을 보여 줍니다. - -# 버전 기록 - -- 2018년 10월: 초기 GDK 릴리스 - -- 2020년 2월: GameInput API의 변경 내용이 업데이트 - -- 2022년 6월: PC에 GameInput에 대한 지원 추가(GDK 2022년 6월 버전 이상) - -# 개인정보처리방침 - -샘플을 컴파일하고 실행하는 경우 샘플 사용량을 추적할 수 있도록 샘플 실행 파일의 파일 이름이 Microsoft에 전송됩니다. 이 데이터 수집을 옵트아웃하려면 Main.cpp에서 "샘플 사용량 원격 분석"이라는 레이블이 지정된 코드 블록을 제거할 수 있습니다. - -일반적인 Microsoft의 개인 정보 정책에 대한 자세한 내용은 [Microsoft 개인정보처리방침](https://privacy.microsoft.com/en-us/privacystatement/)을 참조하세요. - - diff --git a/Samples/System/Gamepad/readme_zh-cn.md b/Samples/System/Gamepad/readme_zh-cn.md deleted file mode 100644 index d4330658..00000000 --- a/Samples/System/Gamepad/readme_zh-cn.md +++ /dev/null @@ -1,45 +0,0 @@ -![](./media/image1.png) - -# 游戏板示例 - -*此示例兼容于 Microsoft 游戏开发工具包(2020 年 6 月)* - -# 说明 - -此示例演示了如何通过 Xbox One 的游戏手柄读取输入 - -![](./media/image3.png) - -# 生成示例 - -如果使用 Xbox One 开发工具包,请将活动解决方案平台设置为 `Gaming.Xbox.XboxOne.x64`。 - -如果使用 Xbox Series X|S,请将可用解决方案平台设置为 `Gaming.Xbox.Scarlett.x64`。 - -对于电脑,可以将可用解决方案平台设置为 Gaming.Desktop.x64。 **这需要 2022 年 6 月 GDK 或更高版本**。 - -*有关详细信息,请参阅* *GDK 文档中的*__运行示例__。 - -# 使用示例 - -按下按钮可显示内容,移动控制杆和扳机可查看其读数。 - -# 实现说明 - -此示例演示如何使用新的 GameInput API 读取来自游戏手柄(包括控制杆和扳机键)的数据。 - -# 版本历史记录 - -- 2018 年 10 月: 初始 GDK 版本 - -- 2020 年 2 月: 针对 GameInput API 的更改进行了更新。 - -- 2022 年 6 月: 已添加对个人电脑上的 GameInput 的支持 (2022 年 6 月 GDK 或更高版本) - -# 隐私声明 - -在编译和运行示例时,将向 Microsoft 发送示例可执行文件的文件名以帮助跟踪示例使用情况。 若要选择退出此数据收集,你可以删除 Main.cpp 中标记为“示例使用遥测”的代码块。 - -有关 Microsoft 的一般隐私策略的详细信息,请参阅 [Microsoft 隐私声明](https://privacy.microsoft.com/en-us/privacystatement/)。 - - diff --git a/Samples/System/GamepadVibration/Assets/LargeLogo.png b/Samples/System/GamepadVibration/Assets/LargeLogo.png deleted file mode 100644 index 416dacd8..00000000 Binary files a/Samples/System/GamepadVibration/Assets/LargeLogo.png and /dev/null differ diff --git a/Samples/System/GamepadVibration/Assets/Logo.png b/Samples/System/GamepadVibration/Assets/Logo.png deleted file mode 100644 index 4d646675..00000000 Binary files a/Samples/System/GamepadVibration/Assets/Logo.png and /dev/null differ diff --git a/Samples/System/GamepadVibration/Assets/SmallLogo.png b/Samples/System/GamepadVibration/Assets/SmallLogo.png deleted file mode 100644 index df5aa71e..00000000 Binary files a/Samples/System/GamepadVibration/Assets/SmallLogo.png and /dev/null differ diff --git a/Samples/System/GamepadVibration/Assets/SplashScreen.png b/Samples/System/GamepadVibration/Assets/SplashScreen.png deleted file mode 100644 index f094c150..00000000 Binary files a/Samples/System/GamepadVibration/Assets/SplashScreen.png and /dev/null differ diff --git a/Samples/System/GamepadVibration/Assets/StoreLogo.png b/Samples/System/GamepadVibration/Assets/StoreLogo.png deleted file mode 100644 index f4407ee6..00000000 Binary files a/Samples/System/GamepadVibration/Assets/StoreLogo.png and /dev/null differ diff --git a/Samples/System/GamepadVibration/DeviceResources.cpp b/Samples/System/GamepadVibration/DeviceResources.cpp deleted file mode 100644 index f7084157..00000000 --- a/Samples/System/GamepadVibration/DeviceResources.cpp +++ /dev/null @@ -1,862 +0,0 @@ -// -// DeviceResources.cpp - A wrapper for the Direct3D 12/12.X device and swapchain -// - -#include "pch.h" -#include "DeviceResources.h" - -using namespace DirectX; -using namespace DX; - -using Microsoft::WRL::ComPtr; - -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wcovered-switch-default" -#pragma clang diagnostic ignored "-Wswitch-enum" -#endif - -#pragma warning(disable : 4061) - -#ifdef _GAMING_DESKTOP -namespace -{ - inline DXGI_FORMAT NoSRGB(DXGI_FORMAT fmt) noexcept - { - switch (fmt) - { - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: return DXGI_FORMAT_R8G8B8A8_UNORM; - case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8A8_UNORM; - case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8X8_UNORM; - default: return fmt; - } - } -} -#endif - -// Constructor for DeviceResources. -DeviceResources::DeviceResources( - DXGI_FORMAT backBufferFormat, - DXGI_FORMAT depthBufferFormat, - UINT backBufferCount, - unsigned int flags) noexcept(false) : - m_backBufferIndex(0), - m_fenceValues{}, -#ifdef _GAMING_XBOX - m_framePipelineToken{}, -#endif - m_rtvDescriptorSize(0), - m_screenViewport{}, - m_scissorRect{}, - m_backBufferFormat(backBufferFormat), - m_depthBufferFormat(depthBufferFormat), - m_backBufferCount(backBufferCount), - m_clearColor{}, - m_window(nullptr), - m_d3dFeatureLevel(D3D_FEATURE_LEVEL_11_0), - m_outputSize{ 0, 0, 1, 1 }, - m_options(flags), - m_deviceNotify(nullptr) -{ - if (backBufferCount < 2 || backBufferCount > MAX_BACK_BUFFER_COUNT) - { - throw std::out_of_range("invalid backBufferCount"); - } -} - -// Destructor for DeviceResources. -DeviceResources::~DeviceResources() -{ - // Ensure that the GPU is no longer referencing resources that are about to be destroyed. - WaitForGpu(); - -#ifdef _GAMING_XBOX - // Ensure we present a blank screen before cleaning up resources. - if (m_commandQueue) - { - std::ignore = m_commandQueue->PresentX(0, nullptr, nullptr); - } -#endif -} - -// Configures the Direct3D device, and stores handles to it and the device context. -void DeviceResources::CreateDeviceResources() -{ -#ifdef _GAMING_XBOX - - // Create the DX12 API device object. - D3D12XBOX_CREATE_DEVICE_PARAMETERS params = {}; - params.Version = D3D12_SDK_VERSION; - -#if defined(_DEBUG) - // Enable the debug layer. - params.ProcessDebugFlags = D3D12_PROCESS_DEBUG_FLAG_DEBUG_LAYER_ENABLED; -#elif defined(PROFILE) - // Enable the instrumented driver. - params.ProcessDebugFlags = D3D12XBOX_PROCESS_DEBUG_FLAG_INSTRUMENTED; -#endif - - params.GraphicsCommandQueueRingSizeBytes = static_cast(D3D12XBOX_DEFAULT_SIZE_BYTES); - params.DisableGeometryShaderAllocations = (m_options & c_GeometryShaders) ? FALSE : TRUE; - params.DisableTessellationShaderAllocations = (m_options & c_TessellationShaders) ? FALSE : TRUE; - -#ifdef _GAMING_XBOX_SCARLETT - params.DisableDXR = (m_options & c_EnableDXR) ? FALSE : TRUE; - params.CreateDeviceFlags = D3D12XBOX_CREATE_DEVICE_FLAG_NONE; - -#if (_GRDK_VER >= 0x585D070E /* GXDK Edition 221000 */) - if (m_options & c_AmplificationShaders) - { - params.AmplificationShaderIndirectArgsBufferSize = static_cast(D3D12XBOX_DEFAULT_SIZE_BYTES); - params.AmplificationShaderPayloadBufferSize = static_cast(D3D12XBOX_DEFAULT_SIZE_BYTES); - } -#endif -#else // _GAMING_XBOX_XBOXONE - m_options &= ~(c_AmplificationShaders | c_EnableDXR); -#endif - - HRESULT hr = D3D12XboxCreateDevice( - nullptr, - ¶ms, - IID_GRAPHICS_PPV_ARGS(m_d3dDevice.ReleaseAndGetAddressOf())); -#ifdef _DEBUG - if (hr == D3D12_ERROR_DRIVER_VERSION_MISMATCH) - { -#ifdef _GAMING_XBOX_SCARLETT - OutputDebugStringA("ERROR: Running a d3d12_xs.lib (Xbox Series X|S) linked binary on an Xbox One is not supported\n"); -#else - OutputDebugStringA("ERROR: Running a d3d12_x.lib (Xbox One) linked binary on a Xbox Series X|S in 'Scarlett' mode is not supported\n"); -#endif - } -#endif - ThrowIfFailed(hr); - - m_d3dDevice->SetName(L"DeviceResources"); - - m_d3dFeatureLevel = D3D_FEATURE_LEVEL_12_0; - -#else // _GAMING_DESKTOP - - DWORD dxgiFactoryFlags = 0; - -#if defined(_DEBUG) - // Enable the debug layer (requires the Graphics Tools "optional feature"). - // - // NOTE: Enabling the debug layer after device creation will invalidate the active device. - { - ComPtr debugController; - if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(debugController.GetAddressOf())))) - { - debugController->EnableDebugLayer(); - } - else - { - OutputDebugStringA("WARNING: Direct3D Debug Device is not available\n"); - } - - ComPtr dxgiInfoQueue; - if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(dxgiInfoQueue.GetAddressOf())))) - { - dxgiFactoryFlags = DXGI_CREATE_FACTORY_DEBUG; - - dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true); - dxgiInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true); - - DXGI_INFO_QUEUE_MESSAGE_ID hide[] = - { - 80 /* IDXGISwapChain::GetContainingOutput: The swapchain's adapter does not control the output on which the swapchain's window resides. */, - }; - DXGI_INFO_QUEUE_FILTER filter = {}; - filter.DenyList.NumIDs = static_cast(std::size(hide)); - filter.DenyList.pIDList = hide; - dxgiInfoQueue->AddStorageFilterEntries(DXGI_DEBUG_DXGI, &filter); - } - } -#endif - - ThrowIfFailed(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf()))); - - ComPtr adapter; - GetAdapter(adapter.GetAddressOf()); - - // Create the DX12 API device object. - HRESULT hr = D3D12CreateDevice( - adapter.Get(), - D3D_FEATURE_LEVEL_11_0, - IID_PPV_ARGS(m_d3dDevice.ReleaseAndGetAddressOf()) - ); - ThrowIfFailed(hr); - - m_d3dDevice->SetName(L"DeviceResources"); - -#ifndef NDEBUG - // Configure debug device (if active). - ComPtr d3dInfoQueue; - if (SUCCEEDED(m_d3dDevice.As(&d3dInfoQueue))) - { -#ifdef _DEBUG - d3dInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true); - d3dInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true); -#endif - D3D12_MESSAGE_ID hide[] = - { - D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE, - D3D12_MESSAGE_ID_UNMAP_INVALID_NULLRANGE, - // Workarounds for debug layer issues on hybrid-graphics systems - D3D12_MESSAGE_ID_EXECUTECOMMANDLISTS_WRONGSWAPCHAINBUFFERREFERENCE, - D3D12_MESSAGE_ID_RESOURCE_BARRIER_MISMATCHING_COMMAND_LIST_TYPE, - }; - D3D12_INFO_QUEUE_FILTER filter = {}; - filter.DenyList.NumIDs = static_cast(std::size(hide)); - filter.DenyList.pIDList = hide; - d3dInfoQueue->AddStorageFilterEntries(&filter); - } -#endif - - // Determine maximum supported feature level for this device - static const D3D_FEATURE_LEVEL s_featureLevels[] = - { -#if defined(NTDDI_WIN10_FE) && (NTDDI_VERSION >= NTDDI_WIN10_FE) - D3D_FEATURE_LEVEL_12_2, -#endif - D3D_FEATURE_LEVEL_12_1, - D3D_FEATURE_LEVEL_12_0, - D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0, - }; - - D3D12_FEATURE_DATA_FEATURE_LEVELS featLevels = - { - static_cast(std::size(s_featureLevels)), s_featureLevels, D3D_FEATURE_LEVEL_11_0 - }; - - hr = m_d3dDevice->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &featLevels, sizeof(featLevels)); - if (SUCCEEDED(hr)) - { - m_d3dFeatureLevel = featLevels.MaxSupportedFeatureLevel; - } - else - { - m_d3dFeatureLevel = D3D_FEATURE_LEVEL_11_0; - } - - // Check device options. - if (m_options & c_AmplificationShaders) - { - D3D12_FEATURE_DATA_D3D12_OPTIONS7 devopt = {}; - if (FAILED(m_d3dDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &devopt, sizeof(devopt)))) - { - devopt = {}; - } - if (devopt.MeshShaderTier == D3D12_MESH_SHADER_TIER_NOT_SUPPORTED) - { - m_options &= ~c_AmplificationShaders; - } - } - - if (m_options & c_EnableDXR) - { - D3D12_FEATURE_DATA_D3D12_OPTIONS5 devopt = {}; - if (FAILED(m_d3dDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &devopt, sizeof(devopt)))) - { - devopt = {}; - } - if (devopt.RaytracingTier == D3D12_RAYTRACING_TIER_NOT_SUPPORTED) - { - m_options &= ~c_EnableDXR; - } - } - -#endif - - // Create the command queue. - D3D12_COMMAND_QUEUE_DESC queueDesc = {}; - queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - - ThrowIfFailed(m_d3dDevice->CreateCommandQueue(&queueDesc, IID_GRAPHICS_PPV_ARGS(m_commandQueue.ReleaseAndGetAddressOf()))); - - m_commandQueue->SetName(L"DeviceResources"); - - // Create descriptor heaps for render target views and depth stencil views. - D3D12_DESCRIPTOR_HEAP_DESC rtvDescriptorHeapDesc = {}; - rtvDescriptorHeapDesc.NumDescriptors = m_backBufferCount; - rtvDescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; - - ThrowIfFailed(m_d3dDevice->CreateDescriptorHeap(&rtvDescriptorHeapDesc, IID_GRAPHICS_PPV_ARGS(m_rtvDescriptorHeap.ReleaseAndGetAddressOf()))); - - m_rtvDescriptorHeap->SetName(L"DeviceResources"); - - m_rtvDescriptorSize = m_d3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); - - if (m_depthBufferFormat != DXGI_FORMAT_UNKNOWN) - { - D3D12_DESCRIPTOR_HEAP_DESC dsvDescriptorHeapDesc = {}; - dsvDescriptorHeapDesc.NumDescriptors = 1; - dsvDescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; - - ThrowIfFailed(m_d3dDevice->CreateDescriptorHeap(&dsvDescriptorHeapDesc, IID_GRAPHICS_PPV_ARGS(m_dsvDescriptorHeap.ReleaseAndGetAddressOf()))); - - m_dsvDescriptorHeap->SetName(L"DeviceResources"); - } - - // Create a command allocator for each back buffer that will be rendered to. - for (UINT n = 0; n < m_backBufferCount; n++) - { - ThrowIfFailed(m_d3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_GRAPHICS_PPV_ARGS(m_commandAllocators[n].ReleaseAndGetAddressOf()))); - - wchar_t name[25] = {}; - swprintf_s(name, L"Render target %u", n); - m_commandAllocators[n]->SetName(name); - } - - // Create a command list for recording graphics commands. - ThrowIfFailed(m_d3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[0].Get(), nullptr, IID_GRAPHICS_PPV_ARGS(m_commandList.ReleaseAndGetAddressOf()))); - ThrowIfFailed(m_commandList->Close()); - - m_commandList->SetName(L"DeviceResources"); - - // Create a fence for tracking GPU execution progress. - ThrowIfFailed(m_d3dDevice->CreateFence(m_fenceValues[m_backBufferIndex], D3D12_FENCE_FLAG_NONE, IID_GRAPHICS_PPV_ARGS(m_fence.ReleaseAndGetAddressOf()))); - m_fenceValues[m_backBufferIndex]++; - - m_fence->SetName(L"DeviceResources"); - - m_fenceEvent.Attach(CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE)); - if (!m_fenceEvent.IsValid()) - { - throw std::system_error(std::error_code(static_cast(GetLastError()), std::system_category()), "CreateEventEx"); - } - -#ifdef _GAMING_XBOX - RegisterFrameEvents(); -#endif -} - -// These resources need to be recreated every time the window size is changed. -void DeviceResources::CreateWindowSizeDependentResources() -{ - if (!m_window) - { - throw std::logic_error("Call SetWindow with a valid Win32 window handle"); - } - - // Wait until all previous GPU work is complete. - WaitForGpu(); - -#ifdef _GAMING_XBOX - // Ensure we present a blank screen before cleaning up resources. - ThrowIfFailed(m_commandQueue->PresentX(0, nullptr, nullptr)); -#endif - - // Release resources that are tied to the swap chain and update fence values. - for (UINT n = 0; n < m_backBufferCount; n++) - { - m_renderTargets[n].Reset(); - m_fenceValues[n] = m_fenceValues[m_backBufferIndex]; - } - - // Determine the render target size in pixels. - const UINT backBufferWidth = std::max(static_cast(m_outputSize.right - m_outputSize.left), 1u); - const UINT backBufferHeight = std::max(static_cast(m_outputSize.bottom - m_outputSize.top), 1u); - -#ifdef _GAMING_XBOX - - // Obtain the back buffers for this window which will be the final render targets - // and create render target views for each of them. - const CD3DX12_HEAP_PROPERTIES swapChainHeapProperties(D3D12_HEAP_TYPE_DEFAULT); - - D3D12_RESOURCE_DESC swapChainBufferDesc = CD3DX12_RESOURCE_DESC::Tex2D( - m_backBufferFormat, - backBufferWidth, - backBufferHeight, - 1, // This resource has only one texture. - 1 // Use a single mipmap level. - ); - swapChainBufferDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; - - const CD3DX12_CLEAR_VALUE swapChainOptimizedClearValue(m_backBufferFormat, m_clearColor); - - for (UINT n = 0; n < m_backBufferCount; n++) - { - ThrowIfFailed(m_d3dDevice->CreateCommittedResource( - &swapChainHeapProperties, - D3D12_HEAP_FLAG_ALLOW_DISPLAY, - &swapChainBufferDesc, - D3D12_RESOURCE_STATE_PRESENT, - &swapChainOptimizedClearValue, - IID_GRAPHICS_PPV_ARGS(m_renderTargets[n].GetAddressOf()))); - - wchar_t name[25] = {}; - swprintf_s(name, L"Render target %u", n); - m_renderTargets[n]->SetName(name); - - D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; - rtvDesc.Format = m_backBufferFormat; - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; - - const CD3DX12_CPU_DESCRIPTOR_HANDLE rtvDescriptor( - m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), - static_cast(n), m_rtvDescriptorSize); - m_d3dDevice->CreateRenderTargetView(m_renderTargets[n].Get(), &rtvDesc, rtvDescriptor); - } - - // Reset the index to the current back buffer. - m_backBufferIndex = 0; - -#else // _GAMING_DESKTOP - - const DXGI_FORMAT backBufferFormat = NoSRGB(m_backBufferFormat); - - // If the swap chain already exists, resize it, otherwise create one. - if (m_swapChain) - { - // If the swap chain already exists, resize it. - HRESULT hr = m_swapChain->ResizeBuffers( - m_backBufferCount, - backBufferWidth, - backBufferHeight, - backBufferFormat, - 0 - ); - - if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) - { -#ifdef _DEBUG - char buff[64] = {}; - sprintf_s(buff, "Device Lost on ResizeBuffers: Reason code 0x%08X\n", - static_cast((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr)); - OutputDebugStringA(buff); -#endif - // 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 - { - ThrowIfFailed(hr); - } - } - else - { - // Create a descriptor for the swap chain. - DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; - swapChainDesc.Width = backBufferWidth; - swapChainDesc.Height = backBufferHeight; - swapChainDesc.Format = backBufferFormat; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapChainDesc.BufferCount = m_backBufferCount; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.Scaling = DXGI_SCALING_STRETCH; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; - - DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsSwapChainDesc = {}; - fsSwapChainDesc.Windowed = TRUE; - - // Create a swap chain for the window. - ComPtr swapChain; - ThrowIfFailed(m_dxgiFactory->CreateSwapChainForHwnd( - m_commandQueue.Get(), - m_window, - &swapChainDesc, - &fsSwapChainDesc, - nullptr, - swapChain.GetAddressOf() - )); - - ThrowIfFailed(swapChain.As(&m_swapChain)); - - // This class does not support exclusive full-screen mode and prevents DXGI from responding to the ALT+ENTER shortcut - ThrowIfFailed(m_dxgiFactory->MakeWindowAssociation(m_window, DXGI_MWA_NO_ALT_ENTER)); - } - - // Obtain the back buffers for this window which will be the final render targets - // and create render target views for each of them. - for (UINT n = 0; n < m_backBufferCount; n++) - { - ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(m_renderTargets[n].GetAddressOf()))); - - wchar_t name[25] = {}; - swprintf_s(name, L"Render target %u", n); - m_renderTargets[n]->SetName(name); - - D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; - rtvDesc.Format = m_backBufferFormat; - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; - - const CD3DX12_CPU_DESCRIPTOR_HANDLE rtvDescriptor( - m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), - static_cast(n), m_rtvDescriptorSize); - m_d3dDevice->CreateRenderTargetView(m_renderTargets[n].Get(), &rtvDesc, rtvDescriptor); - } - - // Reset the index to the current back buffer. - m_backBufferIndex = m_swapChain->GetCurrentBackBufferIndex(); - -#endif - - if (m_depthBufferFormat != DXGI_FORMAT_UNKNOWN) - { - // Allocate a 2-D surface as the depth/stencil buffer and create a depth/stencil view - // on this surface. - const CD3DX12_HEAP_PROPERTIES depthHeapProperties(D3D12_HEAP_TYPE_DEFAULT); - - D3D12_RESOURCE_DESC depthStencilDesc = CD3DX12_RESOURCE_DESC::Tex2D( - m_depthBufferFormat, - backBufferWidth, - backBufferHeight, - 1, // Use a single array entry. - 1 // Use a single mipmap level. - ); - depthStencilDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; - - const CD3DX12_CLEAR_VALUE depthOptimizedClearValue(m_depthBufferFormat, (m_options & c_ReverseDepth) ? 0.0f : 1.0f, 0u); - - ThrowIfFailed(m_d3dDevice->CreateCommittedResource( - &depthHeapProperties, - D3D12_HEAP_FLAG_NONE, - &depthStencilDesc, - D3D12_RESOURCE_STATE_DEPTH_WRITE, - &depthOptimizedClearValue, - IID_GRAPHICS_PPV_ARGS(m_depthStencil.ReleaseAndGetAddressOf()) - )); - - m_depthStencil->SetName(L"Depth stencil"); - - D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; - dsvDesc.Format = m_depthBufferFormat; - dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; - - m_d3dDevice->CreateDepthStencilView(m_depthStencil.Get(), &dsvDesc, m_dsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart()); - } - - // Set the 3D rendering viewport and scissor rectangle to target the entire window. - m_screenViewport.TopLeftX = m_screenViewport.TopLeftY = 0.f; - m_screenViewport.Width = static_cast(backBufferWidth); - m_screenViewport.Height = static_cast(backBufferHeight); - m_screenViewport.MinDepth = D3D12_MIN_DEPTH; - m_screenViewport.MaxDepth = D3D12_MAX_DEPTH; - - m_scissorRect.left = m_scissorRect.top = 0; - m_scissorRect.right = static_cast(backBufferWidth); - m_scissorRect.bottom = static_cast(backBufferHeight); -} - -// This method is called when the Win32 window is created (or re-created). -void DeviceResources::SetWindow(HWND window, int width, int height) noexcept -{ - m_window = window; - - m_outputSize.left = m_outputSize.top = 0; - m_outputSize.right = width; - m_outputSize.bottom = height; -} - -// This method is called when the Win32 window changes size. -bool DeviceResources::WindowSizeChanged(int width, int height) -{ - if (!m_window) - return false; - - RECT newRc; - newRc.left = newRc.top = 0; - newRc.right = width; - newRc.bottom = height; - if (newRc.right == m_outputSize.right && newRc.bottom == m_outputSize.bottom) - { - return false; - } - - m_outputSize = newRc; - CreateWindowSizeDependentResources(); - return true; -} - -// Recreate all device resources and set them back to the current state. -void DeviceResources::HandleDeviceLost() -{ -#ifdef _GAMING_DESKTOP - if (m_deviceNotify) - { - m_deviceNotify->OnDeviceLost(); - } - - for (UINT n = 0; n < m_backBufferCount; n++) - { - m_commandAllocators[n].Reset(); - m_renderTargets[n].Reset(); - } - - m_depthStencil.Reset(); - m_commandQueue.Reset(); - m_commandList.Reset(); - m_fence.Reset(); - m_rtvDescriptorHeap.Reset(); - m_dsvDescriptorHeap.Reset(); - m_swapChain.Reset(); - m_d3dDevice.Reset(); - m_dxgiFactory.Reset(); - -#ifdef _DEBUG - { - ComPtr dxgiDebug; - if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug)))) - { - dxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_IGNORE_INTERNAL)); - } - } -#endif - - CreateDeviceResources(); - CreateWindowSizeDependentResources(); - - if (m_deviceNotify) - { - m_deviceNotify->OnDeviceRestored(); - } -#endif -} - -// Prepare the command list and render target for rendering. -void DeviceResources::Prepare(D3D12_RESOURCE_STATES beforeState, D3D12_RESOURCE_STATES afterState) -{ - // Reset command list and allocator. - ThrowIfFailed(m_commandAllocators[m_backBufferIndex]->Reset()); - ThrowIfFailed(m_commandList->Reset(m_commandAllocators[m_backBufferIndex].Get(), nullptr)); - - if (beforeState != afterState) - { - // Transition the render target into the correct state to allow for drawing into it. - const D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition( - m_renderTargets[m_backBufferIndex].Get(), - beforeState, afterState); - m_commandList->ResourceBarrier(1, &barrier); - } -} - -// Present the contents of the swap chain to the screen. -void DeviceResources::Present(D3D12_RESOURCE_STATES beforeState) -{ - if (beforeState != D3D12_RESOURCE_STATE_PRESENT) - { - // Transition the render target to the state that allows it to be presented to the display. - const D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition( - m_renderTargets[m_backBufferIndex].Get(), - beforeState, D3D12_RESOURCE_STATE_PRESENT); - m_commandList->ResourceBarrier(1, &barrier); - } - - // Send the command list off to the GPU for processing. - ThrowIfFailed(m_commandList->Close()); - m_commandQueue->ExecuteCommandLists(1, CommandListCast(m_commandList.GetAddressOf())); - -#ifdef _GAMING_XBOX - - // Present the backbuffer using the PresentX API. - D3D12XBOX_PRESENT_PLANE_PARAMETERS planeParameters = {}; - planeParameters.Token = m_framePipelineToken; - planeParameters.ResourceCount = 1; - planeParameters.ppResources = m_renderTargets[m_backBufferIndex].GetAddressOf(); - - ThrowIfFailed( - m_commandQueue->PresentX(1, &planeParameters, nullptr) - ); - - // Xbox apps do not need to handle DXGI_ERROR_DEVICE_REMOVED or DXGI_ERROR_DEVICE_RESET. - - // Update the back buffer index. - const UINT64 currentFenceValue = m_fenceValues[m_backBufferIndex]; - m_backBufferIndex = (m_backBufferIndex + 1) % m_backBufferCount; - m_fenceValues[m_backBufferIndex] = currentFenceValue; - -#else // _GAMING_DESKTOP - - // 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. - HRESULT hr = m_swapChain->Present(1, 0); - - // If the device was reset we must completely reinitialize the renderer. - if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) - { -#ifdef _DEBUG - char buff[64] = {}; - sprintf_s(buff, "Device Lost on Present: Reason code 0x%08X\n", - static_cast((hr == DXGI_ERROR_DEVICE_REMOVED) ? m_d3dDevice->GetDeviceRemovedReason() : hr)); - OutputDebugStringA(buff); -#endif - HandleDeviceLost(); - } - else - { - ThrowIfFailed(hr); - } - - MoveToNextFrame(); -#endif -} - -// Handle GPU suspend/resume -void DeviceResources::Suspend() -{ -#ifdef _GAMING_XBOX - m_commandQueue->SuspendX(0); -#endif -} - -void DeviceResources::Resume() -{ -#ifdef _GAMING_XBOX - m_commandQueue->ResumeX(); - - RegisterFrameEvents(); -#endif -} - -// Wait for pending GPU work to complete. -void DeviceResources::WaitForGpu() noexcept -{ - if (m_commandQueue && m_fence && m_fenceEvent.IsValid()) - { - // Schedule a Signal command in the GPU queue. - const UINT64 fenceValue = m_fenceValues[m_backBufferIndex]; - if (SUCCEEDED(m_commandQueue->Signal(m_fence.Get(), fenceValue))) - { - // Wait until the Signal has been processed. - if (SUCCEEDED(m_fence->SetEventOnCompletion(fenceValue, m_fenceEvent.Get()))) - { - std::ignore = WaitForSingleObjectEx(m_fenceEvent.Get(), INFINITE, FALSE); - - // Increment the fence value for the current frame. - m_fenceValues[m_backBufferIndex]++; - } - } - } -} - -#ifdef _GAMING_XBOX -// For PresentX rendering, we should wait for the origin event just before processing input. -void DeviceResources::WaitForOrigin() -{ - // Wait until frame start is signaled - m_framePipelineToken = D3D12XBOX_FRAME_PIPELINE_TOKEN_NULL; - ThrowIfFailed(m_d3dDevice->WaitFrameEventX( - D3D12XBOX_FRAME_EVENT_ORIGIN, - INFINITE, - nullptr, - D3D12XBOX_WAIT_FRAME_EVENT_FLAG_NONE, - &m_framePipelineToken)); -} - -// Set frame interval and register for frame events -void DeviceResources::RegisterFrameEvents() -{ - // First, retrieve the underlying DXGI device from the D3D device. - ComPtr dxgiDevice; - ThrowIfFailed(m_d3dDevice.As(&dxgiDevice)); - - // Identify the physical adapter (GPU or card) this device is running on. - ComPtr dxgiAdapter; - ThrowIfFailed(dxgiDevice->GetAdapter(dxgiAdapter.GetAddressOf())); - - // Retrieve the outputs for the adapter. - ComPtr dxgiOutput; - ThrowIfFailed(dxgiAdapter->EnumOutputs(0, dxgiOutput.GetAddressOf())); - - // Set frame interval and register for frame events - ThrowIfFailed(m_d3dDevice->SetFrameIntervalX( - dxgiOutput.Get(), - D3D12XBOX_FRAME_INTERVAL_60_HZ, - m_backBufferCount - 1u /* Allow n-1 frames of latency */, - D3D12XBOX_FRAME_INTERVAL_FLAG_NONE)); - - ThrowIfFailed(m_d3dDevice->ScheduleFrameEventX( - D3D12XBOX_FRAME_EVENT_ORIGIN, - 0U, - nullptr, - D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE)); -} - -#else // _GAMING_DESKTOP - -// Prepare to render the next frame. -void DeviceResources::MoveToNextFrame() -{ - // Schedule a Signal command in the queue. - const UINT64 currentFenceValue = m_fenceValues[m_backBufferIndex]; - ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), currentFenceValue)); - - // Update the back buffer index. - m_backBufferIndex = m_swapChain->GetCurrentBackBufferIndex(); - - // If the next frame is not ready to be rendered yet, wait until it is ready. - if (m_fence->GetCompletedValue() < m_fenceValues[m_backBufferIndex]) - { - ThrowIfFailed(m_fence->SetEventOnCompletion(m_fenceValues[m_backBufferIndex], m_fenceEvent.Get())); - std::ignore = WaitForSingleObjectEx(m_fenceEvent.Get(), INFINITE, FALSE); - } - - // Set the fence value for the next frame. - m_fenceValues[m_backBufferIndex] = currentFenceValue + 1; -} - -// This method acquires the first available hardware adapter that supports Direct3D 12. -// If no such adapter can be found, try WARP. Otherwise throw an exception. -void DeviceResources::GetAdapter(IDXGIAdapter1** ppAdapter) -{ - *ppAdapter = nullptr; - - ComPtr adapter; - for (UINT adapterIndex = 0; - SUCCEEDED(m_dxgiFactory->EnumAdapterByGpuPreference( - adapterIndex, - DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, - IID_PPV_ARGS(adapter.ReleaseAndGetAddressOf()))); - adapterIndex++) - { - DXGI_ADAPTER_DESC1 desc; - ThrowIfFailed(adapter->GetDesc1(&desc)); - - if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) - { - // Don't select the Basic Render Driver adapter. - continue; - } - - // Check to see if the adapter supports Direct3D 12, but don't create the actual device yet. - if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), nullptr))) - { -#ifdef _DEBUG - wchar_t buff[256] = {}; - swprintf_s(buff, L"Direct3D Adapter (%u): VID:%04X, PID:%04X - %ls\n", adapterIndex, desc.VendorId, desc.DeviceId, desc.Description); - OutputDebugStringW(buff); -#endif - break; - } - } - -#if !defined(NDEBUG) - if (!adapter) - { - // Try WARP12 instead - if (FAILED(m_dxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(adapter.ReleaseAndGetAddressOf())))) - { - throw std::runtime_error("WARP12 not available. Enable the 'Graphics Tools' optional feature"); - } - - OutputDebugStringA("Direct3D Adapter - WARP12\n"); - } -#endif - - if (!adapter) - { - throw std::runtime_error("No Direct3D 12 device found"); - } - - *ppAdapter = adapter.Detach(); -} -#endif diff --git a/Samples/System/GamepadVibration/DeviceResources.h b/Samples/System/GamepadVibration/DeviceResources.h deleted file mode 100644 index 590f30db..00000000 --- a/Samples/System/GamepadVibration/DeviceResources.h +++ /dev/null @@ -1,153 +0,0 @@ -// -// DeviceResources.h - A wrapper for the Direct3D 12/12.X device and swapchain -// - -#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; - - protected: - ~IDeviceNotify() = default; - }; - - // Controls all the DirectX device resources. - class DeviceResources - { - public: - static constexpr unsigned int c_ReverseDepth = 0x1; - static constexpr unsigned int c_GeometryShaders = 0x2; - static constexpr unsigned int c_TessellationShaders = 0x4; - static constexpr unsigned int c_AmplificationShaders = 0x8; - static constexpr unsigned int c_EnableDXR = 0x10; - - DeviceResources(DXGI_FORMAT backBufferFormat = DXGI_FORMAT_B8G8R8A8_UNORM, - DXGI_FORMAT depthBufferFormat = DXGI_FORMAT_D32_FLOAT, - UINT backBufferCount = 2, - unsigned int flags = 0) noexcept(false); - ~DeviceResources(); - - DeviceResources(DeviceResources&&) = default; - DeviceResources& operator= (DeviceResources&&) = default; - - DeviceResources(DeviceResources const&) = delete; - DeviceResources& operator= (DeviceResources const&) = delete; - - void CreateDeviceResources(); - void CreateWindowSizeDependentResources(); - void SetWindow(HWND window, int width, int height) noexcept; - bool WindowSizeChanged(int width, int height); - void HandleDeviceLost(); - void RegisterDeviceNotify(IDeviceNotify* deviceNotify) noexcept { m_deviceNotify = deviceNotify; } - void Prepare(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_PRESENT, - D3D12_RESOURCE_STATES afterState = D3D12_RESOURCE_STATE_RENDER_TARGET); - void Present(D3D12_RESOURCE_STATES beforeState = D3D12_RESOURCE_STATE_RENDER_TARGET); - void Suspend(); - void Resume(); - void WaitForGpu() noexcept; -#ifdef _GAMING_XBOX - void WaitForOrigin(); -#endif - - // Direct3D Properties. - void SetClearColor(_In_reads_(4) const float* rgba) noexcept { memcpy(m_clearColor, rgba, sizeof(m_clearColor)); } - - // Device Accessors. - RECT GetOutputSize() const noexcept { return m_outputSize; } - - // Direct3D Accessors. - auto GetD3DDevice() const noexcept { return m_d3dDevice.Get(); } -#ifdef _GAMING_DESKTOP - auto GetSwapChain() const noexcept { return m_swapChain.Get(); } - auto GetDXGIFactory() const noexcept { return m_dxgiFactory.Get(); } -#endif - HWND GetWindow() const noexcept { return m_window; } - D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const noexcept { return m_d3dFeatureLevel; } - ID3D12Resource* GetRenderTarget() const noexcept { return m_renderTargets[m_backBufferIndex].Get(); } - ID3D12Resource* GetDepthStencil() const noexcept { return m_depthStencil.Get(); } - ID3D12CommandQueue* GetCommandQueue() const noexcept { return m_commandQueue.Get(); } - ID3D12CommandAllocator* GetCommandAllocator() const noexcept { return m_commandAllocators[m_backBufferIndex].Get(); } - auto GetCommandList() const noexcept { return m_commandList.Get(); } - DXGI_FORMAT GetBackBufferFormat() const noexcept { return m_backBufferFormat; } - DXGI_FORMAT GetDepthBufferFormat() const noexcept { return m_depthBufferFormat; } - D3D12_VIEWPORT GetScreenViewport() const noexcept { return m_screenViewport; } - D3D12_RECT GetScissorRect() const noexcept { return m_scissorRect; } - UINT GetCurrentFrameIndex() const noexcept { return m_backBufferIndex; } - UINT GetBackBufferCount() const noexcept { return m_backBufferCount; } - unsigned int GetDeviceOptions() const noexcept { return m_options; } - - CD3DX12_CPU_DESCRIPTOR_HANDLE GetRenderTargetView() const noexcept - { - return CD3DX12_CPU_DESCRIPTOR_HANDLE( - m_rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), - static_cast(m_backBufferIndex), m_rtvDescriptorSize); - } - CD3DX12_CPU_DESCRIPTOR_HANDLE GetDepthStencilView() const noexcept - { - return CD3DX12_CPU_DESCRIPTOR_HANDLE(m_dsvDescriptorHeap->GetCPUDescriptorHandleForHeapStart()); - } - - private: -#ifdef _GAMING_XBOX - void RegisterFrameEvents(); -#else - void MoveToNextFrame(); - void GetAdapter(IDXGIAdapter1** ppAdapter); -#endif - - static constexpr size_t MAX_BACK_BUFFER_COUNT = 3; - - UINT m_backBufferIndex; - - // Direct3D objects. - Microsoft::WRL::ComPtr m_d3dDevice; - Microsoft::WRL::ComPtr m_commandList; - Microsoft::WRL::ComPtr m_commandQueue; - Microsoft::WRL::ComPtr m_commandAllocators[MAX_BACK_BUFFER_COUNT]; - - // Swap chain objects. -#ifdef _GAMING_DESKTOP - Microsoft::WRL::ComPtr m_dxgiFactory; - Microsoft::WRL::ComPtr m_swapChain; -#endif - Microsoft::WRL::ComPtr m_renderTargets[MAX_BACK_BUFFER_COUNT]; - Microsoft::WRL::ComPtr m_depthStencil; - - // Presentation fence objects. - Microsoft::WRL::ComPtr m_fence; - UINT64 m_fenceValues[MAX_BACK_BUFFER_COUNT]; - Microsoft::WRL::Wrappers::Event m_fenceEvent; -#ifdef _GAMING_XBOX - D3D12XBOX_FRAME_PIPELINE_TOKEN m_framePipelineToken; -#endif - - // Direct3D rendering objects. - Microsoft::WRL::ComPtr m_rtvDescriptorHeap; - Microsoft::WRL::ComPtr m_dsvDescriptorHeap; - UINT m_rtvDescriptorSize; - D3D12_VIEWPORT m_screenViewport; - D3D12_RECT m_scissorRect; - - // Direct3D properties. - DXGI_FORMAT m_backBufferFormat; - DXGI_FORMAT m_depthBufferFormat; - UINT m_backBufferCount; - float m_clearColor[4]; - - // Cached device properties. - HWND m_window; - D3D_FEATURE_LEVEL m_d3dFeatureLevel; - RECT m_outputSize; - - // DeviceResources options (see flags above) - unsigned int m_options; - - // The IDeviceNotify can be held directly as it owns the DeviceResources. - IDeviceNotify* m_deviceNotify; - }; -} diff --git a/Samples/System/GamepadVibration/GamepadVibration.cpp b/Samples/System/GamepadVibration/GamepadVibration.cpp deleted file mode 100644 index 04b7ed1e..00000000 --- a/Samples/System/GamepadVibration/GamepadVibration.cpp +++ /dev/null @@ -1,622 +0,0 @@ -//-------------------------------------------------------------------------------------- -// GamepadVibration.cpp -// -// Advanced Technology Group (ATG) -// Copyright (C) Microsoft Corporation. All rights reserved. -//-------------------------------------------------------------------------------------- - -#include "pch.h" -#include "GamepadVibration.h" - -#include "ATGColors.h" -#include "ControllerFont.h" -#include "FindMedia.h" - -extern void ExitSample() noexcept; - -using namespace DirectX; -using namespace DirectX::SimpleMath; - -using Microsoft::WRL::ComPtr; - -namespace -{ - const wchar_t* c_TRIGGER_EFFECT_NAME_TEXT[Sample::TRIGGEREFFECTS_MAX] = - { - L"\n", - L"\n", - L"\n", - L"\n", - L"\n" - }; - - const wchar_t* c_TRIGGER_EFFECT_DESC_TEXT[Sample::TRIGGEREFFECTS_MAX] = - { - L"Use the [LT] and [RT] to test the feedback\n" - L"function of the gamepad. The envelope is set based on\n" - L"the trigger position. The more you pull the triggers,\n" - L"the more feedback you will feel.", - - L"Impulse triggers can provide feedback about the environment.\n" - L"Assuming the player is driving a car, this example uses\n" - L"the impulse triggers to inform a flat tire on the left side.", - - L"Demonstrates how impulse triggers can be combined with the\n" - L"vibration motors to simulate weapon firing and recoil.\n" - L"Press the [LT] to activate the effect.", - - L"Impulse triggers can relay information about the player\'s\n" - L"in-game representation. Here we relay the character\'s\n" - L"heartbeat, which can be used to let the player know that\n" - L"their character is exhausted.", - - L"Impulse triggers can relay information external to the\n" - L"player. This example use the impulse triggers to simulate\n" - L"footsteps which could indicate the presence of a nearby\n" - L"character." - }; - - uint32_t flatTireLeftTriggerDurations[] = { 33, 80, 16 }; - float flatTireLeftTriggerLevels[] = { 0.8f, 0.0f, 0.0f }; - - uint32_t gunWithRecoilLeftTriggerDurations[] = { 20, 10, 90, 10000 }; - float gunWithRecoilLeftTriggerLevels[] = { 1.0f, 0.0f, 0.0f, 0.0f }; - - uint32_t heartbeatLeftTriggerDurations[] = { 25, 200, 25, 10, 745 }; - float heartbeatLeftTriggerLevels[] = { 0.2f, 0.0f, 0.0f, 0.0f, 0.0f }; - uint32_t heartbeatRightTriggerDurations[] = { 25, 200, 25, 10, 745 }; - float heartbeatRightTriggerLevels[] = { 0.0f, 0.0f, 0.2f, 0.02f, 0.0f }; - - uint32_t footstepsLeftTriggerDurations[] = { 25, 600, 25, 600 }; - float footstepsLeftTriggerLevels[] = { 0.3f, 0.0f, 0.0f, 0.0f }; - uint32_t footstepsRightTriggerDurations[] = { 25, 600, 25, 600 }; - float footstepsRightTriggerLevels[] = { 0.0f, 0.0f, 0.3f, 0.0f }; -} - -Sample::Sample() noexcept(false) : - m_frame(0), - m_connected(false), - m_dPadPressed(false), - m_leftMotorSpeed(0), - m_rightMotorSpeed(0), - m_leftTriggerLevel(0), - m_rightTriggerLevel(0), - m_selectedTriggerEffect(TRIGGEREFFECTS::TRIGGEREFFECTS_IMPULSETEST), - m_triggerEffectCounter(0), - m_leftTriggerArraySize(0), - m_pLeftTriggerDurations(nullptr), - m_pLeftTriggerLevels(nullptr), - m_rightTriggerArraySize(0), - m_pRightTriggerDurations(nullptr), - m_pRightTriggerLevels(nullptr), - m_leftTriggerIndex(0), - m_rightTriggerIndex(0), - m_frequency(0), - m_counter(0), - m_leftTriggerIndexUpdateTime(0), - m_rightTriggerIndexUpdateTime(0) -{ - // Renders only 2D, so no need for a depth buffer. - m_deviceResources = std::make_unique(DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN); - m_deviceResources->SetClearColor(ATG::Colors::Background); -} - -Sample::~Sample() -{ - if (m_deviceResources) - { - m_deviceResources->WaitForGpu(); - } -} - -// Initialize the Direct3D resources required to run. -void Sample::Initialize(HWND window, int width, int height) -{ - m_deviceResources->SetWindow(window, width, height); - - m_selectedTriggerEffect = TRIGGEREFFECTS::TRIGGEREFFECTS_IMPULSETEST; - - m_deviceResources->CreateDeviceResources(); - CreateDeviceDependentResources(); - - m_deviceResources->CreateWindowSizeDependentResources(); - CreateWindowSizeDependentResources(); - - HRESULT hr = GameInputCreate(&m_gameInput); - -#ifdef _GAMING_XBOX - DX::ThrowIfFailed(hr); -#else - extern LPCWSTR g_szAppName; - - if (FAILED(hr)) - { - wchar_t buff[256] = {}; - swprintf_s(buff, - L"GameInput creation failed with error: %08X\n\nVerify that GameInputRedist.msi has been installed as noted in the README.", - static_cast(hr)); - std::ignore = MessageBoxW(window, buff, g_szAppName, MB_ICONERROR | MB_OK); - ExitSample(); - } -#endif - - QueryPerformanceFrequency(reinterpret_cast(&m_frequency)); -} - -//-------------------------------------------------------------------------------------- -// Name: InitializeImpulseTriggerEffects() -// Desc: Clear variables used by the tigger effects and initialize them as needed for -// the currently selected effect. -//-------------------------------------------------------------------------------------- -void Sample::InitializeImpulseTriggerEffects() -{ - m_leftTriggerIndex = 0; - m_rightTriggerIndex = 0; - - m_leftMotorSpeed = 0; - m_leftTriggerLevel = 0; - m_rightMotorSpeed = 0; - m_rightTriggerLevel = 0; - - m_triggerEffectCounter = 0; - switch (m_selectedTriggerEffect) - { - case TRIGGEREFFECTS::TRIGGEREFFECTS_IMPULSETEST: - break; - - case TRIGGEREFFECTS::TRIGGEREFFECTS_FLATTIRE: - m_leftTriggerArraySize = 3; - - m_pLeftTriggerDurations = flatTireLeftTriggerDurations; - m_pLeftTriggerLevels = flatTireLeftTriggerLevels; - - // Set the timing for the transition to the second vibration level - // Further transition timings will be handled by the transition code. - QueryPerformanceCounter(reinterpret_cast(&m_counter)); - m_leftTriggerIndexUpdateTime = m_counter + (m_frequency * m_pLeftTriggerDurations[m_leftTriggerIndex]) / 1000; - break; - - case TRIGGEREFFECTS::TRIGGEREFFECTS_GUNWITHRECOIL: - m_leftTriggerArraySize = 4; - - m_pLeftTriggerDurations = gunWithRecoilLeftTriggerDurations; - m_pLeftTriggerLevels = gunWithRecoilLeftTriggerLevels; - break; - - case TRIGGEREFFECTS::TRIGGEREFFECTS_HEARTBEAT: - m_leftTriggerArraySize = 5; - m_rightTriggerArraySize = 5; - - m_pLeftTriggerDurations = heartbeatLeftTriggerDurations; - m_pLeftTriggerLevels = heartbeatLeftTriggerLevels; - m_pRightTriggerDurations = heartbeatRightTriggerDurations; - m_pRightTriggerLevels = heartbeatRightTriggerLevels; - - QueryPerformanceCounter(reinterpret_cast(&m_counter)); - m_leftTriggerIndexUpdateTime = m_counter + (m_frequency * m_pLeftTriggerDurations[m_leftTriggerIndex]) / 1000; - m_rightTriggerIndexUpdateTime = m_counter + (m_frequency * m_pRightTriggerDurations[m_rightTriggerIndex]) / 1000; - break; - - case TRIGGEREFFECTS::TRIGGEREFFECTS_FOOTSTEPS: - m_leftTriggerArraySize = 4; - m_rightTriggerArraySize = 4; - - m_pLeftTriggerDurations = footstepsLeftTriggerDurations; - m_pLeftTriggerLevels = footstepsLeftTriggerLevels; - m_pRightTriggerDurations = footstepsRightTriggerDurations; - m_pRightTriggerLevels = footstepsRightTriggerLevels; - - QueryPerformanceCounter(reinterpret_cast(&m_counter)); - m_leftTriggerIndexUpdateTime = m_counter + (m_frequency * m_pLeftTriggerDurations[m_leftTriggerIndex]) / 1000; - m_rightTriggerIndexUpdateTime = m_counter + (m_frequency * m_pRightTriggerDurations[m_rightTriggerIndex]) / 1000; - break; - - default: - assert(false); - } -} - -#pragma region Frame Update -// Executes basic render loop. -void Sample::Tick() -{ - PIXBeginEvent(PIX_COLOR_DEFAULT, L"Frame %llu", m_frame); - -#ifdef _GAMING_XBOX - m_deviceResources->WaitForOrigin(); -#endif - - m_timer.Tick([&]() - { - Update(m_timer); - }); - - Render(); - - PIXEndEvent(); - m_frame++; -} - -// Updates the world. -void Sample::Update(DX::StepTimer const&) -{ - PIXBeginEvent(PIX_COLOR_DEFAULT, L"Update"); - - if (SUCCEEDED(m_gameInput->GetCurrentReading(GameInputKindGamepad, nullptr, &m_reading))) - { - m_connected = true; - - GameInputGamepadState state = {}; - - if (m_reading->GetGamepadState(&state)) - { - if (!m_dPadPressed) - { - if (state.buttons & GameInputGamepadDPadRight) - { - m_dPadPressed = true; - m_selectedTriggerEffect = static_cast((static_cast(m_selectedTriggerEffect) + 1) % TRIGGEREFFECTS_MAX); - InitializeImpulseTriggerEffects(); - } - - if (state.buttons & GameInputGamepadDPadLeft) - { - m_dPadPressed = true; - m_selectedTriggerEffect = static_cast((static_cast(m_selectedTriggerEffect) + TRIGGEREFFECTS_MAX - 1) % TRIGGEREFFECTS_MAX); - InitializeImpulseTriggerEffects(); - } - } - else if(!(state.buttons & GameInputGamepadDPadRight) && !(state.buttons & GameInputGamepadDPadLeft)) - { - m_dPadPressed = false; - } - - if (state.buttons & GameInputGamepadView) - { - ExitSample(); - } - } - - ComPtr device; - m_reading->GetDevice(&device); - - //Set rumble - - switch (m_selectedTriggerEffect) - { - case TRIGGEREFFECTS::TRIGGEREFFECTS_IMPULSETEST: - // This example uses a very simple vibration envelope waveform by setting the vibration - // levels to the current trigger values. This means the more you pull the triggers, the more - // vibration you will feel. - m_leftTriggerLevel = state.leftTrigger; - m_rightTriggerLevel = state.rightTrigger; - m_leftMotorSpeed = state.leftTrigger; - m_rightMotorSpeed = state.rightTrigger; - break; - - case TRIGGEREFFECTS::TRIGGEREFFECTS_FLATTIRE: - m_leftTriggerLevel = m_pLeftTriggerLevels[m_leftTriggerIndex]; - - // If we've reached or passed the transition time, update m_leftTriggerIndexUpdateTime - // with the next transition time and update the effect index. - // This will cause the effect to change in the next loop iteration. - QueryPerformanceCounter(reinterpret_cast(&m_counter)); - if (m_counter > m_leftTriggerIndexUpdateTime) - { - m_leftTriggerIndex = (m_leftTriggerIndex + 1) % m_leftTriggerArraySize; - m_leftTriggerIndexUpdateTime = m_counter + (m_frequency * m_pLeftTriggerDurations[m_leftTriggerIndex]) / 1000; - } - break; - - case TRIGGEREFFECTS::TRIGGEREFFECTS_GUNWITHRECOIL: - switch (m_triggerEffectCounter) - { - case 0: // Wait for the trigger to be fully released before - // the effect can begin - if (state.leftTrigger <= 1.0f / 255.0f) - { - m_triggerEffectCounter = 1; - } - break; - - case 1: // Wait for the trigger to be depressed enough to cause the gun to fire - if (state.leftTrigger >= 32.0f / 255.0f) - { - QueryPerformanceCounter(reinterpret_cast(&m_counter)); - m_leftTriggerIndexUpdateTime = m_counter + (m_frequency * m_pLeftTriggerDurations[m_leftTriggerIndex]) / 1000; - m_triggerEffectCounter = 2; - } - break; - - case 2: // Delay recoil a little after the bullet has left the gun - m_leftTriggerLevel = m_pLeftTriggerLevels[m_leftTriggerIndex]; - - if (m_leftTriggerIndex == 2) - { - m_leftMotorSpeed = 1.0f; - m_rightMotorSpeed = 1.0f; - } - else - { - m_leftMotorSpeed = 0.0f; - m_rightMotorSpeed = 0.0f; - } - - if (m_leftTriggerIndex == 3) - { - m_leftTriggerIndex = 0; - m_triggerEffectCounter = 0; - break; - } - - QueryPerformanceCounter(reinterpret_cast(&m_counter)); - if (m_counter > m_leftTriggerIndexUpdateTime) - { - m_leftTriggerIndex = (m_leftTriggerIndex + 1) % m_leftTriggerArraySize; - m_leftTriggerIndexUpdateTime = m_counter + (m_frequency * m_pLeftTriggerDurations[m_leftTriggerIndex]) / 1000; - } - break; - } - break; - - case TRIGGEREFFECTS::TRIGGEREFFECTS_HEARTBEAT: - // use the left level/duration for both triggers - m_leftTriggerLevel = m_pLeftTriggerLevels[m_leftTriggerIndex]; - m_rightTriggerLevel = m_pRightTriggerLevels[m_rightTriggerIndex]; - - QueryPerformanceCounter(reinterpret_cast(&m_counter)); - if (m_counter > m_leftTriggerIndexUpdateTime) - { - m_leftTriggerIndex = (m_leftTriggerIndex + 1) % m_leftTriggerArraySize; - m_leftTriggerIndexUpdateTime = m_counter + (m_frequency * m_pLeftTriggerDurations[m_leftTriggerIndex]) / 1000; - } - if (m_counter > m_rightTriggerIndexUpdateTime) - { - m_rightTriggerIndex = (m_rightTriggerIndex + 1) % m_rightTriggerArraySize; - m_rightTriggerIndexUpdateTime = m_counter + (m_frequency * m_pRightTriggerDurations[m_rightTriggerIndex]) / 1000; - } - break; - - case TRIGGEREFFECTS::TRIGGEREFFECTS_FOOTSTEPS: - m_leftTriggerLevel = m_pLeftTriggerLevels[m_leftTriggerIndex]; - m_rightTriggerLevel = m_pRightTriggerLevels[m_rightTriggerIndex]; - - QueryPerformanceCounter(reinterpret_cast(&m_counter)); - if (m_counter > m_leftTriggerIndexUpdateTime) - { - m_leftTriggerIndex = (m_leftTriggerIndex + 1) % m_leftTriggerArraySize; - m_leftTriggerIndexUpdateTime = m_counter + (m_frequency * m_pLeftTriggerDurations[m_leftTriggerIndex]) / 1000; - } - if (m_counter > m_rightTriggerIndexUpdateTime) - { - m_rightTriggerIndex = (m_rightTriggerIndex + 1) % m_rightTriggerArraySize; - m_rightTriggerIndexUpdateTime = m_counter + (m_frequency * m_pRightTriggerDurations[m_rightTriggerIndex]) / 1000; - } - break; - - default: - assert(false); - } - - GameInputRumbleParams vibration = {}; - vibration.lowFrequency = m_leftMotorSpeed; - vibration.highFrequency = m_rightMotorSpeed; - vibration.leftTrigger = m_leftTriggerLevel; - vibration.rightTrigger = m_rightTriggerLevel; - device->SetRumbleState(&vibration); - } - - PIXEndEvent(); -} -#pragma endregion - -#pragma region Frame Render -// Draws the scene. -void Sample::Render() -{ - // Don't try to render anything before the first Update. - if (m_timer.GetFrameCount() == 0) - { - return; - } - - // Prepare the command list to render a new frame. - m_deviceResources->Prepare(); - Clear(); - - auto commandList = m_deviceResources->GetCommandList(); - PIXBeginEvent(commandList, PIX_COLOR_DEFAULT, L"Render"); - - auto const fullscreen = m_deviceResources->GetOutputSize(); - - auto const safeRect = Viewport::ComputeTitleSafeArea(UINT(fullscreen.right - fullscreen.left), UINT(fullscreen.bottom - fullscreen.top)); - - auto heap = m_resourceDescriptors->Heap(); - commandList->SetDescriptorHeaps(1, &heap); - - m_batch->Begin(commandList); - - m_batch->Draw(m_resourceDescriptors->GetGpuHandle(Descriptors::Background), XMUINT2(1920, 1080), fullscreen); - - XMFLOAT2 pos(float(safeRect.left), float(safeRect.top)); - - if (m_connected) - { - DX::DrawControllerString(m_batch.get(), m_font.get(), m_ctrlFont.get(), - L"Use the [DPad] Left and Right to select a vibration effect.", pos, ATG::Colors::OffWhite); - pos.y += m_font->GetLineSpacing() * 2.f; - - // Draw description - m_font->DrawString(m_batch.get(), c_TRIGGER_EFFECT_NAME_TEXT[static_cast(m_selectedTriggerEffect)], pos, ATG::Colors::Green); - pos.y += m_font->GetLineSpacing() * 1.5f; - DX::DrawControllerString(m_batch.get(), m_font.get(), m_ctrlFont.get(), c_TRIGGER_EFFECT_DESC_TEXT[static_cast(m_selectedTriggerEffect)], pos); - } - else - { - m_font->DrawString(m_batch.get(), L"No controller connected", pos, ATG::Colors::Orange); - } - - DX::DrawControllerString(m_batch.get(), - m_smallFont.get(), m_ctrlFont.get(), - L"[View] Exit [Menu] Help", - XMFLOAT2(float(safeRect.left), - float(safeRect.bottom) - m_smallFont->GetLineSpacing()), - ATG::Colors::LightGrey); - - m_batch->End(); - - PIXEndEvent(commandList); - - // Show the new frame. - PIXBeginEvent(PIX_COLOR_DEFAULT, L"Present"); - m_deviceResources->Present(); - m_graphicsMemory->Commit(m_deviceResources->GetCommandQueue()); - PIXEndEvent(); -} - -// Helper method to clear the back buffers. -void Sample::Clear() -{ - auto commandList = m_deviceResources->GetCommandList(); - PIXBeginEvent(commandList, PIX_COLOR_DEFAULT, L"Clear"); - - // Clear the views. - auto const rtvDescriptor = m_deviceResources->GetRenderTargetView(); - - commandList->OMSetRenderTargets(1, &rtvDescriptor, FALSE, nullptr); - commandList->ClearRenderTargetView(rtvDescriptor, ATG::Colors::Background, 0, nullptr); - - // Set the viewport and scissor rect. - auto const viewport = m_deviceResources->GetScreenViewport(); - auto const scissorRect = m_deviceResources->GetScissorRect(); - commandList->RSSetViewports(1, &viewport); - commandList->RSSetScissorRects(1, &scissorRect); - - PIXEndEvent(commandList); -} -#pragma endregion - -#pragma region Message Handlers -// Message handlers -void Sample::OnSuspending() -{ - m_deviceResources->Suspend(); -} - -void Sample::OnResuming() -{ - m_deviceResources->Resume(); - m_timer.ResetElapsedTime(); -} - -void Sample::OnWindowMoved() -{ - auto const r = m_deviceResources->GetOutputSize(); - m_deviceResources->WindowSizeChanged(r.right, r.bottom); -} - -void Sample::OnWindowSizeChanged(int width, int height) -{ - if (!m_deviceResources->WindowSizeChanged(width, height)) - return; - - CreateWindowSizeDependentResources(); -} - -// Properties -void Sample::GetDefaultSize(int& width, int& height) const noexcept -{ - width = 1920; - height = 1080; -} -#pragma endregion - -#pragma region Direct3D Resources -// These are the resources that depend on the device. -void Sample::CreateDeviceDependentResources() -{ - auto device = m_deviceResources->GetD3DDevice(); - -#ifdef _GAMING_DESKTOP - D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = { D3D_SHADER_MODEL_6_0 }; - if (FAILED(device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shaderModel, sizeof(shaderModel))) - || (shaderModel.HighestShaderModel < D3D_SHADER_MODEL_6_0)) - { - throw std::runtime_error("Shader Model 6.0 is not supported!"); - } -#endif - - m_graphicsMemory = std::make_unique(device); - - m_resourceDescriptors = std::make_unique(device, Descriptors::Count); - - const RenderTargetState rtState(m_deviceResources->GetBackBufferFormat(), - m_deviceResources->GetDepthBufferFormat()); - - ResourceUploadBatch upload(device); - upload.Begin(); - - { - const SpriteBatchPipelineStateDescription pd( - rtState, - &CommonStates::AlphaBlend); - - m_batch = std::make_unique(device, upload, pd); - } - - wchar_t strFilePath[MAX_PATH] = {}; - DX::FindMediaFile(strFilePath, MAX_PATH, L"SegoeUI_24.spritefont"); - m_font = std::make_unique(device, upload, - strFilePath, - m_resourceDescriptors->GetCpuHandle(Descriptors::PrintFont), - m_resourceDescriptors->GetGpuHandle(Descriptors::PrintFont)); - - DX::FindMediaFile(strFilePath, MAX_PATH, L"SegoeUI_18.spritefont"); - m_smallFont = std::make_unique(device, upload, - strFilePath, - m_resourceDescriptors->GetCpuHandle(Descriptors::TextFont), - m_resourceDescriptors->GetGpuHandle(Descriptors::TextFont)); - - DX::FindMediaFile(strFilePath, MAX_PATH, L"XboxOneControllerLegendSmall.spritefont"); - m_ctrlFont = std::make_unique(device, upload, - strFilePath, - m_resourceDescriptors->GetCpuHandle(Descriptors::ControllerFont), - m_resourceDescriptors->GetGpuHandle(Descriptors::ControllerFont)); - - DX::FindMediaFile(strFilePath, MAX_PATH, L"gamepad.dds"); - DX::ThrowIfFailed(CreateDDSTextureFromFile(device, upload, strFilePath, - m_background.ReleaseAndGetAddressOf())); - - auto finish = upload.End(m_deviceResources->GetCommandQueue()); - finish.wait(); - - m_deviceResources->WaitForGpu(); - - CreateShaderResourceView(device, m_background.Get(), - m_resourceDescriptors->GetCpuHandle(Descriptors::Background)); -} - -// Allocate all memory resources that change on a window SizeChanged event. -void Sample::CreateWindowSizeDependentResources() -{ - auto const vp = m_deviceResources->GetScreenViewport(); - m_batch->SetViewport(vp); -} - -void Sample::OnDeviceLost() -{ - m_font.reset(); - m_smallFont.reset(); - m_ctrlFont.reset(); - m_batch.reset(); - m_resourceDescriptors.reset(); - m_graphicsMemory.reset(); -} - -void Sample::OnDeviceRestored() -{ - CreateDeviceDependentResources(); - - CreateWindowSizeDependentResources(); -} -#pragma endregion diff --git a/Samples/System/GamepadVibration/GamepadVibration.h b/Samples/System/GamepadVibration/GamepadVibration.h deleted file mode 100644 index 30a0eb03..00000000 --- a/Samples/System/GamepadVibration/GamepadVibration.h +++ /dev/null @@ -1,136 +0,0 @@ -//-------------------------------------------------------------------------------------- -// GamepadVibration.h -// -// Advanced Technology Group (ATG) -// Copyright (C) Microsoft Corporation. All rights reserved. -//-------------------------------------------------------------------------------------- - -#pragma once - -#include "DeviceResources.h" -#include "StepTimer.h" - -#include -#if GAMEINPUT_API_VERSION == 1 -using namespace GameInput::v1; -#elif GAMEINPUT_API_VERSION == 2 -using namespace GameInput::v2; -#elif GAMEINPUT_API_VERSION == 3 -using namespace GameInput::v3; -#endif - -// A basic sample implementation that creates a D3D12 device and -// provides a render loop. -class Sample final : public DX::IDeviceNotify -{ -public: - static constexpr int TRIGGEREFFECTS_MAX = 5; - - enum class TRIGGEREFFECTS - { - TRIGGEREFFECTS_IMPULSETEST = 0, - TRIGGEREFFECTS_FLATTIRE, - TRIGGEREFFECTS_GUNWITHRECOIL, - TRIGGEREFFECTS_HEARTBEAT, - TRIGGEREFFECTS_FOOTSTEPS - }; - - Sample() noexcept(false); - ~Sample(); - - Sample(Sample&&) = default; - Sample& operator= (Sample&&) = default; - - Sample(Sample const&) = delete; - Sample& operator= (Sample const&) = delete; - - // Initialization and management - void Initialize(HWND window, int width, int height); - - // Basic render loop - void Tick(); - - // IDeviceNotify - void OnDeviceLost() override; - void OnDeviceRestored() override; - - // Messages - void OnActivated() {} - void OnDeactivated() {} - void OnSuspending(); - void OnResuming(); - void OnWindowMoved(); - void OnWindowSizeChanged(int width, int height); - - // Properties - void GetDefaultSize(int& width, int& height) const noexcept; - -private: - - void Update(DX::StepTimer const& timer); - void Render(); - - void Clear(); - - void CreateDeviceDependentResources(); - void CreateWindowSizeDependentResources(); - - void InitializeImpulseTriggerEffects(); - - // Device resources. - std::unique_ptr m_deviceResources; - - // Rendering loop timer. - uint64_t m_frame; - DX::StepTimer m_timer; - - //Gamepad states - Microsoft::WRL::ComPtr m_gameInput; - Microsoft::WRL::ComPtr m_reading; - - bool m_connected; - bool m_dPadPressed; - float m_leftMotorSpeed; - float m_rightMotorSpeed; - float m_leftTriggerLevel; - float m_rightTriggerLevel; - - // Variables used to control the Impulse Trigger Effects - TRIGGEREFFECTS m_selectedTriggerEffect; // Effect currently selected - DWORD m_triggerEffectCounter; // General purpose counter for use by trigger effects - - size_t m_leftTriggerArraySize; - uint32_t* m_pLeftTriggerDurations; - float* m_pLeftTriggerLevels; - size_t m_rightTriggerArraySize; - uint32_t* m_pRightTriggerDurations; - float* m_pRightTriggerLevels; - uint32_t m_leftTriggerIndex; - uint32_t m_rightTriggerIndex; - - uint64_t m_frequency; - uint64_t m_counter; - uint64_t m_leftTriggerIndexUpdateTime; - uint64_t m_rightTriggerIndexUpdateTime; - - // DirectXTK objects. - std::unique_ptr m_graphicsMemory; - std::unique_ptr m_resourceDescriptors; - - // UI - std::unique_ptr m_batch; - std::unique_ptr m_font; - std::unique_ptr m_smallFont; - std::unique_ptr m_ctrlFont; - - Microsoft::WRL::ComPtr m_background; - - enum Descriptors : size_t - { - PrintFont, - TextFont, - ControllerFont, - Background, - Count, - }; -}; diff --git a/Samples/System/GamepadVibration/GamepadVibration.sln b/Samples/System/GamepadVibration/GamepadVibration.sln deleted file mode 100644 index 4ef0a6c5..00000000 --- a/Samples/System/GamepadVibration/GamepadVibration.sln +++ /dev/null @@ -1,93 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 15.0.28307.329 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GamepadVibration", "GamepadVibration.vcxproj", "{2C15E275-2897-4556-A4CC-453A026A3881}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DirectXTK12", "..\..\..\Kits\DirectXTK12\DirectXTK12_GDKX_2022.vcxproj", "{052C4858-C76F-4CEA-8A1A-E8E5559E67C2}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|ARM64 = Debug|ARM64 - Debug|Gaming.Xbox.Scarlett.x64 = Debug|Gaming.Xbox.Scarlett.x64 - Debug|Gaming.Xbox.XboxOne.x64 = Debug|Gaming.Xbox.XboxOne.x64 - Profile|x64 = Profile|x64 - Profile|ARM64 = Profile|ARM64 - Profile|Gaming.Xbox.Scarlett.x64 = Profile|Gaming.Xbox.Scarlett.x64 - Profile|Gaming.Xbox.XboxOne.x64 = Profile|Gaming.Xbox.XboxOne.x64 - Release|x64 = Release|x64 - Release|ARM64 = Release|ARM64 - Release|Gaming.Xbox.Scarlett.x64 = Release|Gaming.Xbox.Scarlett.x64 - Release|Gaming.Xbox.XboxOne.x64 = Release|Gaming.Xbox.XboxOne.x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2C15E275-2897-4556-A4CC-453A026A3881}.Debug|x64.ActiveCfg = Debug|x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Debug|x64.Build.0 = Debug|x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Debug|ARM64.Build.0 = Debug|ARM64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Debug|x64.Deploy.0 = Debug|x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Debug|ARM64.Deploy.0 = Debug|ARM64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Xbox.Scarlett.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Debug|Gaming.Xbox.Scarlett.x64.Deploy.0 = Debug|Gaming.Xbox.Scarlett.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Xbox.XboxOne.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Xbox.XboxOne.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Debug|Gaming.Xbox.XboxOne.x64.Deploy.0 = Debug|Gaming.Xbox.XboxOne.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Profile|x64.ActiveCfg = Profile|x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Profile|ARM64.ActiveCfg = Profile|ARM64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Profile|x64.Build.0 = Profile|x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Profile|ARM64.Build.0 = Profile|ARM64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Profile|x64.Deploy.0 = Profile|x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Profile|ARM64.Deploy.0 = Profile|ARM64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Profile|Gaming.Xbox.Scarlett.x64.ActiveCfg = Profile|Gaming.Xbox.Scarlett.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Profile|Gaming.Xbox.Scarlett.x64.Build.0 = Profile|Gaming.Xbox.Scarlett.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Profile|Gaming.Xbox.Scarlett.x64.Deploy.0 = Profile|Gaming.Xbox.Scarlett.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Profile|Gaming.Xbox.XboxOne.x64.ActiveCfg = Profile|Gaming.Xbox.XboxOne.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Profile|Gaming.Xbox.XboxOne.x64.Build.0 = Profile|Gaming.Xbox.XboxOne.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Profile|Gaming.Xbox.XboxOne.x64.Deploy.0 = Profile|Gaming.Xbox.XboxOne.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Release|x64.ActiveCfg = Release|x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Release|ARM64.ActiveCfg = Release|ARM64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Release|x64.Build.0 = Release|x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Release|ARM64.Build.0 = Release|ARM64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Release|x64.Deploy.0 = Release|x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Release|ARM64.Deploy.0 = Release|ARM64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Xbox.Scarlett.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Release|Gaming.Xbox.Scarlett.x64.Deploy.0 = Release|Gaming.Xbox.Scarlett.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Xbox.XboxOne.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Xbox.XboxOne.x64 - {2C15E275-2897-4556-A4CC-453A026A3881}.Release|Gaming.Xbox.XboxOne.x64.Deploy.0 = Release|Gaming.Xbox.XboxOne.x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|x64.ActiveCfg = Debug|x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|x64.Build.0 = Debug|x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|ARM64.Build.0 = Debug|ARM64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Xbox.Scarlett.x64.ActiveCfg = Debug|Gaming.Xbox.Scarlett.x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Xbox.Scarlett.x64.Build.0 = Debug|Gaming.Xbox.Scarlett.x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Xbox.XboxOne.x64.ActiveCfg = Debug|Gaming.Xbox.XboxOne.x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Debug|Gaming.Xbox.XboxOne.x64.Build.0 = Debug|Gaming.Xbox.XboxOne.x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|x64.ActiveCfg = Profile|x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|ARM64.ActiveCfg = Profile|ARM64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|x64.Build.0 = Profile|x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|ARM64.Build.0 = Profile|ARM64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|Gaming.Xbox.Scarlett.x64.ActiveCfg = Profile|Gaming.Xbox.Scarlett.x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|Gaming.Xbox.Scarlett.x64.Build.0 = Profile|Gaming.Xbox.Scarlett.x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|Gaming.Xbox.XboxOne.x64.ActiveCfg = Profile|Gaming.Xbox.XboxOne.x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Profile|Gaming.Xbox.XboxOne.x64.Build.0 = Profile|Gaming.Xbox.XboxOne.x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|x64.ActiveCfg = Release|x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|ARM64.ActiveCfg = Release|ARM64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|x64.Build.0 = Release|x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|ARM64.Build.0 = Release|ARM64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Xbox.Scarlett.x64.ActiveCfg = Release|Gaming.Xbox.Scarlett.x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Xbox.Scarlett.x64.Build.0 = Release|Gaming.Xbox.Scarlett.x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Xbox.XboxOne.x64.ActiveCfg = Release|Gaming.Xbox.XboxOne.x64 - {052C4858-C76F-4CEA-8A1A-E8E5559E67C2}.Release|Gaming.Xbox.XboxOne.x64.Build.0 = Release|Gaming.Xbox.XboxOne.x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {66AF6E3F-DB30-407C-9283-7EE73CC5415D} - EndGlobalSection -EndGlobal diff --git a/Samples/System/GamepadVibration/GamepadVibration.vcxproj b/Samples/System/GamepadVibration/GamepadVibration.vcxproj deleted file mode 100644 index b2a2919f..00000000 --- a/Samples/System/GamepadVibration/GamepadVibration.vcxproj +++ /dev/null @@ -1,800 +0,0 @@ - - - - - Debug - Gaming.Xbox.Scarlett.x64 - - - Profile - Gaming.Xbox.Scarlett.x64 - - - Release - Gaming.Xbox.Scarlett.x64 - - - Release - Gaming.Xbox.XboxOne.x64 - - - Profile - Gaming.Xbox.XboxOne.x64 - - - Debug - Gaming.Xbox.XboxOne.x64 - - - Debug - x64 - - - Debug - ARM64 - - - Release - x64 - - - Release - ARM64 - - - Profile - x64 - - - Profile - ARM64 - - - - GamepadVibration - {2c15e275-2897-4556-a4cc-453a026a3881} - en-US - Win32Proj - - 17.0 - Native - x64 - true - - - - - $(GameDKCoreLatest) - $(GameDKXboxLatest) - - - 142 - 143 - - - Application - v143 - false - true - Unicode - false - false - - - Application - v143 - false - true - Unicode - false - false - - - Application - v143 - false - true - Unicode - false - false - - - Application - v143 - false - true - Unicode - false - false - - - Application - v143 - true - Unicode - false - false - - - Application - v143 - true - Unicode - false - false - - - Application - v143 - Unicode - true - - - Application - v143 - Unicode - true - - - Application - v143 - Unicode - false - true - - - Application - v143 - Unicode - false - true - - - Application - v143 - Unicode - false - true - - - Application - v143 - Unicode - false - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath) - $(Console_SdkLibPath) - $(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath) - $(Console_SdkIncludeRoot) - $(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath) - false - - - $(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath) - $(Console_SdkLibPath) - $(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath) - $(Console_SdkIncludeRoot) - $(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath) - false - - - $(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath) - $(Console_SdkLibPath) - $(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath) - $(Console_SdkIncludeRoot) - $(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath) - false - - - $(Console_SdkLibPath);$(LibraryPath) - $(Console_SdkIncludeRoot);$(IncludePath) - $(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath) - false - - - $(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath) - $(Console_SdkLibPath) - $(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath) - $(Console_SdkIncludeRoot) - $(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath) - true - - - $(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath) - $(Console_SdkLibPath) - $(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath) - $(Console_SdkIncludeRoot) - $(Console_SdkRoot)bin;$(Console_SdkToolPath);$(ExecutablePath) - true - - - $(GameDK)bin;$(ExecutablePath) - $(GDKCrossPlatformPath)windows\include;$(IncludePath); - $(GDKCrossPlatformPath)windows\lib\x64;$(LibraryPath) - true - - - $(GameDK)bin;$(ExecutablePath) - $(GDKCrossPlatformPath)windows\include;$(IncludePath); - $(GDKCrossPlatformPath)windows\lib\ARM64;$(LibraryPath) - true - - - $(GameDK)bin;$(ExecutablePath) - $(GDKCrossPlatformPath)windows\include;$(IncludePath); - $(GDKCrossPlatformPath)windows\lib\x64;$(LibraryPath) - false - - - $(GameDK)bin;$(ExecutablePath) - $(GDKCrossPlatformPath)windows\include;$(IncludePath); - $(GDKCrossPlatformPath)windows\lib\ARM64;$(LibraryPath) - false - - - $(GameDK)bin;$(ExecutablePath) - $(GDKCrossPlatformPath)windows\include;$(IncludePath); - $(GDKCrossPlatformPath)windows\lib\x64;$(LibraryPath) - false - - - $(GameDK)bin;$(ExecutablePath) - $(GDKCrossPlatformPath)windows\include;$(IncludePath); - $(GDKCrossPlatformPath)windows\lib\ARM64;$(LibraryPath) - false - - - false - - - - Microsoft.Xbox.Services.$(XSAPIVersion).C.lib;PlayFabCore.lib;PlayFabServices.lib;libHttpClient.lib;XCurl.lib;appnotify.lib;winhttp.lib;crypt32.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies) - true - Windows - true - true - - - Use - pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - - - MaxSpeed - NDEBUG;%(PreprocessorDefinitions) - Level4 - true - true - true - 5204;5204 - - - 6.0 - - - - - Microsoft.Xbox.Services.$(XSAPIVersion).C.lib;PlayFabCore.lib;PlayFabServices.lib;libHttpClient.lib;XCurl.lib;appnotify.lib;winhttp.lib;crypt32.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies) - true - Windows - true - true - - - Use - pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - - - - - MaxSpeed - NDEBUG;%(PreprocessorDefinitions) - Level4 - true - true - true - 5204;5204 - - - 6.0 - - - - - Microsoft.Xbox.Services.$(XSAPIVersion).C.lib;PlayFabCore.lib;PlayFabServices.lib;libHttpClient.lib;XCurl.lib;appnotify.lib;winhttp.lib;crypt32.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies) - true - Windows - true - true - - - Use - pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - - - MaxSpeed - NDEBUG;PROFILE;%(PreprocessorDefinitions) - Level4 - true - true - true - 5204;5204 - - - 6.0 - - - - - Microsoft.Xbox.Services.$(XSAPIVersion).C.lib;PlayFabCore.lib;PlayFabServices.lib;libHttpClient.lib;XCurl.lib;appnotify.lib;winhttp.lib;crypt32.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies) - true - Windows - true - true - - - Use - pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - - - - - MaxSpeed - NDEBUG;PROFILE;%(PreprocessorDefinitions) - Level4 - true - true - true - 5204;5204 - - - 6.0 - - - - - Microsoft.Xbox.Services.$(XSAPIVersion).C.Debug.lib;PlayFabCore.lib;PlayFabServices.lib;libHttpClient.lib;XCurl.lib;appnotify.lib;winhttp.lib;crypt32.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies) - Windows - true - - - pch.h - Use - false - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - - - Level4 - Disabled - _DEBUG;%(PreprocessorDefinitions) - true - 5204;5204 - - - 6.0 - - - - - Microsoft.Xbox.Services.$(XSAPIVersion).C.Debug.lib;PlayFabCore.lib;PlayFabServices.lib;libHttpClient.lib;XCurl.lib;appnotify.lib;winhttp.lib;crypt32.lib;$(Console_Libs);%(XboxExtensionsDependencies);%(AdditionalDependencies) - Windows - true - - - pch.h - Use - false - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - - - - - Level4 - Disabled - _DEBUG;%(PreprocessorDefinitions) - true - 5204;5204 - - - 6.0 - - - - - $(OutDir)Assets - - - - - Microsoft.Xbox.Services.$(XSAPIVersion).C.Debug.lib;PlayFabCore.lib;PlayFabServices.lib;libHttpClient.lib;XCurl.lib;appnotify.lib;winhttp.lib;crypt32.lib;uuid.lib;xgameruntime.lib;gameinput.lib;d3d12.lib;dxgi.lib;dxguid.lib;kernel32.lib;user32.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;runtimeobject.lib;%(AdditionalDependencies) - true - Windows - /IGNORE:4099 %(AdditionalOptions) - - - PerMonitorHighDPIAware - - - Use - pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - _GAMING_DESKTOP;_WINDOWS;WIN32;_DEBUG;%(PreprocessorDefinitions) - Fast - /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) - Disabled - Level4 - stdcpp17 - true - 5204;5204 - - - 6.0 - true - /Fd "$(OutDir)%(Filename).pdb" %(AdditionalOptions) - - - - - Microsoft.Xbox.Services.$(XSAPIVersion).C.Debug.lib;PlayFabCore.lib;PlayFabServices.lib;libHttpClient.lib;XCurl.lib;appnotify.lib;winhttp.lib;crypt32.lib;uuid.lib;xgameruntime.lib;gameinput.lib;d3d12.lib;dxgi.lib;dxguid.lib;kernel32.lib;user32.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;runtimeobject.lib;%(AdditionalDependencies) - true - Windows - /IGNORE:4099 %(AdditionalOptions) - - - PerMonitorHighDPIAware - - - Use - pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - _GAMING_DESKTOP;_WINDOWS;WIN32;_DEBUG;%(PreprocessorDefinitions) - Fast - /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) - Disabled - Level4 - stdcpp17 - true - 5204;5204 - - - 6.0 - true - /Fd "$(OutDir)%(Filename).pdb" %(AdditionalOptions) - - - - - Microsoft.Xbox.Services.$(XSAPIVersion).C.lib;PlayFabCore.lib;PlayFabServices.lib;libHttpClient.lib;XCurl.lib;appnotify.lib;winhttp.lib;crypt32.lib;uuid.lib;xgameruntime.lib;gameinput.lib;d3d12.lib;dxgi.lib;dxguid.lib;kernel32.lib;user32.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;runtimeobject.lib;%(AdditionalDependencies) - true - Windows - true - true - /IGNORE:4099 %(AdditionalOptions) - - - PerMonitorHighDPIAware - - - Use - pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - _GAMING_DESKTOP;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) - Fast - /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) - MaxSpeed - true - true - Level4 - stdcpp17 - true - 5204;5204 - - - 6.0 - true - /Fd "$(OutDir)%(Filename).pdb" %(AdditionalOptions) - - - - - Microsoft.Xbox.Services.$(XSAPIVersion).C.lib;PlayFabCore.lib;PlayFabServices.lib;libHttpClient.lib;XCurl.lib;appnotify.lib;winhttp.lib;crypt32.lib;uuid.lib;xgameruntime.lib;gameinput.lib;d3d12.lib;dxgi.lib;dxguid.lib;kernel32.lib;user32.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;runtimeobject.lib;%(AdditionalDependencies) - true - Windows - true - true - /IGNORE:4099 %(AdditionalOptions) - - - PerMonitorHighDPIAware - - - Use - pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - _GAMING_DESKTOP;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) - Fast - /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) - MaxSpeed - true - true - Level4 - stdcpp17 - true - 5204;5204 - - - 6.0 - true - /Fd "$(OutDir)%(Filename).pdb" %(AdditionalOptions) - - - - - Microsoft.Xbox.Services.$(XSAPIVersion).C.lib;PlayFabCore.lib;PlayFabServices.lib;libHttpClient.lib;XCurl.lib;appnotify.lib;winhttp.lib;crypt32.lib;uuid.lib;xgameruntime.lib;gameinput.lib;d3d12.lib;dxgi.lib;dxguid.lib;kernel32.lib;user32.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;runtimeobject.lib;%(AdditionalDependencies) - true - Windows - true - true - /IGNORE:4099 %(AdditionalOptions) - - - PerMonitorHighDPIAware - - - Use - pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - PROFILE;_GAMING_DESKTOP;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) - Fast - /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) - MaxSpeed - true - true - Level4 - stdcpp17 - true - 5204;5204 - - - 6.0 - true - /Fd "$(OutDir)%(Filename).pdb" %(AdditionalOptions) - - - - - Microsoft.Xbox.Services.$(XSAPIVersion).C.lib;PlayFabCore.lib;PlayFabServices.lib;libHttpClient.lib;XCurl.lib;appnotify.lib;winhttp.lib;crypt32.lib;uuid.lib;xgameruntime.lib;gameinput.lib;d3d12.lib;dxgi.lib;dxguid.lib;kernel32.lib;user32.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;runtimeobject.lib;%(AdditionalDependencies) - true - Windows - true - true - /IGNORE:4099 %(AdditionalOptions) - - - PerMonitorHighDPIAware - - - Use - pch.h - $(ProjectDir);..\..\..\Kits\ATGTelemetry\GDK;..\..\..\Kits\DirectXTK12\Inc;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - PROFILE;_GAMING_DESKTOP;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions) - Fast - /Zc:__cplusplus /ZH:SHA_256 %(AdditionalOptions) - MaxSpeed - true - true - Level4 - stdcpp17 - true - 5204;5204 - - - 6.0 - true - /Fd "$(OutDir)%(Filename).pdb" %(AdditionalOptions) - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - Create - Create - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - true - true - true - true - true - true - true - true - true - true - true - true - - - - - true - true - true - true - true - true - Document - true - true - true - true - true - true - - - true - true - true - true - true - true - Document - true - true - true - true - true - true - - - true - true - true - true - true - true - Document - true - true - true - true - true - true - - - - - - - - - - - - - - {052c4858-c76f-4cea-8a1a-e8e5559e67c2} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - This project requires the Microsoft GDK with Xbox Extensions to be installed. If you have already installed the GDK, then run Repair to ensure proper integration with Visual Studio. The missing platform is {0}. - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - \ No newline at end of file diff --git a/Samples/System/GamepadVibration/GamepadVibration.vcxproj.filters b/Samples/System/GamepadVibration/GamepadVibration.vcxproj.filters deleted file mode 100644 index 2a596008..00000000 --- a/Samples/System/GamepadVibration/GamepadVibration.vcxproj.filters +++ /dev/null @@ -1,100 +0,0 @@ - - - - - c54cb0f6-3bbd-42fa-a61c-4f1ca4f4fbd6 - - - 75ccde93-91ce-439f-a592-be43a6e1e29b - ico;cur;bmp;dds;dlg;fbx;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms - - - 4b381b87-471d-42c8-8479-f5c44d0a62dc - - - - - - - Common - - - Common - - - ATG Tool Kit - - - ATG Tool Kit - - - ATG Tool Kit - - - ATG Tool Kit - - - ATG Tool Kit - - - ATG Tool Kit - - - ATG Tool Kit - - - - - - - - Common - - - ATG Tool Kit - - - ATG Tool Kit - - - - - - - - - - - - - - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - \ No newline at end of file diff --git a/Samples/System/GamepadVibration/Main.cpp b/Samples/System/GamepadVibration/Main.cpp deleted file mode 100644 index 68ec19a2..00000000 --- a/Samples/System/GamepadVibration/Main.cpp +++ /dev/null @@ -1,397 +0,0 @@ -//-------------------------------------------------------------------------------------- -// Main.cpp -// -// Entry point for Microsoft Game Development Kit (GDK) -// -// Advanced Technology Group (ATG) -// Copyright (C) Microsoft Corporation. All rights reserved. -//-------------------------------------------------------------------------------------- - -#include "pch.h" -#include "GamepadVibration.h" - -#include -#include -#include - -#include "ATGTelemetry.h" - -using namespace DirectX; - -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wcovered-switch-default" -#pragma clang diagnostic ignored "-Wswitch-enum" -#endif - -#pragma warning(disable : 4061) - -namespace -{ - std::unique_ptr g_sample; -#ifdef _GAMING_XBOX - HANDLE g_plmSuspendComplete = nullptr; - HANDLE g_plmSignalResume = nullptr; -#endif -} - -LPCWSTR g_szAppName = L"GamepadVibration"; - -LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); -void ExitSample() noexcept; - -int SampleMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) -{ - UNREFERENCED_PARAMETER(lpCmdLine); - - if (!XMVerifyCPUSupport()) - { -#ifdef _DEBUG - OutputDebugStringA("ERROR: This hardware does not support the required instruction set.\n"); -#if defined(_GAMING_XBOX) && defined(__AVX2__) - OutputDebugStringA("This may indicate a Gaming.Xbox.Scarlett.x64 binary is being run on an Xbox One.\n"); -#endif -#endif - return 1; - } - - HRESULT hr = XGameRuntimeInitialize(); - if (FAILED(hr)) - { - if (hr == E_GAMERUNTIME_DLL_NOT_FOUND || hr == E_GAMERUNTIME_VERSION_MISMATCH) - { -#ifdef _GAMING_DESKTOP - std::ignore = MessageBoxW(nullptr, L"Game Runtime is not installed on this system or needs updating.", g_szAppName, MB_ICONERROR | MB_OK); -#endif - } - return 1; - } - -#ifdef _GAMING_XBOX - // Default main thread to CPU 0 - SetThreadAffinityMask(GetCurrentThread(), 0x1); -#endif - - g_sample = std::make_unique(); - - // Register class and create window -#ifdef _GAMING_XBOX - PAPPSTATE_REGISTRATION hPLM = {}; -#endif - { - // Register class - WNDCLASSEXW wcex = {}; - wcex.cbSize = sizeof(WNDCLASSEXW); - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = WndProc; - wcex.hInstance = hInstance; - wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW); - wcex.hbrBackground = reinterpret_cast(COLOR_WINDOW + 1); - wcex.lpszClassName = L"GamepadVibrationWindowClass"; - if (!RegisterClassExW(&wcex)) - return 1; - - // Create window -#ifdef _GAMING_XBOX - RECT rc = { 0, 0, 1920, 1080 }; -#else - int w, h; - g_sample->GetDefaultSize(w, h); - - RECT rc = { 0, 0, static_cast(w), static_cast(h) }; - AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE); -#endif - - HWND hwnd = CreateWindowExW(0, L"GamepadVibrationWindowClass", g_szAppName, WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, - nullptr, nullptr, hInstance, - g_sample.get()); - if (!hwnd) - return 1; - - ShowWindow(hwnd, nCmdShow); - - // Sample Usage Telemetry - // - // Disable or remove this code block to opt-out of sample usage telemetry - ATG::SendLaunchTelemetry(); - - GetClientRect(hwnd, &rc); - - g_sample->Initialize(hwnd, rc.right - rc.left, rc.bottom - rc.top); - -#ifdef _GAMING_XBOX - g_plmSuspendComplete = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE); - g_plmSignalResume = CreateEventEx(nullptr, nullptr, 0, EVENT_MODIFY_STATE | SYNCHRONIZE); - if (!g_plmSuspendComplete || !g_plmSignalResume) - return 1; - - if (RegisterAppStateChangeNotification([](BOOLEAN quiesced, PVOID context) - { - if (quiesced) - { - ResetEvent(g_plmSuspendComplete); - ResetEvent(g_plmSignalResume); - - // To ensure we use the main UI thread to process the notification, we self-post a message - PostMessage(reinterpret_cast(context), WM_USER, 0, 0); - - // To defer suspend, you must wait to exit this callback - std::ignore = WaitForSingleObject(g_plmSuspendComplete, INFINITE); - } - else - { - SetEvent(g_plmSignalResume); - } - }, hwnd, &hPLM)) - return 1; -#endif - } - - // Main message loop - MSG msg = {}; - OutputDebugStringA("INFO: Sample started.\n"); - while (WM_QUIT != msg.message) - { - if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - else - { - g_sample->Tick(); - } - } - - g_sample.reset(); - -#ifdef _GAMING_XBOX - UnregisterAppStateChangeNotification(hPLM); - - CloseHandle(g_plmSuspendComplete); - CloseHandle(g_plmSignalResume); -#endif - - XGameRuntimeUninitialize(); - - return static_cast(msg.wParam); -} - -// Entry point -int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) -{ - try - { - return SampleMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow); - } - catch (const std::exception& e) - { - OutputDebugStringA("*** ERROR: Unhandled C++ exception thrown: "); - OutputDebugStringA(e.what()); - OutputDebugStringA(" *** \n"); - return 1; - } - catch (...) - { - OutputDebugStringA("*** ERROR: Unknown unhandled C++ exception thrown ***\n"); - return 1; - } -} - -// Windows procedure -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ -#ifdef _GAMING_DESKTOP - static bool s_in_sizemove = false; - static bool s_in_suspend = false; - static bool s_minimized = false; - static bool s_fullscreen = false; -#endif - - auto sample = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); - - switch (message) - { - case WM_CREATE: - if (lParam) - { - auto params = reinterpret_cast(lParam); - SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(params->lpCreateParams)); - } - break; - - case WM_ACTIVATEAPP: - if (sample) - { - if (wParam) - { - sample->OnActivated(); - } - else - { - sample->OnDeactivated(); - } - } - break; - -#ifdef _GAMING_XBOX - case WM_USER: - if (sample) - { - sample->OnSuspending(); - - // Complete deferral - SetEvent(g_plmSuspendComplete); - - std::ignore = WaitForSingleObject(g_plmSignalResume, INFINITE); - - sample->OnResuming(); - } - break; -#else - case WM_PAINT: - if (s_in_sizemove && sample) - { - sample->Tick(); - } - else - { - PAINTSTRUCT ps; - std::ignore = BeginPaint(hWnd, &ps); - EndPaint(hWnd, &ps); - } - break; - - case WM_MOVE: - if (sample) - { - sample->OnWindowMoved(); - } - break; - - case WM_SIZE: - if (wParam == SIZE_MINIMIZED) - { - if (!s_minimized) - { - s_minimized = true; - if (!s_in_suspend && sample) - sample->OnSuspending(); - s_in_suspend = true; - } - } - else if (s_minimized) - { - s_minimized = false; - if (s_in_suspend && sample) - sample->OnResuming(); - s_in_suspend = false; - } - else if (!s_in_sizemove && sample) - { - sample->OnWindowSizeChanged(LOWORD(lParam), HIWORD(lParam)); - } - break; - - case WM_ENTERSIZEMOVE: - s_in_sizemove = true; - break; - - case WM_EXITSIZEMOVE: - s_in_sizemove = false; - if (sample) - { - RECT rc; - GetClientRect(hWnd, &rc); - - sample->OnWindowSizeChanged(rc.right - rc.left, rc.bottom - rc.top); - } - break; - - case WM_GETMINMAXINFO: - if (lParam) - { - auto info = reinterpret_cast(lParam); - info->ptMinTrackSize.x = 320; - info->ptMinTrackSize.y = 200; - } - break; - - case WM_POWERBROADCAST: - switch (wParam) - { - case PBT_APMQUERYSUSPEND: - if (!s_in_suspend && sample) - sample->OnSuspending(); - s_in_suspend = true; - return TRUE; - - case PBT_APMRESUMESUSPEND: - if (!s_minimized) - { - if (s_in_suspend && sample) - sample->OnResuming(); - s_in_suspend = false; - } - return TRUE; - } - break; - - case WM_DESTROY: - PostQuitMessage(0); - break; - - case WM_KEYUP: - if (wParam == VK_ESCAPE) - { - PostQuitMessage(0); - } - break; - - case WM_SYSKEYDOWN: - if (wParam == VK_RETURN && (lParam & 0x60000000) == 0x20000000) - { - // Implements the classic ALT+ENTER fullscreen toggle - if (s_fullscreen) - { - SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); - SetWindowLongPtr(hWnd, GWL_EXSTYLE, 0); - - int width = 800; - int height = 600; - if (sample) - sample->GetDefaultSize(width, height); - - ShowWindow(hWnd, SW_SHOWNORMAL); - - SetWindowPos(hWnd, HWND_TOP, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); - } - else - { - SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP); - SetWindowLongPtr(hWnd, GWL_EXSTYLE, WS_EX_TOPMOST); - - SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); - - ShowWindow(hWnd, SW_SHOWMAXIMIZED); - } - - s_fullscreen = !s_fullscreen; - } - break; - - case WM_MENUCHAR: - // A menu is active and the user presses a key that does not correspond - // to any mnemonic or accelerator key. Ignore so we don't produce an error beep. - return MAKELRESULT(0, MNC_CLOSE); -#endif - } - - return DefWindowProc(hWnd, message, wParam, lParam); -} - -// Exit helper -void ExitSample() noexcept -{ - PostQuitMessage(0); -} diff --git a/Samples/System/GamepadVibration/MicrosoftGameConfig.mgc b/Samples/System/GamepadVibration/MicrosoftGameConfig.mgc deleted file mode 100644 index 775d2c48..00000000 --- a/Samples/System/GamepadVibration/MicrosoftGameConfig.mgc +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - diff --git a/Samples/System/GamepadVibration/StepTimer.h b/Samples/System/GamepadVibration/StepTimer.h deleted file mode 100644 index 2dbefcbc..00000000 --- a/Samples/System/GamepadVibration/StepTimer.h +++ /dev/null @@ -1,190 +0,0 @@ -// -// StepTimer.h - A simple timer that provides elapsed time information -// - -#pragma once - -#include -#include -#include - - -namespace DX -{ - // Helper class for animation and simulation timing. - class StepTimer - { - public: - StepTimer() noexcept(false) : - 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 std::exception(); - } - - if (!QueryPerformanceCounter(&m_qpcLastTime)) - { - throw std::exception(); - } - - // Initialize max delta to 1/10 of a second. - m_qpcMaxDelta = static_cast(m_qpcFrequency.QuadPart / 10); - } - - // Get elapsed time since the previous Update call. - uint64_t GetElapsedTicks() const noexcept { return m_elapsedTicks; } - double GetElapsedSeconds() const noexcept { return TicksToSeconds(m_elapsedTicks); } - - // Get total time since the start of the program. - uint64_t GetTotalTicks() const noexcept { return m_totalTicks; } - double GetTotalSeconds() const noexcept { return TicksToSeconds(m_totalTicks); } - - // Get total number of updates since start of the program. - uint32_t GetFrameCount() const noexcept { return m_frameCount; } - - // Get the current framerate. - uint32_t GetFramesPerSecond() const noexcept { return m_framesPerSecond; } - - // Set whether to use fixed or variable timestep mode. - void SetFixedTimeStep(bool isFixedTimestep) noexcept { m_isFixedTimeStep = isFixedTimestep; } - - // Set how often to call Update when in fixed timestep mode. - void SetTargetElapsedTicks(uint64_t targetElapsed) noexcept { m_targetElapsedTicks = targetElapsed; } - void SetTargetElapsedSeconds(double targetElapsed) noexcept { m_targetElapsedTicks = SecondsToTicks(targetElapsed); } - - // Integer format represents time using 10,000,000 ticks per second. - static constexpr uint64_t TicksPerSecond = 10000000; - - static constexpr double TicksToSeconds(uint64_t ticks) noexcept { return static_cast(ticks) / TicksPerSecond; } - static constexpr uint64_t SecondsToTicks(double seconds) noexcept { 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 std::exception(); - } - - 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 std::exception(); - } - - uint64_t timeDelta = static_cast(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 /= static_cast(m_qpcFrequency.QuadPart); - - const uint32_t 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 (static_cast(std::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 %= static_cast(m_qpcFrequency.QuadPart); - } - } - - private: - // Source timing data uses QPC units. - LARGE_INTEGER m_qpcFrequency; - LARGE_INTEGER m_qpcLastTime; - uint64_t m_qpcMaxDelta; - - // Derived timing data uses a canonical tick format. - uint64_t m_elapsedTicks; - uint64_t m_totalTicks; - uint64_t m_leftOverTicks; - - // Members for tracking the framerate. - uint32_t m_frameCount; - uint32_t m_framesPerSecond; - uint32_t m_framesThisSecond; - uint64_t m_qpcSecondCounter; - - // Members for configuring fixed timestep mode. - bool m_isFixedTimeStep; - uint64_t m_targetElapsedTicks; - }; -} diff --git a/Samples/System/GamepadVibration/media/image1.png b/Samples/System/GamepadVibration/media/image1.png deleted file mode 100644 index 3791445d..00000000 Binary files a/Samples/System/GamepadVibration/media/image1.png and /dev/null differ diff --git a/Samples/System/GamepadVibration/media/image3.png b/Samples/System/GamepadVibration/media/image3.png deleted file mode 100644 index a357e360..00000000 Binary files a/Samples/System/GamepadVibration/media/image3.png and /dev/null differ diff --git a/Samples/System/GamepadVibration/packages.config b/Samples/System/GamepadVibration/packages.config deleted file mode 100644 index 0c27d7a1..00000000 --- a/Samples/System/GamepadVibration/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Samples/System/GamepadVibration/pch.h b/Samples/System/GamepadVibration/pch.h deleted file mode 100644 index f6aa84e4..00000000 --- a/Samples/System/GamepadVibration/pch.h +++ /dev/null @@ -1,163 +0,0 @@ -//-------------------------------------------------------------------------------------- -// pch.h -// -// Header for standard system include files. -// -// Advanced Technology Group (ATG) -// Copyright (C) Microsoft Corporation. All rights reserved. -//-------------------------------------------------------------------------------------- - -#pragma once - -#include -#define _WIN32_WINNT 0x0A00 -#include - -// Use the C++ standard templated min/max -#define NOMINMAX - -// DirectX apps don't need GDI -#define NODRAWTEXT -#define NOGDI -#define NOBITMAP - -// Include if you need this -#define NOMCX - -// Include if you need this -#define NOSERVICE - -// WinHelp is deprecated -#define NOHELP - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -#include - -#include -#include - -#include - -#ifdef _GAMING_DESKTOP -#if _GRDK_EDITION < 251000 -#error The Desktop version of this sample requires the October 2025 GDK or later -#endif -#else -#if _GRDK_VER < 0x65F41800 /* GDK Edition 251000 */ -#error This sample requires the October 2025 GDK or later -#endif - -#if defined(_M_ARM64) -#if _GRDK_EDITION < 260400 -#error ARM64 support requires April 2026 GDK or later -#endif -#endif -#endif - -#ifdef _GAMING_XBOX_SCARLETT -#include -#include -#elif defined(_GAMING_XBOX) -#include -#include -#else -#include -#include - -#ifdef _DEBUG -#include -#endif - -#include "d3dx12.h" -#endif - -#define _XM_NO_XMVECTOR_OVERLOADS_ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _GAMING_XBOX -#include -#else -// To use graphics markup events with the latest version of PIX, change this to include -// then add the NuGet package WinPixEventRuntime to the project. -#include -#endif - -#include -#include -#include - -#include "CommonStates.h" -#include "DDSTextureLoader.h" -#include "DescriptorHeap.h" -#include "DirectXHelpers.h" -#include "GraphicsMemory.h" -#include "RenderTargetState.h" -#include "ResourceUploadBatch.h" -#include "SimpleMath.h" -#include "SpriteBatch.h" -#include "SpriteFont.h" - -// To opt-out of telemetry uncomment the following line -//#define ATG_DISABLE_TELEMETRY - -namespace DX -{ - // Helper class for COM exceptions - class com_exception : public std::exception - { - public: - com_exception(HRESULT hr) noexcept : result(hr) {} - - const char* what() const noexcept override - { - static char s_str[64] = {}; - sprintf_s(s_str, "Failure with HRESULT of %08X", static_cast(result)); - return s_str; - } - - private: - HRESULT result; - }; - - // Helper utility converts D3D API failures into exceptions. - inline void ThrowIfFailed(HRESULT hr) - { - if (FAILED(hr)) - { -#ifdef _DEBUG - char str[64] = {}; - sprintf_s(str, "**ERROR** Fatal Error with HRESULT of %08X\n", static_cast(hr)); - OutputDebugStringA(str); - __debugbreak(); -#endif - throw com_exception(hr); - } - } -} - -// Enable off by default warnings to improve code conformance -#pragma warning(default : 4061 4062 4191 4263 4264 4265 4266 4289 4365 4746 4826 4841 4986 4987 5029 5038 5042) diff --git a/Samples/System/GamepadVibration/readme.md b/Samples/System/GamepadVibration/readme.md deleted file mode 100644 index f758649c..00000000 --- a/Samples/System/GamepadVibration/readme.md +++ /dev/null @@ -1,88 +0,0 @@ - - -![](./media/image1.png) - -# Gamepad Vibration Sample - -*This sample is compatible with the Microsoft Game Development Kit (June 2020)* - -# Description - -This sample demonstrates how to use vibration with a gamepad on an Xbox -One. - -![](./media/image3.png) - -# Building the sample - -- If building for Xbox One, set the active solution platform to `Gaming.Xbox.XboxOne.x64`. -- If building for Xbox Series X|S, set the active solution platform to `Gaming.Xbox.Scarlett.x64`. -- If building for PC, set the active solution platform to x64.\ -**NOTE: This requires the [GameInput NuGet package](https://www.nuget.org/packages/Microsoft.GameInput) and its -included redistributable to be installed. Please see -[GameInput on PC](https://learn.microsoft.com/gaming/gdk/_content/gc/input/overviews/input-nuget) for more information.**. - -*For more information, see* __Running samples__, *in the GDK documentation.* - -# Running the sample - -Ensure the GameInput Redistributable (GameInputRedist.msi) is installed. This installer can be found in the NuGet package, -or it can be installed separately using WinGet via a command prompt with the following command: - -`winget install Microsoft.GameInput` - -# Using the sample - -Use left and right on the DPad to cycle between different vibration -examples. Use the triggers in most of these examples to increase the -amount of vibration. - -Please note that there are some 3^rd^ party controllers which do not -have trigger rumble motors, so effects using those motors on these -controllers will not cause vibration. - -# Implementation notes - -This sample demonstrates how to use the GameInput API to set vibration -levels on an Xbox One gamepad. - -# Update history - -- Initial release April 2019 -- Updated in June 2019 for minor breaking change to - **SetRumbleState**. -- February 2020: Updated for changes to GameInput API. -- June 2022: Added support for GameInput on PC (June 2022 GDK or - later) -- March 2025: Added support for GameInput v1.x on PC via the - [GameInput NuGet package](https://www.nuget.org/packages/Microsoft.GameInput) -- July 2025: Added support for GameInput v2.x on PC via the - [GameInput NuGet package](https://www.nuget.org/packages/Microsoft.GameInput) - -# Privacy statement - -When compiling and running a sample, the file name of the sample -executable will be sent to Microsoft to help track sample usage. To -opt-out of this data collection, you can remove the block of code in -Main.cpp labeled "Sample Usage Telemetry". - -For more information about Microsoft's privacy policies in general, see -the [Microsoft Privacy -Statement](https://privacy.microsoft.com/en-us/privacystatement/). diff --git a/Samples/System/GamepadVibration/readme.txt b/Samples/System/GamepadVibration/readme.txt new file mode 100644 index 00000000..3a05b723 --- /dev/null +++ b/Samples/System/GamepadVibration/readme.txt @@ -0,0 +1,2 @@ +The GamepadVibration sample has been integrated into the new Gamepad sample: +Samples/System/Gamepad \ No newline at end of file diff --git a/Samples/System/GamepadVibration/readme_ja-jp.md b/Samples/System/GamepadVibration/readme_ja-jp.md deleted file mode 100644 index d59740ea..00000000 --- a/Samples/System/GamepadVibration/readme_ja-jp.md +++ /dev/null @@ -1,52 +0,0 @@ -# コントローラー振動のサンプル - -*このサンプルは、Microsoft ゲーム開発キットのプレビュー (2019 年 11 月) -に対応しています。* - -# - -# 説明 - -このサンプルでは、Xbox One -のコントローラーで振動を使用する方法を示します。 - -![](./media/image1.png) - -# サンプルのビルド - -Xbox One の devkit を使用している場合は、アクティブなソリューション -プラットフォームを Gaming.Xbox.XboxOne.x64 に設定します。 - -Project Scarlett を使用している場合は、アクティブなソリューション -プラットフォームを Gaming.Xbox.Scarlett.x64 に設定します。 - -*詳細については、GDK -ドキュメント*の「サンプルの実行」を*参照してください*。 - -# サンプルの使用 - -方向パッドの左と右を使用して、異なる振動の例を切り替えます。 -これらの例のほとんどでトリガーを使用して、振動量を増やします。 - -# 実装に関する注意事項 - -このサンプルでは、GameInput API を使用して Xbox One -のコントローラーに振動レベルを設定する方法を示します。 - -# 更新履歴 - -初期リリース: 2019 年 4 月 - -**SetRumbleState** のちょっとした重要な変更のため2019 年 6 月に更新。 - -2020 年 2 月:GameInput API 変更のための更新。 - -# プライバシーに関する声明 - -サンプルをコンパイルして実行すると、サンプルの使用状況を追跡するため、サンプル実行可能ファイルのファイル名が -Microsoft に送信されます。このデータ収集を無効にするには、「Sample Usage -Telemetry」とラベル付けされた Main.cpp -内のコードのブロックを削除します。 - -Microsoft のプライバシー方針の詳細については、「[Microsoft -プライバシーに関する声明](https://privacy.microsoft.com/en-us/privacystatement/)」を参照してください。 diff --git a/Samples/System/GamepadVibration/readme_ko-kr.md b/Samples/System/GamepadVibration/readme_ko-kr.md deleted file mode 100644 index f4805a8f..00000000 --- a/Samples/System/GamepadVibration/readme_ko-kr.md +++ /dev/null @@ -1,53 +0,0 @@ -# 게임 패드 진동 샘플 - -*이 샘플은 Microsoft 게임 개발 키트 미리 보기(2019년 11월)와 -호환됩니다.* - -# - -# 설명 - -이 샘플에서는 Xbox One의 게임 패드에서 진동을 사용하는 방법을 보여 -줍니다. - -![](./media/image1.png) - -# 샘플 빌드하기 - -Xbox One 개발 키트를 사용하는 경우 활성 솔루션 플랫폼을 -Gaming.Xbox.XboxOne.x64로 설정하세요. - -Project Scarlett을 사용하는 경우 활성 솔루션 플랫폼을 -Gaming.Xbox.Scarlett.x64로 설정하세요. - -*자세한 내용은 GDK 문서에서* 샘플 실행하기*를 참조하세요.* - -# 샘플 사용 - -D-패드 왼쪽과 오른쪽을 사용하여 다른 진동 예제 간을 순환합니다. 대부분의 -예제에서 트리거를 사용하여 진동 크기를 늘립니다. - -# 구현 참고 사항 - -이 샘플에서는 GameInput API를 사용하여 Xbox One 게임 패드에서 진동 -수준을 설정하는 방법을 보여 줍니다. - -# 업데이트 기록 - -초기 릴리스 2019년 4월 - -**SetRumbleState**에 대한 경미한 주요 변경 내용으로 2019년 6월에 -업데이트되었습니다. - -2020년 2월: GameInput API에 대한 변경 내용으로 업데이트되었습니다. - -# 개인정보처리방침 - -샘플을 컴파일하고 실행할 때 샘플 사용을 추적하는 데 도움이 되도록 샘플 -실행 파일의 파일 이름이 Microsoft에 전송됩니다. 이 데이터 수집을 -옵트아웃하려면 Main.cpp에서 \"샘플 사용 원격 분석\"이라고 레이블이 -지정된 코드 블록을 제거할 수 있습니다. - -Microsoft의 개인 정보 보호 정책에 대한 자세한 내용은 [Microsoft -개인정보처리방침](https://privacy.microsoft.com/en-us/privacystatement/)을 -참조하세요. diff --git a/Samples/System/GamepadVibration/readme_zh-cn.md b/Samples/System/GamepadVibration/readme_zh-cn.md deleted file mode 100644 index de0a28d4..00000000 --- a/Samples/System/GamepadVibration/readme_zh-cn.md +++ /dev/null @@ -1,47 +0,0 @@ -# 游戏手柄振动示例 - -此示例与 Microsoft 游戏开发工具包预览版(2019 年 11 月)兼容 - -# - -# 说明 - -本示例演示如何在 Xbox One 的游戏手柄上使用振动模式。 - -![](./media/image1.png) - -# 构建示例 - -如果使用 Xbox One 开发工具包,请将活动解决方案平台设置为 -Gaming.Xbox.XboxOne.x64。 - -如果使用 Project Scarlett,请将活动解决方案平台设置为 -Gaming.Xbox.Scarlett.x64。 - -有关详细信息,请参阅 GDK 文档中的"运行示例"。 - -# 使用示例 - -使用向左和向右方向键在不同振动示例之间循环切换。 -大部分示例都使用触发器来增加振动量。 - -# 实现说明 - -本示例演示如何使用 GameInput API 设置 Xbox One 游戏手柄的振动级别。 - -# 更新历史记录 - -初始发布:2019 年 4 月 - -2019 年 6 月更新了对 SetRumbleState 的次要中断性变更。 - -2020 年 2 月:更新了对 GameInput API 的更改。 - -# 隐私声明 - -在编译和运行示例时,会将示例可执行文件的文件名发送给 -Microsoft,用于帮助跟踪示例使用情况。要选择退出此数据收集,你可以删除 -Main.cpp 中标记为"示例使用遥测"的代码块。 - -有关 Microsoft 的一般隐私策略的详细信息,请参阅《[Microsoft -隐私声明](https://privacy.microsoft.com/en-us/privacystatement/)》。 diff --git a/Samples/System/Haptics/Audio/WaveSampleGenerator.cpp b/Samples/System/Haptics/Audio/WaveSampleGenerator.cpp deleted file mode 100644 index 9ae9206b..00000000 --- a/Samples/System/Haptics/Audio/WaveSampleGenerator.cpp +++ /dev/null @@ -1,379 +0,0 @@ -//-------------------------------------------------------------------------------------- -// WaveSampleGenerator.cpp -// -// Demonstrates how to play an in-memory WAV file via WASAPI. -// -// Advanced Technology Group (ATG) -// Copyright (C) Microsoft Corporation. All rights reserved. -//-------------------------------------------------------------------------------------- - -#include "pch.h" -#include "WaveSampleGenerator.h" - -//-------------------------------------------------------------------------------------- -// Name: WaveSampleReader -// Desc: Class that can read from WAVE data and convert it to floating point -//-------------------------------------------------------------------------------------- - -class WaveSampleReader -{ -public: - WaveSampleReader( const BYTE* pWaveData, DWORD waveSize, WAVEFORMATEXTENSIBLE* pWfx ); - - ~WaveSampleReader() - { - } - - void ReadBlock( FLOAT* pOutput, UINT32 nMaxChannels ); - - bool IsEOF( void ) const - { - return ( ( m_pCurrent - m_pBase ) >= m_nSize ); - } - -private: - - const BYTE* m_pBase; - const BYTE* m_pCurrent; - UINT32 m_nSize; - UINT32 m_nBitsPerSample; - UINT32 m_nChannels; - UINT32 m_nBlockAlign; - bool m_bIsFloat; -}; - -//-------------------------------------------------------------------------------------- -// Name: WaveSampleReader -//-------------------------------------------------------------------------------------- - -WaveSampleReader::WaveSampleReader( const BYTE* pWaveData, DWORD waveSize, WAVEFORMATEXTENSIBLE* pWfx ) : - m_pBase( pWaveData ), - m_pCurrent( pWaveData ), - m_nSize( waveSize ), - m_nBitsPerSample(0), - m_nChannels(0), - m_nBlockAlign(0), - m_bIsFloat(false) -{ - if ( ( pWfx->Format.wFormatTag == WAVE_FORMAT_PCM ) || - ( pWfx->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && pWfx->SubFormat == KSDATAFORMAT_SUBTYPE_PCM ) ) - { - m_bIsFloat = false; - m_nBitsPerSample = pWfx->Format.wBitsPerSample; - - m_nChannels = pWfx->Format.nChannels; - m_nBlockAlign = pWfx->Format.nBlockAlign; - } - else if ( ( pWfx->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT ) || - ( pWfx->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && pWfx->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT ) ) - { - m_bIsFloat = true; - m_nBitsPerSample = pWfx->Format.wBitsPerSample; - - m_nChannels = pWfx->Format.nChannels; - m_nBlockAlign = pWfx->Format.nBlockAlign; - } -} - - -//-------------------------------------------------------------------------------------- -// Name: ReadBlock -// Desc: Read one block's worth of sample data, convert it to floating point and -// store as many channels as is possible in the array provided. -//-------------------------------------------------------------------------------------- - -void WaveSampleReader::ReadBlock( FLOAT* pOutput, UINT32 nMaxChannels ) -{ - if ( !IsEOF() ) - { - const UINT32 nCopyChannels = std::min( nMaxChannels, m_nChannels ); - const UINT32 nSampleIncrement = m_nBitsPerSample / 8; - - const BYTE* pSample = m_pCurrent; - UINT32 nChannel = 0; - - // Copy as many channels as we can - for ( ; nChannel < nCopyChannels; ++nChannel ) - { - FLOAT fValue = 0; - - if ( m_bIsFloat ) - { - fValue = *(FLOAT *)pSample; - } - else - { - switch ( m_nBitsPerSample ) - { - case 16: - fValue = *(INT16 *)( pSample ) / ( (FLOAT)INT16_MAX + 1.0f ); - break; - - case 24: - { - // Convert from 24 bit to 32 bit, replicating top byte into - // low byte. - const UINT32 unpacked = ( ( (UINT32)pSample[2] & 0xFFU ) << 24 ) | - ( ( (UINT32)pSample[1] & 0xFFU ) << 16 ) | - ( ( (UINT32)pSample[0] & 0xFFU ) << 8 ) | - ( ( (UINT32)pSample[2] & 0xFFU ) ); - fValue = ( (INT32)unpacked ) / ( (FLOAT)INT32_MAX + 1.0f ); - } - break; - - case 32: - fValue = *(INT32 *)( pSample ) / ( (FLOAT)INT32_MAX + 1.0f ); - break; - } - } - pOutput[ nChannel ] = fValue; - pSample += nSampleIncrement; - } - - // Fill remaining channels with zero - for ( ; nChannel < nMaxChannels; ++nChannel ) - { - pOutput[ nChannel ] = 0.0f; - } - - // Advance current pointer by one block - m_pCurrent += m_nBlockAlign; - } - else - { - // If we're at EOF then just clear the output buffer - ZeroMemory( pOutput, nMaxChannels * sizeof( FLOAT ) ); - } -} - - -//-------------------------------------------------------------------------------------- -// Name: WaveSampleWriter -// Desc: Class that accepts floating point sample data, and can store it in an -// alternative representation. -//-------------------------------------------------------------------------------------- - -class WaveSampleWriter -{ -public: - WaveSampleWriter( BYTE* pBuffer, DWORD bufferSize, WAVEFORMATEX* pWfx ); - - ~WaveSampleWriter() - { - } - - void WriteBlock( const FLOAT* pInput, UINT32 nMaxChannels ); - - bool IsEOF( void ) const - { - return ( ( m_pCurrent - m_pBase ) >= m_nSize ); - } - -private: - - BYTE* m_pBase; - BYTE* m_pCurrent; - UINT32 m_nSize; - UINT32 m_nBitsPerSample; - UINT32 m_nChannels; - UINT32 m_nBlockAlign; - bool m_bIsFloat; -}; - - -//-------------------------------------------------------------------------------------- -// Name: WaveSampleWriter -//-------------------------------------------------------------------------------------- - -WaveSampleWriter::WaveSampleWriter( BYTE* pBuffer, DWORD bufferSize, WAVEFORMATEX* pWfx ) : - m_pBase( pBuffer ), - m_pCurrent( pBuffer ), - m_nSize( bufferSize ), - m_nBitsPerSample(0), - m_nChannels(0), - m_nBlockAlign(0), - m_bIsFloat(false) -{ - if ( ( pWfx->wFormatTag == WAVE_FORMAT_PCM ) || - ( pWfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE && ((WAVEFORMATEXTENSIBLE*)pWfx)->SubFormat == KSDATAFORMAT_SUBTYPE_PCM ) ) - { - m_bIsFloat = false; - m_nBitsPerSample = pWfx->wBitsPerSample; - - m_nChannels = pWfx->nChannels; - m_nBlockAlign = pWfx->nBlockAlign; - } - else if ( ( pWfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ) || - ( pWfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE && ((WAVEFORMATEXTENSIBLE*)pWfx)->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT ) ) - { - m_bIsFloat = true; - m_nBitsPerSample = pWfx->wBitsPerSample; - - m_nChannels = pWfx->nChannels; - m_nBlockAlign = pWfx->nBlockAlign; - } -} - - -//-------------------------------------------------------------------------------------- -// Name: WriteBlock -// Desc: Given a number of floating point samples, write as many as we can -// into our output buffer. -//-------------------------------------------------------------------------------------- - -void WaveSampleWriter::WriteBlock( const FLOAT* pInput, UINT32 nMaxChannels ) -{ - if ( !IsEOF() ) - { - const UINT32 nCopyChannels = std::min( nMaxChannels, m_nChannels ); - const UINT32 nSampleIncrement = m_nBitsPerSample / 8; - - BYTE* pSample = m_pCurrent; - UINT32 nChannel = 0; - - // Copy as many channels as we can - for ( ; nChannel < nCopyChannels; ++nChannel ) - { - FLOAT fValue = pInput[ nChannel ]; - - if ( m_bIsFloat ) - { - *(FLOAT *)( pSample ) = fValue; - } - else - { - switch ( m_nBitsPerSample ) - { - case 16: - *(INT16 *)( pSample ) = (INT16)( fValue * ( (FLOAT)INT16_MAX ) ); - break; - - case 32: - *(INT32 *)( pSample ) = (INT32)( fValue * ( (FLOAT)INT32_MAX ) ); - break; - } - } - - pSample += nSampleIncrement; - } - - // Fill remaining channels with zero - ZeroMemory( pSample, ( m_nChannels - nChannel ) * nSampleIncrement ); - - // Advance current pointer by one block - m_pCurrent += m_nBlockAlign; - } -} - -//-------------------------------------------------------------------------------------- -// Name: WaveSampleGenerator() -//-------------------------------------------------------------------------------------- -WaveSampleGenerator::WaveSampleGenerator() -{ - m_SampleQueue = nullptr; - m_SampleQueueTail = &m_SampleQueue; -} - - -//-------------------------------------------------------------------------------------- -// Name: ~WaveSampleGenerator() -//-------------------------------------------------------------------------------------- - -WaveSampleGenerator::~WaveSampleGenerator() -{ - // Flush unused samples - Flush(); -} - - -//-------------------------------------------------------------------------------------- -// Name: GenerateSampleBuffer() -// Desc: Create a linked list of sample buffers -//-------------------------------------------------------------------------------------- - -HRESULT WaveSampleGenerator::GenerateSampleBuffer( BYTE* pWaveData, DWORD waveSize, WAVEFORMATEXTENSIBLE* pSourceWfx, UINT32 framesPerPeriod, WAVEFORMATEX *pWfx ) -{ - HRESULT hr = S_OK; - - float sampleRatio = (float)pWfx->nSamplesPerSec / (float)pSourceWfx->Format.nSamplesPerSec; - - UINT32 renderBufferSizeInBytes = framesPerPeriod * pWfx->nBlockAlign; - UINT32 renderDataLength = ( waveSize / pSourceWfx->Format.nBlockAlign * pWfx->nBlockAlign ) + ( renderBufferSizeInBytes - 1 ); - UINT32 renderBufferCount = (UINT32)(renderDataLength * sampleRatio / renderBufferSizeInBytes); - - WaveSampleReader reader( pWaveData, waveSize, pSourceWfx ); - - for( UINT32 i = 0; i < renderBufferCount; i++ ) - { - RenderBuffer* sampleBuffer = new RenderBuffer(); - - sampleBuffer->BufferSize = renderBufferSizeInBytes; - sampleBuffer->BytesFilled = renderBufferSizeInBytes; - sampleBuffer->Buffer = new BYTE[ renderBufferSizeInBytes ]; - - WaveSampleWriter writer( sampleBuffer->Buffer, sampleBuffer->BufferSize, pWfx ); - - while ( !writer.IsEOF() ) - { - constexpr UINT32 nMaxChannels = 8; - FLOAT channelData[ nMaxChannels ]; - - // Get a block of channel data (as much as we're interested in). - // If the reader is at end of file then this returns a block - // of zeroed samples. - reader.ReadBlock( channelData, nMaxChannels ); - - for(unsigned int j=0; jNext; - } - return hr; -} - - -//-------------------------------------------------------------------------------------- -// Name: FillSampleBuffer() -// Desc: File the Data buffer of size BytesToRead with the first item in the queue. -// Caller is responsible for allocating and freeing buffer -//-------------------------------------------------------------------------------------- - -HRESULT WaveSampleGenerator::FillSampleBuffer( UINT32 bytesToRead, BYTE *pData ) -{ - if (nullptr == pData) - { - return E_POINTER; - } - - RenderBuffer *sampleBuffer = m_SampleQueue; - - if (bytesToRead > sampleBuffer->BufferSize) - { - return E_INVALIDARG; - } - - CopyMemory( pData, sampleBuffer->Buffer, bytesToRead ); - - m_SampleQueue = m_SampleQueue->Next; - - return S_OK; -} - - -//-------------------------------------------------------------------------------------- -// Name: Flush() -// Desc: Remove and free unused samples from the queue -//-------------------------------------------------------------------------------------- - -void WaveSampleGenerator::Flush() -{ - while( m_SampleQueue != nullptr ) - { - RenderBuffer *sampleBuffer = m_SampleQueue; - m_SampleQueue = sampleBuffer->Next; - } -} diff --git a/Samples/System/Haptics/Haptics.sln b/Samples/System/Haptics/Haptics.sln deleted file mode 100644 index ded8a2a9..00000000 --- a/Samples/System/Haptics/Haptics.sln +++ /dev/null @@ -1,37 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.10.35013.160 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Haptics", "Haptics.vcxproj", "{05BE229F-8345-468F-9B78-36966862B1F8}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|ARM64 = Debug|ARM64 - Debug|x64 = Debug|x64 - Profile|ARM64 = Profile|ARM64 - Profile|x64 = Profile|x64 - Release|ARM64 = Release|ARM64 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {05BE229F-8345-468F-9B78-36966862B1F8}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {05BE229F-8345-468F-9B78-36966862B1F8}.Debug|ARM64.Build.0 = Debug|ARM64 - {05BE229F-8345-468F-9B78-36966862B1F8}.Debug|x64.ActiveCfg = Debug|x64 - {05BE229F-8345-468F-9B78-36966862B1F8}.Debug|x64.Build.0 = Debug|x64 - {05BE229F-8345-468F-9B78-36966862B1F8}.Profile|ARM64.ActiveCfg = Profile|ARM64 - {05BE229F-8345-468F-9B78-36966862B1F8}.Profile|ARM64.Build.0 = Profile|ARM64 - {05BE229F-8345-468F-9B78-36966862B1F8}.Profile|x64.ActiveCfg = Profile|x64 - {05BE229F-8345-468F-9B78-36966862B1F8}.Profile|x64.Build.0 = Profile|x64 - {05BE229F-8345-468F-9B78-36966862B1F8}.Release|ARM64.ActiveCfg = Release|ARM64 - {05BE229F-8345-468F-9B78-36966862B1F8}.Release|ARM64.Build.0 = Release|ARM64 - {05BE229F-8345-468F-9B78-36966862B1F8}.Release|x64.ActiveCfg = Release|x64 - {05BE229F-8345-468F-9B78-36966862B1F8}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {01A821B7-A353-422C-8FB8-A5F3C53D44BD} - EndGlobalSection -EndGlobal diff --git a/Samples/System/Haptics/Haptics.vcxproj b/Samples/System/Haptics/Haptics.vcxproj deleted file mode 100644 index e05ab351..00000000 --- a/Samples/System/Haptics/Haptics.vcxproj +++ /dev/null @@ -1,579 +0,0 @@ - - - - - Debug - ARM64 - - - Debug - x64 - - - Profile - ARM64 - - - Profile - x64 - - - Release - ARM64 - - - Release - x64 - - - - Haptics - {05be229f-8345-468f-9b78-36966862b1f8} - en-US - Win32Proj - true - - 17.0 - Native - x64 - Haptics - 10.0 - - - - - Application - v143 - false - true - Unicode - false - false - - - Application - v143 - false - true - Unicode - false - false - - - Application - v143 - false - true - Unicode - false - false - - - Application - v143 - false - true - Unicode - false - false - - - Application - v143 - true - Unicode - false - false - - - Application - v143 - true - Unicode - false - false - - - - - - - - - - - - - - - - - - - - - - - - - - $(VC_ReferencesPath_x64); - $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) - $(WindowsSDK_MetadataPath); - $(GDKCrossPlatformPath)windows\include;$(IncludePath); - $(GameDK)bin;$(ExecutablePath) - false - - - $(VC_ReferencesPath_ARM64); - $(VC_LibraryPath_ARM64);$(WindowsSDK_LibraryPath_ARM64) - $(WindowsSDK_MetadataPath); - $(GDKCrossPlatformPath)windows\include;$(IncludePath); - $(GameDK)bin;$(ExecutablePath) - false - - - $(VC_ReferencesPath_x64); - $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) - $(WindowsSDK_MetadataPath); - $(GDKCrossPlatformPath)windows\include;$(IncludePath); - $(GameDK)bin;$(ExecutablePath) - false - - - $(VC_ReferencesPath_ARM64); - $(VC_LibraryPath_ARM64);$(WindowsSDK_LibraryPath_ARM64) - $(WindowsSDK_MetadataPath); - $(GDKCrossPlatformPath)windows\include;$(IncludePath); - $(GameDK)bin;$(ExecutablePath) - false - - - $(VC_ReferencesPath_x64); - $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) - $(WindowsSDK_MetadataPath); - $(GDKCrossPlatformPath)windows\include;$(IncludePath); - $(GameDK)bin;$(ExecutablePath) - true - - - $(VC_ReferencesPath_ARM64); - $(VC_LibraryPath_ARM64);$(WindowsSDK_LibraryPath_ARM64) - $(WindowsSDK_MetadataPath); - $(GDKCrossPlatformPath)windows\include;$(IncludePath); - true - $(GameDK)bin;$(ExecutablePath) - - - false - - - - gameinput.lib;d3d12.lib;dxgi.lib;dxguid.lib;uuid.lib;kernel32.lib;user32.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;runtimeobject.lib;%(AdditionalDependencies) - true - Windows - true - true - - - MaxSpeed - NDEBUG;%(PreprocessorDefinitions) - Level4 - true - true - true - /Zc:__cplusplus %(AdditionalOptions) - Use - pch.h - $(ProjectDir);$(ProjectDir)\shaders\$(Platform);..\..\..\Kits\OpenSource\imgui;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - stdcpp17 - - - 6.0 - true - /Fd "$(OutDir)%(Filename).pdb" %(AdditionalOptions) - - - - - gameinput.lib;d3d12.lib;dxgi.lib;dxguid.lib;uuid.lib;kernel32.lib;user32.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;runtimeobject.lib;%(AdditionalDependencies) - true - Windows - true - true - - - MaxSpeed - NDEBUG;%(PreprocessorDefinitions) - Level4 - true - true - true - /Zc:__cplusplus %(AdditionalOptions) - Use - pch.h - $(ProjectDir);$(ProjectDir)\shaders\$(Platform);..\..\..\Kits\OpenSource\imgui;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - stdcpp17 - - - 6.0 - true - /Fd "$(OutDir)%(Filename).pdb" %(AdditionalOptions) - - - - - gameinput.lib;d3d12.lib;dxgi.lib;dxguid.lib;uuid.lib;kernel32.lib;user32.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;runtimeobject.lib;%(AdditionalDependencies) - true - Windows - true - true - - - MaxSpeed - NDEBUG;PROFILE;%(PreprocessorDefinitions) - Level4 - true - true - true - /Zc:__cplusplus %(AdditionalOptions) - Use - pch.h - $(ProjectDir);$(ProjectDir)\shaders\$(Platform);..\..\..\Kits\OpenSource\imgui;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - stdcpp17 - - - 6.0 - true - /Fd "$(OutDir)%(Filename).pdb" %(AdditionalOptions) - - - - - gameinput.lib;d3d12.lib;dxgi.lib;dxguid.lib;uuid.lib;kernel32.lib;user32.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;runtimeobject.lib;%(AdditionalDependencies) - true - Windows - true - true - - - MaxSpeed - NDEBUG;PROFILE;%(PreprocessorDefinitions) - Level4 - true - true - true - /Zc:__cplusplus %(AdditionalOptions) - Use - pch.h - $(ProjectDir);$(ProjectDir)\shaders\$(Platform);..\..\..\Kits\OpenSource\imgui;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - stdcpp17 - - - 6.0 - true - /Fd "$(OutDir)%(Filename).pdb" %(AdditionalOptions) - - - - - gameinput.lib;d3d12.lib;dxgi.lib;dxguid.lib;uuid.lib;kernel32.lib;user32.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;runtimeobject.lib;%(AdditionalDependencies) - Windows - true - - - false - Level4 - Disabled - DEBUG;_DEBUG;%(PreprocessorDefinitions) - true - /Zc:__cplusplus %(AdditionalOptions) - Use - pch.h - $(ProjectDir);$(ProjectDir)\shaders\$(Platform);..\..\..\Kits\OpenSource\imgui;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - stdcpp17 - - - 6.0 - true - /Fd "$(OutDir)%(Filename).pdb" %(AdditionalOptions) - - - - - gameinput.lib;d3d12.lib;dxgi.lib;dxguid.lib;uuid.lib;kernel32.lib;user32.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;runtimeobject.lib;%(AdditionalDependencies) - Windows - true - - - false - Level4 - Disabled - DEBUG;_DEBUG;%(PreprocessorDefinitions) - true - /Zc:__cplusplus %(AdditionalOptions) - Use - pch.h - $(ProjectDir);$(ProjectDir)\shaders\$(Platform);..\..\..\Kits\OpenSource\imgui;..\..\..\Kits\ATGTK;%(AdditionalIncludeDirectories) - stdcpp17 - - - 6.0 - true - /Fd "$(OutDir)%(Filename).pdb" %(AdditionalOptions) - - - - - - - - 6011;6387;26819;28182;%(DisableSpecificWarnings) - - - 4265;4365;6011;6387;26819;28182;%(DisableSpecificWarnings) - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - 6011;6387;26819;28182;%(DisableSpecificWarnings) - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - 6011;6387;26819;28182;%(DisableSpecificWarnings) - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - 6011;6387;26819;28182;%(DisableSpecificWarnings) - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - 6011;6387;26819;28182;%(DisableSpecificWarnings) - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - - Create - Create - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - Document - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - - - true - Document - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - - - true - Document - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - - - - - Document - true - true - true - true - true - true - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - - - Document - true - true - true - true - true - true - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - - - Document - true - true - true - true - true - true - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - - - Document - true - true - true - true - true - true - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - $(OutDir)/Media - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - \ No newline at end of file diff --git a/Samples/System/Haptics/Haptics.vcxproj.filters b/Samples/System/Haptics/Haptics.vcxproj.filters deleted file mode 100644 index cadf4ca7..00000000 --- a/Samples/System/Haptics/Haptics.vcxproj.filters +++ /dev/null @@ -1,228 +0,0 @@ - - - - - {3d34b4bd-ea46-406c-9824-0dda6444b99f} - - - {474d2779-f286-4074-841b-641a4e0942d0} - - - {ab96ee58-26a3-423c-ba2d-95106afc4757} - - - {41afdda5-4535-4267-8a66-027442e5e840} - - - {fcae9164-8ac1-425d-b241-30e5c18546a8} - - - {bc7472e0-fe60-4401-bc5d-a20209e93581} - - - {3a8c1b54-9311-4dd5-837d-82642273abc0} - - - {d5a2c484-cdc8-4e8d-ac54-8dee8d52bd08} - - - - - - - - ImGui - - - ImGui - - - ImGui - - - ImGui - - - ImGui\ATG - - - ImGui\ATG - - - ImGui\Backends - - - ImGui\Backends - - - ImGui\ATG - - - ATG Tool Kit - - - HapticsManager - - - HapticsManager - - - HapticsManager\Audio - - - HapticsManager\Audio - - - HapticsManager\Audio - - - HapticsManager\Audio - - - - - - - ImGui - - - ImGui - - - ImGui - - - ImGui - - - ImGui - - - ImGui - - - ImGui\ATG - - - ImGui\ATG - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends\Shaders - - - ImGui\Backends - - - ImGui\Backends - - - ImGui\ATG - - - ATG Tool Kit - - - HapticsManager - - - HapticsManager - - - HapticsManager\Audio - - - HapticsManager\Audio - - - HapticsManager\Audio - - - HapticsManager\Audio - - - HapticsManager\Audio - - - HapticsManager\Audio - - - - - Media - - - Media - - - Media - - - Media - - - Media - - - Media - - - Media - - - - - - - - \ No newline at end of file diff --git a/Samples/System/Haptics/Main.cpp b/Samples/System/Haptics/Main.cpp deleted file mode 100644 index 4dee7264..00000000 --- a/Samples/System/Haptics/Main.cpp +++ /dev/null @@ -1,223 +0,0 @@ -//-------------------------------------------------------------------------------------- -// main.cpp -// -// Window setup and message loop -// -// Advanced Technology Group (ATG) -// Copyright (C) Microsoft Corporation. All rights reserved. -//-------------------------------------------------------------------------------------- - -#include "pch.h" - -#include "haptics.h" - -namespace -{ - static constexpr int c_WindowWidth = 1920; - static constexpr int c_WindowHeight = 1080; - - static std::unique_ptr g_d3dDeviceContext; - static std::unique_ptr g_sample; -} - -static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - -static void ToggleFullscreen(HWND hWnd) -{ - static bool isFullscreen = false; - static RECT windowRect = {}; - - if (isFullscreen) - { - // Restore windowed mode - SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE); - SetWindowPos(hWnd, HWND_TOP, - windowRect.left, windowRect.top, - windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, - SWP_FRAMECHANGED); - } - else - { - // Switch to borderless fullscreen - GetWindowRect(hWnd, &windowRect); - SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP | WS_VISIBLE); - SetWindowPos(hWnd, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_FRAMECHANGED); - } - isFullscreen = !isFullscreen; -} - -// Main code -int WINAPI wWinMain(_In_ HINSTANCE /*hInstance*/, _In_opt_ HINSTANCE /*hPrevInstance*/, _In_ LPWSTR /*lpCmdLine*/, _In_ int /*nCmdShow*/) -{ - // Create application window - ImGui_ImplWin32_EnableDpiAwareness(); - WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"Advanced Haptics", nullptr }; - RegisterClassExW(&wc); - - HWND hWnd = CreateWindowW(wc.lpszClassName, L"Advanced Haptics", WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, c_WindowWidth, c_WindowHeight, nullptr, nullptr, wc.hInstance, nullptr); - - // Initialize Direct3D - g_d3dDeviceContext = std::make_unique(); - if (!g_d3dDeviceContext->CreateDevice(hWnd, c_WindowWidth, c_WindowHeight)) - { - UnregisterClassW(wc.lpszClassName, wc.hInstance); - return 1; - } - - // Show the window, top of z-order - ShowWindow(hWnd, SW_SHOWNORMAL); - UpdateWindow(hWnd); - SetForegroundWindow(hWnd); - - // Setup Dear ImGui context - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); (void)io; - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls - io.IniFilename = nullptr; // Disable INI file creation - - // Setup Dear ImGui style - ImGuiAtg::SetAtgStyle(); - ImGuiAtg::SetDpiScale(hWnd); - - // Setup Platform/Renderer backends - ImGui_ImplWin32_Init(hWnd); - g_d3dDeviceContext->DX12_Init(); - - g_sample = std::make_unique(); - g_sample->Initialize(hWnd); - - // Main loop - MSG msg = {}; - while (msg.message != WM_QUIT) - { - if (PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - else - { - g_sample->Update(); - - // Start the Dear ImGui frame - g_d3dDeviceContext->DX12_PreRender(); - ImGui_ImplDX12_NewFrame(); - ImGui_ImplWin32_NewFrame(); - ImGui::NewFrame(); - - ImGuiAtg::HandleStandardInput(); - - // Draw the ImGui controls - g_sample->Draw(); - - // Rendering - ImGui::Render(); - g_d3dDeviceContext->DX12_PostRender(); - } - } - - // Shutdown and cleanup - g_d3dDeviceContext->DX12_Shutdown(); - g_sample->Shutdown(); - g_sample.reset(); - ImGui_ImplDX12_Shutdown(); - ImGui_ImplWin32_Shutdown(); - ImGui::DestroyContext(); - - g_d3dDeviceContext.reset(); - DestroyWindow(hWnd); - UnregisterClassW(wc.lpszClassName, wc.hInstance); - - return 0; -} - -extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - -LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - // Give the sample first crack at messages before passing them to ImGui or the default proc. - if (g_sample && g_sample->WndProcHandler(hWnd, msg, wParam, lParam)) - { - return 1; - } - - if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) - { - return 1; - } - - switch (msg) - { - case WM_GETMINMAXINFO: - { - // Enforce a minimum window size on desktop. - MINMAXINFO* mmi = (MINMAXINFO*)lParam; - mmi->ptMinTrackSize.x = 1280; - mmi->ptMinTrackSize.y = 720; - } - return 0; - - case WM_KEYDOWN: - if (wParam == VK_F11) - { - ToggleFullscreen(hWnd); - return 0; - } - break; - - case WM_SYSKEYDOWN: - if (wParam == VK_RETURN && (lParam & 0x60000000) == 0x20000000) - { - ToggleFullscreen(hWnd); - return 0; - } - break; - - case WM_ACTIVATEAPP: - if (g_sample) - { - if (wParam) - { - g_sample->Activated(); - } - else - { - g_sample->Deactivated(); - } - } - break; - - case WM_SIZE: - if (g_d3dDeviceContext) - g_d3dDeviceContext->DX12_Resize(lParam, wParam); - return 0; - - case WM_DPICHANGED: - { - RECT* rect = (RECT*)lParam; - SetWindowPos(hWnd, NULL, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top, SWP_NOZORDER); - ImGuiAtg::SetDpiScale(hWnd); - } - return 0; - - case WM_SYSCOMMAND: - if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu - { - return 0; - } - break; - - case WM_DESTROY: - PostQuitMessage(0); - return 0; - } - return DefWindowProcW(hWnd, msg, wParam, lParam); -} - -void ExitSample() noexcept -{ - PostQuitMessage(0); -} diff --git a/Samples/System/Haptics/haptics.cpp b/Samples/System/Haptics/haptics.cpp deleted file mode 100644 index 81c07945..00000000 --- a/Samples/System/Haptics/haptics.cpp +++ /dev/null @@ -1,323 +0,0 @@ -//-------------------------------------------------------------------------------------- -// haptics.cpp -// -// Advanced Technology Group (ATG) -// Copyright (C) Microsoft Corporation. All rights reserved. -//-------------------------------------------------------------------------------------- - -#include "pch.h" - -#include - -#include "haptics.h" -#include "HapticsManager/HapticsManager.h" -#include "HapticsManager/Audio/WASAPIManager.h" -#include "HapticsManager/Audio/XAudio2Manager.h" - -using namespace Microsoft::WRL; -using namespace ATG; - -struct MediaItem -{ - std::wstring filename {}; - std::wstring title {}; -}; - -struct DeviceContext -{ - MediaItem mediaItem; - GameInputGamepadState lastGamepadState = {}; -}; - -ComPtr g_gameInput {}; -GameInputCallbackToken g_deviceCallbackToken {}; - -std::unique_ptr g_hapticsManager; -std::vector g_devices {}; -std::map g_deviceContext {}; - -std::vector g_mediaList = -{ - { L"media\\AhoogaHorn.wav", L"Ahooga Horn" }, - { L"media\\car.wav", L"Car" }, - { L"media\\fireworks.wav", L"Fireworks" }, - { L"media\\gun_shot.wav", L"Gun Shot" }, - { L"media\\PenScratch.wav", L"Pen Scratch" }, - { L"media\\ShakeEffect.wav", L"Shake" }, - { L"media\\TommyGun.wav", L"Tommy Gun" }, -}; - -static void DeviceCallback(GameInputCallbackToken, void*, IGameInputDevice* device, uint64_t, GameInputDeviceStatus currentStatus, GameInputDeviceStatus previousStatus) noexcept -{ - const GameInputDeviceInfo* di = nullptr; - LOG_IF_FAILED_AND_RETURN(device->GetDeviceInfo(&di)); - - LOG("DeviceCallback\n VID / PID: %04X / %04X\n Device Id: %s\n Previous: %08X, Current: %08X\n", di->vendorId, di->productId, StringifyDeviceId(di->deviceId), previousStatus, currentStatus); - - bool wasConnected = (previousStatus & GameInputDeviceConnected) != 0; - bool isConnected = (currentStatus & GameInputDeviceConnected) != 0; - - // newly connected device, add to our list - if(isConnected && !wasConnected) - { - g_devices.push_back(device); - } - - // newly disconnected device, remove from our list - if(wasConnected && !isConnected) - { - g_devices.erase(std::remove(g_devices.begin(), g_devices.end(), device), g_devices.end()); - } -} - -static void StopAllHapticEffects() -{ - for(auto& giDevice : g_devices) - { - auto hd = g_hapticsManager->GetHapticsDevice(giDevice); - hd->Stop(); - } -} - -void Sample::Initialize(HWND hWnd) -{ - m_window = hWnd; - - // add the current directory to all of the media file paths - wchar_t exePath[MAX_PATH]; - if(GetModuleFileNameW(nullptr, exePath, MAX_PATH) > 0) - { - // remove the exe name - auto path = std::wstring(exePath); - path = path.substr(0, path.find_last_of(L"\\")); - - // add the full path to the media directory to each media item - for(auto &mi : g_mediaList) - { - mi.filename = path + L"\\" + mi.filename; - } - } - else - { - LOG("Unable to get current exe path\n"); - } - - // initialize GameInput and setup callbacks for all gamepad devices - LOG_IF_FAILED_AND_RETURN(GameInputCreate(&g_gameInput)); - LOG_IF_FAILED_AND_RETURN(g_gameInput->RegisterDeviceCallback(nullptr, - GameInputKind::GameInputKindGamepad, - GameInputDeviceStatus::GameInputDeviceAnyStatus, - GameInputEnumerationKind::GameInputBlockingEnumeration, - nullptr, - DeviceCallback, &g_deviceCallbackToken)); - - // initialize our HapticsManager class - g_hapticsManager = std::make_unique(); - LOG_IF_FAILED_AND_RETURN(g_hapticsManager->Initialize(g_gameInput.Get())); -} - -void Sample::Draw() -{ - ImGuiAtg::BeginFullscreenLayout(); - - // Content on left, log on right, with draggable splitter - ImGuiAtg::BeginSplitV("##LogSplit", 800.0f); - - ImGui::CollapsingHeader("Attached Gamepads", ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf); - - if(g_devices.size() == 0) - { - ImGui::Text("Please connect a haptics-enabled controller"); - } - else - { - // draw a section for each device attached - for(auto& giDevice : g_devices) - { - ComPtr reading; - GameInputGamepadState state; - const GameInputDeviceInfo* di = nullptr; - - // get the current GameInput device info and state - if(FAILED(g_gameInput->GetCurrentReading(GameInputKindGamepad, giDevice, &reading))) - { - continue; - } - reading->GetGamepadState(&state); - LOG_IF_FAILED_AND_RETURN(giDevice->GetDeviceInfo(&di)); - - // get the last state for this device that our sample uses - DeviceContext& context = g_deviceContext[giDevice]; - - // get the haptics device for this controller - const HapticsDevice* hapticsDevice = g_hapticsManager->GetHapticsDevice(giDevice); - - char header[512]{}; - sprintf_s(header, "Name: %s\nVID/PID: %04X / %04X\nDeviceID: %s", di->displayName, di->vendorId, di->productId, StringifyDeviceId(di->deviceId)); - ImGui::CollapsingHeader(header, ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Leaf); - ImGui::Dummy(ImVec2(0, 16.0f)); - ImGui::Indent(16.0f); - ImGui::PushID(giDevice); - - if(!hapticsDevice) - { - ImGui::Text("No haptic device found for this controller"); - } - else - { - ImGui::Text("Select a haptic effect to play..."); - if(ImGui::BeginCombo("##effect", DX::WideToUtf8(context.mediaItem.title).c_str())) - { - for(auto& mi : g_mediaList) - { - bool isSelected = (context.mediaItem.filename == mi.filename); - if(ImGui::Selectable(DX::WideToUtf8(mi.title).c_str(), &isSelected)) - { - context.mediaItem = mi; - } - - if(isSelected) - { - ImGui::SetItemDefaultFocus(); - } - } - ImGui::EndCombo(); - } - - if (ImGui::Button("Browse for file...", ImVec2(ImGuiAtg::Scaled(160), ImGuiAtg::Scaled(50)))) - { - std::wstring selectedFile = OpenWavFileDialog(m_window); - if (!selectedFile.empty()) - { - MediaItem mi; - mi.filename = selectedFile; - mi.title = selectedFile; - g_mediaList.push_back(mi); - context.mediaItem = mi; - } - } - - ImGui::Dummy(ImVec2(0, 20)); - - ImGui::BeginDisabled(hapticsDevice->IsPlaying()); - if(ImGui::Button("Play WASAPI (L1)", ImVec2(ImGuiAtg::Scaled(160), ImGuiAtg::Scaled(50))) || - (IsButtonPressed(state.buttons, context.lastGamepadState.buttons, GameInputGamepadButtons::GameInputGamepadLeftShoulder) && !hapticsDevice->IsPlaying())) - { - hapticsDevice->PlayWAVFile(context.mediaItem.filename.c_str(), HapticPlaybackEngine::WASAPI); - } - ImGui::SameLine(); - - if(ImGui::Button("Play XAudio2 (R1)", ImVec2(ImGuiAtg::Scaled(160), ImGuiAtg::Scaled(50))) || - (IsButtonPressed(state.buttons, context.lastGamepadState.buttons, GameInputGamepadButtons::GameInputGamepadRightShoulder) && !hapticsDevice->IsPlaying())) - { - hapticsDevice->PlayWAVFile(context.mediaItem.filename.c_str(), HapticPlaybackEngine::XAudio2); - } - ImGui::EndDisabled(); - - ImGui::SameLine(); - - if (ImGui::Button("Stop (B/Circle)", ImVec2(ImGuiAtg::Scaled(160), ImGuiAtg::Scaled(50))) || IsButtonPressed(state.buttons, context.lastGamepadState.buttons, GameInputGamepadButtons::GameInputGamepadB)) - { - hapticsDevice->Stop(); - } - } - - ImGui::PopID(); - ImGui::Unindent(16.0f); - ImGui::Dummy(ImVec2(0, 16.0f)); - - context.lastGamepadState = state; - } - - ImGui::Separator(); - ImGui::Dummy(ImVec2(0, 16)); - - // Only show Stop All if we have more than 1 haptics device - if(g_hapticsManager->GetDeviceCount() > 1) - { - ImGui::Indent(16.0f); - if(ImGui::Button("Stop All", ImVec2(ImGuiAtg::Scaled(120), ImGuiAtg::Scaled(50)))) - { - StopAllHapticEffects(); - } - } - } - - ImGuiAtg::SplitNext(); - ImGuiAtg::DrawLogPanel(); - ImGuiAtg::EndSplit(); - - ImGuiAtg::EndFullscreenLayout(); -} - -void Sample::Shutdown() -{ - StopAllHapticEffects(); - g_gameInput->UnregisterCallback(g_deviceCallbackToken); -} - -void Sample::Activated() -{ -} - -void Sample::Deactivated() -{ -} - -LRESULT Sample::WndProcHandler(HWND /*hWnd*/, UINT /*msg*/, WPARAM /*wParam*/, LPARAM /*lParam*/) -{ - return 0; -} - -std::wstring OpenWavFileDialog(HWND owner) -{ - wchar_t szFile[MAX_PATH]{}; - - OPENFILENAMEW ofn{}; - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = owner; - ofn.lpstrFile = szFile; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrFilter = L"WAV Files (*.wav)\0*.wav\0"; - ofn.nFilterIndex = 1; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - - if(GetOpenFileNameW(&ofn)) - { - return szFile; - } - return {}; -} - -const char* StringifyDeviceId(_In_ const APP_LOCAL_DEVICE_ID& deviceId) noexcept -{ - static char buffer[APP_LOCAL_DEVICE_ID_SIZE * 2 + 1] = {}; - - sprintf_s( - buffer, - sizeof(buffer), - "%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x" - "%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x" - "%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x" - "%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x", - deviceId.value[0], deviceId.value[1], deviceId.value[2], deviceId.value[3], - deviceId.value[4], deviceId.value[5], deviceId.value[6], deviceId.value[7], - deviceId.value[8], deviceId.value[9], deviceId.value[10], deviceId.value[11], - deviceId.value[12], deviceId.value[13], deviceId.value[14], deviceId.value[15], - deviceId.value[16], deviceId.value[17], deviceId.value[18], deviceId.value[19], - deviceId.value[20], deviceId.value[21], deviceId.value[22], deviceId.value[23], - deviceId.value[24], deviceId.value[25], deviceId.value[26], deviceId.value[27], - deviceId.value[28], deviceId.value[29], deviceId.value[30], deviceId.value[31]); - - return buffer; -} - -bool IsButtonPressed(GameInputGamepadButtons buttons, GameInputGamepadButtons lastButtons, GameInputGamepadButtons button) -{ - return (buttons & button) && !(lastButtons & button); -} - -void Sample::Update() -{ -} - diff --git a/Samples/System/Haptics/haptics.h b/Samples/System/Haptics/haptics.h deleted file mode 100644 index a062ee8d..00000000 --- a/Samples/System/Haptics/haptics.h +++ /dev/null @@ -1,46 +0,0 @@ -//-------------------------------------------------------------------------------------- -// haptics.h -// -// Advanced Technology Group (ATG) -// Copyright (C) Microsoft Corporation. All rights reserved. -//-------------------------------------------------------------------------------------- - -#pragma once - -#include -#if GAMEINPUT_API_VERSION == 1 -using namespace GameInput::v1; -#elif GAMEINPUT_API_VERSION == 2 -using namespace GameInput::v2; -#elif GAMEINPUT_API_VERSION == 3 -using namespace GameInput::v3; -#endif - -#define RETURN_IF_FAILED(hr) if(FAILED(hr)) return hr; -#define RETURN_IF_NULL_ALLOC(ptr) if(ptr == nullptr) return E_OUTOFMEMORY; - -class Sample -{ -public: - Sample() = default; - ~Sample() = default; - - Sample(Sample const&) = delete; - Sample& operator= (Sample const&) = delete; - - void Initialize(HWND hWnd); - void Update(); - void Draw(); - void Shutdown(); - void Activated(); - void Deactivated(); - LRESULT WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - -private: - HWND m_window = nullptr; -}; - -std::wstring OpenWavFileDialog(HWND owner); -bool IsButtonPressed(GameInputGamepadButtons buttons, GameInputGamepadButtons lastButtons, GameInputGamepadButtons button); - -const char* StringifyDeviceId(_In_ const APP_LOCAL_DEVICE_ID& deviceId) noexcept; diff --git a/Samples/System/Haptics/packages.config b/Samples/System/Haptics/packages.config deleted file mode 100644 index 0c27d7a1..00000000 --- a/Samples/System/Haptics/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Samples/System/Haptics/pch.cpp b/Samples/System/Haptics/pch.cpp deleted file mode 100644 index 4f7e09c0..00000000 --- a/Samples/System/Haptics/pch.cpp +++ /dev/null @@ -1,8 +0,0 @@ -//-------------------------------------------------------------------------------------- -// pch.cpp -// -// Advanced Technology Group (ATG) -// Copyright (C) Microsoft Corporation. All rights reserved. -//-------------------------------------------------------------------------------------- - -#include "pch.h" diff --git a/Samples/System/Haptics/pch.h b/Samples/System/Haptics/pch.h deleted file mode 100644 index b839133c..00000000 --- a/Samples/System/Haptics/pch.h +++ /dev/null @@ -1,115 +0,0 @@ -//-------------------------------------------------------------------------------------- -// pch.h -// -// Advanced Technology Group (ATG) -// Copyright (C) Microsoft Corporation. All rights reserved. -//-------------------------------------------------------------------------------------- - -#pragma once - -#include -#define _WIN32_WINNT 0x0A00 -#include - -// Use the C++ standard templated min/max -#define NOMINMAX - -// Include if you need this -#define NOMCX - -// Include if you need this -#define NOSERVICE - -// WinHelp is deprecated -#define NOHELP - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -#include - -#include -#include - -#include -#include - -#ifdef _DEBUG -#include -#endif - -#define _XM_NO_XMVECTOR_OVERLOADS_ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "StringUtil.h" - -// To use graphics markup events with the latest version of PIX, change this to include -// then add the NuGet package WinPixEventRuntime to the project. -#include - -#include "imgui.h" -#include "backends/imgui_impl_dx12.h" -#include "backends/imgui_impl_win32.h" -#include "imgui/imgui_atg.h" - -namespace DX -{ - // Helper class for COM exceptions - class com_exception : public std::exception - { - public: - com_exception(HRESULT hr) noexcept : result(hr) {} - - const char* what() const noexcept override - { - static char s_str[64] = {}; - sprintf_s(s_str, "Failure with HRESULT of %08X", static_cast(result)); - return s_str; - } - - private: - HRESULT result; - }; - - // Helper utility converts D3D API failures into exceptions. - inline void ThrowIfFailed(HRESULT hr) - { - if (FAILED(hr)) - { -#ifdef _DEBUG - char str[64] = {}; - sprintf_s(str, "**ERROR** Fatal Error with HRESULT of %08X\n", static_cast(hr)); - OutputDebugStringA(str); - __debugbreak(); -#endif - throw com_exception(hr); - } - } -} - -// Enable off by default warnings to improve code conformance -#pragma warning(default : 4061 4062 4191 4263 4264 4265 4266 4289 4365 4746 4826 4841 4986 4987 5029 5038 5042) diff --git a/Samples/System/Haptics/readme.md b/Samples/System/Haptics/readme.md deleted file mode 100644 index 9ae1c84a..00000000 --- a/Samples/System/Haptics/readme.md +++ /dev/null @@ -1,95 +0,0 @@ - - -# Advanced Haptics Sample - -# Description - -This sample demonstrates how to use the Advanced Haptics feature provided by the GameInput API. - -# Building the sample - -Build with Visual Studio 2022 (or greater). - -This sample uses the [GameInput NuGet package](https://www.nuget.org/packages/Microsoft.GameInput) which -will be restored during the build process. Also ensure the GameInput Redistributable is installed as -described below. - -# Running the sample - -Ensure that the GameInput runtime redistributable is installed. This can be found in the NuGet package, or -it can be installed via WinGet by running `winget install Microsoft.GameInput`. - -After starting the title, any connected controllers will be listed. Newly added/removed controllers will -update the UI, and any controllers with haptic capabilities will show a more detailed view allowing the -selection of various haptic effects with playback via WASAPI or XAudio2. Multiple devices can be connected -with individual playback occuring on each. - -# Implementation notes - -This sample demonstrates how to be notified when a controller is plugged in, when haptics are ready, if -available, and how to write audio data to the haptic endpoints using WASAPI and XAudio2. Haptics-related code -is located in the reusable library located in the `HapticsManager` directory. - -# Haptics Manager - -This sample has separated out much of the haptics code into a reusable class that can be integrated into other -projects. To use, copy the HapticsManager.h and HapticsManager.cpp files into your project along with the Audio -subdirectory. Then... - -- After the call to `GameInputCreate`, create an instance of `HapticsManager` and call `Initialize`, passing the -created `IGameInput` instance: -```c++ -ComPtr g_gameInput {}; -std::unique_ptr g_hapticsManager; -... -g_hapticsManager = std::make_unique(); -if (FAILED(g_hapticsManager->Initialize(g_gameInput.Get()))) -{ - // handle error -} -``` -- To write audio data to a haptic-enabled controller, call `GetHapticsDevice` with the `GameInputDevice` to retrieve -the `HapticsDevice` wrapper, then call one of the `Play` methods: -```c++ -const HapticsDevice* hapticsDevice = g_hapticsManager->GetHapticsDevice(giDevice); - -// if the device doesn't have haptic capabilities, hapticsDevice will be nullptr -if (hapticsDevice) -{ - // load and play a WAV file - hapticsDevice->PlayWAVFile("filename.wav", HapticPlaybackEngine::XAudio2); - - // OR play a pre-loaded WAV file - hapticsDevice->PlayWAVData(&wavData, wavDataSize, HapticPlaybackEngine::XAudio2); -} -``` -- To stop playing audio data, call the `Stop` method: -```c++ - hapticsDevice->Stop(); -``` - -# Known Issues/Expectations - -At present, the only haptics-enabled controller supported by GameInput is the PlayStation�5 DualSense� controller. - -# Update history - -- 01/2026 -- Updated with HapticsManager -- 10/2025 -- Initial release diff --git a/Samples/System/Haptics/readme.txt b/Samples/System/Haptics/readme.txt new file mode 100644 index 00000000..8417251d --- /dev/null +++ b/Samples/System/Haptics/readme.txt @@ -0,0 +1,2 @@ +The Haptics sample has been integrated into the new Gamepad sample: +Samples/System/Gamepad \ No newline at end of file diff --git a/Samples/Tools/RemoteIterationToolsSample/FileAttributeSelector.xaml b/Samples/Tools/RemoteIterationToolsSample/FileAttributeSelector.xaml index b6c12477..27b726e8 100644 --- a/Samples/Tools/RemoteIterationToolsSample/FileAttributeSelector.xaml +++ b/Samples/Tools/RemoteIterationToolsSample/FileAttributeSelector.xaml @@ -2,6 +2,7 @@ x:Name="Selector" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="clr-namespace:RemoteIterationToolsSample" Focusable="False"> @@ -14,10 +15,10 @@ - - - - + + + + diff --git a/Samples/Tools/RemoteIterationToolsSample/MainWindow.xaml b/Samples/Tools/RemoteIterationToolsSample/MainWindow.xaml index b7756368..67b00510 100644 --- a/Samples/Tools/RemoteIterationToolsSample/MainWindow.xaml +++ b/Samples/Tools/RemoteIterationToolsSample/MainWindow.xaml @@ -5,58 +5,68 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:RemoteIterationToolsSample" mc:Ignorable="d" - Title="Remote Deployment" Height="961" Width="752" + Title="{x:Static local:Messages.AppWindowTitle}" Height="961" Width="752" Background="#FF1E1E24" WindowStartupLocation="CenterScreen" Closing="Window_Closing"> - - + + - - - + @@ -110,194 +129,467 @@ - - + + - - + + - - + + - - - - - - - - + + + + + + + + + - - - - - + + + + + - - - - + + + + - - + + - -