Graphics
- "DirectX11 초기화 + 프레임 시작/끝 관리"를 전담하는 그래픽스 매니저
수정코드
- 기존 Game(Main)클래스에서 Graphics 클래스로 이동
- 함수 : CreateDeviceAndSwapChaine(), CreateRenderTargetView(), SetViewport()
- 변수 : hwnd, device, deviceContext, swapChain, renderTargetView, viewport, clearColor
Graphics.h
#pragma once
class Graphics
{
public:
Graphics(HWND hwnd);
~Graphics();
void RenderBegin();
void RenderEnd();
ComPtr<ID3D11Device>GetDevice() { return _device; }
ComPtr<ID3D11DeviceContext> GetDeviceContext() { return _deviceContext; }
private:
void CreateDeviceAndSwapChain();
void CreateRenderTargertView();
void SetViewport();
private:
HWND _hwnd;
ComPtr<ID3D11Device> _device = nullptr;
ComPtr<ID3D11DeviceContext> _deviceContext = nullptr;
ComPtr<IDXGISwapChain> _swapChain = nullptr;
ComPtr<ID3D11RenderTargetView> _renderTargetView;
D3D11_VIEWPORT _viewport = { 0 };
float _clearColor[4] = { 0.5f, 0.5f, 0.5f, 0.5f };
};
Graphics.cpp
#include "pch.h"
#include "Graphics.h"
Graphics::Graphics(HWND hwnd)
{
_hwnd = hwnd;
CreateDeviceAndSwapChain();
CreateRenderTargertView();
SetViewport();
}
Graphics::~Graphics()
{
}
void Graphics::CreateDeviceAndSwapChain()
{
DXGI_SWAP_CHAIN_DESC desc;
ZeroMemory(&desc, sizeof(desc));
{
desc.BufferDesc.Width = GWinSizeX;
desc.BufferDesc.Height = GWinSizeY;
desc.BufferDesc.RefreshRate.Numerator = 60;
desc.BufferDesc.RefreshRate.Denominator = 1;
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = 1;
desc.OutputWindow = _hwnd;
desc.Windowed = TRUE;
desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
}
HRESULT hr = ::D3D11CreateDeviceAndSwapChain(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
0,
nullptr,
0,
D3D11_SDK_VERSION,
&desc,
_swapChain.GetAddressOf(),
_device.GetAddressOf(),
nullptr,
_deviceContext.GetAddressOf()
);
CHECK(hr);
}
void Graphics::CreateRenderTargertView()
{
HRESULT hr;
ComPtr<ID3D11Texture2D> backBuffer = nullptr;
hr = _swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)backBuffer.GetAddressOf());
CHECK(hr);
hr = _device->CreateRenderTargetView(backBuffer.Get(), nullptr, _renderTargetView.GetAddressOf());
CHECK(hr);
}
void Graphics::SetViewport()
{
_viewport.TopLeftX = 0.f;
_viewport.TopLeftY = 0.f;
_viewport.Width = static_cast<float>(GWinSizeX);
_viewport.Height = static_cast<float>(GWinSizeY);
_viewport.MinDepth = 0.f;
_viewport.MaxDepth = 1.f;
}
void Graphics::RenderBegin()
{
_deviceContext->OMSetRenderTargets(1, _renderTargetView.GetAddressOf(), nullptr);
_deviceContext->ClearRenderTargetView(_renderTargetView.Get(), _clearColor);
_deviceContext->RSSetViewports(1, &_viewport);
}
void Graphics::RenderEnd()
{
HRESULT hr = _swapChain->Present(1, 0);
CHECK(hr);
}
알면 좋은 부분들
- 왜 이렇게 클래스로 감쌌을까
- 초기화/정리 코드가 한 곳에 모여 관리가 쉬움
- DepthStencil, 여러 RenderTarget, 멀티 뷰포트를 추가하게 되면 Graphics클래스만 수정하면 됨
- 다른 프로젝트나 샘플에도 재사용 가능
- ComPtr 사용 이유
- Com은 Release()를 수동으로 호출 해야함.
- ComPtr을 사용하면서 스코프를 벗어나면 Release() 자동 호출
- Get() vs GetAddressOf()
- 매개변수에서 *이면 Get(), **이면 GetAddressOf()
- CHECK(hr)
- DirectX는 대부분
HRESULT를 리턴
- 사용을 안할 경우 어디에서 터졌는지 찾기 힘듦
- CHECK(hr) 실패 시 assert, 로그 출력, 메시지 박스, 프로그램 종료 등 공동 처리