feat: Add Camera component / Add cooked model and texture loading

This commit is contained in:
2026-10-13 00:29:17 +02:00
parent fa98bf08e8
commit ce55f75ac3
26 changed files with 930 additions and 194 deletions
+52 -3
View File
@@ -1,7 +1,9 @@
#include <destrum/Assets/AssetManager.h>
#include <optional>
#include <stdexcept>
#include <destrum/Assets/ModelFile.h>
#include <destrum/FS/AssetFS.h>
namespace {
@@ -11,6 +13,34 @@ namespace {
}
return std::string{reference};
}
std::optional<std::filesystem::path> FindCookedModel(const std::string& reference) {
if (reference.find("://") == std::string::npos) {
return std::nullopt;
}
try {
const std::filesystem::path cookedPath = AssetFS::GetInstance().GetCookedPathForFile(reference);
if (cookedPath.extension() == ModelFile::Extension) {
return cookedPath;
}
} catch (const std::exception& exception) {
spdlog::warn("Importing {} instead of using its cooked model: {}", reference, exception.what());
}
return std::nullopt;
}
// Cooked texture paths are relative to the model file, imported ones are absolute
void ResolveTexturePaths(ModelDoc::ModelAsset& model, const std::filesystem::path& modelDir) {
for (ModelDoc::MaterialInfo& material : model.materials) {
for (ModelDoc::TextureInfo& texture : material.textures) {
if (texture.embedded || texture.path.empty() || std::filesystem::path{texture.path}.is_absolute()) {
continue;
}
texture.path = (modelDir / texture.path).lexically_normal().generic_string();
}
}
}
}
std::filesystem::path AssetManager::Resolve(std::string_view reference) const {
@@ -32,9 +62,7 @@ ModelDoc::ModelAsset AssetManager::LoadModel(
const ModelDoc::LoadOptions& options) const
{
const std::string sourceReference = ToReference(reference);
ModelDoc::ModelAsset model = ModelDoc::LoadModel(
Resolve(sourceReference).generic_string(),
options);
ModelDoc::ModelAsset model = LoadCookedOrImport(sourceReference, options);
model.sourcePath = sourceReference;
model.skeleton.assetReference.path = sourceReference;
@@ -44,6 +72,9 @@ ModelDoc::ModelAsset AssetManager::LoadModel(
primitive.mesh.assetReference.subresource = primitive.sourceMeshIndex != ModelDoc::InvalidIndex
? "mesh:" + std::to_string(primitive.sourceMeshIndex)
: "primitive:" + std::to_string(index);
if (primitive.mesh.skeleton) {
primitive.mesh.skeleton->assetReference.path = sourceReference;
}
}
for (std::size_t index = 0; index < model.materials.size(); ++index) {
auto& material = model.materials[index];
@@ -59,6 +90,24 @@ ModelDoc::ModelAsset AssetManager::LoadModel(
return model;
}
ModelDoc::ModelAsset AssetManager::LoadCookedOrImport(
const std::string& reference,
const ModelDoc::LoadOptions& options) const
{
if (const auto cookedPath = FindCookedModel(reference)) {
ModelDoc::ModelAsset model = ModelFile::ReadFromFile(*cookedPath);
if (ModelFile::SupportsLoadOptions(model, options)) {
ModelFile::ApplyLoadOptions(model, options);
ResolveTexturePaths(model, cookedPath->parent_path());
spdlog::debug("Loaded cooked model {}", reference);
return model;
}
spdlog::debug("Importing {}, its cooked model doesn't match the requested load options", reference);
}
return ModelDoc::LoadModel(Resolve(reference).generic_string(), options);
}
std::vector<SkeletalAnimation> AssetManager::LoadAnimationClips(
std::string_view reference,
const Skeleton& targetSkeleton) const