Loading...
Searching...
No Matches
AssetImportManager.cpp
Go to the documentation of this file.
1//
2// Created by denzel on 09/12/2025.
3//
4
6
7#include "hellfire/assets/models/ModelImporter.h"
8#include "hellfire/serializers/ModelSerializer.h"
9#include "hellfire/serializers/TextureSerializer.h"
10
11#include <thread>
12#include <mutex>
13#include <vector>
14#include <future>
15
16namespace hellfire {
17 TextureType infer_texture_type(const std::string& name) {
18 std::string lower_name = name;
19 std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(), ::tolower);
20
21 if (lower_name.find("normal") != std::string::npos ||
22 lower_name.find("nrm") != std::string::npos ||
23 lower_name.find("_n.") != std::string::npos) {
25 }
26 if (lower_name.find("rough") != std::string::npos) {
28 }
29 if (lower_name.find("metal") != std::string::npos) {
31 }
32 if (lower_name.find("ao") != std::string::npos ||
33 lower_name.find("occlusion") != std::string::npos) {
35 }
36 if (lower_name.find("emissive") != std::string::npos ||
37 lower_name.find("emission") != std::string::npos) {
39 }
40 if (lower_name.find("spec") != std::string::npos) {
42 }
43
44 return TextureType::DIFFUSE; // Default
45 }
46
48 const std::filesystem::path &project_root) : registry_(registry),
49 asset_manager_(asset_manager), project_root_(project_root),
50 import_output_dir_(project_root / "assets" / "imported") {
51 create_directory(import_output_dir_);
52 }
53
55 std::cout << "=== Scanning for assets to import ===" << std::endl;
56
59
60 std::cout << "=== Import complete ===" << std::endl;
61 }
62
64 auto models = registry_.get_assets_by_type(AssetType::MODEL);
65
66 std::vector<AssetMetadata> to_import;
67
68 for (const auto &meta: models) {
69 // Skip already-imported internal formats
70 std::string ext = meta.filepath.extension().string();
71 std::transform(ext.begin(), ext.end(), ext.begin(), tolower);
72
73 if (ext == ".hfmodel" || ext == ".hfmesh") continue;
74
75 if (needs_import(meta.uuid)) {
76 to_import.push_back(meta);
77 }
78 }
79
80 // Parallel import
81 std::mutex output_mutex;
82 std::mutex registry_mutex;
83
84 auto worker = [&](const AssetMetadata& meta) {
85 bool success = import_model_threaded(meta, registry_mutex);
86
87 std::lock_guard lock(output_mutex);
88 if (success) {
89 std::cout << "Imported: " << meta.name << std::endl;
90 } else {
91 std::cerr << "Failed: " << meta.name << std::endl;
92 }
93 };
94
95 std::vector<std::future<void>> futures;
96 for (const auto& meta : to_import) {
97 futures.push_back(std::async(std::launch::async, worker, meta));
98 }
99 for (auto& f : futures) f.get();
100 }
101
103 auto textures = registry_.get_assets_by_type(AssetType::TEXTURE);
104
105 for (const auto &meta: textures) {
106 // For textures, we just create metadata files if they don't exist
107 auto meta_path = registry_.get_absolute_path(meta.uuid).string() + ".meta";
108
109 if (!std::filesystem::exists(meta_path)) {
110 std::cout << "Creating texture metadata: " << meta.name << std::endl;
111
112 // Infer texture type from filename
113 TextureMetadata tex_meta;
114 tex_meta.type = infer_texture_type(meta.name);
115 tex_meta.generate_mipmaps = true;
116 tex_meta.srgb = (tex_meta.type == TextureType::DIFFUSE ||
117 tex_meta.type == TextureType::EMISSIVE);
118
119 TextureSerializer::save_metadata(
120 registry_.get_absolute_path(meta.uuid),
121 tex_meta
122 );
123 }
124 }
125 }
126
128 auto meta = registry_.get_asset(id);
129 if (!meta) return false;
130
131 switch (meta->type) {
132 case AssetType::MODEL:
133 return import_model(*meta);
135 return import_texture(*meta);
136 default:
137 return false;
138 }
139 }
140
141 bool AssetImportManager::needs_import(AssetID id) const {
142 auto meta = registry_.get_asset(id);
143 if (!meta) return false;
144
145 // Check if .hfmodel file exists for this source
146 auto imported_path = get_imported_path(*meta, ".hfmodel");
147 if (!exists(imported_path)) {
148 return true;
149 }
150
151 // Check if source is newer than imported
152 auto source_path = registry_.get_absolute_path(id);
153 auto source_time = last_write_time(source_path);
154 auto imported_time = last_write_time(imported_path);
155
156 return source_time > imported_time;
157 }
158
160 auto source_path = project_root_ / meta.filepath;
161
162 if (!std::filesystem::exists(source_path)) {
163 std::cerr << "Source file not found: " << source_path << std::endl;
164 return false;
165 }
166
167 // Create output directory for this model's assets
168 auto model_output_dir = import_output_dir_ / meta.name;
169 std::filesystem::create_directories(model_output_dir);
170
171 // Import using ModelImporter
172 ModelImporter importer(registry_, model_output_dir);
173 ImportSettings settings;
174 settings.generate_normals = true;
175 settings.generate_tangents = true;
176 settings.optimize_meshes = true;
177
178 ImportResult result = importer.import(source_path, settings);
179
180 if (!result.success) {
181 std::cerr << "Failed to import model: " << meta.name
182 << " - " << result.error_message << std::endl;
183 return false;
184 }
185
186 // Save the ImportResult as .hfmodel
187 auto model_path = model_output_dir / (meta.name + ".hfmodel");
188 if (!ModelSerializer::save(model_path, result)) {
189 std::cerr << "Failed to save .hfmodel: " << model_path << std::endl;
190 return false;
191 }
192
193 // Register the new .hfmodel in the registry
194 registry_.register_asset(model_path, AssetType::MODEL);
195
196 std::cout << " Created: " << model_path.filename() << std::endl;
197 std::cout << " Meshes: " << result.created_mesh_assets.size() << std::endl;
198 std::cout << " Materials: " << result.created_material_assets.size() << std::endl;
199 std::cout << " Textures: " << result.created_texture_assets.size() << std::endl;
200
201 return true;
202 }
203
205 const AssetMetadata& meta,
206 std::mutex& registry_mutex)
207 {
208 auto source_path = project_root_ / meta.filepath;
209
210 if (!std::filesystem::exists(source_path)) {
211 std::cerr << "Source file not found: " << source_path << std::endl;
212 return false;
213 }
214
215 // Create output directory for this model's assets
216 auto model_output_dir = import_output_dir_ / meta.name;
217 std::filesystem::create_directories(model_output_dir);
218
219 // Import using ModelImporter
220 ModelImporter importer(registry_, model_output_dir);
221 ImportSettings settings;
222 settings.generate_normals = true;
223 settings.generate_tangents = true;
224 settings.optimize_meshes = true;
225
226 ImportResult result = importer.import(source_path, settings);
227
228 if (!result.success) {
229 std::cerr << "Failed to import model: " << meta.name
230 << " - " << result.error_message << std::endl;
231 return false;
232 }
233
234 // Save the ImportResult as .hfmodel
235 auto model_path = model_output_dir / (meta.name + ".hfmodel");
236 if (!ModelSerializer::save(model_path, result)) {
237 std::cerr << "Failed to save .hfmodel: " << model_path << std::endl;
238 return false;
239 }
240
241 {
242 std::lock_guard<std::mutex> lock(registry_mutex);
243 registry_.register_asset(model_path, AssetType::MODEL);
244 }
245
246 return true;
247 }
248
250 // Textures don't need conversion, just metadata
251 auto source_path = registry_.get_absolute_path(meta.uuid);
252
253 TextureMetadata tex_meta;
254 tex_meta.type = infer_texture_type(meta.name);
255 tex_meta.generate_mipmaps = true;
256 tex_meta.srgb = (tex_meta.type == TextureType::DIFFUSE);
257
258 return TextureSerializer::save_metadata(source_path, tex_meta);
259 }
260
261 bool AssetImportManager::has_imported_mesh(AssetID original_id) const {
262 return asset_manager_.get_mesh(original_id) != nullptr;
263 }
264
265 std::filesystem::path AssetImportManager::get_imported_path(const AssetMetadata &meta,
266 const std::string &extension) const {
267 return import_output_dir_ / meta.name / (meta.name + extension);
268 }
269
270
271} // hellfire
std::filesystem::path get_imported_path(const AssetMetadata &meta, const std::string &extension) const
void import_all_pending()
Import all unprocessed assets in registry.
bool import_model(const AssetMetadata &meta)
bool needs_import(AssetID id) const
AssetImportManager(AssetRegistry &registry, AssetManager &asset_manager, const std::filesystem::path &project_root)
std::filesystem::path project_root_
bool has_imported_mesh(AssetID original_id) const
bool import_model_threaded(const AssetMetadata &meta, std::mutex &registry_mutex)
bool import_texture(const AssetMetadata &meta)
std::filesystem::path import_output_dir_
std::shared_ptr< Mesh > get_mesh(AssetID id)
Registry for storing assets.
std::filesystem::path get_absolute_path(AssetID uuid)
Converts external model formats (FBX, GLTF, OBJ) into internal assets this runs once during asset imp...
ImportResult import(const std::filesystem::path &source_path, const ImportSettings &settings={})
Serializes the ImportResult to a .hfmodel file.
static bool save(const std::filesystem::path &filepath, const ImportResult &result)
static bool save_metadata(const std::filesystem::path &texture_path, const TextureMetadata &meta)
TextureType infer_texture_type(const std::string &name)
TextureType
Definition Texture.h:13
std::filesystem::path filepath
Complete result of importing a model file.
std::string error_message
Metadata for texture assets.