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 continue;
111 }
112
113
114 // Only Infer texture type for standalone textures not associated with a model
115 std::cout << "Creating texture metadata: " << meta.name << std::endl;
116
117 TextureMetadata tex_meta;
118 tex_meta.type = infer_texture_type(meta.name);
119 tex_meta.generate_mipmaps = true;
120 tex_meta.srgb = (tex_meta.type == TextureType::DIFFUSE ||
121 tex_meta.type == TextureType::EMISSIVE);
122
123 TextureSerializer::save_metadata(
124 registry_.get_absolute_path(meta.uuid),
125 tex_meta
126 );
127 }
128 }
129
131 auto meta = registry_.get_asset(id);
132 if (!meta) return false;
133
134 switch (meta->type) {
135 case AssetType::MODEL:
136 return import_model(*meta);
138 return import_texture(*meta);
139 default:
140 return false;
141 }
142}
143
144bool AssetImportManager::needs_import(AssetID id) const {
145 auto meta = registry_.get_asset(id);
146 if (!meta) return false;
147
148 // Check if .hfmodel file exists for this source
149 auto imported_path = get_imported_path(*meta, ".hfmodel");
150 if (!exists(imported_path)) {
151 return true;
152 }
153
154 // Check if source is newer than imported
155 auto source_path = registry_.get_absolute_path(id);
156 auto source_time = last_write_time(source_path);
157 auto imported_time = last_write_time(imported_path);
158
159 return source_time > imported_time;
160}
161
163 auto source_path = project_root_ / meta.filepath;
164
165 if (!std::filesystem::exists(source_path)) {
166 std::cerr << "Source file not found: " << source_path << std::endl;
167 return false;
168 }
169
170 // Create output directory for this model's assets
171 auto model_output_dir = import_output_dir_ / meta.name;
172 std::filesystem::create_directories(model_output_dir);
173
174 // Import using ModelImporter
175 ModelImporter importer(registry_, model_output_dir);
176 ImportSettings settings;
177 settings.generate_normals = true;
178 settings.generate_tangents = true;
179 settings.optimize_meshes = true;
180
181 ImportResult result = importer.import(source_path, settings);
182
183 if (!result.success) {
184 std::cerr << "Failed to import model: " << meta.name
185 << " - " << result.error_message << std::endl;
186 return false;
187 }
188
189 // Save the ImportResult as .hfmodel
190 auto model_path = model_output_dir / (meta.name + ".hfmodel");
191 if (!ModelSerializer::save(model_path, result)) {
192 std::cerr << "Failed to save .hfmodel: " << model_path << std::endl;
193 return false;
194 }
195
196 // Register the new .hfmodel in the registry
197 registry_.register_asset(model_path, AssetType::MODEL);
198
199 std::cout << " Created: " << model_path.filename() << std::endl;
200 std::cout << " Meshes: " << result.created_mesh_assets.size() << std::endl;
201 std::cout << " Materials: " << result.created_material_assets.size() << std::endl;
202 std::cout << " Textures: " << result.created_texture_assets.size() << std::endl;
203
204 return true;
205}
206
208 const AssetMetadata &meta,
209 std::mutex &registry_mutex) {
210 auto source_path = project_root_ / meta.filepath;
211
212 if (!std::filesystem::exists(source_path)) {
213 std::cerr << "Source file not found: " << source_path << std::endl;
214 return false;
215 }
216
217 // Create output directory for this model's assets
218 auto model_output_dir = import_output_dir_ / meta.name;
219 std::filesystem::create_directories(model_output_dir);
220
221 // Import using ModelImporter
222 ModelImporter importer(registry_, model_output_dir);
223 ImportSettings settings;
224 settings.generate_normals = true;
225 settings.generate_tangents = true;
226 settings.optimize_meshes = true;
227
228 ImportResult result = importer.import(source_path, settings);
229
230 if (!result.success) {
231 std::cerr << "Failed to import model: " << meta.name
232 << " - " << result.error_message << std::endl;
233 return false;
234 }
235
236 // Save the ImportResult as .hfmodel
237 auto model_path = model_output_dir / (meta.name + ".hfmodel");
238 if (!ModelSerializer::save(model_path, result)) {
239 std::cerr << "Failed to save .hfmodel: " << model_path << std::endl;
240 return false;
241 } {
242 std::lock_guard 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
261bool AssetImportManager::has_imported_mesh(AssetID original_id) const {
262 return asset_manager_.get_mesh(original_id) != nullptr;
263}
264
265std::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.