这是我最后一次尝试创建一个高效的ResourceManager类,它负责分配OpenGL对象(比如阴影、纹理、网格、.)。它将每个资源存储在一个unique_ptr中,然后分发这种类型的const指针,我称之为“观察指针”。它们不能被删除,因为资源分配只能通过ResourceManager类完成。
#pragma once
#include <memory>
#include <vector>
#include <unordered_map>
#include "../render/Shader.h"
#include "../render/Mesh.h"
#include "../render/Texture.h"
namespace Spiky
{
class ResourceManager
{
public:
using ShaderRepo = std::unordered_map<const char*, std::unique_ptr<CShader>>;
using MeshRepo = std::unordered_map<const char*, std::unique_ptr<CMesh>>;
using TextureRepo = std::unordered_map<const char*, std::unique_ptr<CTexture>>;
//Shader
static const CShader* LoadShader(const char* ID, const char* vs, const char* fs)
{
shaderObjects.insert(std::pair<const char*, std::unique_ptr<CShader>>(ID, std::make_unique<CShader>(
(shaderRootDir + std::string(vs)).c_str(),
(shaderRootDir + std::string(fs)).c_str())));
return (shaderObjects.at(ID).get());
}
static const CShader* LoadShader(const char* ID, const char* vs, const char* fs, const char* gs)
{
shaderObjects.insert(std::pair<const char*, std::unique_ptr<CShader>>(ID, std::make_unique<CShader>(
(shaderRootDir + std::string(vs)).c_str(),
(shaderRootDir + std::string(fs)).c_str(),
(shaderRootDir + std::string(gs)).c_str())));
return (shaderObjects.at(ID).get());
}
static CShader* GetShader(const char* ID)
{
return (shaderObjects.at(ID).get());
}
//Mesh
static const CMesh* LoadMesh(const char* ID, Vertex* vertices, unsigned int numVertices, unsigned int* indeces, unsigned int numIndices)
{
meshObjects.insert(std::pair<const char*, std::unique_ptr<CMesh>>(ID, std::make_unique<CMesh>(
vertices,
numVertices,
indeces,
numIndices)));
return (meshObjects.at(ID).get());
}
static const CMesh* LoadMesh(const char* ID, const char* fileName)
{
meshObjects.insert(std::pair<const char*, std::unique_ptr<CMesh>>(ID, std::make_unique<CMesh>(
(meshRootDir + std::string(fileName)).c_str())));
return (meshObjects.at(ID).get());
}
//Texture
static const CTexture* LoadTexture(const char* ID, const char* texturePath, GLenum texTarget = GL_TEXTURE_2D, GLfloat filter = GL_LINEAR,
GLfloat pattern = GL_REPEAT, GLenum attachment = GL_NONE)
{
textureObjects.insert(std::pair<const char*, std::unique_ptr<CTexture>>(ID, std::unique_ptr<CTexture>(new CTexture(
(textureRootDir + std::string(texturePath)).c_str(), texTarget, filter, pattern, attachment))));
return (textureObjects.at(ID).get());
}
static const CTexture* LoadTexture(const char* ID, int width, int height, unsigned char* data = nullptr, GLenum texTarget = GL_TEXTURE_2D,
GLfloat filter = GL_LINEAR, GLfloat pattern = GL_REPEAT, GLenum attachment = GL_NONE)
{
textureObjects.insert(std::pair<const char*, std::unique_ptr<CTexture>>(ID, std::unique_ptr<CTexture>(new CTexture(
width, height, data, texTarget, filter, pattern, attachment))));
return (textureObjects.at(ID).get());
}
static const CTexture* LoadTextureCustomPath(const char* ID, const char* texturePath, GLenum texTarget = GL_TEXTURE_2D, GLfloat filter = GL_LINEAR, GLfloat pattern = GL_REPEAT, GLenum attachment = GL_NONE)
{
textureObjects.insert(std::pair<const char*, std::unique_ptr<CTexture>>(ID, std::unique_ptr<CTexture>(new CTexture(
texturePath, texTarget, filter, pattern, attachment))));
return (textureObjects.at(ID).get());
}
static const* CTexture GetTexture(const char* ID)
{
return (textureObjects.at(ID).get());
}
private:
static ShaderRepo shaderObjects;
static MeshRepo meshObjects;
static TextureRepo textureObjects;
static std::string shaderRootDir;
static std::string meshRootDir;
static std::string textureRootDir;
};
}#include "../core/ResourceManager.h"
namespace Spiky
{
ResourceManager::ShaderRepo ResourceManager::shaderObjects = ShaderRepo();
ResourceManager::MeshRepo ResourceManager::meshObjects = MeshRepo();
ResourceManager::TextureRepo ResourceManager::textureObjects = TextureRepo();
std::string ResourceManager::shaderRootDir = std::string("assets/shaders/");
std::string ResourceManager::meshRootDir = std::string("assets/models/");
std::string ResourceManager::textureRootDir = std::string("assets/images/");
}发布于 2015-11-01 20:39:05
std::string。这是最简单和最通用的解决方案,但它的缺点是潜在的额外分配。Load@,虽然这些函数都很短,但是有大量的东西需要优化:std::make_pair(...)。std::string,而不需要额外的临时对象。std::emplace来避免不必要地创建std::pair。insert和emplace已经返回一个迭代器到插入的元素,或者任何阻止插入的东西,并返回一个bool来指示发生了什么。template静态const CShader* LoadShader(T& ID,const char* vs,const char* fs) { auto res = shaderObjects.emplace(std::forward(ID));if(res.second)尝试{ res.first->second =std::make_unique (shaderRootDir + vs).c_str(),(shaderRootDir+fs).c_str();}catch(.){ shaderObjects.erase(res.first);抛出;}返回res.first->medid.get();}
顺便说一句,我不知道你为什么要用打字机.
据我所见,它们是无用的。
还有,你知道你可以用struct吗?
如果您有一个C++17标准库(因此可以访问try_emplace(...)),那么事情就会变得更加高效:
return &shaderObjects.try_emplace(ID, (shaderRootDir + vs).c_str(),
(shaderRootDir + fs).c_str()).first->second;如果没有,但可以安排CMesh、CTexture和CShader有效地默认-可构造且可交换或可移动-可分配,这也就足够了。
在紧要关头,如果默认构造函数是轻量级且不能抛出的,那么甚至可以使用显式析构函数调用和放置-new。这不太好,但它足够有效,而且很有效:
template<class T>
static const CShader* LoadShader(T&& ID, const char* vs, const char* fs) {
auto res = shaderObjects.emplace(std::forward<T>(ID));
if(res.second)
try {
res.first->second.~CShader(); // noexcept
new((void*)&res.first->second) CShader((shaderRootDir + vs).c_str(),
(shaderRootDir + fs).c_str());
} catch(...) {
new((void*)&res.first->second) CShader(); // efficient and noexcept
shaderObjects.erase(res.first);
throw;
}
return &res.first->second;
}在这种情况下,它们应该直接在映射中,因为std::unordered_map中的元素在被擦除之前都将保持在正确的位置,这意味着我们的动态分配少了一个。
https://codereview.stackexchange.com/questions/109459
复制相似问题