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:
@@ -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) \
|
||||
|
||||
@@ -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 {};
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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}
|
||||
{}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user