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
+17
View File
@@ -166,6 +166,9 @@
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="src\copium\asset\Asset.cpp" />
<ClCompile Include="src\copium\asset\AssetFile.cpp" />
<ClCompile Include="src\copium\asset\AssetManager.cpp" />
<ClCompile Include="src\copium\buffer\RendererVertexBuffer.cpp" />
<ClCompile Include="src\copium\core\Application.cpp" />
<ClCompile Include="src\copium\buffer\Buffer.cpp" />
@@ -184,6 +187,7 @@
<ClCompile Include="src\copium\sampler\DepthAttachment.cpp" />
<ClCompile Include="src\copium\pipeline\DescriptorPool.cpp" />
<ClCompile Include="src\copium\pipeline\DescriptorSet.cpp" />
<ClCompile Include="src\copium\util\RuntimeException.cpp" />
<ClCompile Include="src\copium\util\FileSystem.cpp" />
<ClCompile Include="src\copium\buffer\Framebuffer.cpp" />
<ClCompile Include="src\copium\sampler\Image.cpp" />
@@ -198,14 +202,21 @@
<ClCompile Include="src\copium\core\SwapChain.cpp" />
<ClCompile Include="src\copium\sampler\Texture2D.cpp" />
<ClCompile Include="src\copium\pipeline\ShaderReflector.cpp" />
<ClCompile Include="src\copium\util\MetaFile.cpp" />
<ClCompile Include="src\copium\util\StringUtil.cpp" />
<ClCompile Include="src\copium\util\Timer.cpp" />
<ClCompile Include="src\copium\buffer\UniformBuffer.cpp" />
<ClCompile Include="src\copium\mesh\Vertex.cpp" />
<ClCompile Include="src\copium\buffer\VertexBuffer.cpp" />
<ClCompile Include="src\copium\pipeline\VertexDescriptor.cpp" />
<ClCompile Include="src\copium\mesh\VertexPassthrough.cpp" />
<ClCompile Include="src\copium\util\UUID.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\copium\asset\Asset.h" />
<ClInclude Include="src\copium\asset\AssetFile.h" />
<ClInclude Include="src\copium\asset\AssetManager.h" />
<ClInclude Include="src\copium\asset\AssetMeta.h" />
<ClInclude Include="src\copium\buffer\RendererVertexBuffer.h" />
<ClInclude Include="src\copium\core\Device.h" />
<ClInclude Include="src\copium\core\Vulkan.h" />
@@ -224,6 +235,7 @@
<ClInclude Include="src\copium\core\DebugMessenger.h" />
<ClInclude Include="src\copium\pipeline\DescriptorSet.h" />
<ClInclude Include="src\copium\pipeline\DescriptorPool.h" />
<ClInclude Include="src\copium\util\RuntimeException.h" />
<ClInclude Include="src\copium\util\FileSystem.h" />
<ClInclude Include="src\copium\buffer\Framebuffer.h" />
<ClInclude Include="src\copium\sampler\Image.h" />
@@ -239,14 +251,19 @@
<ClInclude Include="src\copium\core\QueueFamilies.h" />
<ClInclude Include="src\copium\core\SwapChain.h" />
<ClInclude Include="src\copium\pipeline\ShaderReflector.h" />
<ClInclude Include="src\copium\util\MetaFile.h" />
<ClInclude Include="src\copium\util\StringUtil.h" />
<ClInclude Include="src\copium\util\Timer.h" />
<ClInclude Include="src\copium\mesh\Vertex.h" />
<ClInclude Include="src\copium\buffer\VertexBuffer.h" />
<ClInclude Include="src\copium\pipeline\VertexDescriptor.h" />
<ClInclude Include="src\copium\util\UUID.h" />
<ClInclude Include="src\copium\util\VulkanException.h" />
<ClInclude Include="src\copium\mesh\VertexPassthrough.h" />
</ItemGroup>
<ItemGroup>
<None Include="assets\fox.meta" />
<None Include="assets\fox2.meta" />
<None Include="res\shaders\passthrough.frag" />
<None Include="res\shaders\passthrough.vert" />
<None Include="res\shaders\renderer.frag" />
+47
View File
@@ -129,6 +129,27 @@
<ClCompile Include="src\copium\pipeline\ShaderBinding.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\copium\util\UUID.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\copium\asset\AssetManager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\copium\util\MetaFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\copium\util\StringUtil.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\copium\asset\Asset.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\copium\asset\AssetFile.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\copium\util\RuntimeException.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\copium\sampler\DepthAttachment.h">
@@ -248,6 +269,30 @@
<ClInclude Include="src\copium\pipeline\ShaderBinding.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\copium\util\UUID.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\copium\asset\AssetMeta.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\copium\util\MetaFile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\copium\util\StringUtil.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\copium\asset\Asset.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\copium\asset\AssetManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\copium\asset\AssetFile.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\copium\util\RuntimeException.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="res\shaders\shader.frag" />
@@ -256,5 +301,7 @@
<None Include="res\shaders\passthrough.vert" />
<None Include="res\shaders\renderer.frag" />
<None Include="res\shaders\renderer.vert" />
<None Include="assets\fox.meta" />
<None Include="assets\fox2.meta" />
</ItemGroup>
</Project>
+3
View File
@@ -0,0 +1,3 @@
[Texture2D]
filepath=res/textures/texture.png
uuid=f49a5284-d666-0982-95ca-cf68cc3d4f45
+3
View File
@@ -0,0 +1,3 @@
[Texture2D]
filepath=res/textures/texture2.png
uuid=0964e525-22c3-4d25-d5c6-a162965f6e8d
+41
View File
@@ -0,0 +1,41 @@
#include "copium/asset/Asset.h"
namespace Copium
{
Asset::Asset(AssetType type)
{
metaData.type = type;
}
Asset::~Asset() = default;
AssetHandle Asset::GetHandle() const
{
return metaData.handle;
}
AssetType Asset::GetType() const
{
return metaData.type;
}
const std::string& Asset::GetName() const
{
return metaData.name;
}
UUID Asset::GetUUID() const
{
return metaData.uuid;
}
bool Asset::isRuntime() const
{
return metaData.isRuntime;
}
Asset::operator AssetHandle() const
{
return metaData.handle;
}
}
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include "copium/asset/AssetMeta.h"
#include "copium/util/MetaFile.h"
#include "copium/util/UUID.h"
#include <stdint.h>
namespace Copium
{
class Asset
{
friend class AssetManager;
public:
Asset(AssetType type);
virtual ~Asset();
AssetHandle GetHandle() const;
AssetType GetType() const;
const std::string& GetName() const;
UUID GetUUID() const;
bool isRuntime() const;
operator AssetHandle() const;
private:
AssetMeta metaData;
};
}
@@ -0,0 +1,50 @@
#include "copium/asset/AssetFile.h"
#include "copium/util/FileSystem.h"
namespace Copium
{
AssetFile::AssetFile(const std::string& path)
: path{path}
{
Load();
}
bool AssetFile::NeedReload() const
{
return dateModified < FileSystem::DateModified(path);
}
void AssetFile::Load()
{
const std::vector<std::pair<std::string, AssetType>> strToType{{"Texture2D", AssetType::Texture2D}};
MetaFile metaFile{path};
for (auto&& [str, type] : strToType)
{
if (!metaFile.HasMetaClass(str))
continue;
Load(metaFile, str, type);
return;
}
CP_ABORT("Load : Unknown Asset type");
}
const std::string& AssetFile::GetPath() const
{
return path;
}
UUID AssetFile::GetUUID() const
{
return uuid;
}
void AssetFile::Load(const MetaFile& metaFile, const std::string& className, AssetType assetType)
{
const MetaFileClass& metaClass = metaFile.GetMetaClass(className);
uuid = UUID{metaClass.GetValue("uuid")};
type = assetType;
dateModified = FileSystem::DateModified(path);
}
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include "copium/asset/AssetMeta.h"
#include "copium/util/MetaFile.h"
#include "copium/util/UUID.h"
namespace Copium
{
class AssetFile
{
private:
std::string path;
AssetType type;
UUID uuid;
int64_t dateModified;
public:
AssetFile(const std::string& path);
bool NeedReload() const;
void Load();
const std::string& GetPath() const;
UUID GetUUID() const;
private:
void Load(const MetaFile& metaFile, const std::string& className, AssetType assetType);
};
}
@@ -0,0 +1,163 @@
#include "copium/asset/AssetManager.h"
#include "copium/sampler/Texture2D.h"
#include "copium/util/Common.h"
#include "copium/util/MetaFile.h"
#include <fstream>
#include <filesystem>
namespace Copium
{
std::vector<std::string> AssetManager::assetDirs;
std::map<AssetHandle, std::unique_ptr<Asset>> AssetManager::assets;
std::map<std::string, AssetHandle> AssetManager::pathToAssetCache;
std::map<std::string, AssetHandle> AssetManager::nameToAssetCache;
std::vector<AssetFile> AssetManager::cachedAssetFiles;
AssetHandle AssetManager::assetHandle = 1;
AssetHandle AssetManager::runtimeAssetHandle = (1 << 31) + 1;
void AssetManager::RegisterAssetDir(std::string assetDir)
{
if (assetDir.back() == '/')
assetDir.pop_back();
assetDirs.emplace_back(assetDir);
for (std::filesystem::recursive_directory_iterator it(assetDir), end; it != end; ++it)
{
if (std::filesystem::is_directory(it->path()))
continue;
std::filesystem::path assetDirPath{assetDir};
cachedAssetFiles.emplace_back(assetDir + "/" + std::filesystem::absolute(it->path()).string().substr(std::filesystem::absolute(assetDirPath).string().size()).c_str());
}
UUID uuid{};
CP_INFO(uuid.ToString().c_str());
}
void AssetManager::UnregisterAssetDir(std::string assetDir)
{
if (assetDir.back() == '/')
assetDir.pop_back();
for (auto it = assetDirs.begin(); it != assetDirs.end(); ++it)
{
if (*it == assetDir)
{
assetDirs.erase(it);
return;
}
}
}
Asset& AssetManager::GetAsset(AssetHandle handle)
{
auto it = assets.find(handle);
CP_ASSERT(it != assets.end(), "GetAsset : Asset not loaded");
return *it->second.get();
}
Asset& AssetManager::LoadAsset(const std::string& assetPath)
{
CP_DEBUG("LoadAsset : Loading Asset: %s", assetPath.c_str());
for (auto& dir : assetDirs)
{
std::string path = dir + "/" + assetPath;
auto it = pathToAssetCache.find(path);
if (it != pathToAssetCache.end())
return *assets.find(it->second)->second.get();
std::ifstream file{path};
if (!file.good())
continue;
MetaFile metaFile{path};
if (metaFile.HasMetaClass("Texture2D"))
{
return CreateAsset<Texture2D>(metaFile, "Texture2D");
}
CP_ABORT("LoadAsset : Unknown Asset type: %s/%s", dir.c_str(), assetPath.c_str());
}
CP_ABORT("LoadAsset : Unknown Asset: %s", assetPath.c_str());
}
Asset& AssetManager::LoadAsset(const UUID& uuid)
{
CP_DEBUG("LoadAsset : Loading uuid Asset: %s", uuid.ToString().c_str());
for (auto&& assetFile : cachedAssetFiles)
{
if (assetFile.GetUUID() != uuid)
continue;
if (assetFile.NeedReload())
assetFile.Load();
if (assetFile.GetUUID() != uuid)
continue;
CP_DEBUG("LoadAsset : Loading Asset: %s", assetFile.GetPath().c_str());
auto it = pathToAssetCache.find(assetFile.GetPath());
if (it != pathToAssetCache.end())
return *assets.find(it->second)->second.get();
MetaFile metaFile{assetFile.GetPath()};
if (metaFile.HasMetaClass("Texture2D"))
{
return CreateAsset<Texture2D>(metaFile, "Texture2D");
}
CP_ABORT("LoadAsset : Unknown Asset type: %s", assetFile.GetPath().c_str());
}
CP_ABORT("LoadAsset : Asset not found with uuid=%s", uuid.ToString().c_str());
// TODO: Reload the assetCache to see if a new file has appeared with that uuid
}
void AssetManager::UnloadAsset(AssetHandle handle)
{
auto it = assets.find(handle);
CP_ASSERT(it != assets.end(), "UnloadAsset : Asset not loaded");
if (it->second->isRuntime())
nameToAssetCache.erase(it->second->GetName());
else
pathToAssetCache.erase(it->second->GetName());
assets.erase(it);
}
void AssetManager::Cleanup()
{
if (assets.empty())
return;
CP_WARN("Cleanup : Cleaning up %d loaded assets", assets.size());
assets.clear();
nameToAssetCache.clear();
pathToAssetCache.clear();
}
Asset& AssetManager::RegisterRuntimeAsset(const std::string& name, std::unique_ptr<Asset>&& asset)
{
auto it = nameToAssetCache.find(name);
CP_ASSERT(it == nameToAssetCache.end(), "RegistedRuntimeAsset : Asset already exists: %s", name);
AssetHandle handle = runtimeAssetHandle++;
Asset* asset2 = assets.emplace(handle, std::move(asset)).first->second.get();
asset2->metaData.handle = handle;
asset2->metaData.name = name;
asset2->metaData.uuid = UUID();
asset2->metaData.isRuntime = true;
nameToAssetCache.emplace(name, handle);
return *asset2;
}
template <typename T>
Asset& AssetManager::CreateAsset(const MetaFile& metaFile, const std::string& metaFileClass)
{
AssetHandle handle = assetHandle++;
pathToAssetCache.emplace(metaFile.GetFilePath(), handle);
Asset& asset = *assets.emplace(handle, std::make_unique<T>(metaFile)).first->second.get();
asset.metaData.handle = handle;
asset.metaData.name = metaFile.GetFilePath();
asset.metaData.uuid = UUID{metaFile.GetMetaClass(metaFileClass).GetValue("uuid")};
asset.metaData.isRuntime = false;
return asset;
}
}
@@ -0,0 +1,72 @@
#pragma once
#include "copium/asset/Asset.h"
#include "copium/asset/AssetFile.h"
#include "copium/util/Common.h"
#include <map>
#include <vector>
namespace Copium
{
class AssetManager
{
CP_STATIC_CLASS(AssetManager);
private:
static std::vector<std::string> assetDirs;
static std::map<AssetHandle, std::unique_ptr<Asset>> assets;
static std::map<std::string, AssetHandle> pathToAssetCache;
static std::map<std::string, AssetHandle> nameToAssetCache;
static AssetHandle assetHandle;
static AssetHandle runtimeAssetHandle;
static std::vector<AssetFile> cachedAssetFiles; // TODO: Make a set?
public:
static void RegisterAssetDir(std::string assetDir);
static void UnregisterAssetDir(std::string assetDir);
static Asset& GetAsset(AssetHandle handle);
static Asset& LoadAsset(const std::string& assetPath);
static Asset& LoadAsset(const UUID& uuid);
static void UnloadAsset(AssetHandle handle);
static Asset& RegisterRuntimeAsset(const std::string& name, std::unique_ptr<Asset>&& asset);
static void Cleanup();
template <typename AssetT>
static AssetT& LoadAsset(const std::string& assetPath)
{
AssetT* asset = dynamic_cast<AssetT*>(&LoadAsset(assetPath));
CP_ASSERT(asset, "LoadAsset : Invalid Asset cast");
return *asset;
}
template <typename AssetT>
static AssetT& LoadAsset(const UUID& uuid)
{
AssetT* asset = dynamic_cast<AssetT*>(&LoadAsset(uuid));
CP_ASSERT(asset, "LoadAsset : Invalid Asset cast");
return *asset;
}
template <typename AssetT>
static AssetT& GetAsset(AssetHandle handle)
{
Asset& asset = GetAsset(handle);
AssetT* assetT = dynamic_cast<AssetT*>(&asset);
CP_ASSERT(assetT, "GetAsset : Invalid Asset cast");
return *assetT;
}
template <typename AssetT>
static AssetT& RegisterRuntimeAsset(const std::string& name, std::unique_ptr<AssetT>&& assetT)
{
AssetT* ptr = assetT.release();
Asset& asset = RegisterRuntimeAsset(name, std::unique_ptr<Asset>((Asset*)ptr));
return *(AssetT*)&asset;
}
private:
template <typename T>
static Asset& CreateAsset(const MetaFile& metaFile, const std::string& metaFileClass);
};
}
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include "copium/util/UUID.h"
#include <stdint.h>
#include <string>
namespace Copium
{
enum class AssetType
{
Pipeline,
Texture2D,
Sound,
};
using AssetHandle = uint64_t;
struct AssetMeta
{
AssetHandle handle;
AssetType type;
std::string name;
UUID uuid;
bool isRuntime;
};
}
+8 -5
View File
@@ -3,6 +3,7 @@
#include "copium/core/Vulkan.h"
#include "copium/mesh/Vertex.h"
#include "copium/mesh/VertexPassthrough.h"
#include "copium/asset/AssetManager.h"
#include <glm/gtc/matrix_transform.hpp>
@@ -49,6 +50,8 @@ namespace Copium
Application::~Application()
{
vkDeviceWaitIdle(Vulkan::GetDevice());
AssetManager::UnloadAsset(texture2D);
AssetManager::UnloadAsset(texture2D2);
}
bool Application::Update()
@@ -81,8 +84,8 @@ namespace Copium
void Application::InitializeTextureSampler()
{
texture2D = std::make_unique<Texture2D>("res/textures/texture.png");
texture2D2 = std::make_unique<Texture2D>("res/textures/texture2.png");
texture2D = AssetManager::LoadAsset("fox.meta");
texture2D2 = AssetManager::LoadAsset("fox2.meta");
}
void Application::InitializeDescriptorSets()
@@ -90,7 +93,7 @@ namespace Copium
descriptorPool = std::make_unique<DescriptorPool>();
descriptorSet = graphicsPipeline->CreateDescriptorSet(*descriptorPool, 0);
descriptorSet->SetSampler(*texture2D, 1);
descriptorSet->SetSampler(AssetManager::GetAsset<Texture2D>(texture2D), 1);
descriptorSetPassthrough = graphicsPipelinePassthrough->CreateDescriptorSet(*descriptorPool, 0);
descriptorSetPassthrough->SetSampler(framebuffer->GetColorAttachment(), 0);
@@ -144,8 +147,8 @@ namespace Copium
renderer->Quad(glm::vec2{-1 + x * 0.2 + 0.05, -1 + y * 0.2 + 0.05}, glm::vec2{0.1, 0.1}, glm::vec3{x * 0.1, y * 0.1, 1.0});
}
}
renderer->Quad(glm::vec2{-0.9, -0.4}, glm::vec2{0.8, 0.8}, *texture2D);
renderer->Quad(glm::vec2{ 0.1, -0.4}, glm::vec2{0.8, 0.8}, *texture2D2);
renderer->Quad(glm::vec2{-0.9, -0.4}, glm::vec2{0.8, 0.8}, AssetManager::GetAsset<Texture2D>(texture2D));
renderer->Quad(glm::vec2{ 0.1, -0.4}, glm::vec2{0.8, 0.8}, AssetManager::GetAsset<Texture2D>(texture2D2));
renderer->End();
framebuffer->Unbind(*commandBuffer);
+3 -3
View File
@@ -1,12 +1,12 @@
#pragma once
#include "copium/asset/AssetMeta.h"
#include "copium/buffer/Framebuffer.h"
#include "copium/mesh/Mesh.h"
#include "copium/pipeline/DescriptorPool.h"
#include "copium/pipeline/DescriptorSet.h"
#include "copium/pipeline/Pipeline.h"
#include "copium/renderer/Renderer.h"
#include "copium/sampler/Texture2D.h"
namespace Copium
{
@@ -16,8 +16,8 @@ namespace Copium
private:
std::unique_ptr<Renderer> renderer;
std::unique_ptr<Framebuffer> framebuffer;
std::unique_ptr<Texture2D> texture2D;
std::unique_ptr<Texture2D> texture2D2;
AssetHandle texture2D;
AssetHandle texture2D2;
std::unique_ptr<DescriptorPool> descriptorPool;
std::unique_ptr<DescriptorSet> descriptorSet;
std::unique_ptr<DescriptorSet> descriptorSetPassthrough;
+9 -1
View File
@@ -1,5 +1,7 @@
#include "copium/core/Vulkan.h"
#include "copium/asset/AssetManager.h"
namespace Copium
{
std::unique_ptr<Instance> Vulkan::instance;
@@ -10,13 +12,19 @@ namespace Copium
void Vulkan::Initialize()
{
instance = std::make_unique<Instance>("Copium Engine");
window = std::make_unique<Window>( "Copium Engine", 1920, 1080, Window::Mode::Windowed);
window = std::make_unique<Window>("Copium Engine", 1920, 1080, Window::Mode::Windowed);
device = std::make_unique<Device>();
swapChain = std::make_unique<SwapChain>();
// TODO: Make the working directory always be relative to the assets folder
// By looking at where the executable is, since that should always be in the bin folder (it currently isn't though)
AssetManager::RegisterAssetDir("assets/");
}
void Vulkan::Destroy()
{
AssetManager::UnregisterAssetDir("assets/");
AssetManager::Cleanup();
swapChain.reset();
device.reset();
window.reset();
+5 -1
View File
@@ -5,9 +5,13 @@
#include <GLFW/glfw3.h>
int main()
int main(int argc, char** argv)
{
CP_ASSERT(glfwInit() == GLFW_TRUE, "main : Failed to initialize the glfw context");
for (int i = 0; i < argc; i++)
{
CP_INFO(argv[i]);
}
Copium::Vulkan::Initialize();
{
@@ -1,5 +1,6 @@
#include "copium/renderer/Renderer.h"
#include "copium/asset/AssetManager.h"
#include "copium/core/Vulkan.h"
#include "copium/pipeline/PipelineCreator.h"
#include "copium/renderer/RendererVertex.h"
@@ -14,13 +15,18 @@ namespace Copium
Renderer::Renderer(VkRenderPass renderPass)
: descriptorPool{},
ibo{MAX_NUM_INDICES},
emptyTexture{{0, 0, 0, 255}, 1, 1},
samplers{MAX_NUM_TEXTURES, &emptyTexture}
emptyTexture{AssetManager::RegisterRuntimeAsset("empty", std::make_unique<Texture2D>(std::vector<uint8_t>{0, 0, 0, 255}, 1, 1))},
samplers{MAX_NUM_TEXTURES, &AssetManager::GetAsset<Texture2D>(emptyTexture)}
{
InitializeIndexBuffer();
InitializeGraphicsPipeline(renderPass);
}
Renderer::~Renderer()
{
AssetManager::UnloadAsset(emptyTexture);
}
void Renderer::Quad(const glm::vec2& pos, const glm::vec2& size, const glm::vec3& color)
{
AllocateQuad();
@@ -144,7 +150,7 @@ namespace Copium
void Renderer::NextBatch()
{
batchIndex++;
std::fill(samplers.begin(), samplers.end(), &emptyTexture);
std::fill(samplers.begin(), samplers.end(), &AssetManager::GetAsset<Texture2D>(emptyTexture));
if (batchIndex >= batches.size())
{
batches.emplace_back(std::make_unique<Batch>(*graphicsPipeline, descriptorPool, MAX_NUM_VERTICES, samplers));
+2 -1
View File
@@ -19,7 +19,7 @@ namespace Copium
private:
DescriptorPool descriptorPool;
IndexBuffer ibo;
Texture2D emptyTexture;
AssetHandle emptyTexture;
std::unique_ptr<Pipeline> graphicsPipeline;
std::vector<std::unique_ptr<Batch>> batches;
@@ -32,6 +32,7 @@ namespace Copium
void* mappedVertexBuffer;
public:
Renderer(VkRenderPass renderPass);
~Renderer();
void Quad(const glm::vec2& from, const glm::vec2& to, const glm::vec3& color = glm::vec3{1, 1, 1});
void Quad(const glm::vec2& from, const glm::vec2& to, const Sampler& sampler, const glm::vec2& texCoord1 = glm::vec2{0, 0}, const glm::vec2& texCoord2 = glm::vec2{1, 1});
@@ -5,17 +5,20 @@
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
#include <fstream>
namespace Copium
{
Texture2D::Texture2D(const std::string& filename)
: Sampler{}
Texture2D::Texture2D(const MetaFile& metaFile)
: Sampler{}, Asset{AssetType::Texture2D}
{
CP_DEBUG("Texture2D : Loading texture file: %s", filename.c_str());
InitializeTextureImageFromFile(filename);
const std::string& filepath = metaFile.GetMetaClass("Texture2D").GetValue("filepath");
CP_DEBUG("Texture2D : Loading texture file: %s", filepath.c_str());
InitializeTextureImageFromFile(filepath);
}
Texture2D::Texture2D(const std::vector<uint8_t>& rgbaData, int width, int height)
: Sampler{}
: Sampler{}, Asset{AssetType::Texture2D}
{
CP_ASSERT(rgbaData.size() == width * height * 4, "rgbaData has invalid size, should be equal to width * height * 4 (%d) actually is %d", width * height * 4, rgbaData.size());
InitializeTextureImageFromData((void*)rgbaData.data(), width, height);
+3 -2
View File
@@ -1,5 +1,6 @@
#pragma once
#include "copium/asset/Asset.h"
#include "copium/buffer/CommandBufferScoped.h"
#include "copium/sampler/Image.h"
#include "copium/sampler/Sampler.h"
@@ -9,7 +10,7 @@
namespace Copium
{
class Texture2D final : public Sampler
class Texture2D final : public Sampler, public Asset
{
CP_DELETE_COPY_AND_MOVE_CTOR(Texture2D);
private:
@@ -17,7 +18,7 @@ namespace Copium
VkDeviceMemory imageMemory;
VkImageView imageView;
public:
Texture2D(const std::string& filename);
Texture2D(const MetaFile& metaFile);
Texture2D(const std::vector<uint8_t>& rgbaData, int width, int height);
~Texture2D() override;
+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}
{}
};
}