feat: add export / file packing
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
#ifndef DESTRUM_PACKFILE_H
|
||||
#define DESTRUM_PACKFILE_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace PackFile {
|
||||
inline constexpr std::uint32_t Version = 1;
|
||||
inline constexpr std::string_view Extension = ".dpak";
|
||||
|
||||
struct Entry {
|
||||
std::string path;
|
||||
std::uint64_t offset{0};
|
||||
std::uint64_t size{0};
|
||||
};
|
||||
|
||||
struct Source {
|
||||
std::string path;
|
||||
std::filesystem::path file;
|
||||
};
|
||||
|
||||
// Paths are "<scheme>/<relative path>", e.g. "engine/shaders/mesh.vert.spv"
|
||||
void Write(const std::vector<Source>& files, const std::filesystem::path& path);
|
||||
|
||||
class Reader {
|
||||
public:
|
||||
explicit Reader(std::filesystem::path path);
|
||||
|
||||
[[nodiscard]] const Entry* Find(std::string_view path) const;
|
||||
[[nodiscard]] std::vector<std::uint8_t> Read(const Entry& entry) const;
|
||||
[[nodiscard]] const std::vector<Entry>& Entries() const { return m_Entries; }
|
||||
[[nodiscard]] const std::filesystem::path& Path() const { return m_Path; }
|
||||
|
||||
private:
|
||||
std::filesystem::path m_Path;
|
||||
std::vector<Entry> m_Entries;
|
||||
std::unordered_map<std::string, std::size_t> m_ByPath;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // DESTRUM_PACKFILE_H
|
||||
@@ -3,12 +3,14 @@
|
||||
|
||||
#include <filesystem>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <destrum/Singleton.h>
|
||||
#include <destrum/Assets/PackFile.h>
|
||||
|
||||
#include <destrum/FS/Manifest.h>
|
||||
|
||||
@@ -18,17 +20,26 @@ struct FSMount {
|
||||
std::filesystem::path root;
|
||||
std::optional<AssetManifest> manifest;
|
||||
std::optional<std::filesystem::path> sourceRoot;
|
||||
std::shared_ptr<const PackFile::Reader> pack;
|
||||
};
|
||||
|
||||
class AssetFS final: public Singleton<AssetFS> {
|
||||
public:
|
||||
static constexpr std::string_view PackName = "assets.dpak";
|
||||
|
||||
void Init(std::filesystem::path exeDir);
|
||||
void Reset();
|
||||
void Mount(std::string scheme, std::filesystem::path root);
|
||||
void MountPack(const std::filesystem::path& packPath, const std::filesystem::path& root);
|
||||
void ReloadManifest(std::string_view scheme);
|
||||
|
||||
std::vector<uint8_t> ReadBytes(std::string_view vpath);
|
||||
|
||||
[[nodiscard]] std::vector<uint8_t> ReadFile(const std::filesystem::path& fullPath) const;
|
||||
[[nodiscard]] bool Exists(const std::filesystem::path& fullPath) const;
|
||||
[[nodiscard]] std::vector<std::filesystem::path> ListFiles(const FSMount& mount) const;
|
||||
[[nodiscard]] bool IsPacked() const;
|
||||
|
||||
[[nodiscard]] std::filesystem::path GetFullPath(std::string_view vpath) const;
|
||||
|
||||
[[nodiscard]] std::filesystem::path GetCookedPathForFile(std::string_view vpath) const;
|
||||
@@ -43,7 +54,7 @@ public:
|
||||
bool WriteFile(std::string_view vpath, std::string_view contents);
|
||||
|
||||
private:
|
||||
static std::vector<uint8_t> ReadFile(const std::filesystem::path& fullPath);
|
||||
void AddMount(std::string scheme, std::filesystem::path root, std::shared_ptr<const PackFile::Reader> pack);
|
||||
|
||||
std::vector<FSMount> mounts;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
@@ -29,7 +30,7 @@ struct AssetManifest {
|
||||
};
|
||||
|
||||
namespace FS {
|
||||
AssetManifest LoadAssetManifest(const std::filesystem::path& manifestPath);
|
||||
AssetManifest ParseAssetManifest(std::span<const std::uint8_t> bytes);
|
||||
}
|
||||
|
||||
#endif //MANIFEST_H
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
//
|
||||
// Link against: assimp
|
||||
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/postprocess.h>
|
||||
@@ -43,6 +44,7 @@
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
@@ -998,8 +1000,12 @@ static void CollectMergedPerNodeMeshes(const aiScene* scene,
|
||||
|
||||
// ─── Public API ───────────────────────────────────────────────────────────────
|
||||
|
||||
static ModelAsset LoadModel(const std::string& path, const LoadOptions& options = {}) {
|
||||
// The importer owns io, without one it reads from disk
|
||||
static ModelAsset LoadModel(const std::string& path, const LoadOptions& options = {},
|
||||
std::unique_ptr<Assimp::IOSystem> io = nullptr) {
|
||||
Assimp::Importer importer;
|
||||
if (io)
|
||||
importer.SetIOHandler(io.release());
|
||||
const aiScene* scene = LoadScene(importer, path, options);
|
||||
|
||||
ModelAsset model{};
|
||||
@@ -1084,16 +1090,18 @@ static const aiScene* LoadAnimationScene(
|
||||
Assimp::Importer& importer,
|
||||
const std::string& path
|
||||
) {
|
||||
if (!std::filesystem::exists(path)) {
|
||||
if (!importer.GetIOHandler()->Exists(path.c_str())) {
|
||||
throw std::runtime_error("Animation file does not exist: " + path);
|
||||
}
|
||||
|
||||
if (!std::filesystem::is_regular_file(path)) {
|
||||
throw std::runtime_error("Animation path is not a regular file: " + path);
|
||||
}
|
||||
if (importer.IsDefaultIOHandler()) {
|
||||
if (!std::filesystem::is_regular_file(path)) {
|
||||
throw std::runtime_error("Animation path is not a regular file: " + path);
|
||||
}
|
||||
|
||||
if (std::filesystem::file_size(path) == 0) {
|
||||
throw std::runtime_error("Animation file is empty: " + path);
|
||||
if (std::filesystem::file_size(path) == 0) {
|
||||
throw std::runtime_error("Animation file is empty: " + path);
|
||||
}
|
||||
}
|
||||
|
||||
// Important: do not use mesh post-process flags for animation-only files.
|
||||
@@ -1141,9 +1149,12 @@ static const aiScene* LoadAnimationScene(
|
||||
|
||||
static std::vector<SkeletalAnimation> LoadAnimationClips(
|
||||
const std::string& path,
|
||||
const Skeleton& targetSkeleton
|
||||
const Skeleton& targetSkeleton,
|
||||
std::unique_ptr<Assimp::IOSystem> io = nullptr
|
||||
) {
|
||||
Assimp::Importer importer;
|
||||
if (io)
|
||||
importer.SetIOHandler(io.release());
|
||||
const aiScene* scene = LoadAnimationScene(importer, path);
|
||||
|
||||
auto clips = LoadAnimations(scene, targetSkeleton);
|
||||
|
||||
Reference in New Issue
Block a user