Add Asset system

- Add Abstract Asset class which defines Assets
- Add AssetManager class to keep track of all the Asset
- Add AssetFile class to cache the asset without loading it
- Add UUID class to uniquely identify assets
- Add MetaFile class to load meta asset files
This commit is contained in:
Thraix
2023-04-13 21:00:36 +02:00
parent 431ad9c573
commit d9e7fd7019
29 changed files with 1002 additions and 37 deletions
+15 -9
View File
@@ -1,5 +1,6 @@
#pragma once
#include "copium/util/RuntimeException.h"
#include "copium/util/VulkanException.h"
#include <iostream>
@@ -11,30 +12,31 @@
#define CP_TERM_CLEAR "\033[0m"
#define CP_DEBUG(format, ...) std::cout << CP_TERM_GRAY << "[DBG] " << Copium::String::Format(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
#define CP_INFO(format, ...) std::cout << "[INF] " << Copium::String::Format(format, __VA_ARGS__) << std::endl
#define CP_INFO(format, ...) std::cout << "[INF] " << Copium::String::Format(format, __VA_ARGS__) << std::endl
#define CP_WARN(format, ...) std::cout << CP_TERM_YELLOW << "[WRN] " << Copium::String::Format(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
#define CP_ERR(format, ...) std::cout << CP_TERM_RED << "[ERR] " << Copium::String::Format(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
// Continue traces, will not print the [XXX] tag before the log
#define CP_DEBUG_CONT(format, ...) std::cout << CP_TERM_GRAY << " " << Copium::String::Format(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
#define CP_INFO_CONT(format, ...) std::cout << " " << Copium::String::Format(format, __VA_ARGS__) << std::endl
#define CP_INFO_CONT(format, ...) std::cout << " " << Copium::String::Format(format, __VA_ARGS__) << std::endl
#define CP_WARN_CONT(format, ...) std::cout << CP_TERM_YELLOW << " " << Copium::String::Format(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
#define CP_ERR_CONT(format, ...) std::cout << CP_TERM_RED << " " << Copium::String::Format(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
#define CP_UNIMPLEMENTED() CP_WARN("%s is unimplemented", __FUNCTION__)
#define CP_ABORT(format, ...) \
do \
{ \
CP_ERR(format, __VA_ARGS__); \
throw std::runtime_error(Copium::String::Format(format, __VA_ARGS__)); \
CP_ERR("Aborted at %s:%d", __FILE__, __LINE__); \
CP_ERR_CONT(format, __VA_ARGS__); \
throw Copium::RuntimeException(Copium::String::Format(format, __VA_ARGS__)); \
} while(false)
#define CP_ASSERT(Function, format, ...) \
do \
{ \
if(!(Function)) \
{ \
CP_ERR(format, __VA_ARGS__); \
throw std::runtime_error(Copium::String::Format(format, __VA_ARGS__)); \
CP_ERR("Assertion failed at %s:%d", __FILE__, __LINE__); \
CP_ERR_CONT(format, __VA_ARGS__); \
throw Copium::RuntimeException(Copium::String::Format(format, __VA_ARGS__)); \
} \
} while(false)
#define CP_VK_ASSERT(Function, format, ...) \
@@ -42,11 +44,15 @@
{ \
if(Function != VK_SUCCESS) \
{ \
CP_ERR(format, __VA_ARGS__); \
throw VulkanException(Copium::String::Format(format, __VA_ARGS__)); \
CP_ERR("Assertion failed at %s:%d", __FILE__, __LINE__); \
CP_ERR_CONT(format, __VA_ARGS__); \
throw Copium::VulkanException(Copium::String::Format(format, __VA_ARGS__)); \
} \
} while(false)
#define CP_UNIMPLEMENTED() CP_WARN("%s is unimplemented", __FUNCTION__)
#define CP_ABORT_UNIMPLEMENTED() CP_ABORT("%s is unimplemented", __FUNCTION__)
#define CP_STATIC_CLASS(ClassName)\
ClassName() = delete
#define CP_DELETE_COPY_AND_MOVE_CTOR(ClassName) \
+179
View File
@@ -0,0 +1,179 @@
#include "copium/util/MetaFile.h"
#include "copium/util/Common.h"
#include "copium/util/StringUtil.h"
#include <fstream>
namespace Copium
{
std::string MetaFileClass::GetValue(const std::string& key, const std::string& val) const
{
auto it = values.find(key);
if(it != values.end())
return it->second;
return val;
}
bool MetaFileClass::HasValue(const std::string& key) const
{
return values.find(key) != values.end();
}
const std::string& MetaFileClass::GetValue(const std::string& key) const
{
auto it = values.find(key);
CP_ASSERT(it != values.end(), "GetValue : Value does not exist: %s", key.c_str());
return it->second;
}
const std::map<std::string, std::string>& MetaFileClass::GetValues() const
{
return values;
}
void MetaFileClass::AddValue(const std::string& key, const std::string& val)
{
values.emplace(key, val);
}
std::ostream& operator<<(std::ostream& stream, const MetaFileClass& file)
{
for(auto value : file.GetValues())
{
stream << value.first << "=" << value.second << std::endl;
}
return stream;
}
MetaFile::MetaFile() {}
MetaFile::MetaFile(const std::string& filepath)
: filepath{filepath}
{
std::ifstream stream(filepath);
CP_ASSERT(stream.is_open(), "MetaFile : Could not find meta file: %s", filepath.c_str());
LoadMetaFile(stream);
}
MetaFile::MetaFile(std::istream& stream)
{
LoadMetaFile(stream);
}
bool MetaFile::HasMetaClass(const std::string& className) const
{
return classes.find(className) != classes.end();
}
MetaFileClass& MetaFile::GetMetaClass(const std::string& className)
{
auto it = classes.find(className);
CP_ASSERT(it != classes.end(), "GetMetaClass : class does not exist: %s", className.c_str());
return it->second;
}
const MetaFileClass& MetaFile::GetMetaClass(const std::string& className) const
{
auto it = classes.find(className);
CP_ASSERT(it != classes.end(), "GetMetaClass : class does not exist: ", className.c_str());
return it->second;
}
const std::string& MetaFile::GetFilePath() const
{
return filepath;
}
void MetaFile::AddMetaClass(const std::string& name, const MetaFileClass& metaClass)
{
classes[name] = metaClass;
}
std::ostream& operator<<(std::ostream& stream, const MetaFile& file)
{
for(auto metaClass : file.classes)
{
stream << "[" << metaClass.first << "]" << std::endl;
stream << metaClass.second;
}
return stream;
}
std::istream& operator>>(std::istream& stream, MetaFile& file)
{
file.classes.clear();
file.LoadMetaFile(stream);
return stream;
}
void MetaFile::LoadMetaFile(std::istream& stream)
{
std::string currentClass = "";
auto metaClassIt = classes.end();
std::string line;
while(std::getline(stream, line))
{
std::string_view trimmedLine = StringUtil::Trim(line);
if(trimmedLine.empty())
continue;
if(trimmedLine == "---")
{
return;
}
if(trimmedLine.front() == '[' && trimmedLine.back() == ']' )
{
currentClass = StringUtil::Trim(line);
currentClass = currentClass.substr(1, currentClass.size() - 2);
metaClassIt = classes.find(currentClass);
CP_ASSERT(metaClassIt == classes.end(), "LoadMetaFile : Meta file contains two of the same class: %s", currentClass.c_str());
metaClassIt = classes.emplace(currentClass, MetaFileClass{}).first;
continue;
}
size_t pos = line.find("=");
if(pos == std::string::npos)
{
CP_WARN("LoadMetaFile : Meta file line does not contain \'=\'");
continue;
}
std::string_view key = StringUtil::Trim(std::string_view(line.c_str(), pos));
std::string_view value = StringUtil::Trim(std::string_view(line.c_str() + pos + 1));
if(key.length() == 0)
{
CP_WARN("LoadMetaFile : MetaFile key is empty");
continue;
}
CP_ASSERT(metaClassIt != classes.end(), "LoadMetaFile : No meta file header specified: ", filepath.c_str());
auto res = metaClassIt->second.values.emplace(key, value);
if(!res.second)
{
CP_WARN("LoadMetaFile : Meta file key is defined twice: %s", std::string(key).c_str());
}
}
}
std::vector<MetaFile> MetaFile::ReadList(const std::string& file)
{
std::vector<MetaFile> metaFiles;
std::ifstream stream{file};
if(stream)
{
MetaFile meta;
while(!stream.eof())
{
MetaFile meta{};
stream >> meta;
if(meta.classes.empty())
continue;
metaFiles.emplace_back(meta);
}
return metaFiles;
}
return {};
}
}
+56
View File
@@ -0,0 +1,56 @@
#pragma once
#include <iostream>
#include <map>
#include <string>
#include <vector>
namespace Copium
{
class MetaFileClass
{
friend class MetaFile;
private:
std::map<std::string, std::string> values;
public:
MetaFileClass() {}
MetaFileClass(const std::map<std::string, std::string>& values)
: values{values}
{}
std::string GetValue(const std::string& key, const std::string& val) const;
bool HasValue(const std::string& key) const;
const std::string& GetValue(const std::string& key) const;
const std::map<std::string, std::string>& GetValues() const;
void AddValue(const std::string& key, const std::string& val);
friend std::ostream& operator<<(std::ostream& stream, const MetaFileClass& file);
};
class MetaFile
{
private:
std::string filepath;
std::map<std::string, MetaFileClass> classes; // map<class, map<variable, value>>
public:
MetaFile();
MetaFile(const std::string& filepath);
MetaFile(std::istream& stream);
bool HasMetaClass(const std::string& className) const;
MetaFileClass& GetMetaClass(const std::string& className);
const MetaFileClass& GetMetaClass(const std::string& className) const;
const std::string& GetFilePath() const;
void AddMetaClass(const std::string& name, const MetaFileClass& metaClass);
friend std::ostream& operator<<(std::ostream& stream, const MetaFile& file);
friend std::istream& operator>>(std::istream& stream, MetaFile& file);
static std::vector<MetaFile> ReadList(const std::string& file);
private:
void LoadMetaFile(std::istream& stream);
};
}
@@ -0,0 +1,13 @@
#include "copium/util/RuntimeException.h"
namespace Copium
{
RuntimeException::RuntimeException(const std::string& str)
: errorMessage{str}
{}
const std::string& RuntimeException::GetErrorMessage() const
{
return errorMessage;
}
}
@@ -0,0 +1,16 @@
#pragma once
#include <stdexcept>
namespace Copium
{
class RuntimeException
{
private:
std::string errorMessage;
public:
RuntimeException(const std::string& str);
const std::string& GetErrorMessage() const;
};
}
@@ -0,0 +1,37 @@
#include "copium/util/StringUtil.h"
namespace Copium
{
size_t StringUtil::GetTrimStartPos(const std::string_view& str)
{
size_t pos = 0;
while(pos < str.size() && (str[pos] == ' ' || str[pos] == '\t'))
pos++;
return pos;
}
size_t StringUtil::GetTrimEndPos(const std::string_view& str)
{
if(str.empty())
return 0;
size_t pos = str.size() - 1;
while(pos > 0 && (str[pos] == ' ' || str[pos] == '\t'))
pos--;
return pos;
}
std::string_view StringUtil::Trim(const std::string_view& str)
{
size_t start = GetTrimStartPos(str);
size_t end = GetTrimEndPos(str);
if(start == str.size() || start > end)
return "";
return std::string_view(str.data() + start, end - start + 1);
}
std::string_view StringUtil::Trim(const std::string& str)
{
return Trim(std::string_view(str));
}
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include "copium/util/Common.h"
#include <string>
#include <string_view>
namespace Copium
{
class StringUtil
{
CP_STATIC_CLASS(StringUtil);
public:
static std::string_view Trim(const std::string& str);
static std::string_view Trim(const std::string_view& str);
private:
static size_t GetTrimStartPos(const std::string_view& str);
static size_t GetTrimEndPos(const std::string_view& str);
};
}
+93
View File
@@ -0,0 +1,93 @@
#include "copium/util/UUID.h"
#include "copium/util/Common.h"
namespace Copium
{
std::random_device UUID::randomDevice{};
std::mt19937 UUID::randomGenerator{randomDevice()};
std::uniform_int_distribution<uint64_t> UUID::randomDistribution{std::numeric_limits<uint64_t>::min(), std::numeric_limits<uint64_t>::max()};
UUID::UUID()
: msb{randomDistribution(randomGenerator)}, lsb{randomDistribution(randomGenerator)}
{}
UUID::UUID(uint64_t msb, uint64_t lsb)
: msb{msb}, lsb{lsb}
{}
UUID::UUID(const std::string& uuidString)
: msb{0}, lsb{0}
{
CP_ASSERT(uuidString.size() == 36, "UUID : Invalid UUID string size: %s", uuidString.c_str());
for (int i = 0; i < 18; i++)
{
if (i == 8 || i == 13) // skip "-"
continue;
msb <<= 4;
msb |= HexToDec(uuidString[i]);
}
for (int i = 19; i < 36; i++)
{
if (i == 23) // skip "-"
continue;
lsb <<= 4;
lsb |= HexToDec(uuidString[i]);
}
}
std::string UUID::ToString() const
{
std::string string;
string.reserve(36);
for (int i = 0; i < 16; i++)
{
if (i == 8 || i == 12) string.push_back('-');
string.push_back(DecToHex((msb >> (60 - i * 4)) & 0xf));
}
string.push_back('-');
for (int i = 0; i < 16; i++)
{
if (i == 4) string.push_back('-');
string.push_back(DecToHex((lsb >> (60 - i * 4)) & 0xf));
}
return string;
}
bool UUID::operator==(const UUID& rhs)
{
return msb == rhs.msb && lsb == rhs.lsb;
}
bool UUID::operator!=(const UUID& rhs)
{
return !(*this == rhs);
}
bool UUID::operator<(const UUID& rhs)
{
if (msb != rhs.msb)
return msb < rhs.msb;
return lsb < rhs.lsb;
}
std::ostream& operator<<(std::ostream& os, const UUID& uuid)
{
return os << uuid.ToString();
}
uint8_t UUID::HexToDec(char c) const
{
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
CP_ABORT("HexToDec : Invalid char value: %c (%d)", c, (int)c);
}
char UUID::DecToHex(uint8_t nibble) const
{
if (nibble >= 0 && nibble <= 9) return '0' + nibble;
if (nibble >= 10 && nibble <= 15) return 'a' + nibble - 10;
CP_ABORT("DecToHex : Invalid nibble value: %d", (int)nibble);
}
}
+35
View File
@@ -0,0 +1,35 @@
#pragma once
#include <stdint.h>
#include <iostream>
#include <random>
namespace Copium
{
class UUID
{
private:
uint64_t msb;
uint64_t lsb;
static std::random_device randomDevice;
static std::mt19937 randomGenerator;
static std::uniform_int_distribution<uint64_t> randomDistribution;
public:
UUID();
UUID(uint64_t msb, uint64_t lsb);
// Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
UUID(const std::string& uuidString);
std::string ToString() const;
bool operator==(const UUID& rhs);
bool operator!=(const UUID& rhs);
bool operator<(const UUID& rhs);
friend std::ostream& operator<<(std::ostream& os, const UUID& uuid);
private:
uint8_t HexToDec(char c) const;
char DecToHex(uint8_t byte) const;
};
}
@@ -1,14 +1,16 @@
#pragma once
#include "copium/util/RuntimeException.h"
#include <stdexcept>
namespace Copium
{
class VulkanException : public std::runtime_error
{
public:
VulkanException(const std::string& str)
: runtime_error{str.c_str()}
{}
};
class VulkanException : public RuntimeException
{
public:
VulkanException(const std::string& str)
: RuntimeException{str}
{}
};
}