[DirectX] 리소스 기본 설계
in Study on WinAPI&DirectX
Res 클래스 설계
enum class RES_TYPE
{
MESHDATA,
MATERIAL, // 재질
PREFAB,
MESH, // 형태
TEXTURE, // 이미지
SOUND, // 사운드
GRAPHICS_SHADER,
COMPUTE_SHADER,
END
}
// 헤더파일
#pragma once
#include "CEntity.h"
class CRes :
public CEntity
{
private:
const RES_TYPE m_Type;
int m_iRefCount;
wstring m_strKey;
wstring m_strRelativePath;
private:
void SetKey(const wstring& _strKey) { m_strKey = _strKey; }
void SetRelativePath(const wstring& _strPath) { m_strRelativePath = _strPath; }
void AddRef() { ++m_iRefCount; }
void Release();
public:
// 리소스 바인딩
virtual void UpdateData() = 0;
// 리소스는 Clone 을 구현하지 않는다.
virtual CRes* Clone() { return nullptr; assert(nullptr); }
public:
const wstring& GetKey() { return m_strKey; }
const wstring& GetRelativePath() { return m_strRelativePath; }
public:
CRes(RES_TYPE _type);
virtual ~CRes();
friend class CResMgr;
};
// cpp 파일
#include "pch.h"
#include "CRes.h"
CRes::CRes(RES_TYPE _type)
: m_Type(_type)
, m_iRefCount(0)
{
}
CRes::~CRes()
{
}
void CRes::Release()
{
--m_iRefCount;
if (m_iRefCount == 0)
{
delete this;
}
}
Mesh 클래스 구현
// 헤더파일
#include "CRes.h"
class CMesh
: public CRes
{
private:
ComPtr<ID3D11Buffer> m_VB;
D3D11_BUFFER_DESC m_tVBDesc;
UINT m_VtxCount;
ComPtr<ID3D11Buffer> m_IB;
D3D11_BUFFER_DESC m_tIBDesc;
UINT m_IdxCount;
void* m_pVtxSys;
void* m_pIdxSys;
public:
void Create(void* _VtxSysMem, UINT _iVtxCount, void* _IdxSysMem, UINT _IdxCount);
void render();
private:
virtual void UpdateData() override;
public:
CMesh();
~CMesh();
};
// cpp 파일
#include "pch.h"
#include "CMesh.h"
#include "CDevice.h"
CMesh::CMesh()
: CRes(RES_TYPE::MESH)
, m_tVBDesc{}
, m_VtxCount(0)
, m_tIBDesc{}
, m_IdxCount(0)
, m_pVtxSys(nullptr)
, m_pIdxSys(nullptr)
{
}
CMesh::~CMesh()
{
if (nullptr != m_pVtxSys)
delete m_pVtxSys;
if (nullptr != m_pIdxSys)
delete m_pIdxSys;
}
void CMesh::Create(void* _VtxSysMem, UINT _iVtxCount, void* _IdxSysMem, UINT _IdxCount)
{
m_VtxCount = _iVtxCount;
m_IdxCount = _IdxCount;
// SystemMem 데이터 복사
m_pVtxSys = new Vtx[m_VtxCount];
memcpy(m_pVtxSys, _VtxSysMem, sizeof(Vtx) * m_VtxCount);
m_pIdxSys = new UINT[m_IdxCount];
memcpy(m_pIdxSys, _IdxSysMem, sizeof(UINT) * m_IdxCount);
// Vertex 버퍼 생성
m_tVBDesc.BindFlags = D3D11_BIND_FLAG::D3D11_BIND_VERTEX_BUFFER;
m_tVBDesc.CPUAccessFlags = 0;
m_tVBDesc.Usage = D3D11_USAGE_DEFAULT;
m_tVBDesc.ByteWidth = sizeof(Vtx) * m_VtxCount;
D3D11_SUBRESOURCE_DATA tSub = {};
tSub.pSysMem = _VtxSysMem;
if (FAILED(DEVICE->CreateBuffer(&m_tVBDesc, &tSub, m_VB.GetAddressOf())))
{
assert(nullptr);
}
// Index 버퍼 생성
m_tIBDesc.BindFlags = D3D11_BIND_FLAG::D3D11_BIND_INDEX_BUFFER;
m_tIBDesc.CPUAccessFlags = 0;
m_tIBDesc.Usage = D3D11_USAGE_DEFAULT;
m_tIBDesc.ByteWidth = sizeof(UINT) * m_IdxCount;
tSub.pSysMem = _IdxSysMem;
if (FAILED(DEVICE->CreateBuffer(&m_tIBDesc, &tSub, m_IB.GetAddressOf())))
{
assert(nullptr);
}
}
void CMesh::UpdateData()
{
UINT iStride = sizeof(Vtx);
UINT iOffset = 0;
CONTEXT->IASetVertexBuffers(0, 1, m_VB.GetAddressOf(), &iStride, &iOffset);
CONTEXT->IASetIndexBuffer(m_IB.Get(), DXGI_FORMAT_R32_UINT, 0);
}
void CMesh::render()
{
UpdateData();
CONTEXT->DrawIndexed(m_IdxCount, 0, 0);
}
Shader 클래스 구현
DirectX 12식 그래픽스 클래스를 구현하는 과정.
우선 쉐이더 클래스부터 구현한다.
#pragma once
#include "CRes.h"
class CShader :
public CRes
{
protected:
ComPtr<ID3DBlob> m_ErrBlob;
public:
CShader(RES_TYPE _eType);
~CShader();
};
#include "pch.h"
#include "CShader.h"
CShader::CShader(RES_TYPE _eType)
: CRes(_eType)
{
}
CShader::~CShader()
{
}
GraphicsShader 클래스 구현
// 헤더파일
#pragma once
#include "CShader.h"
class CGraphicsShader :
public CShader
{
private:
ComPtr<ID3DBlob> m_VSBlob;
ComPtr<ID3DBlob> m_HSBlob;
ComPtr<ID3DBlob> m_DSBlob;
ComPtr<ID3DBlob> m_GSBlob;
ComPtr<ID3DBlob> m_PSBlob;
ComPtr<ID3D11VertexShader> m_VS;
ComPtr<ID3D11HullShader> m_HS;
ComPtr<ID3D11DomainShader> m_DS;
ComPtr<ID3D11GeometryShader> m_GS;
ComPtr<ID3D11PixelShader> m_PS;
ComPtr<ID3D11InputLayout> m_Layout;
D3D11_PRIMITIVE_TOPOLOGY m_eTopology;
//RS_TYPE;
//BS_TYPE;
//DS_TYPE;
public:
void CreateVertexShader(const wstring& _strFileName, const string& _strFuncName);
void CreatePixelShader(const wstring& _strFileName, const string& _strFuncName);
void SetTopology(D3D11_PRIMITIVE_TOPOLOGY _Topology) { m_eTopology = _Topology; }
virtual void UpdateData() override;
public:
CGraphicsShader();
~CGraphicsShader();
};
// cpp 파일
#include "pch.h"
#include "CGraphicsShader.h"
#include "CPathMgr.h"
#include "CDevice.h"
CGraphicsShader::CGraphicsShader()
: CShader(RES_TYPE::GRAPHICS_SHADER)
, m_eTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST)
{
}
CGraphicsShader::~CGraphicsShader()
{
}
void CGraphicsShader::CreateVertexShader(const wstring& _strFileName, const string& _strFuncName)
{
// Shader 파일 경로
wstring strShaderFile = CPathMgr::GetInst()->GetContentPath();
strShaderFile += _strFileName;
// VertexShader Compile
if (FAILED(D3DCompileFromFile(strShaderFile.c_str(), nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE
, _strFuncName.c_str(), "vs_5_0", 0, 0, m_VSBlob.GetAddressOf(), m_ErrBlob.GetAddressOf())))
{
MessageBoxA(nullptr, (const char*)m_ErrBlob->GetBufferPointer()
, "Vertex Shader Compile Failed!!", MB_OK);
}
// 컴파일된 객체로 VertexShader, PixelShader 를 만든다.
DEVICE->CreateVertexShader(m_VSBlob->GetBufferPointer(), m_VSBlob->GetBufferSize()
, nullptr, m_VS.GetAddressOf());
// InputLayout 생성
D3D11_INPUT_ELEMENT_DESC LayoutDesc[2] = {};
LayoutDesc[0].SemanticName = "POSITION";
LayoutDesc[0].SemanticIndex = 0;
LayoutDesc[0].AlignedByteOffset = 0;
LayoutDesc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
LayoutDesc[0].InputSlot = 0;
LayoutDesc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
LayoutDesc[0].InstanceDataStepRate = 0;
LayoutDesc[1].SemanticName = "COLOR";
LayoutDesc[1].SemanticIndex = 0;
LayoutDesc[1].AlignedByteOffset = 12;
LayoutDesc[1].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
LayoutDesc[1].InputSlot = 0;
LayoutDesc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
LayoutDesc[1].InstanceDataStepRate = 0;
if (FAILED(DEVICE->CreateInputLayout(LayoutDesc, 2
, m_VSBlob->GetBufferPointer(), m_VSBlob->GetBufferSize()
, m_Layout.GetAddressOf())))
{
assert(nullptr);
}
}
void CGraphicsShader::CreatePixelShader(const wstring& _strFileName, const string& _strFuncName)
{
// Shader 파일 경로
wstring strShaderFile = CPathMgr::GetInst()->GetContentPath();
strShaderFile += _strFileName;
// PixelShader Compile
if (FAILED(D3DCompileFromFile(strShaderFile.c_str(), nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE
, _strFuncName.c_str(), "ps_5_0", 0, 0, m_PSBlob.GetAddressOf(), m_ErrBlob.GetAddressOf())))
{
MessageBoxA(nullptr, (const char*)m_ErrBlob->GetBufferPointer()
, "Pixel Shader Compile Failed!!", MB_OK);
}
// 컴파일된 객체로 PixelShader 를 만든다.
DEVICE->CreatePixelShader(m_PSBlob->GetBufferPointer(), m_PSBlob->GetBufferSize()
, nullptr, m_PS.GetAddressOf());
}
void CGraphicsShader::UpdateData()
{
CONTEXT->IASetInputLayout(m_Layout.Get());
CONTEXT->IASetPrimitiveTopology(m_eTopology);
CONTEXT->VSSetShader(m_VS.Get(), nullptr, 0);
//CONTEXT->HSSetShader(m_HS.Get(), nullptr, 0);
//CONTEXT->DSSetShader(m_DS.Get(), nullptr, 0);
//CONTEXT->GSSetShader(m_GS.Get(), nullptr, 0);
CONTEXT->PSSetShader(m_PS.Get(), nullptr, 0);
}
MeshRender 클래스 구현
#pragma once
#include "CComponent.h"
class CMesh;
class CGraphicsShader;
class CMeshRender :
public CComponent
{
private:
CMesh* m_pMesh;
CGraphicsShader* m_pShader;
public:
void SetMesh(CMesh* _Mesh) { m_pMesh = _Mesh; }
void SetShader(CGraphicsShader* _Shader) { m_pShader = _Shader; }
CMesh* GetMesh() { return m_pMesh; }
CGraphicsShader* GetShader() { return m_pShader; }
public:
virtual void finaltick() override;
void render();
CLONE(CMeshRender);
public:
CMeshRender();
~CMeshRender();
};
#include "pch.h"
#include "CMeshRender.h"
#include "CGraphicsShader.h"
#include "CMesh.h"
CMeshRender::CMeshRender()
: CComponent(COMPONENT_TYPE::MESHRENDER)
, m_pMesh(nullptr)
, m_pShader(nullptr)
{
}
CMeshRender::~CMeshRender()
{
}
void CMeshRender::finaltick()
{
}
void CMeshRender::render()
{
if (nullptr == m_pMesh || nullptr == m_pShader)
return;
// Transform 에 UpdateData 요청
m_pShader->UpdateData();
m_pMesh->render();
}
CTransform 클래스 구현
#pragma once
#include "CComponent.h"
class CTransform :
public CComponent
{
private:
Vec3 m_vRelativePos;
Vec3 m_vRelativeScale;
Vec3 m_vRelativeRot;
public:
virtual void finaltick() override;
void UpdateData();
CLONE(CTransform);
public:
CTransform();
~CTransform();
};
#include "pch.h"
#include "CTransform.h"
CTransform::CTransform()
: CComponent(COMPONENT_TYPE::TRANSFORM)
{
}
CTransform::~CTransform()
{
}
void CTransform::finaltick()
{
}
void CTransform::UpdateData()
{
// 위치값을 상수버퍼에 저장
}
클래스 구현에 따른 CGameObject의 변화
#pragma once
#include "CEntity.h"
class CComponent;
class CTransform;
class CMeshRender;
class CGameObject :
public CEntity
{
private:
CComponent* m_arrCom[(UINT)COMPONENT_TYPE::END];
public:
void render();
public:
void AddComponent(CComponent* _Component);
CTransform* Transform() { return (CTransform*)m_arrCom[(UINT)COMPONENT_TYPE::TRANSFORM]; }
CMeshRender* MeshRender() { return (CMeshRender*)m_arrCom[(UINT)COMPONENT_TYPE::MESHRENDER]; }
CLONE(CGameObject)
public:
CGameObject();
~CGameObject();
};
#include "pch.h"
#include "CGameObject.h"
#include "CComponent.h"
#include "CMeshRender.h"
CGameObject::CGameObject()
: m_arrCom{}
{
}
CGameObject::~CGameObject()
{
/*for (UINT i = 0; i < (UINT)COMPONENT_TYPE::END; ++i)
{
if (nullptr != m_arrCom[i])
delete m_arrCom[i];
}*/
Safe_Del_Array(m_arrCom);
}
void CGameObject::render()
{
if (nullptr == MeshRender())
return;
MeshRender()->render();
}
void CGameObject::AddComponent(CComponent* _Component)
{
// 이미 보유하고 있는 컴포넌트인 경우
assert(!m_arrCom[(UINT)_Component->GetType()]);
_Component->m_pOwner = this;
m_arrCom[(UINT)_Component->GetType()] = _Component;
}