#pragma once #include #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 {}; } }; class TextLoader: Loader { public: [[nodiscard]] static auto get_supported_extensions() -> std::unordered_set { return { ".glsl", ".txt", ".hlsl" }; } [[nodiscard]] auto get_name() const -> std::string_view override { return "TextLoader"; } [[nodiscard]] auto load(const 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(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 { if (TextLoader::get_supported_extensions().contains(file_extension)) { return std::make_unique(); } return {}; } }; } // namespace lt