370 строки
10 KiB
C++
370 строки
10 KiB
C++
//--------------------------------------------------------------------------------------
|
|
// SimpleTexturePC.cpp
|
|
//
|
|
// Advanced Technology Group (ATG)
|
|
// Copyright (C) Microsoft Corporation. All rights reserved.
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
#include "pch.h"
|
|
#include "SimpleTexturePC.h"
|
|
|
|
#include "ATGColors.h"
|
|
#include "FindMedia.h"
|
|
#include "ReadData.h"
|
|
|
|
extern void ExitSample() noexcept;
|
|
|
|
using namespace DirectX;
|
|
|
|
using Microsoft::WRL::ComPtr;
|
|
|
|
namespace
|
|
{
|
|
struct Vertex
|
|
{
|
|
XMFLOAT4 position;
|
|
XMFLOAT2 texcoord;
|
|
};
|
|
|
|
std::vector<uint8_t> LoadBGRAImage(const wchar_t* filename, uint32_t& width, uint32_t& height)
|
|
{
|
|
ComPtr<IWICImagingFactory> wicFactory;
|
|
DX::ThrowIfFailed(CoCreateInstance(CLSID_WICImagingFactory2, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&wicFactory)));
|
|
|
|
ComPtr<IWICBitmapDecoder> decoder;
|
|
DX::ThrowIfFailed(wicFactory->CreateDecoderFromFilename(filename, nullptr, GENERIC_READ, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf()));
|
|
|
|
ComPtr<IWICBitmapFrameDecode> frame;
|
|
DX::ThrowIfFailed(decoder->GetFrame(0, frame.GetAddressOf()));
|
|
|
|
DX::ThrowIfFailed(frame->GetSize(&width, &height));
|
|
|
|
WICPixelFormatGUID pixelFormat;
|
|
DX::ThrowIfFailed(frame->GetPixelFormat(&pixelFormat));
|
|
|
|
uint32_t rowPitch = width * sizeof(uint32_t);
|
|
uint32_t imageSize = rowPitch * height;
|
|
|
|
std::vector<uint8_t> image;
|
|
image.resize(size_t(imageSize));
|
|
|
|
if (memcmp(&pixelFormat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID)) == 0)
|
|
{
|
|
DX::ThrowIfFailed(frame->CopyPixels(nullptr, rowPitch, imageSize, reinterpret_cast<BYTE*>(image.data())));
|
|
}
|
|
else
|
|
{
|
|
ComPtr<IWICFormatConverter> formatConverter;
|
|
DX::ThrowIfFailed(wicFactory->CreateFormatConverter(formatConverter.GetAddressOf()));
|
|
|
|
BOOL canConvert = FALSE;
|
|
DX::ThrowIfFailed(formatConverter->CanConvert(pixelFormat, GUID_WICPixelFormat32bppBGRA, &canConvert));
|
|
if (!canConvert)
|
|
{
|
|
throw std::exception("CanConvert");
|
|
}
|
|
|
|
DX::ThrowIfFailed(formatConverter->Initialize(frame.Get(), GUID_WICPixelFormat32bppBGRA,
|
|
WICBitmapDitherTypeErrorDiffusion, nullptr, 0, WICBitmapPaletteTypeMedianCut));
|
|
|
|
DX::ThrowIfFailed(formatConverter->CopyPixels(nullptr, rowPitch, imageSize, reinterpret_cast<BYTE*>(image.data())));
|
|
}
|
|
|
|
return image;
|
|
}
|
|
}
|
|
|
|
Sample::Sample() noexcept(false)
|
|
{
|
|
// Use gamma-correct rendering.
|
|
m_deviceResources = std::make_unique<DX::DeviceResources>(DXGI_FORMAT_B8G8R8A8_UNORM_SRGB);
|
|
m_deviceResources->RegisterDeviceNotify(this);
|
|
}
|
|
|
|
// Initialize the Direct3D resources required to run.
|
|
void Sample::Initialize(HWND window, int width, int height)
|
|
{
|
|
m_gamePad = std::make_unique<GamePad>();
|
|
|
|
m_keyboard = std::make_unique<Keyboard>();
|
|
|
|
m_deviceResources->SetWindow(window, width, height);
|
|
|
|
m_deviceResources->CreateDeviceResources();
|
|
CreateDeviceDependentResources();
|
|
|
|
m_deviceResources->CreateWindowSizeDependentResources();
|
|
CreateWindowSizeDependentResources();
|
|
}
|
|
|
|
#pragma region Frame Update
|
|
// Executes basic render loop.
|
|
void Sample::Tick()
|
|
{
|
|
m_timer.Tick([&]()
|
|
{
|
|
Update(m_timer);
|
|
});
|
|
|
|
Render();
|
|
}
|
|
|
|
// Updates the world.
|
|
void Sample::Update(DX::StepTimer const&)
|
|
{
|
|
auto pad = m_gamePad->GetState(0);
|
|
if (pad.IsConnected())
|
|
{
|
|
if (pad.IsViewPressed())
|
|
{
|
|
ExitSample();
|
|
}
|
|
}
|
|
|
|
auto kb = m_keyboard->GetState();
|
|
if (kb.Escape)
|
|
{
|
|
ExitSample();
|
|
}
|
|
}
|
|
#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;
|
|
}
|
|
|
|
Clear();
|
|
|
|
m_deviceResources->PIXBeginEvent(L"Render");
|
|
auto context = m_deviceResources->GetD3DDeviceContext();
|
|
|
|
// Set input assembler state.
|
|
context->IASetInputLayout(m_spInputLayout.Get());
|
|
|
|
UINT strides = sizeof(Vertex);
|
|
UINT offsets = 0;
|
|
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
|
context->IASetVertexBuffers(0, 1, m_spVertexBuffer.GetAddressOf(), &strides, &offsets);
|
|
|
|
context->IASetIndexBuffer(m_spIndexBuffer.Get(), DXGI_FORMAT_R16_UINT, 0);
|
|
|
|
// Set shaders.
|
|
context->VSSetShader(m_spVertexShader.Get(), nullptr, 0);
|
|
context->GSSetShader(nullptr, nullptr, 0);
|
|
context->PSSetShader(m_spPixelShader.Get(), nullptr, 0);
|
|
|
|
// Set texture and sampler.
|
|
auto sampler = m_spSampler.Get();
|
|
context->PSSetSamplers(0, 1, &sampler);
|
|
|
|
auto texture = m_spTexture.Get();
|
|
context->PSSetShaderResources(0, 1, &texture);
|
|
|
|
// Draw quad.
|
|
context->DrawIndexed(6, 0, 0);
|
|
|
|
m_deviceResources->PIXEndEvent();
|
|
|
|
// Show the new frame.
|
|
m_deviceResources->Present();
|
|
}
|
|
|
|
// Helper method to clear the back buffers.
|
|
void Sample::Clear()
|
|
{
|
|
m_deviceResources->PIXBeginEvent(L"Clear");
|
|
|
|
// Clear the views.
|
|
auto context = m_deviceResources->GetD3DDeviceContext();
|
|
auto renderTarget = m_deviceResources->GetRenderTargetView();
|
|
auto depthStencil = m_deviceResources->GetDepthStencilView();
|
|
|
|
// Use linear clear color for gamma-correct rendering.
|
|
context->ClearRenderTargetView(renderTarget, ATG::ColorsLinear::Background);
|
|
|
|
context->ClearDepthStencilView(depthStencil, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
|
|
|
|
context->OMSetRenderTargets(1, &renderTarget, depthStencil);
|
|
|
|
// Set the viewport.
|
|
auto viewport = m_deviceResources->GetScreenViewport();
|
|
context->RSSetViewports(1, &viewport);
|
|
|
|
m_deviceResources->PIXEndEvent();
|
|
}
|
|
#pragma endregion
|
|
|
|
#pragma region Message Handlers
|
|
// Message handlers
|
|
void Sample::OnActivated()
|
|
{
|
|
}
|
|
|
|
void Sample::OnDeactivated()
|
|
{
|
|
}
|
|
|
|
void Sample::OnSuspending()
|
|
{
|
|
}
|
|
|
|
void Sample::OnResuming()
|
|
{
|
|
m_timer.ResetElapsedTime();
|
|
}
|
|
|
|
void Sample::OnWindowSizeChanged(int width, int height)
|
|
{
|
|
if (!m_deviceResources->WindowSizeChanged(width, height))
|
|
return;
|
|
|
|
CreateWindowSizeDependentResources();
|
|
}
|
|
|
|
// Properties
|
|
void Sample::GetDefaultSize(int& width, int& height) const
|
|
{
|
|
width = 1280;
|
|
height = 720;
|
|
}
|
|
#pragma endregion
|
|
|
|
#pragma region Direct3D Resources
|
|
// These are the resources that depend on the device.
|
|
void Sample::CreateDeviceDependentResources()
|
|
{
|
|
auto device = m_deviceResources->GetD3DDevice();
|
|
|
|
// Load and create shaders.
|
|
auto vertexShaderBlob = DX::ReadData(L"VertexShader.cso");
|
|
|
|
DX::ThrowIfFailed(
|
|
device->CreateVertexShader(vertexShaderBlob.data(), vertexShaderBlob.size(),
|
|
nullptr, m_spVertexShader.ReleaseAndGetAddressOf()));
|
|
|
|
auto pixelShaderBlob = DX::ReadData(L"PixelShader.cso");
|
|
|
|
DX::ThrowIfFailed(
|
|
device->CreatePixelShader(pixelShaderBlob.data(), pixelShaderBlob.size(),
|
|
nullptr, m_spPixelShader.ReleaseAndGetAddressOf()));
|
|
|
|
// Create input layout.
|
|
static const D3D11_INPUT_ELEMENT_DESC s_inputElementDesc[2] =
|
|
{
|
|
{ "SV_Position", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
|
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA , 0 },
|
|
};
|
|
|
|
DX::ThrowIfFailed(
|
|
device->CreateInputLayout(s_inputElementDesc, _countof(s_inputElementDesc),
|
|
vertexShaderBlob.data(), vertexShaderBlob.size(),
|
|
m_spInputLayout.ReleaseAndGetAddressOf()));
|
|
|
|
// Create vertex buffer.
|
|
static const Vertex s_vertexData[4] =
|
|
{
|
|
{ { -0.5f, -0.5f, 0.5f, 1.0f }, { 0.f, 1.f } },
|
|
{ { 0.5f, -0.5f, 0.5f, 1.0f }, { 1.f, 1.f } },
|
|
{ { 0.5f, 0.5f, 0.5f, 1.0f }, { 1.f, 0.f } },
|
|
{ { -0.5f, 0.5f, 0.5f, 1.0f }, { 0.f, 0.f } },
|
|
};
|
|
|
|
D3D11_SUBRESOURCE_DATA initialData = {};
|
|
initialData.pSysMem = s_vertexData;
|
|
|
|
D3D11_BUFFER_DESC bufferDesc = {};
|
|
bufferDesc.ByteWidth = sizeof(s_vertexData);
|
|
bufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
|
|
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
|
bufferDesc.StructureByteStride = sizeof(Vertex);
|
|
|
|
DX::ThrowIfFailed(
|
|
device->CreateBuffer(&bufferDesc, &initialData,
|
|
m_spVertexBuffer.ReleaseAndGetAddressOf()));
|
|
|
|
// Create index buffer.
|
|
static const uint16_t s_indexData[6] =
|
|
{
|
|
3,1,0,
|
|
2,1,3,
|
|
};
|
|
|
|
initialData.pSysMem = s_indexData;
|
|
|
|
bufferDesc.ByteWidth = sizeof(s_indexData);
|
|
bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
|
bufferDesc.StructureByteStride = sizeof(uint16_t);
|
|
|
|
DX::ThrowIfFailed(
|
|
device->CreateBuffer(&bufferDesc, &initialData,
|
|
m_spIndexBuffer.ReleaseAndGetAddressOf()));
|
|
|
|
// Create sampler.
|
|
D3D11_SAMPLER_DESC samplerDesc = {};
|
|
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
|
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
|
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
|
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
|
samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
|
samplerDesc.MinLOD = 0;
|
|
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
|
|
|
|
DX::ThrowIfFailed(
|
|
device->CreateSamplerState(&samplerDesc,
|
|
m_spSampler.ReleaseAndGetAddressOf()));
|
|
|
|
// Create texture.
|
|
D3D11_TEXTURE2D_DESC txtDesc = {};
|
|
txtDesc.MipLevels = txtDesc.ArraySize = 1;
|
|
txtDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; // sunset.jpg is in sRGB colorspace
|
|
txtDesc.SampleDesc.Count = 1;
|
|
txtDesc.Usage = D3D11_USAGE_IMMUTABLE;
|
|
txtDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
|
|
|
wchar_t buff[MAX_PATH];
|
|
DX::FindMediaFile(buff, MAX_PATH, L"sunset.jpg");
|
|
auto image = LoadBGRAImage(buff, txtDesc.Width, txtDesc.Height);
|
|
|
|
initialData.pSysMem = image.data();
|
|
initialData.SysMemPitch = txtDesc.Width * sizeof(uint32_t);
|
|
|
|
ComPtr<ID3D11Texture2D> tex;
|
|
DX::ThrowIfFailed(
|
|
device->CreateTexture2D(&txtDesc, &initialData,
|
|
tex.GetAddressOf()));
|
|
|
|
DX::ThrowIfFailed(
|
|
device->CreateShaderResourceView(tex.Get(),
|
|
nullptr, m_spTexture.ReleaseAndGetAddressOf()));
|
|
}
|
|
|
|
// Allocate all memory resources that change on a window SizeChanged event.
|
|
void Sample::CreateWindowSizeDependentResources()
|
|
{
|
|
}
|
|
|
|
void Sample::OnDeviceLost()
|
|
{
|
|
m_spInputLayout.Reset();
|
|
m_spVertexBuffer.Reset();
|
|
m_spIndexBuffer.Reset();
|
|
m_spVertexShader.Reset();
|
|
m_spPixelShader.Reset();
|
|
m_spSampler.Reset();
|
|
m_spTexture.Reset();
|
|
}
|
|
|
|
void Sample::OnDeviceRestored()
|
|
{
|
|
CreateDeviceDependentResources();
|
|
|
|
CreateWindowSizeDependentResources();
|
|
}
|
|
#pragma endregion
|