WinRT: created SDLmain library using most of VC++ 2012's template for Direct3D 11 apps. Most of this will be moved into SDL itself.

This commit is contained in:
David Ludwig
2012-10-27 20:12:31 -04:00
parent 39084bc6b8
commit 7652fa94d0
12 changed files with 1233 additions and 0 deletions

View File

@@ -0,0 +1,199 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\main\windowsrt\BasicTimer.h" />
<ClInclude Include="..\..\src\main\windowsrt\CubeRenderer.h" />
<ClInclude Include="..\..\src\main\windowsrt\Direct3DBase.h" />
<ClInclude Include="..\..\src\main\windowsrt\DirectXHelper.h" />
<ClInclude Include="..\..\src\main\windowsrt\SDLmain_WinRT_common.h" />
<ClInclude Include="..\..\src\main\windowsrt\SDL_WinRTApp.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\main\windowsrt\CubeRenderer.cpp" />
<ClCompile Include="..\..\src\main\windowsrt\Direct3DBase.cpp" />
<ClCompile Include="..\..\src\main\windowsrt\SDL_WinRTApp.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{48666378-b527-43f5-8968-f867a6f8d2a3}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<ProjectName>SDLmain_VS2012_WinRT</ProjectName>
<RootNamespace>SDLmain_VS2012_WinRT</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|arm'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|arm'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>false</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,76 @@
#pragma once
#include <wrl.h>
// Helper class for basic timing.
ref class BasicTimer sealed
{
public:
// Initializes internal timer values.
BasicTimer()
{
if (!QueryPerformanceFrequency(&m_frequency))
{
throw ref new Platform::FailureException();
}
Reset();
}
// Reset the timer to initial values.
void Reset()
{
Update();
m_startTime = m_currentTime;
m_total = 0.0f;
m_delta = 1.0f / 60.0f;
}
// Update the timer's internal values.
void Update()
{
if (!QueryPerformanceCounter(&m_currentTime))
{
throw ref new Platform::FailureException();
}
m_total = static_cast<float>(
static_cast<double>(m_currentTime.QuadPart - m_startTime.QuadPart) /
static_cast<double>(m_frequency.QuadPart)
);
if (m_lastTime.QuadPart == m_startTime.QuadPart)
{
// If the timer was just reset, report a time delta equivalent to 60Hz frame time.
m_delta = 1.0f / 60.0f;
}
else
{
m_delta = static_cast<float>(
static_cast<double>(m_currentTime.QuadPart - m_lastTime.QuadPart) /
static_cast<double>(m_frequency.QuadPart)
);
}
m_lastTime = m_currentTime;
}
// Duration in seconds between the last call to Reset() and the last call to Update().
property float Total
{
float get() { return m_total; }
}
// Duration in seconds between the previous two calls to Update().
property float Delta
{
float get() { return m_delta; }
}
private:
LARGE_INTEGER m_frequency;
LARGE_INTEGER m_currentTime;
LARGE_INTEGER m_startTime;
LARGE_INTEGER m_lastTime;
float m_total;
float m_delta;
};

View File

@@ -0,0 +1,256 @@
#include "SDLmain_WinRT_common.h"
#include "CubeRenderer.h"
using namespace DirectX;
using namespace Microsoft::WRL;
using namespace Windows::Foundation;
using namespace Windows::UI::Core;
CubeRenderer::CubeRenderer() :
m_loadingComplete(false),
m_indexCount(0)
{
}
void CubeRenderer::CreateDeviceResources()
{
Direct3DBase::CreateDeviceResources();
auto loadVSTask = DX::ReadDataAsync("SimpleVertexShader.cso");
auto loadPSTask = DX::ReadDataAsync("SimplePixelShader.cso");
auto createVSTask = loadVSTask.then([this](Platform::Array<byte>^ fileData) {
DX::ThrowIfFailed(
m_d3dDevice->CreateVertexShader(
fileData->Data,
fileData->Length,
nullptr,
&m_vertexShader
)
);
const D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
DX::ThrowIfFailed(
m_d3dDevice->CreateInputLayout(
vertexDesc,
ARRAYSIZE(vertexDesc),
fileData->Data,
fileData->Length,
&m_inputLayout
)
);
});
auto createPSTask = loadPSTask.then([this](Platform::Array<byte>^ fileData) {
DX::ThrowIfFailed(
m_d3dDevice->CreatePixelShader(
fileData->Data,
fileData->Length,
nullptr,
&m_pixelShader
)
);
CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);
DX::ThrowIfFailed(
m_d3dDevice->CreateBuffer(
&constantBufferDesc,
nullptr,
&m_constantBuffer
)
);
});
auto createCubeTask = (createPSTask && createVSTask).then([this] () {
VertexPositionColor cubeVertices[] =
{
{XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT3(0.0f, 0.0f, 0.0f)},
{XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT3(0.0f, 0.0f, 1.0f)},
{XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT3(0.0f, 1.0f, 0.0f)},
{XMFLOAT3(-0.5f, 0.5f, 0.5f), XMFLOAT3(0.0f, 1.0f, 1.0f)},
{XMFLOAT3( 0.5f, -0.5f, -0.5f), XMFLOAT3(1.0f, 0.0f, 0.0f)},
{XMFLOAT3( 0.5f, -0.5f, 0.5f), XMFLOAT3(1.0f, 0.0f, 1.0f)},
{XMFLOAT3( 0.5f, 0.5f, -0.5f), XMFLOAT3(1.0f, 1.0f, 0.0f)},
{XMFLOAT3( 0.5f, 0.5f, 0.5f), XMFLOAT3(1.0f, 1.0f, 1.0f)},
};
D3D11_SUBRESOURCE_DATA vertexBufferData = {0};
vertexBufferData.pSysMem = cubeVertices;
vertexBufferData.SysMemPitch = 0;
vertexBufferData.SysMemSlicePitch = 0;
CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER);
DX::ThrowIfFailed(
m_d3dDevice->CreateBuffer(
&vertexBufferDesc,
&vertexBufferData,
&m_vertexBuffer
)
);
unsigned short cubeIndices[] =
{
0,2,1, // -x
1,2,3,
4,5,6, // +x
5,7,6,
0,1,5, // -y
0,5,4,
2,6,7, // +y
2,7,3,
0,4,6, // -z
0,6,2,
1,3,7, // +z
1,7,5,
};
m_indexCount = ARRAYSIZE(cubeIndices);
D3D11_SUBRESOURCE_DATA indexBufferData = {0};
indexBufferData.pSysMem = cubeIndices;
indexBufferData.SysMemPitch = 0;
indexBufferData.SysMemSlicePitch = 0;
CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER);
DX::ThrowIfFailed(
m_d3dDevice->CreateBuffer(
&indexBufferDesc,
&indexBufferData,
&m_indexBuffer
)
);
});
createCubeTask.then([this] () {
m_loadingComplete = true;
});
}
void CubeRenderer::CreateWindowSizeDependentResources()
{
Direct3DBase::CreateWindowSizeDependentResources();
float aspectRatio = m_windowBounds.Width / m_windowBounds.Height;
float fovAngleY = 70.0f * XM_PI / 180.0f;
// Note that the m_orientationTransform3D matrix is post-multiplied here
// in order to correctly orient the scene to match the display orientation.
// This post-multiplication step is required for any draw calls that are
// made to the swap chain render target. For draw calls to other targets,
// this transform should not be applied.
XMStoreFloat4x4(
&m_constantBufferData.projection,
XMMatrixTranspose(
XMMatrixMultiply(
XMMatrixPerspectiveFovRH(
fovAngleY,
aspectRatio,
0.01f,
100.0f
),
XMLoadFloat4x4(&m_orientationTransform3D)
)
)
);
}
void CubeRenderer::Update(float timeTotal, float timeDelta)
{
(void) timeDelta; // Unused parameter.
XMVECTOR eye = XMVectorSet(0.0f, 0.7f, 1.5f, 0.0f);
XMVECTOR at = XMVectorSet(0.0f, -0.1f, 0.0f, 0.0f);
XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
XMStoreFloat4x4(&m_constantBufferData.view, XMMatrixTranspose(XMMatrixLookAtRH(eye, at, up)));
XMStoreFloat4x4(&m_constantBufferData.model, XMMatrixTranspose(XMMatrixRotationY(timeTotal * XM_PIDIV4)));
}
void CubeRenderer::Render()
{
const float midnightBlue[] = { 0.098f, 0.098f, 0.439f, 1.000f };
m_d3dContext->ClearRenderTargetView(
m_renderTargetView.Get(),
midnightBlue
);
m_d3dContext->ClearDepthStencilView(
m_depthStencilView.Get(),
D3D11_CLEAR_DEPTH,
1.0f,
0
);
// Only draw the cube once it is loaded (loading is asynchronous).
if (!m_loadingComplete)
{
return;
}
m_d3dContext->OMSetRenderTargets(
1,
m_renderTargetView.GetAddressOf(),
m_depthStencilView.Get()
);
m_d3dContext->UpdateSubresource(
m_constantBuffer.Get(),
0,
NULL,
&m_constantBufferData,
0,
0
);
UINT stride = sizeof(VertexPositionColor);
UINT offset = 0;
m_d3dContext->IASetVertexBuffers(
0,
1,
m_vertexBuffer.GetAddressOf(),
&stride,
&offset
);
m_d3dContext->IASetIndexBuffer(
m_indexBuffer.Get(),
DXGI_FORMAT_R16_UINT,
0
);
m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_d3dContext->IASetInputLayout(m_inputLayout.Get());
m_d3dContext->VSSetShader(
m_vertexShader.Get(),
nullptr,
0
);
m_d3dContext->VSSetConstantBuffers(
0,
1,
m_constantBuffer.GetAddressOf()
);
m_d3dContext->PSSetShader(
m_pixelShader.Get(),
nullptr,
0
);
m_d3dContext->DrawIndexed(
m_indexCount,
0,
0
);
}

View File

@@ -0,0 +1,44 @@
#pragma once
#include "Direct3DBase.h"
struct ModelViewProjectionConstantBuffer
{
DirectX::XMFLOAT4X4 model;
DirectX::XMFLOAT4X4 view;
DirectX::XMFLOAT4X4 projection;
};
struct VertexPositionColor
{
DirectX::XMFLOAT3 pos;
DirectX::XMFLOAT3 color;
};
// This class renders a simple spinning cube.
ref class CubeRenderer sealed : public Direct3DBase
{
public:
CubeRenderer();
// Direct3DBase methods.
virtual void CreateDeviceResources() override;
virtual void CreateWindowSizeDependentResources() override;
virtual void Render() override;
// Method for updating time-dependent objects.
void Update(float timeTotal, float timeDelta);
private:
bool m_loadingComplete;
Microsoft::WRL::ComPtr<ID3D11InputLayout> m_inputLayout;
Microsoft::WRL::ComPtr<ID3D11Buffer> m_vertexBuffer;
Microsoft::WRL::ComPtr<ID3D11Buffer> m_indexBuffer;
Microsoft::WRL::ComPtr<ID3D11VertexShader> m_vertexShader;
Microsoft::WRL::ComPtr<ID3D11PixelShader> m_pixelShader;
Microsoft::WRL::ComPtr<ID3D11Buffer> m_constantBuffer;
uint32 m_indexCount;
ModelViewProjectionConstantBuffer m_constantBufferData;
};

View File

@@ -0,0 +1,344 @@
#include "SDLmain_WinRT_common.h"
#include "Direct3DBase.h"
using namespace DirectX;
using namespace Microsoft::WRL;
using namespace Windows::UI::Core;
using namespace Windows::Foundation;
using namespace Windows::Graphics::Display;
// Constructor.
Direct3DBase::Direct3DBase()
{
}
// Initialize the Direct3D resources required to run.
void Direct3DBase::Initialize(CoreWindow^ window)
{
m_window = window;
CreateDeviceResources();
CreateWindowSizeDependentResources();
}
// Recreate all device resources and set them back to the current state.
void Direct3DBase::HandleDeviceLost()
{
// Reset these member variables to ensure that UpdateForWindowSizeChange recreates all resources.
m_windowBounds.Width = 0;
m_windowBounds.Height = 0;
m_swapChain = nullptr;
CreateDeviceResources();
UpdateForWindowSizeChange();
}
// These are the resources that depend on the device.
void Direct3DBase::CreateDeviceResources()
{
// This flag adds support for surfaces with a different color channel ordering
// than the API default. It is required for compatibility with Direct2D.
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
#if defined(_DEBUG)
// If the project is in a debug build, enable debugging via SDK Layers with this flag.
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
// This array defines the set of DirectX hardware feature levels this app will support.
// Note the ordering should be preserved.
// Don't forget to declare your application's minimum required feature level in its
// description. All applications are assumed to support 9.1 unless otherwise stated.
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};
// Create the Direct3D 11 API device object and a corresponding context.
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;
DX::ThrowIfFailed(
D3D11CreateDevice(
nullptr, // Specify nullptr to use the default adapter.
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
creationFlags, // Set set debug and Direct2D compatibility flags.
featureLevels, // List of feature levels this app can support.
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps.
&device, // Returns the Direct3D device created.
&m_featureLevel, // Returns feature level of device created.
&context // Returns the device immediate context.
)
);
// Get the Direct3D 11.1 API device and context interfaces.
DX::ThrowIfFailed(
device.As(&m_d3dDevice)
);
DX::ThrowIfFailed(
context.As(&m_d3dContext)
);
}
// Allocate all memory resources that change on a window SizeChanged event.
void Direct3DBase::CreateWindowSizeDependentResources()
{
// Store the window bounds so the next time we get a SizeChanged event we can
// avoid rebuilding everything if the size is identical.
m_windowBounds = m_window->Bounds;
// Calculate the necessary swap chain and render target size in pixels.
float windowWidth = ConvertDipsToPixels(m_windowBounds.Width);
float windowHeight = ConvertDipsToPixels(m_windowBounds.Height);
// The width and height of the swap chain must be based on the window's
// landscape-oriented width and height. If the window is in a portrait
// orientation, the dimensions must be reversed.
m_orientation = DisplayProperties::CurrentOrientation;
bool swapDimensions =
m_orientation == DisplayOrientations::Portrait ||
m_orientation == DisplayOrientations::PortraitFlipped;
m_renderTargetSize.Width = swapDimensions ? windowHeight : windowWidth;
m_renderTargetSize.Height = swapDimensions ? windowWidth : windowHeight;
if(m_swapChain != nullptr)
{
// If the swap chain already exists, resize it.
DX::ThrowIfFailed(
m_swapChain->ResizeBuffers(
2, // Double-buffered swap chain.
static_cast<UINT>(m_renderTargetSize.Width),
static_cast<UINT>(m_renderTargetSize.Height),
DXGI_FORMAT_B8G8R8A8_UNORM,
0
)
);
}
else
{
// Otherwise, create a new one using the same adapter as the existing Direct3D device.
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
swapChainDesc.Width = static_cast<UINT>(m_renderTargetSize.Width); // Match the size of the window.
swapChainDesc.Height = static_cast<UINT>(m_renderTargetSize.Height);
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
swapChainDesc.Stereo = false;
swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency.
swapChainDesc.Scaling = DXGI_SCALING_NONE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect.
swapChainDesc.Flags = 0;
ComPtr<IDXGIDevice1> dxgiDevice;
DX::ThrowIfFailed(
m_d3dDevice.As(&dxgiDevice)
);
ComPtr<IDXGIAdapter> dxgiAdapter;
DX::ThrowIfFailed(
dxgiDevice->GetAdapter(&dxgiAdapter)
);
ComPtr<IDXGIFactory2> dxgiFactory;
DX::ThrowIfFailed(
dxgiAdapter->GetParent(
__uuidof(IDXGIFactory2),
&dxgiFactory
)
);
Windows::UI::Core::CoreWindow^ window = m_window.Get();
DX::ThrowIfFailed(
dxgiFactory->CreateSwapChainForCoreWindow(
m_d3dDevice.Get(),
reinterpret_cast<IUnknown*>(window),
&swapChainDesc,
nullptr, // Allow on all displays.
&m_swapChain
)
);
// Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
// ensures that the application will only render after each VSync, minimizing power consumption.
DX::ThrowIfFailed(
dxgiDevice->SetMaximumFrameLatency(1)
);
}
// Set the proper orientation for the swap chain, and generate the
// 3D matrix transformation for rendering to the rotated swap chain.
DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
switch (m_orientation)
{
case DisplayOrientations::Landscape:
rotation = DXGI_MODE_ROTATION_IDENTITY;
m_orientationTransform3D = XMFLOAT4X4( // 0-degree Z-rotation
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
break;
case DisplayOrientations::Portrait:
rotation = DXGI_MODE_ROTATION_ROTATE270;
m_orientationTransform3D = XMFLOAT4X4( // 90-degree Z-rotation
0.0f, 1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
break;
case DisplayOrientations::LandscapeFlipped:
rotation = DXGI_MODE_ROTATION_ROTATE180;
m_orientationTransform3D = XMFLOAT4X4( // 180-degree Z-rotation
-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
break;
case DisplayOrientations::PortraitFlipped:
rotation = DXGI_MODE_ROTATION_ROTATE90;
m_orientationTransform3D = XMFLOAT4X4( // 270-degree Z-rotation
0.0f, -1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
break;
default:
throw ref new Platform::FailureException();
}
DX::ThrowIfFailed(
m_swapChain->SetRotation(rotation)
);
// Create a render target view of the swap chain back buffer.
ComPtr<ID3D11Texture2D> backBuffer;
DX::ThrowIfFailed(
m_swapChain->GetBuffer(
0,
__uuidof(ID3D11Texture2D),
&backBuffer
)
);
DX::ThrowIfFailed(
m_d3dDevice->CreateRenderTargetView(
backBuffer.Get(),
nullptr,
&m_renderTargetView
)
);
// Create a depth stencil view.
CD3D11_TEXTURE2D_DESC depthStencilDesc(
DXGI_FORMAT_D24_UNORM_S8_UINT,
static_cast<UINT>(m_renderTargetSize.Width),
static_cast<UINT>(m_renderTargetSize.Height),
1,
1,
D3D11_BIND_DEPTH_STENCIL
);
ComPtr<ID3D11Texture2D> depthStencil;
DX::ThrowIfFailed(
m_d3dDevice->CreateTexture2D(
&depthStencilDesc,
nullptr,
&depthStencil
)
);
CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D);
DX::ThrowIfFailed(
m_d3dDevice->CreateDepthStencilView(
depthStencil.Get(),
&depthStencilViewDesc,
&m_depthStencilView
)
);
// Set the rendering viewport to target the entire window.
CD3D11_VIEWPORT viewport(
0.0f,
0.0f,
m_renderTargetSize.Width,
m_renderTargetSize.Height
);
m_d3dContext->RSSetViewports(1, &viewport);
}
// This method is called in the event handler for the SizeChanged event.
void Direct3DBase::UpdateForWindowSizeChange()
{
if (m_window->Bounds.Width != m_windowBounds.Width ||
m_window->Bounds.Height != m_windowBounds.Height ||
m_orientation != DisplayProperties::CurrentOrientation)
{
ID3D11RenderTargetView* nullViews[] = {nullptr};
m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
m_renderTargetView = nullptr;
m_depthStencilView = nullptr;
m_d3dContext->Flush();
CreateWindowSizeDependentResources();
}
}
// Method to deliver the final image to the display.
void Direct3DBase::Present()
{
// The application may optionally specify "dirty" or "scroll"
// rects to improve efficiency in certain scenarios.
DXGI_PRESENT_PARAMETERS parameters = {0};
parameters.DirtyRectsCount = 0;
parameters.pDirtyRects = nullptr;
parameters.pScrollRect = nullptr;
parameters.pScrollOffset = nullptr;
// 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->Present1(1, 0, &parameters);
// Discard the contents of the render target.
// This is a valid operation only when the existing contents will be entirely
// overwritten. If dirty or scroll rects are used, this call should be removed.
m_d3dContext->DiscardView(m_renderTargetView.Get());
// Discard the contents of the depth stencil.
m_d3dContext->DiscardView(m_depthStencilView.Get());
// If the device was removed either by a disconnect or a driver upgrade, we
// must recreate all device resources.
if (hr == DXGI_ERROR_DEVICE_REMOVED)
{
HandleDeviceLost();
}
else
{
DX::ThrowIfFailed(hr);
}
}
// Method to convert a length in device-independent pixels (DIPs) to a length in physical pixels.
float Direct3DBase::ConvertDipsToPixels(float dips)
{
static const float dipsPerInch = 96.0f;
return floor(dips * DisplayProperties::LogicalDpi / dipsPerInch + 0.5f); // Round to nearest integer.
}

View File

@@ -0,0 +1,38 @@
#pragma once
#include "DirectXHelper.h"
// Helper class that initializes DirectX APIs for 3D rendering.
ref class Direct3DBase abstract
{
internal:
Direct3DBase();
public:
virtual void Initialize(Windows::UI::Core::CoreWindow^ window);
virtual void HandleDeviceLost();
virtual void CreateDeviceResources();
virtual void CreateWindowSizeDependentResources();
virtual void UpdateForWindowSizeChange();
virtual void Render() = 0;
virtual void Present();
virtual float ConvertDipsToPixels(float dips);
protected private:
// Direct3D Objects.
Microsoft::WRL::ComPtr<ID3D11Device1> m_d3dDevice;
Microsoft::WRL::ComPtr<ID3D11DeviceContext1> m_d3dContext;
Microsoft::WRL::ComPtr<IDXGISwapChain1> m_swapChain;
Microsoft::WRL::ComPtr<ID3D11RenderTargetView> m_renderTargetView;
Microsoft::WRL::ComPtr<ID3D11DepthStencilView> m_depthStencilView;
// Cached renderer properties.
D3D_FEATURE_LEVEL m_featureLevel;
Windows::Foundation::Size m_renderTargetSize;
Windows::Foundation::Rect m_windowBounds;
Platform::Agile<Windows::UI::Core::CoreWindow> m_window;
Windows::Graphics::Display::DisplayOrientations m_orientation;
// Transform used for display orientation.
DirectX::XMFLOAT4X4 m_orientationTransform3D;
};

View File

@@ -0,0 +1,36 @@
#pragma once
#include <wrl/client.h>
#include <ppl.h>
#include <ppltasks.h>
namespace DX
{
inline void ThrowIfFailed(HRESULT hr)
{
if (FAILED(hr))
{
// Set a breakpoint on this line to catch Win32 API errors.
throw Platform::Exception::CreateException(hr);
}
}
// Function that reads from a binary file asynchronously.
inline Concurrency::task<Platform::Array<byte>^> ReadDataAsync(Platform::String^ filename)
{
using namespace Windows::Storage;
using namespace Concurrency;
auto folder = Windows::ApplicationModel::Package::Current->InstalledLocation;
return create_task(folder->GetFileAsync(filename)).then([] (StorageFile^ file)
{
return FileIO::ReadBufferAsync(file);
}).then([] (Streams::IBuffer^ fileBuffer) -> Platform::Array<byte>^
{
auto fileData = ref new Platform::Array<byte>(fileBuffer->Length);
Streams::DataReader::FromBuffer(fileBuffer)->ReadBytes(fileData);
return fileData;
});
}
}

View File

@@ -0,0 +1,148 @@
#include "SDLmain_WinRT_common.h"
#include "SDL_WinRTApp.h"
#include "BasicTimer.h"
using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::UI::Core;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::Graphics::Display;
using namespace concurrency;
SDL_WinRTApp::SDL_WinRTApp() :
m_windowClosed(false),
m_windowVisible(true)
{
}
void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView)
{
applicationView->Activated +=
ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &SDL_WinRTApp::OnActivated);
CoreApplication::Suspending +=
ref new EventHandler<SuspendingEventArgs^>(this, &SDL_WinRTApp::OnSuspending);
CoreApplication::Resuming +=
ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnResuming);
m_renderer = ref new CubeRenderer();
}
void SDL_WinRTApp::SetWindow(CoreWindow^ window)
{
window->SizeChanged +=
ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &SDL_WinRTApp::OnWindowSizeChanged);
window->VisibilityChanged +=
ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &SDL_WinRTApp::OnVisibilityChanged);
window->Closed +=
ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &SDL_WinRTApp::OnWindowClosed);
window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
window->PointerPressed +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerPressed);
window->PointerMoved +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerMoved);
m_renderer->Initialize(CoreWindow::GetForCurrentThread());
}
void SDL_WinRTApp::Load(Platform::String^ entryPoint)
{
}
void SDL_WinRTApp::Run()
{
BasicTimer^ timer = ref new BasicTimer();
while (!m_windowClosed)
{
if (m_windowVisible)
{
timer->Update();
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
m_renderer->Update(timer->Total, timer->Delta);
m_renderer->Render();
m_renderer->Present(); // This call is synchronized to the display frame rate.
}
else
{
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
}
}
void SDL_WinRTApp::Uninitialize()
{
}
void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
{
m_renderer->UpdateForWindowSizeChange();
}
void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
{
m_windowVisible = args->Visible;
}
void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
{
m_windowClosed = true;
}
void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
{
// Insert your code here.
}
void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args)
{
// Insert your code here.
}
void SDL_WinRTApp::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
{
CoreWindow::GetForCurrentThread()->Activate();
}
void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
{
// Save app state asynchronously after requesting a deferral. Holding a deferral
// indicates that the application is busy performing suspending operations. Be
// aware that a deferral may not be held indefinitely. After about five seconds,
// the app will be forced to exit.
SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
create_task([this, deferral]()
{
// Insert your code here.
deferral->Complete();
});
}
void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args)
{
// Restore any data or state that was unloaded on suspend. By default, data
// and state are persisted when resuming from suspend. Note that this event
// does not occur if the app was previously terminated.
}
IFrameworkView^ Direct3DApplicationSource::CreateView()
{
return ref new SDL_WinRTApp();
}
int SDL_WinRT_RunApplication(/*Platform::Array<Platform::String^>^*/)
{
auto direct3DApplicationSource = ref new Direct3DApplicationSource();
CoreApplication::Run(direct3DApplicationSource);
return 0;
}

View File

@@ -0,0 +1,40 @@
#pragma once
#include "SDLmain_WinRT_common.h"
#include "CubeRenderer.h"
ref class SDL_WinRTApp sealed : public Windows::ApplicationModel::Core::IFrameworkView
{
public:
SDL_WinRTApp();
// IFrameworkView Methods.
virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView);
virtual void SetWindow(Windows::UI::Core::CoreWindow^ window);
virtual void Load(Platform::String^ entryPoint);
virtual void Run();
virtual void Uninitialize();
protected:
// Event Handlers.
void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args);
void OnLogicalDpiChanged(Platform::Object^ sender);
void OnActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args);
void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args);
void OnResuming(Platform::Object^ sender, Platform::Object^ args);
void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args);
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
private:
CubeRenderer^ m_renderer;
bool m_windowClosed;
bool m_windowVisible;
};
ref class Direct3DApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
{
public:
virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView();
};

View File

@@ -0,0 +1,7 @@
#pragma once
#include <wrl/client.h>
#include <d3d11_1.h>
#include <DirectXMath.h>
#include <memory>
#include <agile.h>

View File

@@ -0,0 +1,10 @@
struct PixelShaderInput
{
float4 pos : SV_POSITION;
float3 color : COLOR0;
};
float4 main(PixelShaderInput input) : SV_TARGET
{
return float4(input.color,1.0f);
}

View File

@@ -0,0 +1,35 @@
cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
matrix model;
matrix view;
matrix projection;
};
struct VertexShaderInput
{
float3 pos : POSITION;
float3 color : COLOR0;
};
struct VertexShaderOutput
{
float4 pos : SV_POSITION;
float3 color : COLOR0;
};
VertexShaderOutput main(VertexShaderInput input)
{
VertexShaderOutput output;
float4 pos = float4(input.pos, 1.0f);
// Transform the vertex position into projected space.
pos = mul(pos, model);
pos = mul(pos, view);
pos = mul(pos, projection);
output.pos = pos;
// Pass through the color without modification.
output.color = input.color;
return output;
}