diff --git a/data/assets/textures/awesomeface.asset b/data/assets/textures/awesomeface.asset new file mode 100644 index 0000000..70280ee Binary files /dev/null and b/data/assets/textures/awesomeface.asset differ diff --git a/data/engine/icons/asset/dir.asset b/data/engine/icons/asset/dir.asset new file mode 100644 index 0000000..b8989ff Binary files /dev/null and b/data/engine/icons/asset/dir.asset differ diff --git a/data/engine/icons/asset/img.asset b/data/engine/icons/asset/img.asset new file mode 100644 index 0000000..9d8249a Binary files /dev/null and b/data/engine/icons/asset/img.asset differ diff --git a/data/engine/icons/asset/scene.asset b/data/engine/icons/asset/scene.asset new file mode 100644 index 0000000..5d10a62 Binary files /dev/null and b/data/engine/icons/asset/scene.asset differ diff --git a/data/engine/icons/asset/txt.asset b/data/engine/icons/asset/txt.asset new file mode 100644 index 0000000..079266d Binary files /dev/null and b/data/engine/icons/asset/txt.asset differ diff --git a/docs/architecture/assets.rst b/docs/architecture/assets.rst index 6832ec9..9bb6709 100644 --- a/docs/architecture/assets.rst +++ b/docs/architecture/assets.rst @@ -5,6 +5,7 @@ Layout {version} | 4 bytes, ie. uint32_t {general metadata} | sizeof(AssetMetadata) {specialized metadata} | sizeof(XXXAssetMetadata), eg. TextureAssetMetadata +{n} | 4 bytes, ie. uint32_t {blob_0...n metadata} | n * sizeof(BlobMetadata) {blob_0...n data} | variable size based on actual data {end marker} | 8 byte, ie size_t for marking the END @@ -13,7 +14,8 @@ Sections --------------------------------------------------------------------------------------------------- version -> The version of the asset for forward compatibility general metadata -> Common asset metadata such as file-path, asset-type, creator, etc. -specialized metadata -> Metadata specific to the asset, eg. texture dimensions for Textures +specialized metadata -> Metadata specific to the asset, eg. texture dimensions for Textures. +n -> The number of blobs. blob_0...n metadata -> Metadata specifying how the actual data is packed, required for unpacking. blob_0...n data -> The actual data, packed and compressed to be reacdy for direct engine consumption. diff --git a/docs/architecture/resource.rst b/docs/architecture/resource.rst new file mode 100644 index 0000000..856d384 --- /dev/null +++ b/docs/architecture/resource.rst @@ -0,0 +1,4 @@ +Resource Management + +=================================================================================================== + diff --git a/modules/asset_baker/CMakeLists.txt b/modules/asset_baker/CMakeLists.txt index 99b95d8..4115268 100644 --- a/modules/asset_baker/CMakeLists.txt +++ b/modules/asset_baker/CMakeLists.txt @@ -6,4 +6,5 @@ target_link_libraries( asset_baker PRIVATE asset_parser PRIVATE stb::stb + PRIVATE logger ) diff --git a/modules/asset_baker/include/asset_baker/bakers.hpp b/modules/asset_baker/include/asset_baker/bakers.hpp new file mode 100644 index 0000000..6a32262 --- /dev/null +++ b/modules/asset_baker/include/asset_baker/bakers.hpp @@ -0,0 +1,120 @@ +#pragma once + +#include +#include +#include +#include +#include + +#define STB_IMAGE_IMPLEMENTATION +#include + +namespace lt { + +class Loader +{ +public: + [[nodiscard]] virtual auto get_name() const -> std::string_view = 0; + + Loader() = default; + + Loader(Loader &&) = default; + + Loader(const Loader &) = delete; + + auto operator=(Loader &&) -> Loader & = default; + + auto operator=(const Loader &) -> Loader & = delete; + + virtual ~Loader() = default; + +private: +}; + +class TextureLoader: public Loader +{ +public: + TextureLoader() = default; + + [[nodiscard]] virtual auto load(std::filesystem::path file_path) const + -> Assets::TextureAsset::PackageData + = 0; +}; + + +class StbLoader: public TextureLoader +{ +public: + StbLoader() = default; + + void load(std::filesystem::path path); + + [[nodiscard]] static auto get_supported_extensions() -> std::unordered_set + { + return { ".png" }; + } + + [[nodiscard]] auto get_name() const -> std::string_view override + { + return "StbLoader"; + } + + [[nodiscard]] auto load(std::filesystem::path file_path) const + -> Assets::TextureAsset::PackageData override + { + auto width = int {}; + auto height = int {}; + auto channels = int {}; + + auto *pixels = stbi_load(file_path.string().c_str(), &width, &height, &channels, 4); + if (!pixels) + { + throw std::runtime_error { + std::format("Failed to load image file at: {} using stbi_load", file_path.string()), + }; + } + + const auto metadata = Assets::Asset::Metadata { + .type = Assets::Asset::Type::Texture, + }; + + const auto texture_metadata = Assets::TextureAsset::Metadata { + .format = Assets::TextureAsset::Format::RGBA8, + .num_components = static_cast(channels), + .pixel_size = { + static_cast(width), + static_cast(height), + {}, + }, + }; + + auto pixels_blob = Assets::Blob {}; + pixels_blob.resize(static_cast(width) * height * channels); + + // TODO(Light): figure out if it's possible to directly populate a blob with stbi functions + memcpy(pixels_blob.data(), pixels, pixels_blob.size()); + stbi_image_free(pixels); + + return Assets::TextureAsset::PackageData { + .metadata = metadata, + .texture_metadata = texture_metadata, + .pixels = std::move(pixels_blob), + }; + } +}; + +class TextureLoaderFactory +{ +public: + static auto create(std::string_view file_extension) -> std::unique_ptr + { + if (StbLoader::get_supported_extensions().contains(file_extension)) + { + return std::make_unique(); + } + + return {}; + } +}; + +} // namespace lt diff --git a/modules/asset_baker/src/baker.cpp b/modules/asset_baker/src/baker.cpp index d9dc6c0..2d3333c 100644 --- a/modules/asset_baker/src/baker.cpp +++ b/modules/asset_baker/src/baker.cpp @@ -1,85 +1,70 @@ +#include #include #include #include -#include +#include -#define STB_IMAGE_IMPLEMENTATION -#include - -#define ASSERT(x, ...) \ - if (!(x)) \ - { \ - log(__VA_ARGS__); \ - return -1; \ - } - - -template -void log(Args &&...args) +void try_packing_texture( + const std::filesystem::path &in_path, + const std::filesystem::path &out_path +) { - (std::cout << ... << args); - std::cout << '\n'; -} - -auto convert_image(const std::filesystem::path &input, const std::filesystem::path &output) -> bool -{ - auto width = int {}; - auto height = int {}; - auto channels = int {}; - - auto *pixels = stbi_load(input.string().c_str(), &width, &height, &channels, 4); - - if (!pixels) - return false; - - auto texture_info = Assets::TextureInfo { - .size = static_cast(width * height * 4), - .format = Assets::TextureFormat::RGBA8, - .pixel_size = { - static_cast(width), - static_cast(height), - 0ul, - }, - .original_file = input.string(), - }; - - auto file = Assets::pack_texture(&texture_info, pixels); - - stbi_image_free(pixels); - - Assets::save_binary_file(output.string().c_str(), file); - - return true; -} - -int main(int argc, char *argv[]) -{ - std::ios_base::sync_with_stdio(false); - - ASSERT( - argc == 3, - "Argc MUST be 3, 1: execution-path(implicit), 2: input-directory, 3: output-directory" - ); - - for (const auto &p : std::filesystem::directory_iterator(argv[1])) + auto texture_loader = lt::TextureLoaderFactory::create(in_path.extension().string()); + if (!texture_loader) { - if (p.path().extension() == ".png") - { - log("Found a texture: ", p); - - auto newp = p.path(); - newp.replace_extension(".asset_texture"); - convert_image(p.path(), newp); - } - else if (p.path().extension() == ".obj") - { - log("Found a mesh -> ", p, " (unsupported)"); - } - else - { - log("Unknown -> ", p); - } + // Don't log anything; this is expected. + return; } - return 0; + try + { + Assets::TextureAsset::pack(texture_loader->load(in_path), out_path); + + log_inf("Packed a texture:"); + 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("\tloader : {}", texture_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 +{ + if (argc != 2) + { + throw std::logic_error("Argc should be 2 -- exe dir (implicit) and target dir"); + } + + for (const auto &directory_iterator : + std::filesystem::recursive_directory_iterator(argv[1])) // NOLINT + { + if (directory_iterator.is_directory()) + { + continue; + } + + const auto &in_path = directory_iterator.path(); + + auto out_path = in_path; + out_path.replace_extension(".asset"); + + try_packing_texture(in_path, out_path); + } + + return EXIT_SUCCESS; +} +catch (const std::exception &exp) +{ + log_crt("Terminating due to uncaught exception:"); + log_crt("\texception.what: {}:", exp.what()); + + return EXIT_FAILURE; } diff --git a/modules/asset_parser/CMakeLists.txt b/modules/asset_parser/CMakeLists.txt index a53a21a..6c892c0 100644 --- a/modules/asset_parser/CMakeLists.txt +++ b/modules/asset_parser/CMakeLists.txt @@ -7,4 +7,5 @@ target_link_libraries( asset_parser PRIVATE LZ4::lz4_static PRIVATE nlohmann_json::nlohmann_json + PRIVATE logger ) diff --git a/modules/asset_parser/include/asset_parser/assets/texture.hpp b/modules/asset_parser/include/asset_parser/assets/texture.hpp index 7a9a1bd..e69de29 100644 --- a/modules/asset_parser/include/asset_parser/assets/texture.hpp +++ b/modules/asset_parser/include/asset_parser/assets/texture.hpp @@ -1,34 +0,0 @@ -#pragma once - -#include -#include - -namespace Assets { - -enum class TextureFormat : uint8_t -{ - None = 0, - RGBA8, -}; - -struct TextureInfo -{ - size_t size; - CompressionMode compression_mode; - TextureFormat format; - std::array pixel_size; - std::string original_file; -}; - -auto read_texture_info(AssetFile *file) -> TextureInfo; - -void unpack_texture( - TextureInfo *info, - const void *source_buffer, - size_t source_size, - void *destination -); - -auto pack_texture(TextureInfo *info, void *pixel_data) -> AssetFile; - -} // namespace Assets diff --git a/modules/asset_parser/include/asset_parser/parser.hpp b/modules/asset_parser/include/asset_parser/parser.hpp index 5dcb56b..49e7ee0 100644 --- a/modules/asset_parser/include/asset_parser/parser.hpp +++ b/modules/asset_parser/include/asset_parser/parser.hpp @@ -1,34 +1,276 @@ #pragma once +#include #include -#include +#include +#include +#include +#include #include namespace Assets { -struct AssetFile -{ - uint32_t version; +constexpr auto current_version = uint32_t { 1 }; +struct BlobMetadata +{ + enum class Tag : uint8_t + { + color, + depth, + vertices, + indices, + }; + + Tag tag; + + size_t offset; + + CompressionType compression_type; + + size_t compressed_size; + + size_t uncompressed_size; +}; + + +using Blob = std::vector; + +class Asset +{ +public: enum class Type : uint32_t // NOLINT(performance-enum-size) { Texture, Mesh, Material, - } type; + }; - std::string json; - std::vector blob; + struct Metadata + { + Type type; + }; + + 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; }; -enum class CompressionMode : uint32_t // NOLINT(performance-enum-size) +class TextureAsset: public Asset { - None, - LZ4, - LZ4HC, -}; +public: + enum class Format : uint32_t // NOLINT(performance-enum-size) + { + None = 0, + RGBA8, + }; -auto save_binary_file(const char *path, const AssetFile &in_file) -> bool; -auto load_binary_file(const char *path, AssetFile &out_file) -> bool; + struct Metadata + { + Format format; + + uint32_t num_components; + + std::array 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(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(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 *)¤t_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(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(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 diff --git a/modules/asset_parser/include/compressors/compressors.hpp b/modules/asset_parser/include/compressors/compressors.hpp new file mode 100644 index 0000000..dfee965 --- /dev/null +++ b/modules/asset_parser/include/compressors/compressors.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include + +namespace Assets { + +enum class CompressionType : uint32_t // NOLINT(performance-enum-size) +{ + None, + LZ4, + LZ4HC, +}; + +} diff --git a/modules/asset_parser/src/assets/texture.cpp b/modules/asset_parser/src/assets/texture.cpp index 850524f..3e1b00b 100644 --- a/modules/asset_parser/src/assets/texture.cpp +++ b/modules/asset_parser/src/assets/texture.cpp @@ -2,79 +2,11 @@ #include #include +// [version], [type] -- +// [asset_metadata], [blob_metadata] -- +// [blob] -- + namespace Assets { -using namespace nlohmann; - -auto read_texture_info(AssetFile *file) -> TextureInfo -{ - json texture_meta_data = json::parse(file->json); - - return TextureInfo { - .size = texture_meta_data["bufferSize"], - .compression_mode = texture_meta_data["compression"], - .format = texture_meta_data["format"], - .pixel_size = { - texture_meta_data["width"], - texture_meta_data["height"], - 0, - }, - .original_file = texture_meta_data["originalFile"], - }; -} - -void unpack_texture( - TextureInfo *info, - const void *source_buffer, - size_t source_size, - void *destination -) -{ - if (info->compression_mode == CompressionMode::LZ4) - { - LZ4_decompress_safe( - (const char *)source_buffer, - (char *)destination, - source_size, - info->size - ); - } - else - { - memcpy(destination, source_buffer, source_size); - } -} - -auto pack_texture(TextureInfo *info, void *pixel_data) -> AssetFile -{ - json metadata; - metadata["format"] = info->format; - metadata["width"] = info->pixel_size[0]; - metadata["height"] = info->pixel_size[1]; - metadata["bufferSize"] = info->size; - metadata["originalFile"] = info->original_file; - metadata["compression"] = CompressionMode::LZ4; - - AssetFile file; - file.type = AssetFile::Type::Texture; - file.version = 1u; - - const int compress_staging = LZ4_compressBound(info->size); - file.blob.resize(compress_staging); - const int compression_size = LZ4_compress_default( - (const char *)pixel_data, - (char *)file.blob.data(), - info->size, - compress_staging - ); - file.blob.resize(compression_size); - - - metadata["compression"] = CompressionMode::LZ4; - - file.json = metadata.dump(); - - return file; -} } // namespace Assets diff --git a/modules/asset_parser/src/parser.cpp b/modules/asset_parser/src/parser.cpp index 55849c4..903ce81 100644 --- a/modules/asset_parser/src/parser.cpp +++ b/modules/asset_parser/src/parser.cpp @@ -1,56 +1,62 @@ #include +#include #include -#include -#include +#include namespace Assets { -auto save_binary_file(const char *path, const AssetFile &file) -> bool -{ - std::ofstream outstream(path, std::ios::binary | std::ios::out); - - outstream.write((const char *)&file.version, sizeof(uint32_t)); - outstream.write((const char *)&file.type, sizeof(AssetFile::Type)); - - uint32_t json_size = file.json.size(); - uint32_t blob_size = file.blob.size(); - outstream.write((const char *)&json_size, sizeof(uint32_t)); - outstream.write((const char *)&blob_size, sizeof(uint32_t)); - - outstream.write(file.json.c_str(), json_size); - outstream.write((const char *)file.blob.data(), blob_size); - - outstream.close(); - - outstream.close(); - - return true; -} - -auto load_binary_file(const char *path, AssetFile &out_file) -> bool -{ - std::ifstream instream(path, std::ios::binary); - instream.seekg(0ull); - - if (!instream.is_open()) - return false; - - instream.read((char *)&out_file.version, sizeof(uint32_t)); - instream.read((char *)&out_file.type, sizeof(AssetFile::Type)); - - uint32_t json_size; - uint32_t blob_size; - instream.read((char *)&json_size, sizeof(uint32_t)); - instream.read((char *)&blob_size, sizeof(uint32_t)); - - out_file.json.resize(json_size); - out_file.blob.resize(blob_size); - instream.read((char *)out_file.json.data(), json_size); - instream.read((char *)out_file.blob.data(), blob_size); - - instream.close(); - - return true; -} +// void Asset::unpack(std::byte *destination) +// { +// if (!m_stream.is_open()) +// { +// throw std::logic_error { +// "Failed to unpack asset: " +// "ifstream is closed", +// }; +// } +// +// switch (m_metadata.blob_compression_type) +// { +// case CompressionType::None: +// if (m_metadata.packed_size != m_metadata.unpacked_size) +// { +// throw std::logic_error { +// "Failed to unpack asset: " +// "compression type set to none but packed/unpacked sizes differ", +// }; +// } +// +// m_stream.read( +// std::bit_cast(destination), +// static_cast(m_metadata.packed_size) +// ); +// m_stream.close(); +// +// case CompressionType::LZ4: +// m_stream.close(); +// throw std::logic_error { +// "Failed to unpack asset: " +// "LZ4 compression is not implemented yet", +// }; +// +// +// case CompressionType::LZ4HC: +// m_stream.close(); +// throw std::logic_error { +// "Failed to unpack asset: " +// "LZ4HC compression is not implemented yet", +// }; +// +// default: +// m_stream.close(); +// throw std::logic_error { +// std::format( +// "Failed to unpack asset: " +// "Compression type was not recognized: {}", +// std::to_underlying(m_metadata.blob_compression_type) +// ), +// }; +// } +// } } // namespace Assets diff --git a/modules/engine/CMakeLists.txt b/modules/engine/CMakeLists.txt index 22206cb..becfdec 100644 --- a/modules/engine/CMakeLists.txt +++ b/modules/engine/CMakeLists.txt @@ -104,7 +104,7 @@ target_link_libraries( PUBLIC opengl::opengl PUBLIC glfw PUBLIC imgui - PUBLIC stb::stb + PUBLIC asset_parser PUBLIC yaml-cpp::yaml-cpp PUBLIC EnTT::EnTT ) diff --git a/modules/engine/include/engine/utils/file_manager.hpp b/modules/engine/include/engine/utils/file_manager.hpp index 0689e37..dea824f 100644 --- a/modules/engine/include/engine/utils/file_manager.hpp +++ b/modules/engine/include/engine/utils/file_manager.hpp @@ -7,7 +7,7 @@ namespace Light { class BasicFileHandle { public: -virtual ~BasicFileHandle() = default; + virtual ~BasicFileHandle() = default; BasicFileHandle( uint8_t *data = nullptr, uint32_t size = 0ull, @@ -58,13 +58,12 @@ virtual ~BasicFileHandle() = default; return is_valid(); } -protected: +private: // made protected for custom free(): uint8_t *m_data; uint32_t m_size; -private: const std::string m_path; const std::string m_name; @@ -72,68 +71,10 @@ private: const std::string m_extension; }; -class ImageFileHandle: public BasicFileHandle -{ -public: -virtual ~ImageFileHandle() = default; - ImageFileHandle( - uint8_t *data, - uint32_t size, - const std::string &path, - const std::string &name, - const std::string &extension, - uint32_t width, - uint32_t height, - uint32_t components, - uint32_t desiredComponents - ) - : BasicFileHandle(data, size, path, name, extension) - , m_width(width) - , m_height(height) - , m_components(components) - , m_desired_components(desiredComponents) - { - } - - void release() override; - - [[nodiscard]] auto get_width() const -> uint32_t - { - return m_width; - } - - [[nodiscard]] auto get_height() const -> uint32_t - { - return m_height; - } - - [[nodiscard]] auto get_components() const -> uint32_t - { - return m_components; - } - - [[nodiscard]] auto get_desired_components() const -> uint32_t - { - return m_desired_components; - } - -private: - uint32_t m_width; - - uint32_t m_height; - - uint32_t m_components; - - uint32_t m_desired_components; -}; - class FileManager { public: static auto read_text_file(const std::string &path) -> BasicFileHandle; - - static auto read_image_file(const std::string &path, int32_t desiredComponents) - -> ImageFileHandle; }; } // namespace Light diff --git a/modules/engine/include/engine/utils/resource_manager.hpp b/modules/engine/include/engine/utils/resource_manager.hpp index 58e5b1e..b4f5ea7 100644 --- a/modules/engine/include/engine/utils/resource_manager.hpp +++ b/modules/engine/include/engine/utils/resource_manager.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include namespace Light { @@ -26,13 +27,9 @@ public: instance().load_shader_impl(name, vertexPath, pixelPath); } - static void load_texture( - const std::string &name, - const std::string &path, - unsigned int desiredComponents = 4u - ) + static void load_texture(const std::string &name, const std::string &path) { - instance().load_texture_impl(name, path, desiredComponents); + instance().load_texture_impl(name, path); } static void release_texture(const std::string &name) @@ -59,11 +56,7 @@ private: const std::string &pixelPath ); - void load_texture_impl( - const std::string &name, - const std::string &path, - unsigned int desiredComponents = 4u - ); + void load_texture_impl(const std::string &name, const std::filesystem::path &path); void release_texture_impl(const std::string &name); diff --git a/modules/engine/src/utils/file_manager.cpp b/modules/engine/src/utils/file_manager.cpp index 81ed290..e528546 100644 --- a/modules/engine/src/utils/file_manager.cpp +++ b/modules/engine/src/utils/file_manager.cpp @@ -1,7 +1,5 @@ -#define STB_IMAGE_IMPLEMENTATION #include #include -#include namespace Light { @@ -27,7 +25,6 @@ void BasicFileHandle::release() m_size = 0ull; } - auto FileManager::read_text_file(const std::string &path) -> BasicFileHandle { // parse path info @@ -63,52 +60,52 @@ auto FileManager::read_text_file(const std::string &path) -> BasicFileHandle return { data, static_cast(size), path, name, extension }; } -auto FileManager::read_image_file(const std::string &path, int32_t desiredComponents) - -> ImageFileHandle -{ - // parse path info - auto name = path.substr(0, path.find('.') + -1); - auto extension = path.substr(path.find('.') + 1); +// auto FileManager::read_image_file(const std::string &path, int32_t desiredComponents) +// -> ImageFileHandle +// { +// // parse path info +// auto name = path.substr(0, path.find('.') + -1); +// auto extension = path.substr(path.find('.') + 1); +// +// // load image +// auto width = 0; +// auto height = 0; +// auto fetchedComponents = 0; +// auto *pixels = stbi_load(path.c_str(), &width, &height, &fetchedComponents, desiredComponents); +// +// // check +// if (!pixels) +// { +// log_wrn("Failed to load image file: <{}>", path); +// } +// else if (fetchedComponents != desiredComponents) +// { +// log_wrn( +// "Mismatch of fetched/desired components: <{}> ({}/{})", +// name + '.' + extension, +// fetchedComponents, +// desiredComponents +// ); +// } +// +// return ImageFileHandle( +// pixels, +// width * height, +// path, +// name, +// extension, +// width, +// height, +// fetchedComponents, +// desiredComponents +// ); +// } - // load image - auto width = 0; - auto height = 0; - auto fetchedComponents = 0; - auto *pixels = stbi_load(path.c_str(), &width, &height, &fetchedComponents, desiredComponents); - - // check - if (!pixels) - { - log_wrn("Failed to load image file: <{}>", path); - } - else if (fetchedComponents != desiredComponents) - { - log_wrn( - "Mismatch of fetched/desired components: <{}> ({}/{})", - name + '.' + extension, - fetchedComponents, - desiredComponents - ); - } - - return ImageFileHandle( - pixels, - width * height, - path, - name, - extension, - width, - height, - fetchedComponents, - desiredComponents - ); -} - -void ImageFileHandle::release() -{ - stbi_image_free(reinterpret_cast(m_data)); - m_data = nullptr; - m_size = 0ull; -} +// void ImageFileHandle::release() +// { +// stbi_image_free(reinterpret_cast(m_data)); +// m_data = nullptr; +// m_size = 0ull; +// } } // namespace Light diff --git a/modules/engine/src/utils/resource_manager.cpp b/modules/engine/src/utils/resource_manager.cpp index ab33375..e698f02 100644 --- a/modules/engine/src/utils/resource_manager.cpp +++ b/modules/engine/src/utils/resource_manager.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -12,49 +14,44 @@ void ResourceManager::load_shader_impl( const std::string &pixelPath ) { - // check lt_assert(!vertexPath.empty(), "Empty 'vertexPath'"); lt_assert(!pixelPath.empty(), "Empty 'pixelPath'"); - // load files auto vertexFile = FileManager::read_text_file(vertexPath); auto pixelFile = FileManager::read_text_file(pixelPath); - // check lt_assert(vertexFile.is_valid(), "Failed to read vertex file: {}", vertexPath); lt_assert(pixelFile.is_valid(), "Failed to read vertex file: {}", pixelPath); - // create shader m_shaders[name] = Ref( Shader::create(vertexFile, pixelFile, GraphicsContext::get_shared_context()) ); - // free file vertexFile.release(); pixelFile.release(); } -void ResourceManager::load_texture_impl( - const std::string &name, - const std::string &path, - unsigned int desiredComponents /* = 4u */ -) +void ResourceManager::load_texture_impl(const std::string &name, const std::filesystem::path &path) { - // load file - auto imgFile = FileManager::read_image_file(path, desiredComponents); + 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(blob_metadata.uncompressed_size); + asset.unpack_blob(blob_metadata.tag, blob.data(), blob.size()); - // create texture m_textures[name] = Ref(Texture::create( - imgFile.get_width(), - imgFile.get_height(), - imgFile.get_components(), - imgFile.get_data(), + metadata.pixel_size[0], + metadata.pixel_size[1], + metadata.num_components, + std::bit_cast(blob.data()), GraphicsContext::get_shared_context(), path )); - - // free file - imgFile.release(); } void ResourceManager::release_texture_impl(const std::string &name) diff --git a/modules/mirror/src/editor_layer.cpp b/modules/mirror/src/editor_layer.cpp index c27cbbe..d623013 100644 --- a/modules/mirror/src/editor_layer.cpp +++ b/modules/mirror/src/editor_layer.cpp @@ -28,7 +28,7 @@ EditorLayer::EditorLayer(const std::string &name) m_camera_entity = m_scene->create_entity("Camera"); m_camera_entity.add_component(SceneCamera(), true); - ResourceManager::load_texture("Awesomeface", "data/assets/textures/awesomeface.png"); + ResourceManager::load_texture("Awesomeface", "data/assets/textures/awesomeface.asset"); auto entity = Entity { m_scene->create_entity("Awesomeface", {}) }; entity.add_component( diff --git a/modules/mirror/src/panel/asset_browser.cpp b/modules/mirror/src/panel/asset_browser.cpp index c7175d5..7656263 100644 --- a/modules/mirror/src/panel/asset_browser.cpp +++ b/modules/mirror/src/panel/asset_browser.cpp @@ -10,10 +10,10 @@ AssetBrowserPanel::AssetBrowserPanel(Ref active_scene) , m_assets_path("./data/assets") , m_active_scene(std::move(active_scene)) { - ResourceManager::load_texture("_Assets_Directory", "data/engine/icons/asset/dir.png"); - ResourceManager::load_texture("_Assets_Scene", "data/engine/icons/asset/scene.png"); - ResourceManager::load_texture("_Assets_Image", "data/engine/icons/asset/img.png"); - ResourceManager::load_texture("_Assets_Text", "data/engine/icons/asset/txt.png"); + ResourceManager::load_texture("_Assets_Directory", "data/engine/icons/asset/dir.asset"); + ResourceManager::load_texture("_Assets_Scene", "data/engine/icons/asset/scene.asset"); + ResourceManager::load_texture("_Assets_Image", "data/engine/icons/asset/img.asset"); + ResourceManager::load_texture("_Assets_Text", "data/engine/icons/asset/txt.asset"); m_directory_texture = ResourceManager::get_texture("_Assets_Directory"); m_scene_texture = ResourceManager::get_texture("_Assets_Scene");