feat(render): add model ID system with concurrent lookup and namespace-based loading

- Extract `ModelID` and `Model` struct to new `model.hpp`
- Replace `std::unordered_map` with `tbb::concurrent_hash_map` for thread safety
- Add `get_model(ModelID)`, `get_model_id`, `get_model_name` methods
- Parse model names in `namespace:name` format to construct asset paths
- Update `load_model` to accept `string_view` and use ID-based management
This commit is contained in:
2026-07-27 21:03:31 +08:00
parent 15d5af34b9
commit ab605f7590
4 changed files with 81 additions and 20 deletions

View File

@@ -6,8 +6,6 @@
#include <string> #include <string>
namespace Cubed { namespace Cubed {
using ModelID = uint32_t;
struct Position { struct Position {
glm::vec3 value{0.0f}; glm::vec3 value{0.0f};
}; };
@@ -25,10 +23,6 @@ struct EntityInfo {
std::string uuid; std::string uuid;
}; };
struct Model {
ModelID id;
};
struct Health { struct Health {
float hp = 20; float hp = 20;
float max_hp = 20; float max_hp = 20;

View File

@@ -0,0 +1,7 @@
#pragma once
#include <cstdint>
using ModelID = uint32_t;
struct Model {
ModelID id;
};

View File

@@ -1,6 +1,9 @@
#pragma once #pragma once
#include "Cubed/gameplay/model.hpp"
#include "Cubed/render/model_node.hpp" #include "Cubed/render/model_node.hpp"
#include "Cubed/tools/model_loader.hpp" #include "Cubed/tools/model_loader.hpp"
#include <tbb/concurrent_hash_map.h>
namespace Cubed { namespace Cubed {
class ModelManager { class ModelManager {
public: public:
@@ -11,11 +14,20 @@ public:
ModelManager& operator=(ModelManager&&) = delete; ModelManager& operator=(ModelManager&&) = delete;
~ModelManager(); ~ModelManager();
const ModelNode& get_model(const std::string& model_name); const ModelNode& get_model(const std::string& model_name);
const ModelNode& get_model(ModelID id);
ModelID get_model_id(const std::string& name);
const std::string& get_model_name(ModelID id);
void init(); void init();
private: private:
ModelLoader m_loader; ModelLoader m_loader;
std::unordered_map<std::string, ModelNode> m_models; ModelID m_next = 0;
const ModelNode& load_model(const std::string& model_name); using ModelMap = tbb::concurrent_hash_map<ModelID, ModelNode>;
using IDMap = tbb::concurrent_hash_map<std::string, ModelID>;
using NameMap = tbb::concurrent_hash_map<ModelID, std::string>;
ModelMap m_models;
IDMap m_id_map;
NameMap m_name_map;
const ModelNode& load_model(std::string_view model_name);
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -1,5 +1,6 @@
#include "Cubed/render/model_manager.hpp" #include "Cubed/render/model_manager.hpp"
#include "Cubed/tools/cubed_assert.hpp"
#include "Cubed/tools/log.hpp" #include "Cubed/tools/log.hpp"
namespace Cubed { namespace Cubed {
@@ -12,21 +13,68 @@ void ModelManager::init() {
}; };
const ModelNode& ModelManager::get_model(const std::string& model_name) { const ModelNode& ModelManager::get_model(const std::string& model_name) {
auto it = m_models.find(model_name); return get_model(get_model_id(model_name));
if (it == m_models.end()) {
return load_model(model_name);
}
return it->second;
} }
const ModelNode& ModelManager::load_model(const std::string& model_name) { const ModelNode& ModelManager::get_model(ModelID id) {
std::string path = ASSETS_PATH + model_name;
auto model = m_loader.load(path); ModelMap::const_accessor cacc;
auto [it, instert] = m_models.try_emplace(model_name, std::move(model)); if (!m_models.find(cacc, id)) {
if (!instert) { return cacc->second;
Logger::error("Model Key {} already exist!", model_name);
} }
return it->second; return load_model(get_model_name(id));
}
const ModelNode& get_model(const std::string& model_name);
const ModelNode& get_model(ModelID id);
ModelID ModelManager::get_model_id(const std::string& name) {
IDMap::const_accessor cacc;
if (m_id_map.find(cacc, name)) {
return cacc->second;
}
ASSERT_MSG(false, std::format("ModelManager: Can't find {}", name));
return 0;
}
const std::string& ModelManager::get_model_name(ModelID id) {
NameMap::const_accessor cacc;
if (m_name_map.find(cacc, id)) {
return cacc->second;
}
ASSERT_MSG(false, std::format("ModelManager: Can't find {}", id));
static std::string n = "";
return n;
}
const ModelNode& ModelManager::load_model(std::string_view model_name) {
auto p = model_name.find(':');
if (p == std::string::npos) {
Logger::error("Can't Parse Model name {}", model_name);
ASSERT(false);
}
auto name = model_name.substr(p + 1);
auto space = model_name.substr(0, p);
if (name.empty()) {
Logger::error("Can't Parse Model name {}", model_name);
ASSERT(false);
}
std::string path;
if (space == "cubed") {
path = std::format("{}model/creature/{}", ASSETS_PATH, name);
} else {
path = std::format("./{}/model/creature/{}", space, name);
}
auto model = m_loader.load(path);
ModelMap::accessor acc;
if (m_models.insert(acc, m_next++)) {
acc->second = std::move(model);
} else {
Logger::error("Can't Insert Model {}", model_name);
ASSERT(false);
}
m_id_map.emplace(model_name, acc->first);
m_name_map.emplace(acc->first, model_name);
return acc->second;
} }
} // namespace Cubed } // namespace Cubed