2025-11-28 00:35:46 +09:00

1632 lines
53 KiB
C++

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
#include "DxgiSample.h"
/******************************************************************
* *
* WinMain *
* *
* Application entrypoint *
* *
******************************************************************/
int WINAPI WinMain(
HINSTANCE /*hInstance*/,
HINSTANCE /*hPrevInstance*/,
LPSTR /*lpCmdLine*/,
int /*nCmdShow*/
)
{
// Ignoring the return value because we want to continue running even in the
// unlikely event that HeapSetInformation fails.
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
if (SUCCEEDED(CoInitialize(NULL)))
{
{
DXGISampleApp app;
if (SUCCEEDED(app.Initialize()))
{
app.RunMessageLoop();
}
}
CoUninitialize();
}
return 0;
}
/******************************************************************
* *
* Static Data *
* *
******************************************************************/
/*static*/ const D3D10_INPUT_ELEMENT_DESC DXGISampleApp::s_InputLayout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0},
};
/*static*/ const SimpleVertex DXGISampleApp::s_VertexArray[] =
{
{ D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 1.0f, 1.0f )},
{ D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 1.0f )},
{ D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 0.0f, 0.0f )},
{ D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR2( 1.0f, 0.0f )}
};
/*static*/ const SHORT DXGISampleApp::s_FacesIndexArray[] =
{
3, 1, 0,
2, 1, 3
};
static const WCHAR sc_helloWorld[] = L"Hello, World!";
/******************************************************************
* *
* DXGISampleApp::DXGISampleApp *
* *
* Constructor -- initialize member data *
* *
******************************************************************/
DXGISampleApp::DXGISampleApp() :
m_hwnd(NULL),
m_pD2DFactory(NULL),
m_pWICFactory(NULL),
m_pDWriteFactory(NULL),
m_pDevice(NULL),
m_pSwapChain(NULL),
m_pRenderTargetView(NULL),
m_pState(NULL),
m_pDepthStencil(NULL),
m_pDepthStencilView(NULL),
m_pOffscreenTexture(NULL),
m_pShader(NULL),
m_pVertexBuffer(NULL),
m_pVertexLayout(NULL),
m_pFacesIndexBuffer(NULL),
m_pTextureRV(NULL),
m_pBackBufferRT(NULL),
m_pBackBufferTextBrush(NULL),
m_pBackBufferGradientBrush(NULL),
m_pGridPatternBitmapBrush(NULL),
m_pRenderTarget(NULL),
m_pLGBrush(NULL),
m_pBlackBrush(NULL),
m_pBitmap(NULL),
m_pTechniqueNoRef(NULL),
m_pWorldVariableNoRef(NULL),
m_pViewVariableNoRef(NULL),
m_pProjectionVariableNoRef(NULL),
m_pDiffuseVariableNoRef(NULL),
m_pTextFormat(NULL),
m_pPathGeometry(NULL)
{
}
/******************************************************************
* *
* DXGISampleApp::~DXGISampleApp *
* *
* Destructor -- tear down member data *
* *
******************************************************************/
DXGISampleApp::~DXGISampleApp()
{
SafeRelease(&m_pD2DFactory);
SafeRelease(&m_pWICFactory);
SafeRelease(&m_pDWriteFactory);
SafeRelease(&m_pDevice);
SafeRelease(&m_pSwapChain);
SafeRelease(&m_pRenderTargetView);
SafeRelease(&m_pState);
SafeRelease(&m_pDepthStencil);
SafeRelease(&m_pDepthStencilView);
SafeRelease(&m_pOffscreenTexture);
SafeRelease(&m_pShader);
SafeRelease(&m_pVertexBuffer);
SafeRelease(&m_pVertexLayout);
SafeRelease(&m_pFacesIndexBuffer);
SafeRelease(&m_pTextureRV);
SafeRelease(&m_pBackBufferRT);
SafeRelease(&m_pBackBufferTextBrush);
SafeRelease(&m_pBackBufferGradientBrush);
SafeRelease(&m_pGridPatternBitmapBrush);
SafeRelease(&m_pRenderTarget);
SafeRelease(&m_pLGBrush);
SafeRelease(&m_pBlackBrush);
SafeRelease(&m_pBitmap);
SafeRelease(&m_pTextFormat);
SafeRelease(&m_pPathGeometry);
}
/******************************************************************
* *
* DXGISampleApp::Initialize *
* *
* Create application window and device-independent resources *
* *
******************************************************************/
HRESULT DXGISampleApp::Initialize()
{
HRESULT hr;
hr = CreateDeviceIndependentResources();
if (SUCCEEDED(hr))
{
// Register the window class.
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = DXGISampleApp::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = HINST_THISCOMPONENT;
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpszClassName = L"D2DDXGISampleApp";
RegisterClassEx(&wcex);
// Create the application window.
//
// Because the CreateWindow function takes its size in pixels, we
// obtain the system DPI and use it to scale the window size.
FLOAT dpiX, dpiY;
m_pD2DFactory->GetDesktopDpi(&dpiX, &dpiY);
m_hwnd = CreateWindow(
L"D2DDXGISampleApp",
L"Direct2D Demo App",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
static_cast<UINT>(ceil(640.f * dpiX / 96.f)),
static_cast<UINT>(ceil(480.f * dpiY / 96.f)),
NULL,
NULL,
HINST_THISCOMPONENT,
this
);
hr = m_hwnd ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
// Create a timer and receive WM_TIMER messages at a rough
// granularity of 33msecs. If you need a more precise timer,
// consider modifying the message loop and calling more precise
// timing functions.
SetTimer(
m_hwnd,
0, //timerId
33, //msecs
NULL //lpTimerProc
);
ShowWindow(m_hwnd, SW_SHOWNORMAL);
UpdateWindow(m_hwnd);
}
}
return hr;
}
/******************************************************************
* *
* DXGISampleApp::CreateDeviceIndependentResources *
* *
* This method is used to create resources which are not bound *
* to any device. Their lifetime effectively extends for the *
* duration of the app. These resources include the D2D, *
* DWrite, and WIC factories; and a DWrite Text Format object *
* (used for identifying particular font characteristics) and *
* a D2D geometry. *
* *
******************************************************************/
HRESULT DXGISampleApp::CreateDeviceIndependentResources()
{
static const WCHAR msc_fontName[] = L"Verdana";
static const FLOAT msc_fontSize = 50;
ID2D1GeometrySink *pSink = NULL;
HRESULT hr;
// Create D2D factory
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);
if (SUCCEEDED(hr))
{
// Create a WIC factory
hr = CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<void **>(&m_pWICFactory)
);
}
if (SUCCEEDED(hr))
{
// Create DWrite factory
hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(m_pDWriteFactory),
reinterpret_cast<IUnknown **>(&m_pDWriteFactory)
);
}
if (SUCCEEDED(hr))
{
// Create DWrite text format object
hr = m_pDWriteFactory->CreateTextFormat(
msc_fontName,
NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
msc_fontSize,
L"", //locale
&m_pTextFormat
);
}
if (SUCCEEDED(hr))
{
// Center the text both horizontally and vertically.
m_pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
m_pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
// Create the path geometry.
hr = m_pD2DFactory->CreatePathGeometry(&m_pPathGeometry);
}
if (SUCCEEDED(hr))
{
// Write to the path geometry using the geometry sink. We are going to create an
// hour glass.
hr = m_pPathGeometry->Open(&pSink);
}
if (SUCCEEDED(hr))
{
pSink->SetFillMode(D2D1_FILL_MODE_ALTERNATE);
pSink->BeginFigure(
D2D1::Point2F(0, 0),
D2D1_FIGURE_BEGIN_FILLED
);
pSink->AddLine(D2D1::Point2F(200, 0));
pSink->AddBezier(
D2D1::BezierSegment(
D2D1::Point2F(150, 50),
D2D1::Point2F(150, 150),
D2D1::Point2F(200, 200))
);
pSink->AddLine(D2D1::Point2F(0, 200));
pSink->AddBezier(
D2D1::BezierSegment(
D2D1::Point2F(50, 150),
D2D1::Point2F(50, 50),
D2D1::Point2F(0, 0))
);
pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
hr = pSink->Close();
}
SafeRelease(&pSink);
return hr;
}
/******************************************************************
* *
* DXGISampleApp::CreateDeviceResources *
* *
* This method is responsible for creating the D3D device and *
* all corresponding device-bound resources that are required to *
* render. *
* *
* Of the objects created in this method, 5 are interesting ... *
* *
* 1. D3D Device (m_pDevice) -- This device must support 32bpp *
* BGRA *
* *
* 2. DXGI Swap Chain (m_pSwapChain) -- Mapped to current *
* window (m_hwnd) *
* *
* 3. D2D Surface Render Target (m_pBackBufferRT) -- Allows *
* us to use D2D to draw directly into a swap chain *
* buffer, in order to show (for example) a background *
* gradient. *
* *
* 4. D3D Offscreen Texture (m_pOffscreenTexture) -- Texture *
* which is mapped to our 3D model. *
* *
* 5. D2D Surface Render Target (m_pRenderTarget) -- Allows us *
* to use D2D to draw into the (4) D3D offscreen *
* texture. This texture will then be mapped and *
* displayed on our 3D model. *
* *
******************************************************************/
HRESULT DXGISampleApp::CreateDeviceResources()
{
HRESULT hr = S_OK;
RECT rcClient;
ID3D10Device1 *pDevice = NULL;
IDXGIDevice *pDXGIDevice = NULL;
IDXGIAdapter *pAdapter = NULL;
IDXGIFactory *pDXGIFactory = NULL;
IDXGISurface *pSurface = NULL;
Assert(m_hwnd);
GetClientRect(m_hwnd, &rcClient);
UINT nWidth = abs(rcClient.right - rcClient.left);
UINT nHeight = abs(rcClient.bottom - rcClient.top);
// If we don't have a device, need to create one now and all
// accompanying D3D resources.
if (!m_pDevice)
{
UINT nDeviceFlags = D3D10_CREATE_DEVICE_BGRA_SUPPORT;
// Create device
hr = CreateD3DDevice(
NULL,
D3D10_DRIVER_TYPE_HARDWARE,
nDeviceFlags,
&pDevice
);
if (FAILED(hr))
{
hr = CreateD3DDevice(
NULL,
D3D10_DRIVER_TYPE_WARP,
nDeviceFlags,
&pDevice
);
}
if (SUCCEEDED(hr))
{
hr = pDevice->QueryInterface(&m_pDevice);
}
if (SUCCEEDED(hr))
{
hr = pDevice->QueryInterface(&pDXGIDevice);
}
if (SUCCEEDED(hr))
{
hr = pDXGIDevice->GetAdapter(&pAdapter);
}
if (SUCCEEDED(hr))
{
hr = pAdapter->GetParent(IID_PPV_ARGS(&pDXGIFactory));
}
if (SUCCEEDED(hr))
{
DXGI_SWAP_CHAIN_DESC swapDesc;
::ZeroMemory(&swapDesc, sizeof(swapDesc));
swapDesc.BufferDesc.Width = nWidth;
swapDesc.BufferDesc.Height = nHeight;
swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapDesc.BufferDesc.RefreshRate.Numerator = 60;
swapDesc.BufferDesc.RefreshRate.Denominator = 1;
swapDesc.SampleDesc.Count = 1;
swapDesc.SampleDesc.Quality = 0;
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.BufferCount = 1;
swapDesc.OutputWindow = m_hwnd;
swapDesc.Windowed = TRUE;
hr = pDXGIFactory->CreateSwapChain(m_pDevice, &swapDesc, &m_pSwapChain);
}
if (SUCCEEDED(hr))
{
hr = CreateD3DDeviceResources();
}
if (SUCCEEDED(hr))
{
hr = RecreateSizedResources(nWidth, nHeight);
}
if (SUCCEEDED(hr))
{
hr = CreateD2DDeviceResources();
}
}
SafeRelease(&pDevice);
SafeRelease(&pDXGIDevice);
SafeRelease(&pAdapter);
SafeRelease(&pDXGIFactory);
SafeRelease(&pSurface);
return hr;
}
/******************************************************************
* *
* DXGISampleApp::RecreateSizedResources *
* *
* This method is responsible for (re)creating all device *
* resources that depend on the window size. *
* *
******************************************************************/
HRESULT DXGISampleApp::RecreateSizedResources(UINT nWidth, UINT nHeight)
{
HRESULT hr = S_OK;
IDXGISurface *pBackBuffer = NULL;
ID3D10Resource *pBackBufferResource = NULL;
ID3D10RenderTargetView *viewList[1] = {NULL};
// Ensure that nobody is holding onto one of the old resources
SafeRelease(&m_pBackBufferRT);
SafeRelease(&m_pRenderTargetView);
m_pDevice->OMSetRenderTargets(1, viewList, NULL);
// Resize render target buffers
hr = m_pSwapChain->ResizeBuffers(1, nWidth, nHeight, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
if (SUCCEEDED(hr))
{
D3D10_TEXTURE2D_DESC texDesc;
texDesc.ArraySize = 1;
texDesc.BindFlags = D3D10_BIND_DEPTH_STENCIL;
texDesc.CPUAccessFlags = 0;
texDesc.Format = DXGI_FORMAT_D16_UNORM;
texDesc.Height = nHeight;
texDesc.Width = nWidth;
texDesc.MipLevels = 1;
texDesc.MiscFlags = 0;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D10_USAGE_DEFAULT;
SafeRelease(&m_pDepthStencil);
hr = m_pDevice->CreateTexture2D(&texDesc, NULL, &m_pDepthStencil);
}
if (SUCCEEDED(hr))
{
// Create the render target view and set it on the device
hr = m_pSwapChain->GetBuffer(
0,
IID_PPV_ARGS(&pBackBufferResource)
);
}
if (SUCCEEDED(hr))
{
D3D10_RENDER_TARGET_VIEW_DESC renderDesc;
renderDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
renderDesc.ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2D;
renderDesc.Texture2D.MipSlice = 0;
SafeRelease(&m_pRenderTargetView);
hr = m_pDevice->CreateRenderTargetView(pBackBufferResource, &renderDesc, &m_pRenderTargetView);
}
if (SUCCEEDED(hr))
{
D3D10_DEPTH_STENCIL_VIEW_DESC depthViewDesc;
depthViewDesc.Format = DXGI_FORMAT_D16_UNORM;
depthViewDesc.ViewDimension = D3D10_DSV_DIMENSION_TEXTURE2D;
depthViewDesc.Texture2D.MipSlice = 0;
SafeRelease(&m_pDepthStencilView);
hr = m_pDevice->CreateDepthStencilView(m_pDepthStencil, &depthViewDesc, &m_pDepthStencilView);
}
if (SUCCEEDED(hr))
{
viewList[0] = m_pRenderTargetView;
m_pDevice->OMSetRenderTargets(1, viewList, m_pDepthStencilView);
// Set a new viewport based on the new dimensions
D3D10_VIEWPORT viewport;
viewport.Width = nWidth;
viewport.Height = nHeight;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.MinDepth = 0;
viewport.MaxDepth = 1;
m_pDevice->RSSetViewports(1, &viewport);
// Get a surface in the swap chain
hr = m_pSwapChain->GetBuffer(
0,
IID_PPV_ARGS(&pBackBuffer)
);
}
if (SUCCEEDED(hr))
{
// Reset the projection matrix now that the swapchain is resized.
D3DMatrixPerspectiveFovLH(
&m_ProjectionMatrix,
(float)D3DX_PI * 0.24f, // fovy
nWidth / (float)nHeight, // aspect
0.1f, // zn
100.0f // zf
);
m_pProjectionVariableNoRef->SetMatrix((float*)&m_ProjectionMatrix);
// Create the DXGI Surface Render Target.
FLOAT dpiX;
FLOAT dpiY;
m_pD2DFactory->GetDesktopDpi(&dpiX, &dpiY);
D2D1_RENDER_TARGET_PROPERTIES props =
D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
dpiX,
dpiY
);
// Create a D2D render target which can draw into the surface in the swap chain
SafeRelease(&m_pBackBufferRT);
hr = m_pD2DFactory->CreateDxgiSurfaceRenderTarget(
pBackBuffer,
&props,
&m_pBackBufferRT
);
}
SafeRelease(&pBackBuffer);
SafeRelease(&pBackBufferResource);
return hr;
}
/******************************************************************
* *
* DXGISampleApp::CreateD3DDeviceResources *
* *
* This method creates all the remaining D3D device resources *
* required to render the scene. This method is called from *
* CreateDeviceResources, and as such, it relies on the device *
* and swap chain aleady being created. *
* *
******************************************************************/
HRESULT DXGISampleApp::CreateD3DDeviceResources()
{
HRESULT hr = S_OK;
// Create rasterizer state object
D3D10_RASTERIZER_DESC rsDesc;
rsDesc.AntialiasedLineEnable = FALSE;
rsDesc.CullMode = D3D10_CULL_NONE;
rsDesc.DepthBias = 0;
rsDesc.DepthBiasClamp = 0;
rsDesc.DepthClipEnable = TRUE;
rsDesc.FillMode = D3D10_FILL_SOLID;
rsDesc.FrontCounterClockwise = FALSE; // Must be FALSE for 10on9
rsDesc.MultisampleEnable = FALSE;
rsDesc.ScissorEnable = FALSE;
rsDesc.SlopeScaledDepthBias = 0;
hr = m_pDevice->CreateRasterizerState(&rsDesc, &m_pState);
if (SUCCEEDED(hr))
{
m_pDevice->RSSetState(m_pState);
m_pDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Allocate a offscreen D3D surface for D2D to render our 2D content into
D3D10_TEXTURE2D_DESC texDesc;
texDesc.ArraySize = 1;
texDesc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
texDesc.CPUAccessFlags = 0;
texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
texDesc.Height = 512;
texDesc.Width = 512;
texDesc.MipLevels = 1;
texDesc.MiscFlags = 0;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D10_USAGE_DEFAULT;
hr = m_pDevice->CreateTexture2D(&texDesc, NULL, &m_pOffscreenTexture);
}
if (SUCCEEDED(hr))
{
// Convert the Direct2D texture into a Shader Resource View
SafeRelease(&m_pTextureRV);
hr = m_pDevice->CreateShaderResourceView(m_pOffscreenTexture, NULL, &m_pTextureRV);
}
if (SUCCEEDED(hr))
{
D3D10_BUFFER_DESC bd;
bd.Usage = D3D10_USAGE_DEFAULT;
bd.ByteWidth = sizeof(s_VertexArray);
bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA InitData;
InitData.pSysMem = s_VertexArray;
hr = m_pDevice->CreateBuffer(&bd, &InitData, &m_pVertexBuffer);
if (SUCCEEDED(hr))
{
// Set vertex buffer
UINT stride = sizeof(SimpleVertex);
UINT offset = 0;
ID3D10Buffer *pVertexBuffer = m_pVertexBuffer;
m_pDevice->IASetVertexBuffers(
0, // StartSlot
1, // NumBuffers
&pVertexBuffer,
&stride,
&offset
);
}
}
if (SUCCEEDED(hr))
{
D3D10_BUFFER_DESC bd;
bd.Usage = D3D10_USAGE_DEFAULT;
bd.ByteWidth = sizeof(s_FacesIndexArray);
bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
D3D10_SUBRESOURCE_DATA InitData;
InitData.pSysMem = s_FacesIndexArray;
hr = m_pDevice->CreateBuffer(&bd, &InitData, &m_pFacesIndexBuffer);
}
if (SUCCEEDED(hr))
{
// Load pixel shader
hr = LoadResourceShader(
m_pDevice,
MAKEINTRESOURCE(IDR_PIXEL_SHADER),
&m_pShader
);
}
if (SUCCEEDED(hr))
{
// Obtain the technique
m_pTechniqueNoRef = m_pShader->GetTechniqueByName("Render");
hr = m_pTechniqueNoRef ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr))
{
// Obtain the variables
m_pWorldVariableNoRef = m_pShader->GetVariableByName("World")->AsMatrix();
hr = m_pWorldVariableNoRef ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr))
{
m_pViewVariableNoRef = m_pShader->GetVariableByName("View")->AsMatrix();
hr = m_pViewVariableNoRef ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
// Initialize the view matrix.
D3DXVECTOR3 Eye(0.0f, 2.0f, -6.0f);
D3DXVECTOR3 At(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 Up(0.0f, 1.0f, 0.0f);
D3DMatrixLookAtLH(&m_ViewMatrix, &Eye, &At, &Up);
m_pViewVariableNoRef->SetMatrix((float*)&m_ViewMatrix);
}
}
if (SUCCEEDED(hr))
{
m_pDiffuseVariableNoRef = m_pShader->GetVariableByName("txDiffuse")->AsShaderResource();
hr = m_pDiffuseVariableNoRef ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr))
{
m_pProjectionVariableNoRef = m_pShader->GetVariableByName("Projection")->AsMatrix();
hr = m_pProjectionVariableNoRef ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr))
{
// Define the input layout
UINT numElements = ARRAYSIZE(s_InputLayout);
// Create the input layout
D3D10_PASS_DESC PassDesc;
m_pTechniqueNoRef->GetPassByIndex(0)->GetDesc(&PassDesc);
hr = m_pDevice->CreateInputLayout(
s_InputLayout,
numElements,
PassDesc.pIAInputSignature,
PassDesc.IAInputSignatureSize,
&m_pVertexLayout
);
if (SUCCEEDED(hr))
{
// Set the input layout
m_pDevice->IASetInputLayout(m_pVertexLayout);
}
}
return hr;
}
/******************************************************************
* *
* DXGISampleApp::CreateD2DDeviceResources *
* *
* This method creates all window-size-independent D2D resources. *
* *
******************************************************************/
HRESULT DXGISampleApp::CreateD2DDeviceResources()
{
HRESULT hr = S_OK;
IDXGISurface *pDxgiSurface = NULL;
ID2D1GradientStopCollection *pGradientStops = NULL;
hr = m_pOffscreenTexture->QueryInterface(&pDxgiSurface);
if (SUCCEEDED(hr))
{
// Create a D2D render target which can draw into our offscreen D3D
// surface. Given that we use a constant size for the texture, we
// fix the DPI at 96.
D2D1_RENDER_TARGET_PROPERTIES props =
D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
96,
96
);
SafeRelease(&m_pRenderTarget);
hr = m_pD2DFactory->CreateDxgiSurfaceRenderTarget(
pDxgiSurface,
&props,
&m_pRenderTarget
);
}
if (SUCCEEDED(hr))
{
// Create a linear gradient brush for the window background
static const D2D1_GRADIENT_STOP stopsBackground[] =
{
{ 0.f, { 0.f, 0.f, 0.2f, 1.f}}, // Starting with blue
{ 1.f, { 0.f, 0.f, 0.5f, 1.f}} // Toward black
};
hr = m_pRenderTarget->CreateGradientStopCollection(
stopsBackground,
ARRAYSIZE(stopsBackground),
&pGradientStops
);
}
if (SUCCEEDED(hr))
{
hr = m_pBackBufferRT->CreateLinearGradientBrush(
D2D1::LinearGradientBrushProperties(
D2D1::Point2F(0.0f, 0.0f),
D2D1::Point2F(0.0f, 1.0f)),
pGradientStops,
&m_pBackBufferGradientBrush
);
}
if (SUCCEEDED(hr))
{
// Create a red brush for text drawn into the back buffer
hr = m_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Red),
&m_pBackBufferTextBrush
);
}
if (SUCCEEDED(hr))
{
// Create a linear gradient brush for the 2D geometry
static const D2D1_GRADIENT_STOP stopsGeometry[] =
{
{ 0.f, { 0.f, 1.f, 1.f, 0.25f}}, // Starting with lt.blue
{ 1.f, { 0.f, 0.f, 1.f, 1.f}}, // Toward blue
};
SafeRelease(&pGradientStops);
hr = m_pRenderTarget->CreateGradientStopCollection(
stopsGeometry,
ARRAYSIZE(stopsGeometry),
&pGradientStops
);
if (SUCCEEDED(hr))
{
hr = m_pRenderTarget->CreateLinearGradientBrush(
D2D1::LinearGradientBrushProperties(
D2D1::Point2F(100, 0),
D2D1::Point2F(100, 200)),
D2D1::BrushProperties(),
pGradientStops,
&m_pLGBrush
);
}
}
if (SUCCEEDED(hr))
{
// create a black brush
hr = m_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black),
&m_pBlackBrush
);
}
if (SUCCEEDED(hr))
{
hr = LoadResourceBitmap(
m_pRenderTarget,
m_pWICFactory,
L"SampleImage",
L"Image",
100,
0,
&m_pBitmap
);
}
if (SUCCEEDED(hr))
{
hr = CreateGridPatternBrush(m_pRenderTarget, &m_pGridPatternBitmapBrush);
if (SUCCEEDED(hr))
{
m_pGridPatternBitmapBrush->SetOpacity(0.5f);
}
}
SafeRelease(&pDxgiSurface);
SafeRelease(&pGradientStops);
return hr;
}
//
// Creates a pattern brush.
//
HRESULT DXGISampleApp::CreateGridPatternBrush(
ID2D1RenderTarget *pRenderTarget,
ID2D1BitmapBrush **ppBitmapBrush
)
{
HRESULT hr = S_OK;
// Create a compatible render target.
ID2D1BitmapRenderTarget *pCompatibleRenderTarget = NULL;
hr = pRenderTarget->CreateCompatibleRenderTarget(
D2D1::SizeF(10.0f, 10.0f),
&pCompatibleRenderTarget
);
if (SUCCEEDED(hr))
{
// Draw a pattern.
ID2D1SolidColorBrush *pGridBrush = NULL;
hr = pCompatibleRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF(0.93f, 0.94f, 0.96f, 1.0f)),
&pGridBrush
);
if (SUCCEEDED(hr))
{
pCompatibleRenderTarget->BeginDraw();
pCompatibleRenderTarget->FillRectangle(D2D1::RectF(0.0f, 0.0f, 10.0f, 1.0f), pGridBrush);
pCompatibleRenderTarget->FillRectangle(D2D1::RectF(0.0f, 0.1f, 1.0f, 10.0f), pGridBrush);
pCompatibleRenderTarget->EndDraw();
// Retrieve the bitmap from the render target.
ID2D1Bitmap *pGridBitmap = NULL;
hr = pCompatibleRenderTarget->GetBitmap(&pGridBitmap);
if (SUCCEEDED(hr))
{
// Choose the tiling mode for the bitmap brush.
D2D1_BITMAP_BRUSH_PROPERTIES brushProperties =
D2D1::BitmapBrushProperties(D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP);
// Create the bitmap brush.
hr = m_pRenderTarget->CreateBitmapBrush(pGridBitmap, brushProperties, ppBitmapBrush);
pGridBitmap->Release();
}
pGridBrush->Release();
}
pCompatibleRenderTarget->Release();
}
return hr;
}
/******************************************************************
* *
* DXGISampleApp::DiscardDeviceResources *
* *
* Certain resources (eg. device, swap chain, RT) are bound to a *
* particular D3D device. Under certain conditions (eg. change *
* display mode, remoting, removing a video adapter), it is *
* necessary to discard device-specific resources. This method *
* just releases all of the device-bound resources that we're *
* holding onto. *
* *
******************************************************************/
void DXGISampleApp::DiscardDeviceResources()
{
SafeRelease(&m_pDevice);
SafeRelease(&m_pSwapChain);
SafeRelease(&m_pRenderTargetView);
SafeRelease(&m_pState);
SafeRelease(&m_pDepthStencil);
SafeRelease(&m_pDepthStencilView);
SafeRelease(&m_pOffscreenTexture);
SafeRelease(&m_pShader);
SafeRelease(&m_pVertexBuffer);
SafeRelease(&m_pVertexLayout);
SafeRelease(&m_pFacesIndexBuffer);
SafeRelease(&m_pTextureRV);
SafeRelease(&m_pBackBufferRT);
SafeRelease(&m_pBackBufferTextBrush);
SafeRelease(&m_pBackBufferGradientBrush);
SafeRelease(&m_pGridPatternBitmapBrush);
SafeRelease(&m_pRenderTarget);
SafeRelease(&m_pLGBrush);
SafeRelease(&m_pBlackBrush);
SafeRelease(&m_pBitmap);
}
/******************************************************************
* *
* DXGISampleApp::RunMessageLoop *
* *
* This is the main message pump for the application *
* *
******************************************************************/
void DXGISampleApp::RunMessageLoop()
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
/******************************************************************
* *
* DXGISampleApp::OnRender *
* *
* This method is called when the app needs to paint the window. *
* It uses a D2D RT to draw a gradient background into the swap *
* chain buffer. Then, it uses a separate D2D RT to draw a *
* 2D scene into a D3D texture. This texture is mapped onto a *
* simple planar 3D model and displayed using D3D. *
* *
******************************************************************/
HRESULT DXGISampleApp::OnRender()
{
HRESULT hr;
static float t = 0.0f;
static DWORD dwTimeStart = 0;
hr = CreateDeviceResources();
if (SUCCEEDED(hr) && m_pRenderTarget)
{
DWORD dwTimeCur = GetTickCount();
if ( dwTimeStart == 0 )
{
dwTimeStart = dwTimeCur;
}
t = ( dwTimeCur - dwTimeStart) / 3000.0f;
float a = (t * 360.0f) * ((float)D3DX_PI / 180.0f);
D3DMatrixRotationY(&m_WorldMatrix, a);
// Swap chain will tell us how big the back buffer is
DXGI_SWAP_CHAIN_DESC swapDesc;
hr = m_pSwapChain->GetDesc(&swapDesc);
if (SUCCEEDED(hr))
{
m_pDevice->ClearDepthStencilView(
m_pDepthStencilView,
D3D10_CLEAR_DEPTH,
1,
0
);
// Draw a gradient background before we draw the cube
if (m_pBackBufferRT)
{
m_pBackBufferRT->BeginDraw();
m_pBackBufferGradientBrush->SetTransform(
D2D1::Matrix3x2F::Scale(m_pBackBufferRT->GetSize())
);
D2D1_RECT_F rect = D2D1::RectF(
0.0f,
0.0f,
(float)swapDesc.BufferDesc.Width,
(float)swapDesc.BufferDesc.Height
);
m_pBackBufferRT->FillRectangle(&rect, m_pBackBufferGradientBrush);
hr = m_pBackBufferRT->EndDraw();
}
if (SUCCEEDED(hr))
{
m_pDiffuseVariableNoRef->SetResource(NULL);
m_pTechniqueNoRef->GetPassByIndex(0)->Apply(0);
// Draw the D2D content into a D3D surface.
hr = RenderD2DContentIntoSurface();
}
if (SUCCEEDED(hr))
{
m_pDiffuseVariableNoRef->SetResource(m_pTextureRV);
// Update variables that change once per frame.
m_pWorldVariableNoRef->SetMatrix((float*)&m_WorldMatrix);
// Set the index buffer.
m_pDevice->IASetIndexBuffer(m_pFacesIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
// Render the scene
m_pTechniqueNoRef->GetPassByIndex(0)->Apply(0);
m_pDevice->DrawIndexed(
ARRAYSIZE(s_FacesIndexArray),
0,
0
);
// Draw some text using a red brush on top of everything
if (m_pBackBufferRT)
{
m_pBackBufferRT->BeginDraw();
m_pBackBufferRT->SetTransform(D2D1::Matrix3x2F::Identity());
// Text format object will center the text in layout
D2D1_SIZE_F rtSize = m_pBackBufferRT->GetSize();
m_pBackBufferRT->DrawText(
sc_helloWorld,
ARRAYSIZE(sc_helloWorld) - 1,
m_pTextFormat,
D2D1::RectF(0.0f, 0.0f, rtSize.width, rtSize.height),
m_pBackBufferTextBrush
);
hr = m_pBackBufferRT->EndDraw();
}
if (SUCCEEDED(hr))
{
hr = m_pSwapChain->Present(1, 0);
}
}
}
}
// If the device is lost for any reason, we need to recreate it
if (hr == DXGI_ERROR_DEVICE_RESET ||
hr == DXGI_ERROR_DEVICE_REMOVED ||
hr == D2DERR_RECREATE_TARGET)
{
hr = S_OK;
DiscardDeviceResources();
}
return hr;
}
/******************************************************************
* *
* DXGISampleApp::RenderD2DContentIntoSurface *
* *
* This method renders a simple 2D scene into a D2D render target *
* that maps to a D3D texture. It's important that the return *
* code from RT->EndDraw() is handed back to the caller, since *
* it's possible for the render target device to be lost while *
* the application is running, and the caller needs to handle *
* that error condition. *
* *
******************************************************************/
HRESULT DXGISampleApp::RenderD2DContentIntoSurface()
{
HRESULT hr;
D2D1_SIZE_F renderTargetSize = m_pRenderTarget->GetSize();
m_pRenderTarget->BeginDraw();
m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
m_pRenderTarget->FillRectangle(
D2D1::RectF(0.0f, 0.0f, renderTargetSize.width, renderTargetSize.height),
m_pGridPatternBitmapBrush
);
D2D1_SIZE_F size = m_pBitmap->GetSize();
m_pRenderTarget->DrawBitmap(
m_pBitmap,
D2D1::RectF(0.0f, 0.0f, size.width, size.height)
);
// Draw the bitmap at the bottom corner of the window
m_pRenderTarget->DrawBitmap(
m_pBitmap,
D2D1::RectF(
renderTargetSize.width - size.width,
renderTargetSize.height - size.height,
renderTargetSize.width,
renderTargetSize.height)
);
// Set the world transform to a 45 degree rotation at the center of the render target
// and write "Hello, World"
m_pRenderTarget->SetTransform(
D2D1::Matrix3x2F::Rotation(
45,
D2D1::Point2F(
renderTargetSize.width / 2,
renderTargetSize.height / 2))
);
m_pRenderTarget->DrawText(
sc_helloWorld,
ARRAYSIZE(sc_helloWorld) - 1,
m_pTextFormat,
D2D1::RectF(0, 0, renderTargetSize.width, renderTargetSize.height),
m_pBlackBrush
);
// Reset back to the identity transform
m_pRenderTarget->SetTransform(
D2D1::Matrix3x2F::Translation(0, renderTargetSize.height - 200)
);
m_pRenderTarget->FillGeometry(m_pPathGeometry, m_pLGBrush);
m_pRenderTarget->SetTransform(
D2D1::Matrix3x2F::Translation(renderTargetSize.width - 200, 0)
);
m_pRenderTarget->FillGeometry(m_pPathGeometry, m_pLGBrush);
hr = m_pRenderTarget->EndDraw();
return hr;
}
/******************************************************************
* *
* DXGISampleApp::OnResize *
* *
* This method is called in response to a WM_SIZE window message *
* *
* When the window resizes, we need to resize the D3D swap chain *
* and remap the corresponding D2D render target *
* *
******************************************************************/
void DXGISampleApp::OnResize(UINT width, UINT height)
{
if (!m_pDevice)
{
CreateDeviceResources();
}
else
{
RecreateSizedResources(width, height);
}
}
/******************************************************************
* *
* DXGISampleApp::OnGetMinMaxInfo *
* *
* This method is called in response to a WM_GETMINMAXINFO window *
* message. We use it to set the minimum size of the window. *
* *
******************************************************************/
void DXGISampleApp::OnGetMinMaxInfo(MINMAXINFO *pMinMaxInfo)
{
FLOAT dpiX, dpiY;
m_pD2DFactory->GetDesktopDpi(&dpiX, &dpiY);
pMinMaxInfo->ptMinTrackSize.x = static_cast<UINT>(ceil(200.f * dpiX / 96.f));
pMinMaxInfo->ptMinTrackSize.y = static_cast<UINT>(ceil(200.f * dpiY / 96.f));
}
/******************************************************************
* *
* DXGISampleApp::OnTimer *
* *
* *
******************************************************************/
void DXGISampleApp::OnTimer()
{
InvalidateRect(m_hwnd, NULL, FALSE);
}
/******************************************************************
* *
* DXGISampleApp::WndProc *
* *
* This static method handles our app's window messages *
* *
******************************************************************/
LRESULT CALLBACK DXGISampleApp::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
if (message == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
DXGISampleApp *pDXGISampleApp = (DXGISampleApp *)pcs->lpCreateParams;
::SetWindowLongPtrW(
hwnd,
GWLP_USERDATA,
reinterpret_cast<LONG_PTR>(pDXGISampleApp)
);
result = 1;
}
else
{
DXGISampleApp *pDXGISampleApp = reinterpret_cast<DXGISampleApp *>(
::GetWindowLongPtrW(
hwnd,
GWLP_USERDATA
));
bool wasHandled = false;
if (pDXGISampleApp)
{
switch (message)
{
case WM_SIZE:
{
UINT width = LOWORD(lParam);
UINT height = HIWORD(lParam);
pDXGISampleApp->OnResize(width, height);
}
result = 0;
wasHandled = true;
break;
case WM_GETMINMAXINFO:
{
MINMAXINFO *pMinMaxInfo = reinterpret_cast<MINMAXINFO *>(lParam);
pDXGISampleApp->OnGetMinMaxInfo(pMinMaxInfo);
}
result = 0;
wasHandled = true;
break;
case WM_PAINT:
case WM_DISPLAYCHANGE:
{
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
pDXGISampleApp->OnRender();
EndPaint(hwnd, &ps);
}
result = 0;
wasHandled = true;
break;
case WM_TIMER:
{
pDXGISampleApp->OnTimer();
}
result = 0;
wasHandled = true;
break;
case WM_DESTROY:
{
PostQuitMessage(0);
}
result = 1;
wasHandled = true;
break;
}
}
if (!wasHandled)
{
result = DefWindowProc(hwnd, message, wParam, lParam);
}
}
return result;
}
/******************************************************************
* *
* DXGISampleApp::CreateD3DDevice *
* *
******************************************************************/
HRESULT DXGISampleApp::CreateD3DDevice(
IDXGIAdapter *pAdapter,
D3D10_DRIVER_TYPE driverType,
UINT flags,
ID3D10Device1 **ppDevice
)
{
HRESULT hr = S_OK;
static const D3D10_FEATURE_LEVEL1 levelAttempts[] =
{
D3D10_FEATURE_LEVEL_10_0,
D3D10_FEATURE_LEVEL_9_3,
D3D10_FEATURE_LEVEL_9_2,
D3D10_FEATURE_LEVEL_9_1,
};
for (UINT level = 0; level < ARRAYSIZE(levelAttempts); level++)
{
ID3D10Device1 *pDevice = NULL;
hr = D3D10CreateDevice1(
pAdapter,
driverType,
NULL,
flags,
levelAttempts[level],
D3D10_1_SDK_VERSION,
&pDevice
);
if (SUCCEEDED(hr))
{
// transfer reference
*ppDevice = pDevice;
pDevice = NULL;
break;
}
}
return hr;
}
/******************************************************************
* *
* DXGISampleApp::LoadResourceBitmap *
* *
* This method loads and creates a D2D bitmap from a DLL resource.*
* The resultinig bitmap is bound to the supplied D2D render *
* target device (pRT) and must be cleaned up when the RT is *
* lost or released. *
* *
******************************************************************/
HRESULT DXGISampleApp::LoadResourceBitmap(
ID2D1RenderTarget *pRenderTarget,
IWICImagingFactory *pIWICFactory,
PCWSTR resourceName,
PCWSTR resourceType,
UINT destinationWidth,
UINT destinationHeight,
ID2D1Bitmap **ppBitmap
)
{
HRESULT hr = S_OK;
IWICBitmapDecoder *pDecoder = NULL;
IWICBitmapFrameDecode *pSource = NULL;
IWICStream *pStream = NULL;
IWICFormatConverter *pConverter = NULL;
IWICBitmapScaler *pScaler = NULL;
HRSRC imageResHandle = NULL;
HGLOBAL imageResDataHandle = NULL;
void *pImageFile = NULL;
DWORD imageFileSize = 0;
// Locate the resource.
imageResHandle = FindResourceW(
HINST_THISCOMPONENT,
resourceName,
resourceType
);
hr = imageResHandle ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
// Load the resource.
imageResDataHandle = LoadResource(HINST_THISCOMPONENT, imageResHandle);
hr = imageResDataHandle ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr))
{
// Lock it to get a system memory pointer.
pImageFile = LockResource(imageResDataHandle);
hr = pImageFile ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr))
{
// Calculate the size.
imageFileSize = SizeofResource(HINST_THISCOMPONENT, imageResHandle);
hr = imageFileSize ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr))
{
// Create a WIC stream to map onto the memory.
hr = pIWICFactory->CreateStream(&pStream);
}
if (SUCCEEDED(hr))
{
// Initialize the stream with the memory pointer and size.
hr = pStream->InitializeFromMemory(
reinterpret_cast<BYTE*>(pImageFile),
imageFileSize
);
}
if (SUCCEEDED(hr))
{
// Create a decoder for the stream.
hr = pIWICFactory->CreateDecoderFromStream(
pStream,
NULL,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
}
if (SUCCEEDED(hr))
{
// Create the initial frame.
hr = pDecoder->GetFrame(0, &pSource);
}
if (SUCCEEDED(hr))
{
// Convert the image format to 32bppPBGRA
// (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
hr = pIWICFactory->CreateFormatConverter(&pConverter);
}
if (SUCCEEDED(hr))
{
// If a new width or height was specified, create an
// IWICBitmapScaler and use it to resize the image.
if (destinationWidth != 0 || destinationHeight != 0)
{
UINT originalWidth, originalHeight;
hr = pSource->GetSize(&originalWidth, &originalHeight);
if (SUCCEEDED(hr))
{
if (destinationWidth == 0)
{
FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight);
destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth));
}
else if (destinationHeight == 0)
{
FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth);
destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight));
}
hr = pIWICFactory->CreateBitmapScaler(&pScaler);
if (SUCCEEDED(hr))
{
hr = pScaler->Initialize(
pSource,
destinationWidth,
destinationHeight,
WICBitmapInterpolationModeCubic
);
if (SUCCEEDED(hr))
{
hr = pConverter->Initialize(
pScaler,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
}
}
}
else
{
hr = pConverter->Initialize(
pSource,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
}
if (SUCCEEDED(hr))
{
//create a Direct2D bitmap from the WIC bitmap.
hr = pRenderTarget->CreateBitmapFromWicBitmap(pConverter, NULL, ppBitmap);
}
SafeRelease(&pDecoder);
SafeRelease(&pSource);
SafeRelease(&pStream);
SafeRelease(&pConverter);
SafeRelease(&pScaler);
return hr;
}
/******************************************************************
* *
* DXGISampleApp::LoadResourceShader *
* *
* This method loads and creates a pixel shader from a DLL *
* resource *
* *
******************************************************************/
HRESULT DXGISampleApp::LoadResourceShader(
ID3D10Device *pDevice,
PCWSTR pszResource,
ID3D10Effect **ppShader)
{
HRESULT hr;
HRSRC hResource = ::FindResource(HINST_THISCOMPONENT, pszResource, RT_RCDATA);
hr = hResource ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
HGLOBAL hResourceData = ::LoadResource(HINST_THISCOMPONENT, hResource);
hr = hResourceData ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
LPVOID pData = ::LockResource(hResourceData);
hr = pData ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
hr = ::D3D10CreateEffectFromMemory(
pData,
::SizeofResource(HINST_THISCOMPONENT, hResource),
0,
pDevice,
NULL,
ppShader
);
}
}
}
return hr;
}