refactor: asset loading/caching

This commit is contained in:
light7734 2025-07-10 21:51:17 +03:30
parent eca1bc91e6
commit b572b61f4b
Signed by: light7734
GPG key ID: 8C30176798F1A6BA
14 changed files with 174 additions and 140 deletions

View file

@ -2,20 +2,29 @@
#include <filesystem>
namespace Assets {
class TextAsset;
class TextureAsset;
} // namespace Assets
namespace Light {
class Shader;
class Texture;
/**
* Asset is the data on the disk.
* Resource is the data on the gpu/cpu
*
* eg. TextureAsset is the file on the disk
* eg. Texture is the representation of it in the GPU
*/
class AssetManager
{
public:
static auto instance() -> AssetManager &
{
static auto instance = AssetManager {};
return instance;
}
static void load_shader(
const std::string &name,
const std::filesystem::path &vertex_path,
@ -43,6 +52,8 @@ public:
private:
AssetManager() = default;
static auto instance() -> AssetManager &;
void load_shader_impl(
const std::string &name,
const std::filesystem::path &vertex_path,
@ -51,6 +62,14 @@ private:
void load_texture_impl(const std::string &name, const std::filesystem::path &path);
auto get_or_load_text_asset(const std::filesystem::path &path) -> Ref<Assets::TextAsset>;
auto get_or_load_texture_asset(const std::filesystem::path &path) -> Ref<Assets::TextureAsset>;
std::unordered_map<std::string, Ref<Assets::TextAsset>> m_text_assets;
std::unordered_map<std::string, Ref<Assets::TextureAsset>> m_texture_assets;
std::unordered_map<std::string, Ref<Shader>> m_shaders;
std::unordered_map<std::string, Ref<Texture>> m_textures;

View file

@ -1,13 +1,19 @@
#include <asset_manager/asset_manager.hpp>
#include <asset_parser/assets/text.hpp>
#include <asset_parser/assets/texture.hpp>
#include <logger/logger.hpp>
#include <renderer/graphics_context.hpp>
#include <renderer/shader.hpp>
#include <renderer/texture.hpp>
#include <asset_manager/asset_manager.hpp>
#include <logger/logger.hpp>
namespace Light {
/* static */ auto AssetManager::instance() -> AssetManager &
{
static auto instance = AssetManager {};
return instance;
}
void AssetManager::load_shader_impl(
const std::string &name,
const std::filesystem::path &vertex_path,
@ -21,21 +27,9 @@ void AssetManager::load_shader_impl(
log_trc("\tvertex path: {}", vertex_path.string());
log_trc("\tpixel path : {}", pixel_path.string());
auto vertex_asset = Assets::TextAsset { vertex_path };
auto pixel_asset = Assets::TextAsset { pixel_path };
auto vertex_blob_metadata = vertex_asset.get_blob_metadata(Assets::BlobMetadata::Tag::text);
auto pixel_blob_metadata = pixel_asset.get_blob_metadata(Assets::BlobMetadata::Tag::text);
auto vertex_blob = Assets::Blob(vertex_blob_metadata.uncompressed_size);
auto pixel_blob = Assets::Blob(pixel_blob_metadata.uncompressed_size);
vertex_asset.unpack_blob(vertex_blob_metadata.tag, vertex_blob.data(), vertex_blob.size());
pixel_asset.unpack_blob(pixel_blob_metadata.tag, pixel_blob.data(), pixel_blob.size());
m_shaders[name] = Ref<Shader>(Shader::create(
std::move(vertex_blob),
std::move(pixel_blob),
get_or_load_text_asset(vertex_path.string()),
get_or_load_text_asset(pixel_path),
GraphicsContext::get_shared_context()
));
}
@ -57,21 +51,9 @@ void AssetManager::load_texture_impl(const std::string &name, const std::filesys
log_trc("\tname: {}", name);
log_trc("\tpath: {}", path.string());
auto asset = Assets::TextureAsset { path };
const auto metadata = asset.get_metadata();
const auto blob_metadata = asset.get_blob_metadata(Assets::BlobMetadata::Tag::color);
auto blob = std::vector<std::byte>(blob_metadata.uncompressed_size);
asset.unpack_blob(blob_metadata.tag, blob.data(), blob.size());
m_textures[name] = Ref<Texture>(Texture::create(
metadata.pixel_size[0],
metadata.pixel_size[1],
metadata.num_components,
std::bit_cast<unsigned char *>(blob.data()),
GraphicsContext::get_shared_context(),
path
));
m_textures[name] = Ref<Texture>(
Texture::create(get_or_load_texture_asset(path), GraphicsContext::get_shared_context())
);
}
catch (const std::exception &exp)
{
@ -82,4 +64,29 @@ void AssetManager::load_texture_impl(const std::string &name, const std::filesys
}
}
auto AssetManager::get_or_load_text_asset(const std::filesystem::path &path)
-> Ref<Assets::TextAsset>
{
const auto key = std::filesystem::canonical(path).string();
if (!m_text_assets.contains(key))
{
m_text_assets.emplace(key, create_ref<Assets::TextAsset>(path));
}
return m_text_assets[key];
}
auto AssetManager::get_or_load_texture_asset(const std::filesystem::path &path)
-> Ref<Assets::TextureAsset>
{
const auto key = std::filesystem::canonical(path).string();
if (!m_texture_assets.contains(key))
{
m_texture_assets.emplace(key, create_ref<Assets::TextureAsset>(path));
}
return m_texture_assets[key];
}
} // namespace Light

View file

@ -31,7 +31,8 @@ public:
TextAsset(const std::filesystem::path &path);
void unpack_blob(BlobMetadata::Tag tag, std::byte *destination, size_t destination_capacity);
void unpack_blob(BlobMetadata::Tag tag, std::byte *destination, size_t destination_capacity)
const;
[[nodiscard]] auto get_asset_metadata() const -> const Asset::Metadata &;
@ -48,7 +49,7 @@ private:
BlobMetadata m_text_blob_metadata {};
std::ifstream m_stream;
mutable std::ifstream m_stream;
};
} // namespace Assets

View file

@ -80,7 +80,7 @@ void TextAsset::unpack_blob(
BlobMetadata::Tag tag,
std::byte *destination,
size_t destination_capacity
)
) const
{
if (tag != BlobMetadata::Tag::text)
{

View file

@ -3,7 +3,6 @@
#include <glm/glm.hpp>
#include <utility>
#include <utility>
namespace Light {
@ -31,7 +30,7 @@ struct SpriteRendererComponent
Ref<Texture> texture;
glm::vec4 tint{};
glm::vec4 tint {};
};
} // namespace Light

View file

@ -269,16 +269,17 @@ void SceneSerializer::serialize_entity(YAML::Emitter &out, Entity entity)
if (entity.has_component<SpriteRendererComponent>())
{
out << YAML::Key << "SpriteRendererComponent";
out << YAML::BeginMap; // sprite renderer component;
// TODO(Light): get scene serialization/de-serialization working.
// out << YAML::Key << "SpriteRendererComponent";
// out << YAML::BeginMap; // sprite renderer component;
auto &spriteRendererComponent = entity.get_component<SpriteRendererComponent>();
// auto &spriteRendererComponent = entity.get_component<SpriteRendererComponent>();
out << YAML::Key << "Texture" << YAML::Value
<< spriteRendererComponent.texture->GetFilePath();
out << YAML::Key << "Tint" << YAML::Value << spriteRendererComponent.tint;
// out << YAML::Key << "Texture" << YAML::Value
// << spriteRendererComponent.texture->GetFilePath();
// out << YAML::Key << "Tint" << YAML::Value << spriteRendererComponent.tint;
out << YAML::EndMap; // sprite renderer component
// out << YAML::EndMap; // sprite renderer component
}
// #todo:

View file

@ -1,6 +1,5 @@
#pragma once
#include <renderer/shader.hpp>
namespace Light {
@ -8,7 +7,7 @@ namespace Light {
class glShader: public Shader
{
public:
glShader(Assets::Blob vertex_blob, Assets::Blob pixel_blob);
glShader(const Ref<Assets::TextAsset> &vertex_asset, const Ref<Assets::TextAsset> &pixel_asset);
~glShader() override;

View file

@ -1,6 +1,5 @@
#pragma once
#include <renderer/texture.hpp>
namespace Light {
@ -8,13 +7,7 @@ namespace Light {
class glTexture: public Texture
{
public:
glTexture(
unsigned int width,
unsigned int height,
unsigned int components,
unsigned char *pixels,
const std::string &filePath
);
glTexture(const Ref<Assets::TextureAsset> &asset);
~glTexture() override;
@ -23,7 +16,11 @@ public:
auto get_texture() -> void * override;
private:
unsigned int m_texture_id;
[[nodiscard]] auto map_num_components_to_format(uint32_t num_components) const -> int;
[[nodiscard]] auto map_num_components_to_internal_format(uint32_t num_components) const -> int;
uint32_t m_texture_id {};
};
} // namespace Light

View file

@ -1,9 +1,13 @@
#pragma once
#include <asset_parser/assets/text.hpp>
#include <glm/glm.hpp>
namespace Assets {
class TextAsset;
} // namespace Assets
namespace Light {
class SharedContext;
@ -11,7 +15,7 @@ class SharedContext;
class Shader
{
public:
enum Stage
enum Stage : uint8_t
{
none = 0,
@ -21,8 +25,8 @@ public:
};
static auto create(
Assets::Blob vertex_blob,
Assets::Blob pixel_blob,
Ref<Assets::TextAsset> vertex_asset,
Ref<Assets::TextAsset> pixel_asset,
const Ref<SharedContext> &shared_context
) -> Ref<Shader>;

View file

@ -1,6 +1,10 @@
#pragma once
namespace Assets {
class TextureAsset;
}
namespace Light {
@ -10,33 +14,26 @@ class Texture
{
public:
static Ref<Texture> create(
unsigned int width,
unsigned int height,
unsigned int components,
unsigned char *pixels,
const Ref<SharedContext>& sharedContext,
const std::string &filePath
Ref<Assets::TextureAsset> asset,
const Ref<SharedContext> &shared_context
);
virtual ~Texture() = default;
Texture(Texture &&) = default;
auto operator=(Texture &&) -> Texture & = default;
Texture(const Texture &) = delete;
auto operator=(const Texture &) -> Texture & = delete;
virtual ~Texture() = default;
virtual void bind(unsigned int slot = 0) = 0;
virtual auto get_texture() -> void * = 0;
[[nodiscard]] auto GetFilePath() const -> const std::string &
{
return m_file_path;
}
protected:
std::string m_file_path;
Texture(std::string filePath);
Texture() = default;
};
} // namespace Light

View file

@ -1,14 +1,27 @@
#include <renderer/gl/shader.hpp>
#include <asset_parser/assets/text.hpp>
#include <glad/gl.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/matrix.hpp>
#include <renderer/gl/shader.hpp>
namespace Light {
glShader::glShader(Assets::Blob vertex_blob, Assets::Blob pixel_blob)
glShader::glShader(
const Ref<Assets::TextAsset> &vertex_asset,
const Ref<Assets::TextAsset> &pixel_asset
)
: m_shader_id(glCreateProgram())
{
auto vertex_blob_metadata = vertex_asset->get_blob_metadata(Assets::BlobMetadata::Tag::text);
auto pixel_blob_metadata = pixel_asset->get_blob_metadata(Assets::BlobMetadata::Tag::text);
auto vertex_blob = Assets::Blob(vertex_blob_metadata.uncompressed_size);
auto pixel_blob = Assets::Blob(pixel_blob_metadata.uncompressed_size);
vertex_asset->unpack_blob(vertex_blob_metadata.tag, vertex_blob.data(), vertex_blob.size());
pixel_asset->unpack_blob(pixel_blob_metadata.tag, pixel_blob.data(), pixel_blob.size());
auto vertex_source = std::string {
vertex_blob.data(),
vertex_blob.data() + vertex_blob.size(), // NOLINT

View file

@ -1,58 +1,35 @@
#include <glad/gl.h>
#include <asset_parser/assets/texture.hpp>
#include <debug/assertions.hpp>
#include <glad/gl.h>
#include <renderer/gl/texture.hpp>
namespace Light {
glTexture::glTexture(
unsigned int width,
unsigned int height,
unsigned int components,
unsigned char *pixels,
const std::string &filePath
)
: Texture(filePath)
, m_texture_id(NULL)
glTexture::glTexture(const Ref<Assets::TextureAsset> &asset)
{
// create texture
glCreateTextures(GL_TEXTURE_2D, 1, &m_texture_id);
const auto metadata = asset->get_metadata();
const auto blob_metadata = asset->get_blob_metadata(Assets::BlobMetadata::Tag::color);
// set texture parameters
glCreateTextures(GL_TEXTURE_2D, 1, &m_texture_id);
glTextureParameteri(m_texture_id, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTextureParameteri(m_texture_id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureParameteri(m_texture_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextureParameteri(m_texture_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// determine formats
auto format = components == 4u ? GL_RGBA :
components == 3u ? GL_RGB :
components == 2u ? GL_RG :
components == 1u ? GL_RED :
NULL;
auto blob = std::vector<std::byte>(blob_metadata.uncompressed_size);
asset->unpack_blob(blob_metadata.tag, blob.data(), blob.size());
auto internalFormat = format == GL_RGBA ? GL_RGBA8 :
format == GL_RGB ? GL_RGB8 :
format == GL_RG ? GL_RG8 :
format == GL_RED ? GL_R8 :
NULL;
// check
lt_assert(format, "Invalid number of components: {}", components);
// #todo: isn't there something like glTextureImage2D ???
// create texture and mipsmaps
bind();
glTexImage2D(
GL_TEXTURE_2D,
0,
internalFormat,
width,
height,
map_num_components_to_internal_format(metadata.num_components),
static_cast<int>(metadata.pixel_size[0]),
static_cast<int>(metadata.pixel_size[1]),
0,
format,
map_num_components_to_format(metadata.num_components),
GL_UNSIGNED_BYTE,
pixels
std::bit_cast<unsigned char *>(blob.data())
);
glGenerateMipmap(GL_TEXTURE_2D);
}
@ -73,4 +50,33 @@ auto glTexture::get_texture() -> void *
return (void *)(intptr_t)m_texture_id;
}
[[nodiscard]] auto glTexture::map_num_components_to_format(uint32_t num_components) const -> int
{
switch (num_components)
{
case 4u: return GL_RGBA;
case 3u: return GL_RGB;
case 2u: return GL_RG;
case 1u: return GL_RED;
default: lt_assert(false, "Invalid number of components: {}", num_components);
}
return {};
}
[[nodiscard]] auto glTexture::map_num_components_to_internal_format(uint32_t num_components) const
-> int
{
switch (num_components)
{
case 4u: return GL_RGBA8;
case 3u: return GL_RGB8;
case 2u: return GL_RG8;
case 1u: return GL_R8;
default: lt_assert(false, "Invalid number of components: {}", num_components);
}
return {};
}
} // namespace Light

View file

@ -1,5 +1,6 @@
#include <renderer/shader.hpp>
#include <asset_parser/assets/text.hpp>
#include <renderer/gl/shader.hpp>
#include <renderer/shader.hpp>
#ifdef LIGHT_PLATFORM_WINDOWS
#include <renderer/dx/shader.hpp>
@ -10,9 +11,9 @@
namespace Light {
auto Shader::create(
Assets::Blob vertex_blob,
Assets::Blob pixel_blob,
/* static */ auto Shader::create(
Ref<Assets::TextAsset> vertex_asset,
Ref<Assets::TextAsset> pixel_asset,
const Ref<SharedContext> &shared_context
) -> Ref<Shader>
{
@ -22,12 +23,12 @@ auto Shader::create(
switch (GraphicsContext::get_graphics_api())
{
case GraphicsAPI::OpenGL:
return create_ref<glShader>(std::move(vertex_blob), std::move(pixel_blob));
return create_ref<glShader>(std::move(vertex_asset), std::move(pixel_asset));
case GraphicsAPI::DirectX:
lt_win(return create_ref<dxShader>(
vertexFile,
pixelFile,
vertex_asset,
pixel_asset,
std::static_pointer_cast<dxSharedContext>(sharedContext)
););

View file

@ -8,23 +8,17 @@
#endif
#include <renderer/graphics_context.hpp>
#include <utility>
namespace Light {
auto Texture::create(
unsigned int width,
unsigned int height,
unsigned int components,
unsigned char *pixels,
const Ref<SharedContext> & /*sharedContext*/,
const std::string &filePath
/* static */ auto Texture::create(
Ref<Assets::TextureAsset> asset,
const Ref<SharedContext> &shared_context
) -> Ref<Texture>
{
switch (GraphicsContext::get_graphics_api())
{
case GraphicsAPI::OpenGL:
return create_ref<glTexture>(width, height, components, pixels, filePath);
case GraphicsAPI::OpenGL: return create_ref<glTexture>(std::move(asset));
case GraphicsAPI::DirectX:
lt_win(return create_ref<dxTexture>(
@ -46,8 +40,4 @@ auto Texture::create(
}
}
Texture::Texture(std::string filePath): m_file_path(std::move(filePath))
{
}
} // namespace Light