엔진에서 모든 리소스의 공통 저장소
리소스(Mesh, Texture, Shader, Material, Animation)를 모두 이름(wstring key)로 관리
Load() : 파일에서 리소스를 로드하거나, 이미 있으면 그대로 반환
Add() : 메모리에 이미 있는 리소스 등록
Get() : 이름으로 리소스 조회
CreateDefault~() : 기본 리소스 생성
엔진의 Data Asset창고이자, 러닝 타임에서 필요한 모든 리소스를 한 곳에서 공유하는 허브 역할
만약 ResourceManage가 없다면, GameObject/Component에서 각 Mesh/Material를 새로 로드하기에 메모리 낭비.
서로 다른 오브젝트가 동일한 리소스를 참조하지 못함
#pragma once
class Mesh;
class Material;
class Shader;
class Animation;
class Texture;
class ResourceManager
{
public:
ResourceManager(ComPtr<ID3D11Device> device);
void Init();
template<typename T>
shared_ptr<T> Load(const wstring& key, const wstring& path);
template<typename T>
bool Add(const wstring& key, shared_ptr<T> object); // 키값을 넣고, Object를 넣으면 _resources 배열에서 알맞는 리소스를 저장하는
template<typename T>
shared_ptr<T> Get(const wstring& key);
template<typename T>
ResourceType GetResourceType();
private:
void CreateDefaultTexture();
void CreateDefaultMesh();
void CreateDefaultShader();
void CreateDefaultMaterial();
void CreateDefaultAnimation();
private:
ComPtr<ID3D11Device> _device;
using KeyObjMap = map<wstring/*Key*/, shared_ptr<ResourceBase>>;
// map의 배열
array<KeyObjMap, RESOURCE_TYPE_COUNT> _resources;
};
template<typename T>
shared_ptr<T> ResourceManager::Load(const wstring& key, const wstring& path)
{
return shared_ptr<T>();
}
template<typename T>
bool ResourceManager::Add(const wstring& key, shared_ptr<T> object)
{
ResourceType resourceType = GetResourceType<T>();
KeyObjMap& keyObjMap = _resources[static_cast<uint8>(resourceType)];
auto findIt = keyObjMap.find(key);
if (findIt != keyObjMap.end())
return false;
keyObjMap[key] = object;
return true;
}
template<typename T>
shared_ptr<T> ResourceManager::Get(const wstring& key)
{
ResourceType resourceType = GetResourceType<T>();
KeyObjMap& keyObjMap = _resources[static_cast<uint8>(resourceType)];
auto findIt = keyObjMap.find(key);
if (findIt != keyObjMap.end())
return static_pointer_cast<T>(findIt->second);
return nullptr;
}
template<typename T>
ResourceType ResourceManager::GetResourceType()
{
// constexpr : if else문을 100%로 컴파일 타임에 되게끔 유도
//if constexpr (std::is_same_v<T, Mesh>)
if (std::is_same_v<T, Mesh>)
return ResourceType::Mesh;
if (std::is_same_v<T, Material>)
return ResourceType::Material;
if (std::is_same_v<T, Texture>)
return ResourceType::Texture;
if (std::is_same_v<T, Shader>)
return ResourceType::Shader;
if (std::is_same_v<T, Animation>)
return ResourceType::Animation;
assert(false);
return ResourceType::None;
}
#include "pch.h"
#include "ResourceManager.h"
#include "Texture.h"
#include "Shader.h"
#include "Mesh.h"
#include "Material.h"
#include "Animation.h"
ResourceManager::ResourceManager(ComPtr<ID3D11Device> device)
: _device(device)
{
}
void ResourceManager::Init()
{
CreateDefaultTexture();
CreateDefaultMesh();
CreateDefaultShader();
CreateDefaultMaterial();
CreateDefaultAnimation();
}
void ResourceManager::CreateDefaultTexture()
{
{
auto texture = make_shared<Texture>(_device);
texture->SetName(L"Skeleton");
texture->Create(L"Skeleton.png");
Add(texture->GetName(), texture);
}
{
auto texture = make_shared<Texture>(_device);
texture->SetName(L"Snake");
texture->Create(L"Snake.bmp");
Add(texture->GetName(), texture);
}
}
void ResourceManager::CreateDefaultMesh()
{
shared_ptr<Mesh> mesh = make_shared<Mesh>(_device);
mesh->SetName(L"Rectangle");
mesh->CreateDefaultRectangle();
Add(mesh->GetName(), mesh);
}
void ResourceManager::CreateDefaultShader()
{
// Layout과 Shader 생성
auto vertexShader = make_shared<VertexShader>(_device);
vertexShader->Create(L"Default.hlsl", "VS", "vs_5_0"); // CreateVS
// GPU와 쉐이더랑 연결
auto inputLayout = make_shared<InputLayout>(_device);
inputLayout->Create(VertexTextureData::descs, vertexShader->GetBlob()); // CreateInputLayout
// PixelShader 생성
auto pixelShader = make_shared<PixelShader>(_device);
pixelShader->Create(L"Default.hlsl", "PS", "ps_5_0"); // CreatePS
// shader
shared_ptr<Shader> shader = make_shared<Shader>();
shader->SetName(L"Default");
shader->_vertexShader = vertexShader;
shader->_inputLayout = inputLayout;
shader->_pixelShader = pixelShader;
Add(shader->GetName(), shader);
}
void ResourceManager::CreateDefaultMaterial()
{
shared_ptr<Material> material = make_shared<Material>();
material->SetName(L"Default");
material->SetShader(Get<Shader>(L"Default"));
material->SetTexture(Get<Texture>(L"Skeleton"));
Add(material->GetName(), material);
}
void ResourceManager::CreateDefaultAnimation()
{
shared_ptr<Animation> animation = make_shared<Animation>();
animation->SetName(L"SnakeAnim");
animation->SetTexture(Get<Texture>(L"Snake"));
animation->SetLoop(true);
animation->AddKeyframe(Keyframe{ Vec2{0.f, 0.f}, Vec2{100.f, 100.f}, 0.1f });
animation->AddKeyframe(Keyframe{ Vec2{100.f, 0.f}, Vec2{100.f, 100.f}, 0.1f });
animation->AddKeyframe(Keyframe{ Vec2{200.f, 0.f}, Vec2{100.f, 100.f}, 0.1f });
animation->AddKeyframe(Keyframe{ Vec2{300.f, 0.f}, Vec2{100.f, 100.f}, 0.1f });
Add(animation->GetName(), animation);
}
#pragma once
enum class ResourceType : uint8
{
None = -1,
Mesh,
Shader,
Texture,
Material,
Animation,
End
};
enum
{
RESOURCE_TYPE_COUNT = static_cast<uint8>(ResourceType::End)
};
class ResourceBase : public enable_shared_from_this<ResourceBase>
{
public:
ResourceBase(ResourceType type);
virtual ~ResourceBase();
ResourceType GetType() { return _type; }
void SetName(const wstring& name) { _name = name; }
const wstring& GetName() { return _name; }
uint32 GetID() { return _id; }
protected:
virtual void Load(const wstring& path) { }
virtual void Save(const wstring& path) { }
protected:
ResourceType _type = ResourceType::None;
wstring _name;
wstring _path;
uint32 _id = 0;
};