add file handle
This commit is contained in:
parent
315985450e
commit
b05c6dd27c
@ -20,6 +20,6 @@ namespace engineapi {
|
|||||||
meta["data"] = YAML::Text_Serialize(refl::Any{handle.res, handle->meta});
|
meta["data"] = YAML::Text_Serialize(refl::Any{handle.res, handle->meta});
|
||||||
result.push_back(meta);
|
result.push_back(meta);
|
||||||
}
|
}
|
||||||
FileManager::SaveTextFile(handle, YAML::Dump(result));
|
//FileManager::SaveTextFile(handle, YAML::Dump(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
93
engine/src/engine/asset/file_handle.cpp
Normal file
93
engine/src/engine/asset/file_handle.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include "file_handle.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#define READ_DATA_SIZE 1024
|
||||||
|
namespace engineapi {
|
||||||
|
FileHandle& FileHandle::Open(FILE_OP _op, bool is_binarry)
|
||||||
|
{
|
||||||
|
op = _op;
|
||||||
|
string file_path = RealPath();
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case engineapi::FILE_OP::READ:
|
||||||
|
{
|
||||||
|
vfile = std::ifstream(file_path, is_binarry ? std::ios::binary : 0);
|
||||||
|
if (!Reader().is_open()) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case engineapi::FILE_OP::WRITE:
|
||||||
|
vfile = std::ofstream(file_path, is_binarry ? std::ios::binary : 0);
|
||||||
|
break;
|
||||||
|
case engineapi::FILE_OP::APPEND:
|
||||||
|
vfile = std::ofstream(file_path, is_binarry ? std::ios::app | std::ios::binary : std::ios::app);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
flag = FileFlag::File_Success | (is_binarry ? FileFlag::File_Binary : 0);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
int FileHandle::Read(void* data, int size)
|
||||||
|
{
|
||||||
|
auto& fi = Reader();
|
||||||
|
if (!fi) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fi.read((char*)data, size);
|
||||||
|
return fi.gcount();
|
||||||
|
}
|
||||||
|
string FileHandle::ReadUntil(const string& token)
|
||||||
|
{
|
||||||
|
auto& fi = Reader();
|
||||||
|
size_t cur = fi.tellg();
|
||||||
|
fi.seekg(0, std::ios::end);
|
||||||
|
size_t size = (size_t)fi.tellg() - cur;
|
||||||
|
fi.seekg(cur);
|
||||||
|
size_t buffer_size = READ_DATA_SIZE;
|
||||||
|
string buffer;
|
||||||
|
char chunk[READ_DATA_SIZE];
|
||||||
|
while (buffer_size < size) {
|
||||||
|
fi.read(chunk, READ_DATA_SIZE);
|
||||||
|
buffer.append(chunk, READ_DATA_SIZE);
|
||||||
|
size_t offset = buffer_size > READ_DATA_SIZE ? buffer_size - READ_DATA_SIZE - token.size() : 0;
|
||||||
|
size_t it = buffer.substr(offset).find(token);
|
||||||
|
if (it != std::string::npos) {
|
||||||
|
buffer_size = offset + it;
|
||||||
|
buffer.resize(buffer_size);
|
||||||
|
fi.seekg(cur + buffer_size + token.size());
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
buffer_size += READ_DATA_SIZE;
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
vector<char> FileHandle::ReadUntil(const vector<char>& token)
|
||||||
|
{
|
||||||
|
auto& fi = Reader();
|
||||||
|
size_t cur = fi.tellg();
|
||||||
|
fi.seekg(0, std::ios::end);
|
||||||
|
size_t size = (size_t)fi.tellg() - cur;
|
||||||
|
fi.seekg(cur);
|
||||||
|
size_t buffer_size = READ_DATA_SIZE;
|
||||||
|
vector<char> buffer(buffer_size);
|
||||||
|
while (buffer_size < size) {
|
||||||
|
fi.read(buffer.data(), READ_DATA_SIZE);
|
||||||
|
size_t offset = buffer_size > READ_DATA_SIZE ? buffer_size - READ_DATA_SIZE - token.size() : 0;
|
||||||
|
auto it = std::search(buffer.begin() + offset, buffer.end(), token.begin(), token.end());
|
||||||
|
if (it != buffer.end()) {
|
||||||
|
buffer_size += it - buffer.end();
|
||||||
|
buffer.resize(buffer_size);
|
||||||
|
fi.seekg(cur + buffer_size + token.size());
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
buffer_size += READ_DATA_SIZE;
|
||||||
|
buffer.insert(buffer.end(), READ_DATA_SIZE, 0);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
void FileHandle::Write(const char* data,size_t size)
|
||||||
|
{
|
||||||
|
Writer().write(data, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
65
engine/src/engine/asset/file_handle.h
Normal file
65
engine/src/engine/asset/file_handle.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#include "res/package_path.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <fstream>
|
||||||
|
#include <variant>
|
||||||
|
namespace engineapi {
|
||||||
|
using std::vector;
|
||||||
|
enum class FILE_OP
|
||||||
|
{
|
||||||
|
READ,
|
||||||
|
WRITE,
|
||||||
|
APPEND,
|
||||||
|
NONE
|
||||||
|
};
|
||||||
|
class FileHandle : PackagePath{
|
||||||
|
protected:
|
||||||
|
uint32_t flag{0};
|
||||||
|
FILE_OP op{ FILE_OP::NONE};
|
||||||
|
std::variant<std::ifstream, std::ofstream, nullptr_t> vfile{nullptr};
|
||||||
|
public:
|
||||||
|
using PackagePath::PackagePath;
|
||||||
|
FileHandle(const PackagePath& path) : PackagePath(path){}
|
||||||
|
uint32_t Flag() {
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
operator bool() {
|
||||||
|
return flag & File_Success;
|
||||||
|
}
|
||||||
|
std::ifstream& Reader() {
|
||||||
|
return std::get<std::ifstream>(vfile);
|
||||||
|
}
|
||||||
|
std::ofstream& Writer() {
|
||||||
|
return std::get<std::ofstream>(vfile);
|
||||||
|
}
|
||||||
|
FileHandle& Open(FILE_OP op, bool is_binarry = false);
|
||||||
|
int Read(void* data, int size);
|
||||||
|
template<typename T = vector<char>>
|
||||||
|
T ReadAll() {
|
||||||
|
Reader().seekg(0);
|
||||||
|
return ReadLeft<T>();
|
||||||
|
}
|
||||||
|
template<typename T = vector<char>>
|
||||||
|
T ReadLeft();
|
||||||
|
string ReadUntil(const string& token);
|
||||||
|
vector<char> ReadUntil(const vector<char>& token);
|
||||||
|
void Write(const char* data, size_t size);
|
||||||
|
};
|
||||||
|
template<typename T>
|
||||||
|
inline T FileHandle::ReadLeft()
|
||||||
|
{
|
||||||
|
auto& fi = Reader();
|
||||||
|
size_t cur = fi.tellg();
|
||||||
|
fi.seekg(0, std::ios::end);
|
||||||
|
size_t size = (size_t)fi.tellg() - cur;
|
||||||
|
fi.seekg(cur);
|
||||||
|
T data;
|
||||||
|
data.resize(size, '\0');
|
||||||
|
fi.read(data.data(), size);
|
||||||
|
// 检查实际读取的字节数
|
||||||
|
size_t read = (size_t)fi.gcount();
|
||||||
|
if (read != size) {
|
||||||
|
data.resize(read);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,80 +26,5 @@ namespace engineapi {
|
|||||||
path.append(pack_path.path.substr(name.size() + 1));
|
path.append(pack_path.path.substr(name.size() + 1));
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
FileFlag FileManager::LoadErrorFlag(const PackagePath& pack_path)
|
|
||||||
{
|
|
||||||
uint32_t flag = FindPathFlag(pack_path);
|
|
||||||
if (flag & FileFlag::File_Http) {
|
|
||||||
return FileFlag::File_Http;
|
|
||||||
}
|
|
||||||
zlog::info("Failed to load file: {}", pack_path.path);
|
|
||||||
return FileFlag::File_Not_Exist;
|
|
||||||
}
|
|
||||||
result<string, FileFlag> FileManager::LoadTextFile(const PackagePath& pack_path)
|
|
||||||
{
|
|
||||||
ifstream file;
|
|
||||||
file.exceptions(ifstream::failbit | ifstream::badbit);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string path = RealPath(pack_path);
|
|
||||||
file.open(path);
|
|
||||||
stringstream stream;
|
|
||||||
stream << file.rdbuf();
|
|
||||||
file.close();
|
|
||||||
return stream.str();
|
|
||||||
}
|
|
||||||
catch (ifstream::failure e)
|
|
||||||
{
|
|
||||||
return LoadErrorFlag(pack_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result<vector<char>,FileFlag> FileManager::LoadBinaryFile(const PackagePath& pack_path)
|
|
||||||
{
|
|
||||||
string path = RealPath(pack_path);
|
|
||||||
// ate:在文件末尾开始读取,从文件末尾开始读取的优点是我们可以使用读取位置来确定文件的大小并分配缓冲区
|
|
||||||
ifstream file(path, std::ios::ate | std::ios::binary);
|
|
||||||
if (!file.is_open()) {
|
|
||||||
return LoadErrorFlag(pack_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用读取位置来确定文件的大小并分配缓冲区
|
|
||||||
size_t fileSize = (size_t)file.tellg();
|
|
||||||
vector<char> data(fileSize);
|
|
||||||
|
|
||||||
// 返回文件开头,真正读取内容
|
|
||||||
file.seekg(0);
|
|
||||||
file.read(data.data(), fileSize);
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
result<json, FileFlag> FileManager::LoadJsonFile(const PackagePath& pack_path)
|
|
||||||
{
|
|
||||||
string path = RealPath(pack_path);
|
|
||||||
std::ifstream f(path);
|
|
||||||
if (!f.is_open())
|
|
||||||
{
|
|
||||||
return LoadErrorFlag(pack_path);
|
|
||||||
}
|
|
||||||
json data;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
data = json::parse(f);
|
|
||||||
}
|
|
||||||
catch (json::exception& e)
|
|
||||||
{
|
|
||||||
zlog::error("Asset format error: {}", path);
|
|
||||||
string msg = e.what();
|
|
||||||
zlog::error("Error detail: {}", msg);
|
|
||||||
return FileFlag::File_Error;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
void FileManager::SaveTextFile(const PackagePath& pack_path,const string& value)
|
|
||||||
{
|
|
||||||
string path = RealPath(pack_path);
|
|
||||||
std::ofstream of(path);
|
|
||||||
of.write(value.data(), value.size());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -66,13 +66,5 @@ namespace engineapi
|
|||||||
public:
|
public:
|
||||||
//外界不应该使用绝对路径
|
//外界不应该使用绝对路径
|
||||||
static string RealPath(const PackagePath& pack_path);
|
static string RealPath(const PackagePath& pack_path);
|
||||||
|
|
||||||
static FileFlag LoadErrorFlag(const PackagePath& pack_path);
|
|
||||||
|
|
||||||
static result<string, FileFlag> LoadTextFile(const PackagePath& pack_path);
|
|
||||||
static result<vector<char>, FileFlag> LoadBinaryFile(const PackagePath& pack_path);
|
|
||||||
static result<json, FileFlag> LoadJsonFile(const PackagePath& pack_path);
|
|
||||||
|
|
||||||
static void SaveTextFile(const PackagePath& pack_path, const string& value);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,11 +12,12 @@ namespace engineapi
|
|||||||
using Ubpa::NameID;
|
using Ubpa::NameID;
|
||||||
enum FileFlag : uint32_t {
|
enum FileFlag : uint32_t {
|
||||||
File_Default = 0,
|
File_Default = 0,
|
||||||
File_Binary = 1 << 0,
|
File_Success = 1 << 0,
|
||||||
File_Compress = 1 << 1,
|
File_Binary = 1 << 1,
|
||||||
File_Http = 1 << 2,
|
File_Compress = 1 << 2,
|
||||||
File_Not_Exist = 1 << 3,
|
File_Http = 1 << 3,
|
||||||
File_Error = 1 << 4,
|
File_Not_Exist = 1 << 4,
|
||||||
|
File_Error = 1 << 5,
|
||||||
};
|
};
|
||||||
struct PackagePath {
|
struct PackagePath {
|
||||||
string_view path;
|
string_view path;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "resource_manager.h"
|
#include "resource_manager.h"
|
||||||
#include "file_manager.h"
|
#include "file_manager.h"
|
||||||
|
#include "file_handle.h"
|
||||||
#include "yaml/yaml.h"
|
#include "yaml/yaml.h"
|
||||||
namespace engineapi {
|
namespace engineapi {
|
||||||
void ResourceManager::Init()
|
void ResourceManager::Init()
|
||||||
@ -60,15 +61,17 @@ namespace engineapi {
|
|||||||
|
|
||||||
MetaBundle ResourceManager::GetMeta(PackagePath path)
|
MetaBundle ResourceManager::GetMeta(PackagePath path)
|
||||||
{
|
{
|
||||||
|
FileHandle handle(path + ".meta");
|
||||||
|
if (!handle.Open(FILE_OP::READ, mFileFlag & FileFlag::File_Binary)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
meta::result<MetaBundle, YAML::SerializeError> res;
|
meta::result<MetaBundle, YAML::SerializeError> res;
|
||||||
if (mFileFlag & FileFlag::File_Binary) {
|
if (mFileFlag & FileFlag::File_Binary) {
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto res_text = FileManager::LoadTextFile(path + ".meta");
|
string text = handle.ReadAll<string>();
|
||||||
if (res_text) {
|
res = YAML::Text_Unserialize<MetaBundle>(text);
|
||||||
res = YAML::Text_Unserialize<MetaBundle>(res_text.value());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!res) {
|
if (!res) {
|
||||||
return {};
|
return {};
|
||||||
@ -77,12 +80,14 @@ namespace engineapi {
|
|||||||
}
|
}
|
||||||
void ResourceManager::SaveMeta(PackagePath path, const MetaBundle& bundle)
|
void ResourceManager::SaveMeta(PackagePath path, const MetaBundle& bundle)
|
||||||
{
|
{
|
||||||
|
FileHandle handle(path + ".meta");
|
||||||
|
handle.Open(FILE_OP::WRITE, mFileFlag & FileFlag::File_Binary);
|
||||||
if (mFileFlag & FileFlag::File_Binary) {
|
if (mFileFlag & FileFlag::File_Binary) {
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
string text = YAML::Text_Serialize(bundle);
|
string text = YAML::Text_Serialize(bundle);
|
||||||
FileManager::SaveTextFile(path + ".meta", text);
|
handle.Write(text.data(), text.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void ResourceManager::SaveDirtyFiles()
|
void ResourceManager::SaveDirtyFiles()
|
||||||
@ -104,9 +109,11 @@ namespace engineapi {
|
|||||||
constexpr const char* FileFlagName = "/engine/assets/file_flag.meta";
|
constexpr const char* FileFlagName = "/engine/assets/file_flag.meta";
|
||||||
void ResourceManager::LoadFileFlag()
|
void ResourceManager::LoadFileFlag()
|
||||||
{
|
{
|
||||||
auto res_text = FileManager::LoadTextFile(FileFlagName);
|
FileHandle handle(FileFlagName);
|
||||||
if (res_text) {
|
handle.Open(FILE_OP::READ);
|
||||||
auto res = YAML::Text_Unserialize<table<string, uint32_t>>(res_text.value());
|
if (handle) {
|
||||||
|
string text = handle.ReadAll<string>();
|
||||||
|
auto res = YAML::Text_Unserialize<table<string, uint32_t>>(text);
|
||||||
if (res) {
|
if (res) {
|
||||||
for (auto it : res.value()) {
|
for (auto it : res.value()) {
|
||||||
mFileFlagTable.emplace(NameID(it.first), it);
|
mFileFlagTable.emplace(NameID(it.first), it);
|
||||||
@ -121,8 +128,10 @@ namespace engineapi {
|
|||||||
for (auto it : mFileFlagTable) {
|
for (auto it : mFileFlagTable) {
|
||||||
res.emplace(it.second);
|
res.emplace(it.second);
|
||||||
}
|
}
|
||||||
|
FileHandle handle(FileFlagName);
|
||||||
|
handle.Open(FILE_OP::WRITE);
|
||||||
string text = YAML::Text_Serialize(res);
|
string text = YAML::Text_Serialize(res);
|
||||||
FileManager::SaveTextFile(FileFlagName, text);
|
handle.Write(text.data(), text.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -52,10 +52,13 @@ namespace engineapi {
|
|||||||
template<typename FLoader, typename ...Args>
|
template<typename FLoader, typename ...Args>
|
||||||
inline FLoader& ResourceManager::RegisterLoader(Name ext, Args&& ...args)
|
inline FLoader& ResourceManager::RegisterLoader(Name ext, Args&& ...args)
|
||||||
{
|
{
|
||||||
FLoader* ptr = new FLoader(std::forward<Args>(args)...);
|
auto& ptr = mFileLoader[ext];
|
||||||
|
if (ptr) {
|
||||||
|
delete ptr;
|
||||||
|
}
|
||||||
|
ptr = new FLoader(std::forward<Args>(args)...);
|
||||||
ptr->SetFileFlag(GetFileFlag(ext));
|
ptr->SetFileFlag(GetFileFlag(ext));
|
||||||
mFileLoader[ext] = ptr;
|
return *(FLoader*)ptr;
|
||||||
return *ptr;
|
|
||||||
}
|
}
|
||||||
template<typename Res>
|
template<typename Res>
|
||||||
inline RscHandle<Res> ResourceManager::Load(PackagePath path, bool reload_resource)
|
inline RscHandle<Res> ResourceManager::Load(PackagePath path, bool reload_resource)
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "render/asset/vertex.h"
|
#include "render/asset/vertex.h"
|
||||||
#include "vkmeta_vertex_gen.inl"
|
#include "vkmeta_vertex_gen.inl"
|
||||||
#include <spirv_cross/spirv_reflect.hpp>
|
#include <spirv_cross/spirv_reflect.hpp>
|
||||||
|
#include "asset/file_handle.h"
|
||||||
using namespace engineapi;
|
using namespace engineapi;
|
||||||
namespace vulkanapi {
|
namespace vulkanapi {
|
||||||
vk::ShaderStageFlagBits GetShaderType(string_view ext)
|
vk::ShaderStageFlagBits GetShaderType(string_view ext)
|
||||||
@ -40,26 +41,31 @@ namespace vulkanapi {
|
|||||||
auto set = compiler.get_decoration(ub.id, spv::Decoration::DecorationDescriptorSet);
|
auto set = compiler.get_decoration(ub.id, spv::Decoration::DecorationDescriptorSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ResourceBundle VulkanGlslLoader::LoadFile(PackagePath handle, const MetaBundle& meta)
|
ResourceBundle VulkanGlslLoader::LoadFile(PackagePath path, const MetaBundle& meta)
|
||||||
{
|
{
|
||||||
auto m = meta.FetchMeta<ShaderProgram>();
|
auto m = meta.FetchMeta<ShaderProgram>();
|
||||||
auto program = m ? ResourceManager::GetSingleton().LoaderEmplaceResource<vkShaderProgram>(m->guid)
|
auto program = m ? ResourceManager::GetSingleton().LoaderEmplaceResource<vkShaderProgram>(m->guid)
|
||||||
: ResourceManager::GetSingleton().LoaderEmplaceResource<vkShaderProgram>();
|
: ResourceManager::GetSingleton().LoaderEmplaceResource<vkShaderProgram>();
|
||||||
|
FileHandle handle(path + ".meta");
|
||||||
|
if (!handle.Open(FILE_OP::READ, mFileFlag & FileFlag::File_Binary)) {
|
||||||
|
return program;
|
||||||
|
}
|
||||||
if (mFileFlag & FileFlag::File_Binary) {
|
if (mFileFlag & FileFlag::File_Binary) {
|
||||||
|
vector<char> data = handle.ReadAll();
|
||||||
|
std::vector<unsigned int> spirv(data.size() / 4);
|
||||||
|
std::memcpy(spirv.data(), data.data(), data.size());
|
||||||
|
program->Load(spirv);
|
||||||
|
LoadShaderInfo(program->GetGuid(), spirv);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto res = FileManager::LoadTextFile(handle);
|
string glsl = handle.ReadAll<string>();
|
||||||
if (res) {
|
auto shader_enum = GetShaderType(path.GetExtension());
|
||||||
string glsl = res.value();
|
auto spirv = GlslToSpirv::spirv(glsl, shader_enum, path.GetFileName());
|
||||||
auto shader_enum = GetShaderType(handle.GetExtension());
|
|
||||||
auto spirv = GlslToSpirv::spirv(glsl, shader_enum, handle.GetFileName());
|
|
||||||
if (spirv) {
|
if (spirv) {
|
||||||
program->Load(*spirv);
|
program->Load(*spirv);
|
||||||
LoadShaderInfo(program->GetGuid(), *spirv);
|
LoadShaderInfo(program->GetGuid(), *spirv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
void vkShaderProgram::Load(const std::vector<unsigned int>& spirv)
|
void vkShaderProgram::Load(const std::vector<unsigned int>& spirv)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user