feat: text asset

fix: miscalculated offset for asset blobs

refactor: remove file manager completely
This commit is contained in:
light7734 2025-07-09 21:30:17 +03:30
parent 40e92bb1da
commit fc2fe26160
Signed by: light7734
GPG key ID: 8C30176798F1A6BA
34 changed files with 635 additions and 485 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -19,4 +19,3 @@ void main()
vso_Tint = a_Tint;
vso_TexCoord = a_TexCoord;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,5 +1,6 @@
#pragma once
#include <asset_parser/assets/text.hpp>
#include <asset_parser/assets/texture.hpp>
#include <filesystem>
#include <logger/logger.hpp>
@ -117,4 +118,66 @@ public:
}
};
class TextLoader: Loader
{
public:
[[nodiscard]] static auto get_supported_extensions() -> std::unordered_set<std::string_view>
{
return { ".glsl", ".txt", ".hlsl" };
}
[[nodiscard]] auto get_name() const -> std::string_view override
{
return "TextLoader";
}
[[nodiscard]] auto load(std::filesystem::path file_path) const -> Assets::TextAsset::PackageData
{
auto stream = std::ifstream { file_path, std::ios::binary };
if (!stream.good())
{
throw std::runtime_error {
std::format(
"Failed to open ifstream for text loading of file: {}",
file_path.string()
),
};
}
auto file_size = std::filesystem::file_size(file_path);
auto text_blob = Assets::Blob(file_size);
stream.read((char *)(text_blob.data()), static_cast<long>(file_size)); // NOLINT
const auto metadata = Assets::Asset::Metadata {
.type = Assets::Asset::Type::Text,
};
const auto text_metadata = Assets::TextAsset::Metadata {
.lines = {},
};
return Assets::TextAsset::PackageData {
.metadata = metadata,
.text_metadata = {},
.text_blob = std::move(text_blob),
};
}
};
class TextLoaderFactory
{
public:
static auto create(std::string_view file_extension) -> std::unique_ptr<TextLoader>
{
if (TextLoader::get_supported_extensions().contains(file_extension))
{
return std::make_unique<TextLoader>();
}
return {};
}
};
} // namespace lt

View file

@ -1,4 +1,5 @@
#include <asset_baker/bakers.hpp>
#include <asset_parser/assets/text.hpp>
#include <asset_parser/assets/texture.hpp>
#include <asset_parser/parser.hpp>
#include <filesystem>
@ -20,14 +21,14 @@ void try_packing_texture(
{
Assets::TextureAsset::pack(texture_loader->load(in_path), out_path);
log_inf("Packed a texture:");
log_inf("Packed a texture asset:");
log_inf("\tloader : {}", texture_loader->get_name());
log_inf("\tin path: {}", in_path.string());
log_inf("\tout path: {}", out_path.string());
}
catch (const std::exception &exp)
{
log_err("Failed to pack texture:");
log_err("Failed to pack texture asset:");
log_err("\tloader : {}", texture_loader->get_name());
log_err("\tin path : {}", in_path.string());
log_err("\tout path: {}", out_path.string());
@ -35,6 +36,34 @@ void try_packing_texture(
}
}
void try_packing_text(const std::filesystem::path &in_path, const std::filesystem::path &out_path)
{
auto text_loader = lt::TextLoaderFactory::create(in_path.extension().string());
if (!text_loader)
{
// Don't log anything; this is expected.
return;
}
try
{
Assets::TextAsset::pack(text_loader->load(in_path), out_path);
log_inf("Packed a text asset:");
log_inf("\tloader : {}", text_loader->get_name());
log_inf("\tin path: {}", in_path.string());
log_inf("\tout path: {}", out_path.string());
}
catch (const std::exception &exp)
{
log_err("Failed to pack a text asset:");
log_err("\tloader : {}", text_loader->get_name());
log_err("\tin path : {}", in_path.string());
log_err("\tout path: {}", out_path.string());
log_err("\texp.what: {}", exp.what());
}
}
auto main(int argc, char *argv[]) -> int32_t
try
{
@ -57,6 +86,7 @@ try
out_path.replace_extension(".asset");
try_packing_texture(in_path, out_path);
try_packing_text(in_path, out_path);
}
return EXIT_SUCCESS;

View file

@ -1,6 +1,7 @@
add_library_module(asset_parser
parser.cpp
assets/texture.cpp
assets/text.cpp
)
target_link_libraries(

View file

@ -0,0 +1,54 @@
#pragma once
#include <asset_parser/parser.hpp>
#include <compressors/compressors.hpp>
#include <cstdint>
#include <filesystem>
#include <fstream>
#include <logger/logger.hpp>
namespace Assets {
class TextAsset: public Asset
{
public:
struct Metadata
{
uint32_t lines {};
};
/** Data required to pack a text asset */
struct PackageData
{
Asset::Metadata metadata;
Metadata text_metadata;
Blob text_blob;
};
static void pack(const PackageData &data, const std::filesystem::path &out_path);
TextAsset(const std::filesystem::path &path);
void unpack_blob(BlobMetadata::Tag tag, std::byte *destination, size_t destination_capacity);
[[nodiscard]] auto get_asset_metadata() const -> const Asset::Metadata &;
[[nodiscard]] auto get_metadata() const -> const Metadata &;
[[nodiscard]] auto get_blob_metadata(BlobMetadata::Tag tag) const -> const BlobMetadata &;
private:
uint32_t version {};
Asset::Metadata m_asset_metadata {};
Metadata m_metadata {};
BlobMetadata m_text_blob_metadata {};
std::ifstream m_stream;
};
} // namespace Assets

View file

@ -0,0 +1,64 @@
#pragma once
#include <asset_parser/parser.hpp>
#include <compressors/compressors.hpp>
#include <cstdint>
#include <filesystem>
#include <fstream>
#include <logger/logger.hpp>
namespace Assets {
class TextureAsset: public Asset
{
public:
enum class Format : uint32_t // NOLINT(performance-enum-size)
{
None = 0,
RGBA8,
};
struct Metadata
{
Format format;
uint32_t num_components;
std::array<uint32_t, 3> pixel_size;
};
/** Data required to pack a texture asset */
struct PackageData
{
Asset::Metadata metadata;
Metadata texture_metadata;
Blob pixels;
};
static void pack(const PackageData &data, const std::filesystem::path &out_path);
TextureAsset(const std::filesystem::path &path);
void unpack_blob(BlobMetadata::Tag tag, std::byte *destination, size_t destination_capacity);
[[nodiscard]] auto get_asset_metadata() const -> const Asset::Metadata &;
[[nodiscard]] auto get_metadata() const -> const Metadata &;
[[nodiscard]] auto get_blob_metadata(BlobMetadata::Tag tag) const -> const BlobMetadata &;
private:
uint32_t version {};
Asset::Metadata m_asset_metadata {};
Metadata m_metadata {};
BlobMetadata m_pixel_blob_metadata {};
std::ifstream m_stream;
};
} // namespace Assets

View file

@ -16,6 +16,7 @@ struct BlobMetadata
{
enum class Tag : uint8_t
{
text,
color,
depth,
vertices,
@ -41,7 +42,9 @@ class Asset
public:
enum class Type : uint32_t // NOLINT(performance-enum-size)
{
None,
Texture,
Text,
Mesh,
Material,
};
@ -53,224 +56,13 @@ public:
Asset() = default;
Asset(Metadata metadata, std::filesystem::path path, std::ifstream stream)
: m_metadata(metadata)
, m_file_path(std::move(path))
, m_stream(std::move(stream))
{
}
/** Directly unpacks from disk to the destination.
*
* @note The destination MUST have at least blob_metadata.unpacked_size bytes available for
* writing, otherwise segfault could occur!
*/
void unpack_blob(BlobMetadata::Tag blob_tag, std::byte *destination);
[[nodiscard]] auto get_metadata() const -> const Metadata &
{
return m_metadata;
}
[[nodiscard]] auto get_file_path() const -> std::filesystem::path
{
return m_file_path;
}
private:
Metadata m_metadata;
std::filesystem::path m_file_path;
std::ifstream m_stream;
};
class TextureAsset: public Asset
{
public:
enum class Format : uint32_t // NOLINT(performance-enum-size)
{
None = 0,
RGBA8,
};
struct Metadata
{
Format format;
uint32_t num_components;
std::array<uint32_t, 3> pixel_size;
};
/** Data required to pack a texture */
struct PackageData
{
Asset::Metadata metadata;
Metadata texture_metadata;
Blob pixels;
};
TextureAsset(const std::filesystem::path &path)
{
m_stream = std::ifstream { path, std::ios::binary };
if (!m_stream.is_open())
{
throw std::runtime_error { std::format(
"Failed to open ifm_stream for loading texture asset at: {}",
path.string()
) };
}
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
m_stream.read((char *)&version, sizeof(version));
m_stream.read((char *)&m_asset_metadata, sizeof(m_asset_metadata));
m_stream.read((char *)&m_metadata, sizeof(m_metadata));
auto num_blobs = uint32_t {};
m_stream.read((char *)&num_blobs, sizeof(num_blobs));
if (num_blobs != 1)
{
throw std::runtime_error {
std::format("Failed to load texture asset: invalid number of blobs: {}", num_blobs)
};
}
m_stream.read((char *)&m_pixel_blob_metadata, sizeof(m_pixel_blob_metadata));
if (m_pixel_blob_metadata.tag != BlobMetadata::Tag::color)
{
throw std::runtime_error {
std::format(
"Failed to load texture asset: invalid blob tag, expected {}, got {}",
std::to_underlying(BlobMetadata::Tag::color),
std::to_underlying(m_pixel_blob_metadata.tag)
),
};
}
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
}
void unpack_blob(BlobMetadata::Tag tag, std::byte *destination, size_t destination_capacity)
{
if (tag != BlobMetadata::Tag::color)
{
throw std::runtime_error { std::format(
"Invalid tag for unpack_blob of TextureAsset: {}",
std::to_underlying(tag)
) };
}
m_stream.seekg(static_cast<long>(m_pixel_blob_metadata.offset));
switch (m_pixel_blob_metadata.compression_type)
{
case Assets::CompressionType::None:
if (m_pixel_blob_metadata.uncompressed_size != m_pixel_blob_metadata.compressed_size)
{
throw std::runtime_error("Failed to unpack blob from TextureAsset: "
"compressed/uncompressed size mismatch for no compression "
"type");
}
if (m_pixel_blob_metadata.uncompressed_size > destination_capacity)
{
throw std::runtime_error("Failed to unpack blob from TextureAsset: "
"uncompressed_size > destination_capacity, unpacking "
"would result in segfault");
}
if (!m_stream.is_open())
{
throw std::runtime_error("Failed to unpack blob from TextureAsset: ifstream is "
"closed");
}
m_stream.read(
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
(char *)destination,
static_cast<long>(m_pixel_blob_metadata.uncompressed_size)
);
return;
default:
throw std::runtime_error(std::format(
"Failed to unpack blob from TextureAsset: unsupported "
"compression type: {}",
std::to_underlying(m_pixel_blob_metadata.compression_type)
));
}
}
static void pack(const PackageData &data, const std::filesystem::path &out_path)
{
const auto &[metadata, texture_metadata, pixels] = data;
auto stream = std::ofstream { out_path, std::ios::binary | std::ios::trunc };
if (!stream.is_open())
{
throw std::runtime_error {
std::format("Failed to open ofstream for packing texture at: {}", out_path.string())
};
}
stream.seekp(0);
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
stream.write((char *)&current_version, sizeof(current_version));
stream.write((char *)&metadata, sizeof(metadata));
stream.write((char *)&texture_metadata, sizeof(texture_metadata));
constexpr auto number_of_blobs = uint32_t { 1 };
stream.write((char *)&number_of_blobs, sizeof(number_of_blobs));
auto pixels_metadata = BlobMetadata {
.tag = BlobMetadata::Tag::color,
.offset = static_cast<size_t>(stream.tellp()),
.compression_type = CompressionType::None,
.compressed_size = pixels.size(),
.uncompressed_size = pixels.size(),
};
stream.write((char *)&pixels_metadata, sizeof(pixels_metadata));
stream.write((char *)&pixels[0], static_cast<long>(pixels.size()));
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
}
[[nodiscard]] auto get_asset_metadata() const -> const Asset::Metadata &
{
return m_asset_metadata;
}
[[nodiscard]] auto get_metadata() const -> const Metadata &
{
return m_metadata;
}
[[nodiscard]] auto get_blob_metadata(BlobMetadata::Tag tag) const -> const BlobMetadata &
{
if (tag != BlobMetadata::Tag::color)
{
throw std::runtime_error { std::format(
"Invalid tag for get_blob_metadata of TextureAsset: {}",
std::to_underlying(tag)
) };
}
return m_pixel_blob_metadata;
}
private:
Asset::Metadata m_asset_metadata {};
Metadata m_metadata {};
BlobMetadata m_pixel_blob_metadata {};
uint32_t version {};
std::ifstream m_stream;
};
} // namespace Assets

View file

@ -0,0 +1,156 @@
#include <asset_parser/assets/text.hpp>
#include <lz4.h>
#include <nlohmann/json.hpp>
namespace Assets {
/* static */ void TextAsset::pack(const PackageData &data, const std::filesystem::path &out_path)
{
const auto &[metadata, text_metadata, text] = data;
auto stream = std::ofstream { out_path, std::ios::binary | std::ios::trunc };
if (!stream.is_open())
{
throw std::runtime_error {
std::format("Failed to open ofstream for packing Text at: {}", out_path.string())
};
}
stream.seekp(0);
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
stream.write((char *)&current_version, sizeof(current_version));
stream.write((char *)&metadata, sizeof(metadata));
stream.write((char *)&text_metadata, sizeof(text_metadata));
constexpr auto number_of_blobs = uint32_t { 1 };
stream.write((char *)&number_of_blobs, sizeof(number_of_blobs));
auto textblob_metadata = BlobMetadata {
.tag = BlobMetadata::Tag::text,
.offset = static_cast<size_t>(stream.tellp()) + sizeof(BlobMetadata),
.compression_type = CompressionType::None,
.compressed_size = text.size(),
.uncompressed_size = text.size(),
};
stream.write((char *)&textblob_metadata, sizeof(textblob_metadata));
stream.write((char *)text.data(), static_cast<long>(text.size()));
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
}
TextAsset::TextAsset(const std::filesystem::path &path)
{
m_stream = std::ifstream { path, std::ios::binary };
if (!m_stream.is_open())
{
throw std::runtime_error {
std::format("Failed to open ifstream for loading Text asset at: {}", path.string())
};
}
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
m_stream.read((char *)&version, sizeof(version));
m_stream.read((char *)&m_asset_metadata, sizeof(m_asset_metadata));
m_stream.read((char *)&m_metadata, sizeof(m_metadata));
auto num_blobs = uint32_t {};
m_stream.read((char *)&num_blobs, sizeof(num_blobs));
if (num_blobs != 1)
{
throw std::runtime_error {
std::format("Failed to load Text asset: invalid number of blobs: {}", num_blobs)
};
}
m_stream.read((char *)&m_text_blob_metadata, sizeof(m_text_blob_metadata));
if (m_text_blob_metadata.tag != BlobMetadata::Tag::text)
{
throw std::runtime_error {
std::format(
"Failed to load Text asset: invalid blob tag, expected {}, got {}",
std::to_underlying(BlobMetadata::Tag::text),
std::to_underlying(m_text_blob_metadata.tag)
),
};
}
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
}
void TextAsset::unpack_blob(
BlobMetadata::Tag tag,
std::byte *destination,
size_t destination_capacity
)
{
if (tag != BlobMetadata::Tag::text)
{
throw std::runtime_error {
std::format("Invalid tag for unpack_blob of TextAsset: {}", std::to_underlying(tag))
};
}
m_stream.seekg(static_cast<long>(m_text_blob_metadata.offset));
switch (m_text_blob_metadata.compression_type)
{
case Assets::CompressionType::None:
if (m_text_blob_metadata.uncompressed_size != m_text_blob_metadata.compressed_size)
{
throw std::runtime_error("Failed to unpack blob from TextAsset: "
"compressed/uncompressed size mismatch for no compression "
"type");
}
if (m_text_blob_metadata.uncompressed_size > destination_capacity)
{
throw std::runtime_error("Failed to unpack blob from TextAsset: "
"uncompressed_size > destination_capacity, unpacking "
"would result in segfault");
}
if (!m_stream.is_open())
{
throw std::runtime_error("Failed to unpack blob from TextAsset: ifstream is "
"closed");
}
m_stream.read(
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
(char *)destination,
static_cast<long>(m_text_blob_metadata.uncompressed_size)
);
return;
default:
throw std::runtime_error(std::format(
"Failed to unpack blob from TextAsset: unsupported "
"compression type: {}",
std::to_underlying(m_text_blob_metadata.compression_type)
));
}
}
[[nodiscard]] auto TextAsset::get_asset_metadata() const -> const Asset::Metadata &
{
return m_asset_metadata;
}
[[nodiscard]] auto TextAsset::get_metadata() const -> const Metadata &
{
return m_metadata;
}
[[nodiscard]] auto TextAsset::get_blob_metadata(BlobMetadata::Tag tag) const -> const BlobMetadata &
{
if (tag != BlobMetadata::Tag::text)
{
throw std::runtime_error { std::format(
"Invalid tag for get_blob_metadata of TextAsset: {}",
std::to_underlying(tag)
) };
}
return m_text_blob_metadata;
}
} // namespace Assets

View file

@ -2,11 +2,157 @@
#include <lz4.h>
#include <nlohmann/json.hpp>
// [version], [type] --
// [asset_metadata], [blob_metadata] --
// [blob] --
namespace Assets {
/* static */ void TextureAsset::pack(const PackageData &data, const std::filesystem::path &out_path)
{
const auto &[metadata, texture_metadata, pixels] = data;
auto stream = std::ofstream { out_path, std::ios::binary | std::ios::trunc };
if (!stream.is_open())
{
throw std::runtime_error {
std::format("Failed to open ofstream for packing texture at: {}", out_path.string())
};
}
stream.seekp(0);
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
stream.write((char *)&current_version, sizeof(current_version));
stream.write((char *)&metadata, sizeof(metadata));
stream.write((char *)&texture_metadata, sizeof(texture_metadata));
constexpr auto number_of_blobs = uint32_t { 1 };
stream.write((char *)&number_of_blobs, sizeof(number_of_blobs));
auto pixels_metadata = BlobMetadata {
.tag = BlobMetadata::Tag::color,
.offset = static_cast<size_t>(stream.tellp()) + sizeof(BlobMetadata),
.compression_type = CompressionType::None,
.compressed_size = pixels.size(),
.uncompressed_size = pixels.size(),
};
stream.write((char *)&pixels_metadata, sizeof(pixels_metadata));
stream.write((char *)&pixels[0], static_cast<long>(pixels.size()));
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
}
TextureAsset::TextureAsset(const std::filesystem::path &path)
{
m_stream = std::ifstream { path, std::ios::binary };
if (!m_stream.is_open())
{
throw std::runtime_error {
std::format("Failed to open ifstream for loading texture asset at: {}", path.string())
};
}
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
m_stream.read((char *)&version, sizeof(version));
m_stream.read((char *)&m_asset_metadata, sizeof(m_asset_metadata));
m_stream.read((char *)&m_metadata, sizeof(m_metadata));
auto num_blobs = uint32_t {};
m_stream.read((char *)&num_blobs, sizeof(num_blobs));
if (num_blobs != 1)
{
throw std::runtime_error {
std::format("Failed to load texture asset: invalid number of blobs: {}", num_blobs)
};
}
m_stream.read((char *)&m_pixel_blob_metadata, sizeof(m_pixel_blob_metadata));
if (m_pixel_blob_metadata.tag != BlobMetadata::Tag::color)
{
throw std::runtime_error {
std::format(
"Failed to load texture asset: invalid blob tag, expected {}, got {}",
std::to_underlying(BlobMetadata::Tag::color),
std::to_underlying(m_pixel_blob_metadata.tag)
),
};
}
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
}
void TextureAsset::unpack_blob(
BlobMetadata::Tag tag,
std::byte *destination,
size_t destination_capacity
)
{
if (tag != BlobMetadata::Tag::color)
{
throw std::runtime_error {
std::format("Invalid tag for unpack_blob of TextureAsset: {}", std::to_underlying(tag))
};
}
m_stream.seekg(static_cast<long>(m_pixel_blob_metadata.offset));
switch (m_pixel_blob_metadata.compression_type)
{
case Assets::CompressionType::None:
if (m_pixel_blob_metadata.uncompressed_size != m_pixel_blob_metadata.compressed_size)
{
throw std::runtime_error("Failed to unpack blob from TextureAsset: "
"compressed/uncompressed size mismatch for no compression "
"type");
}
if (m_pixel_blob_metadata.uncompressed_size > destination_capacity)
{
throw std::runtime_error("Failed to unpack blob from TextureAsset: "
"uncompressed_size > destination_capacity, unpacking "
"would result in segfault");
}
if (!m_stream.is_open())
{
throw std::runtime_error("Failed to unpack blob from TextureAsset: ifstream is "
"closed");
}
m_stream.read(
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
(char *)destination,
static_cast<long>(m_pixel_blob_metadata.uncompressed_size)
);
return;
default:
throw std::runtime_error(std::format(
"Failed to unpack blob from TextureAsset: unsupported "
"compression type: {}",
std::to_underlying(m_pixel_blob_metadata.compression_type)
));
}
}
[[nodiscard]] auto TextureAsset::get_asset_metadata() const -> const Asset::Metadata &
{
return m_asset_metadata;
}
[[nodiscard]] auto TextureAsset::get_metadata() const -> const Metadata &
{
return m_metadata;
}
[[nodiscard]] auto TextureAsset::get_blob_metadata(BlobMetadata::Tag tag) const
-> const BlobMetadata &
{
if (tag != BlobMetadata::Tag::color)
{
throw std::runtime_error { std::format(
"Invalid tag for get_blob_metadata of TextureAsset: {}",
std::to_underlying(tag)
) };
}
return m_pixel_blob_metadata;
}
} // namespace Assets

View file

@ -38,7 +38,6 @@ if(NOT WIN32)
scene/scene.cpp
time/timer.cpp
user_interface/user_interface.cpp
utils/file_manager.cpp
utils/resource_manager.cpp
utils/serializer.cpp
utils/stringifier.cpp
@ -90,7 +89,6 @@ else()
scene/scene.cpp
time/timer.cpp
user_interface/user_interface.cpp
utils/file_manager.cpp
utils/resource_manager.cpp
utils/serializer.cpp
utils/stringifier.cpp

View file

@ -1,7 +1,7 @@
#pragma once
#include <asset_parser/assets/text.hpp>
#include <engine/base/base.hpp>
#include <engine/utils/file_manager.hpp>
#include <glm/glm.hpp>
namespace Light {
@ -13,16 +13,17 @@ class Shader
public:
enum Stage
{
NONE = 0,
VERTEX = 1,
PIXEL = 2,
GEOMETRY = 3
none = 0,
vertex,
pixel,
geometry,
};
static auto create(
const BasicFileHandle& vertexFile,
const BasicFileHandle& pixelFile,
const Ref<SharedContext>& sharedContext
Assets::Blob vertex_blob,
Assets::Blob pixel_blob,
const Ref<SharedContext> &shared_context
) -> Ref<Shader>;
virtual ~Shader() = default;

View file

@ -3,7 +3,6 @@
#include <d3d11.h>
#include <engine/base/base.hpp>
#include <engine/graphics/shader.hpp>
#include <engine/utils/file_manager.hpp>
#include <wrl.h>
namespace Light {

View file

@ -2,14 +2,13 @@
#include <engine/base/base.hpp>
#include <engine/graphics/shader.hpp>
#include <engine/utils/file_manager.hpp>
namespace Light {
class glShader: public Shader
{
public:
glShader(BasicFileHandle vertexFile, BasicFileHandle pixelFile);
glShader(Assets::Blob vertex_blob, Assets::Blob pixel_blob);
~glShader() override;
@ -18,9 +17,9 @@ public:
void un_bind() override;
private:
unsigned int compile_shader(const std::string& source, Shader::Stage stage);
unsigned int compile_shader(const std::string &source, Shader::Stage stage);
unsigned int m_shader_id{0u};
unsigned int m_shader_id { 0u };
};
} // namespace Light

View file

@ -1,80 +0,0 @@
#pragma once
#include <engine/base/base.hpp>
namespace Light {
class BasicFileHandle
{
public:
virtual ~BasicFileHandle() = default;
BasicFileHandle(
uint8_t *data = nullptr,
uint32_t size = 0ull,
std::string path = "",
std::string name = "",
std::string extension = ""
);
virtual void release();
auto get_data() -> uint8_t *
{
return m_data;
}
auto get_size() const -> uint32_t
{
return m_size;
}
auto get_path() -> const std::string &
{
return m_path;
}
auto get_name() -> const std::string &
{
return m_name;
}
auto get_extension() -> const std::string &
{
return m_extension;
}
auto get_name_with_extention() -> const std::string &
{
return m_name + '.' + m_extension;
}
[[nodiscard]] auto is_valid() const -> bool
{
return !!m_data;
}
operator bool() const
{
return is_valid();
}
private:
// made protected for custom free():
uint8_t *m_data;
uint32_t m_size;
const std::string m_path;
const std::string m_name;
const std::string m_extension;
};
class FileManager
{
public:
static auto read_text_file(const std::string &path) -> BasicFileHandle;
};
} // namespace Light

View file

@ -20,23 +20,18 @@ public:
static void load_shader(
const std::string &name,
const std::string &vertexPath,
const std::string &pixelPath
const std::filesystem::path &vertex_path,
const std::filesystem::path &pixel_path
)
{
instance().load_shader_impl(name, vertexPath, pixelPath);
instance().load_shader_impl(name, vertex_path, pixel_path);
}
static void load_texture(const std::string &name, const std::string &path)
static void load_texture(const std::string &name, const std::filesystem::path &path)
{
instance().load_texture_impl(name, path);
}
static void release_texture(const std::string &name)
{
instance().release_texture_impl(name);
}
static auto get_shader(const std::string &name) -> Ref<Shader>
{
return instance().m_shaders[name];
@ -52,14 +47,12 @@ private:
void load_shader_impl(
const std::string &name,
const std::string &vertexPath,
const std::string &pixelPath
const std::filesystem::path &vertex_path,
const std::filesystem::path &pixel_path
);
void load_texture_impl(const std::string &name, const std::filesystem::path &path);
void release_texture_impl(const std::string &name);
std::unordered_map<std::string, Ref<Shader>> m_shaders;
std::unordered_map<std::string, Ref<Texture>> m_textures;

View file

@ -19,8 +19,8 @@ QuadRendererProgram::QuadRendererProgram(
// #todo: don't use relative path
ResourceManager::load_shader(
"LT_ENGINE_RESOURCES_QUAD_SHADER",
"data/assets/shaders/quads/vs.glsl",
"data/assets/shaders/quads/ps.glsl"
"data/assets/shaders/quads/vs.asset",
"data/assets/shaders/quads/ps.asset"
);
m_shader = ResourceManager::get_shader("LT_ENGINE_RESOURCES_QUAD_SHADER");

View file

@ -19,8 +19,8 @@ TextureRendererProgram::TextureRendererProgram(
// #todo: don't use relative path
ResourceManager::load_shader(
"LT_ENGINE_RESOURCES_TEXTURE_SHADER",
"data/assets/shaders/texture/vs.glsl",
"data/assets/shaders/texture/ps.glsl"
"data/assets/shaders/texture/vs.asset",
"data/assets/shaders/texture/ps.asset"
);
m_shader = ResourceManager::get_shader("LT_ENGINE_RESOURCES_TEXTURE_SHADER");

View file

@ -19,8 +19,8 @@ TintedTextureRendererProgram::TintedTextureRendererProgram(
// #todo: don't use relative path
ResourceManager::load_shader(
"LT_ENGINE_RESOURCES_TINTED_TEXTURE_SHADER",
"data/assets/shaders/tinted_texture/vs.glsl",
"data/assets/shaders/tinted_texture/ps.glsl"
"data/assets/shaders/tinted_texture/vs.asset",
"data/assets/shaders/tinted_texture/ps.asset"
);
m_shader = ResourceManager::get_shader("LT_ENGINE_RESOURCES_TINTED_TEXTURE_SHADER");

View file

@ -11,15 +11,18 @@
namespace Light {
auto Shader::create(
const BasicFileHandle& vertexFile,
const BasicFileHandle& pixelFile,
const Ref<SharedContext>& /*sharedContext*/
Assets::Blob vertex_blob,
Assets::Blob pixel_blob,
const Ref<SharedContext> &shared_context
) -> Ref<Shader>
{
std::ignore = shared_context;
// load shader source
switch (GraphicsContext::get_graphics_api())
{
case GraphicsAPI::OpenGL: return create_ref<glShader>(vertexFile, pixelFile);
case GraphicsAPI::OpenGL:
return create_ref<glShader>(std::move(vertex_blob), std::move(pixel_blob));
case GraphicsAPI::DirectX:
lt_win(return create_ref<dxShader>(

View file

@ -6,27 +6,29 @@
namespace Light {
glShader::glShader(BasicFileHandle vertexFile, BasicFileHandle pixelFile)
glShader::glShader(Assets::Blob vertex_blob, Assets::Blob pixel_blob)
: m_shader_id(glCreateProgram())
{
// create
m_shader_id = glCreateProgram();
auto vertex_source = std::string {
vertex_blob.data(),
vertex_blob.data() + vertex_blob.size(), // NOLINT
};
std::string const vertexSource(vertexFile.get_data(), vertexFile.get_data() + vertexFile.get_size());
std::string const pixelSource(pixelFile.get_data(), pixelFile.get_data() + pixelFile.get_size());
auto pixel_source = std::string {
pixel_blob.data(),
pixel_blob.data() + pixel_blob.size(), // NOLINT
};
unsigned int const vertexShader = compile_shader(vertexSource, Shader::Stage::VERTEX);
unsigned int const pixelShader = compile_shader(pixelSource, Shader::Stage::PIXEL);
const auto vertex_shader = compile_shader(vertex_source, Shader::Stage::vertex);
const auto pixel_shader = compile_shader(pixel_source, Shader::Stage::pixel);
// attach shaders
glAttachShader(m_shader_id, vertexShader);
glAttachShader(m_shader_id, pixelShader);
glAttachShader(m_shader_id, vertex_shader);
glAttachShader(m_shader_id, pixel_shader);
// link shader program
glLinkProgram(m_shader_id);
// delete shaders (free memory)
glDeleteShader(vertexShader);
glDeleteShader(pixelShader);
glDeleteShader(vertex_shader);
glDeleteShader(pixel_shader);
}
glShader::~glShader()
@ -44,38 +46,14 @@ void glShader::un_bind()
glUseProgram(NULL);
}
// shaderc::SpvCompilationResult glShader::compile_glsl(basic_file_handle file, Shader::Stage stage)
// {
// // compile options
// shaderc::CompileOptions options;
// options.SetTargetEnvironment(shaderc_target_env_opengl, shaderc_env_version_opengl_4_5);
// options.SetOptimizationLevel(shaderc_optimization_level_performance);
//
// // compile
// shaderc::Compiler compiler;
// shaderc::SpvCompilationResult result = compiler.CompileGlslToSpv(reinterpret_cast<const
// char*>(file.GetData()), stage == Shader::Stage::VERTEX ?
// shaderc_shader_kind::shaderc_vertex_shader : shaderc_shader_kind::shaderc_fragment_shader,
// file.GetName().c_str(), options);
//
// // log error
// if (result.GetCompilationStatus() != shaderc_compilation_status_success)
// {
// log_err("Failed to compile {} shader at {}...", stage == Shader::Stage::VERTEX ?
// "vertex" : "pixel", file.GetPath()); log_err(" {}", result.GetErrorMessage());
// }
//
// return result;
// }
auto glShader::compile_shader(const std::string& source, Shader::Stage stage) -> unsigned int
auto glShader::compile_shader(const std::string &source, Shader::Stage stage) -> unsigned int
{
// &(address of) needs an lvalue
const auto *lvalue_source = source.c_str();
auto shader = glCreateShader(
stage == Shader::Stage::VERTEX ? GL_VERTEX_SHADER :
stage == Shader::Stage::PIXEL ? GL_FRAGMENT_SHADER :
stage == Shader::Stage::GEOMETRY ? GL_GEOMETRY_SHADER :
stage == Shader::Stage::vertex ? GL_VERTEX_SHADER :
stage == Shader::Stage::pixel ? GL_FRAGMENT_SHADER :
stage == Shader::Stage::geometry ? GL_GEOMETRY_SHADER :
NULL
);
@ -96,7 +74,7 @@ auto glShader::compile_shader(const std::string& source, Shader::Stage stage) ->
log_err(
"glShader::glShader: failed to compile {} shader:\n {}",
stage == Shader::Stage::VERTEX ? "Vertex" : "Pixel",
stage == Shader::Stage::vertex ? "Vertex" : "Pixel",
errorLog
);

View file

@ -1,63 +0,0 @@
#include <engine/utils/file_manager.hpp>
#include <utility>
namespace Light {
BasicFileHandle::BasicFileHandle(
uint8_t *data,
uint32_t size,
std::string path,
std::string name,
std::string extension
)
: m_data(data)
, m_size(size)
, m_path(std::move(path))
, m_name(std::move(name))
, m_extension(std::move(extension))
{
}
void BasicFileHandle::release()
{
delete m_data;
m_data = nullptr;
m_size = 0ull;
}
auto FileManager::read_text_file(const std::string &path) -> BasicFileHandle
{
// parse path info
auto name = path.substr(0, path.find('.') + -1);
auto extension = path.substr(path.find('.') + 1);
// open file
auto file = std::ifstream { path.c_str(), std::ios_base::in | std::ios_base::binary };
// check
if (!file)
{
log_wrn("Failed to load text file: {}", path);
file.close();
return nullptr;
}
// fetch file size
file.seekg(0, std::ios::end);
auto size = file.tellg();
file.seekg(0, std::ios::beg);
if (!size)
{
log_wrn("Empty text file: {}", path);
}
// read file
auto *data = new uint8_t[size];
file.read(reinterpret_cast<char *>(data), size);
file.close();
return { data, static_cast<unsigned int>(size), path, name, extension };
}
} // namespace Light

View file

@ -1,68 +1,85 @@
#include <asset_parser/assets/text.hpp>
#include <asset_parser/assets/texture.hpp>
#include <asset_parser/parser.hpp>
#include <engine/graphics/graphics_context.hpp>
#include <engine/graphics/shader.hpp>
#include <engine/graphics/texture.hpp>
#include <engine/utils/file_manager.hpp>
#include <engine/utils/resource_manager.hpp>
#include <logger/logger.hpp>
namespace Light {
void ResourceManager::load_shader_impl(
const std::string &name,
const std::string &vertexPath,
const std::string &pixelPath
const std::filesystem::path &vertex_path,
const std::filesystem::path &pixel_path
)
{
lt_assert(!vertexPath.empty(), "Empty 'vertexPath'");
lt_assert(!pixelPath.empty(), "Empty 'pixelPath'");
try
{
log_trc("Loading shader:");
log_trc("\tname : {}", name);
log_trc("\tvertex path: {}", vertex_path.string());
log_trc("\tpixel path : {}", pixel_path.string());
auto vertexFile = FileManager::read_text_file(vertexPath);
auto pixelFile = FileManager::read_text_file(pixelPath);
auto vertex_asset = Assets::TextAsset { vertex_path };
auto pixel_asset = Assets::TextAsset { pixel_path };
lt_assert(vertexFile.is_valid(), "Failed to read vertex file: {}", vertexPath);
lt_assert(pixelFile.is_valid(), "Failed to read vertex file: {}", pixelPath);
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);
m_shaders[name] = Ref<Shader>(
Shader::create(vertexFile, pixelFile, GraphicsContext::get_shared_context())
);
auto vertex_blob = Assets::Blob(vertex_blob_metadata.uncompressed_size);
auto pixel_blob = Assets::Blob(pixel_blob_metadata.uncompressed_size);
vertexFile.release();
pixelFile.release();
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),
GraphicsContext::get_shared_context()
));
}
catch (const std::exception &exp)
{
log_err("Failed to load shader:");
log_err("\tname : {}", name);
log_err("\tvertex path: {}", vertex_path.string());
log_err("\tpixel path : {}", pixel_path.string());
log_err("\texception : {}", exp.what());
}
}
void ResourceManager::load_texture_impl(const std::string &name, const std::filesystem::path &path)
{
log_trc("Loading texture:");
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
));
}
void ResourceManager::release_texture_impl(const std::string &name)
{
if (!m_textures[name])
try
{
log_wrn("Failed to find texture named: {}", name);
return;
}
log_trc("Loading texture:");
log_trc("\tname: {}", name);
log_trc("\tpath: {}", path.string());
m_textures[name] = nullptr;
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
));
}
catch (const std::exception &exp)
{
log_err("Failed to load texture:");
log_err("\tname : {}", name);
log_err("\tpath : {}", path.string());
log_err("\texception: {}", exp.what());
}
}
} // namespace Light