feat: asset baking

Only supported .png textures at the moment
This commit is contained in:
light7734 2025-07-09 15:30:54 +03:30
parent 71d08cbe9f
commit 38997b3908
Signed by: light7734
GPG key ID: 8C30176798F1A6BA
23 changed files with 594 additions and 393 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -5,6 +5,7 @@ Layout
{version} | 4 bytes, ie. uint32_t {version} | 4 bytes, ie. uint32_t
{general metadata} | sizeof(AssetMetadata) {general metadata} | sizeof(AssetMetadata)
{specialized metadata} | sizeof(XXXAssetMetadata), eg. TextureAssetMetadata {specialized metadata} | sizeof(XXXAssetMetadata), eg. TextureAssetMetadata
{n} | 4 bytes, ie. uint32_t
{blob_0...n metadata} | n * sizeof(BlobMetadata) {blob_0...n metadata} | n * sizeof(BlobMetadata)
{blob_0...n data} | variable size based on actual data {blob_0...n data} | variable size based on actual data
{end marker} | 8 byte, ie size_t for marking the END {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 version -> The version of the asset for forward compatibility
general metadata -> Common asset metadata such as file-path, asset-type, creator, etc. 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 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. blob_0...n data -> The actual data, packed and compressed to be reacdy for direct engine consumption.

View file

@ -0,0 +1,4 @@
Resource Management
===================================================================================================

View file

@ -6,4 +6,5 @@ target_link_libraries(
asset_baker asset_baker
PRIVATE asset_parser PRIVATE asset_parser
PRIVATE stb::stb PRIVATE stb::stb
PRIVATE logger
) )

View file

@ -0,0 +1,120 @@
#pragma once
#include <asset_parser/assets/texture.hpp>
#include <filesystem>
#include <logger/logger.hpp>
#include <string_view>
#include <unordered_set>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
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<std::string_view>
{
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<uint32_t>(channels),
.pixel_size = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height),
{},
},
};
auto pixels_blob = Assets::Blob {};
pixels_blob.resize(static_cast<size_t>(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<TextureLoader>
{
if (StbLoader::get_supported_extensions().contains(file_extension))
{
return std::make_unique<StbLoader>();
}
return {};
}
};
} // namespace lt

View file

@ -1,85 +1,70 @@
#include <asset_baker/bakers.hpp>
#include <asset_parser/assets/texture.hpp> #include <asset_parser/assets/texture.hpp>
#include <asset_parser/parser.hpp> #include <asset_parser/parser.hpp>
#include <filesystem> #include <filesystem>
#include <iostream> #include <logger/logger.hpp>
#define STB_IMAGE_IMPLEMENTATION void try_packing_texture(
#include <stb_image.h> const std::filesystem::path &in_path,
const std::filesystem::path &out_path
#define ASSERT(x, ...) \ )
if (!(x)) \ {
{ \ auto texture_loader = lt::TextureLoaderFactory::create(in_path.extension().string());
log(__VA_ARGS__); \ if (!texture_loader)
return -1; \ {
// Don't log anything; this is expected.
return;
} }
try
{
Assets::TextureAsset::pack(texture_loader->load(in_path), out_path);
template<typename... Args> log_inf("Packed a texture:");
void log(Args &&...args) log_inf("\tloader : {}", texture_loader->get_name());
{ log_inf("\tin path: {}", in_path.string());
(std::cout << ... << args); log_inf("\tout path: {}", out_path.string());
std::cout << '\n'; }
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 convert_image(const std::filesystem::path &input, const std::filesystem::path &output) -> bool auto main(int argc, char *argv[]) -> int32_t
try
{ {
auto width = int {}; if (argc != 2)
auto height = int {}; {
auto channels = int {}; throw std::logic_error("Argc should be 2 -- exe dir (implicit) and target dir");
}
auto *pixels = stbi_load(input.string().c_str(), &width, &height, &channels, 4); for (const auto &directory_iterator :
std::filesystem::recursive_directory_iterator(argv[1])) // NOLINT
{
if (directory_iterator.is_directory())
{
continue;
}
if (!pixels) const auto &in_path = directory_iterator.path();
return false;
auto texture_info = Assets::TextureInfo { auto out_path = in_path;
.size = static_cast<size_t>(width * height * 4), out_path.replace_extension(".asset");
.format = Assets::TextureFormat::RGBA8,
.pixel_size = {
static_cast<uint32_t>(width),
static_cast<uint32_t>(height),
0ul,
},
.original_file = input.string(),
};
auto file = Assets::pack_texture(&texture_info, pixels); try_packing_texture(in_path, out_path);
}
stbi_image_free(pixels); return EXIT_SUCCESS;
Assets::save_binary_file(output.string().c_str(), file);
return true;
} }
catch (const std::exception &exp)
int main(int argc, char *argv[])
{ {
std::ios_base::sync_with_stdio(false); log_crt("Terminating due to uncaught exception:");
log_crt("\texception.what: {}:", exp.what());
ASSERT( return EXIT_FAILURE;
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]))
{
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);
}
}
return 0;
} }

View file

@ -7,4 +7,5 @@ target_link_libraries(
asset_parser asset_parser
PRIVATE LZ4::lz4_static PRIVATE LZ4::lz4_static
PRIVATE nlohmann_json::nlohmann_json PRIVATE nlohmann_json::nlohmann_json
PRIVATE logger
) )

View file

@ -1,34 +0,0 @@
#pragma once
#include <array>
#include <asset_parser/parser.hpp>
namespace Assets {
enum class TextureFormat : uint8_t
{
None = 0,
RGBA8,
};
struct TextureInfo
{
size_t size;
CompressionMode compression_mode;
TextureFormat format;
std::array<uint32_t, 3> 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

View file

@ -1,34 +1,276 @@
#pragma once #pragma once
#include <compressors/compressors.hpp>
#include <cstdint> #include <cstdint>
#include <string> #include <filesystem>
#include <fstream>
#include <logger/logger.hpp>
#include <utility>
#include <vector> #include <vector>
namespace Assets { namespace Assets {
struct AssetFile constexpr auto current_version = uint32_t { 1 };
{
uint32_t version;
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<std::byte>;
class Asset
{
public:
enum class Type : uint32_t // NOLINT(performance-enum-size) enum class Type : uint32_t // NOLINT(performance-enum-size)
{ {
Texture, Texture,
Mesh, Mesh,
Material, Material,
} type; };
std::string json; struct Metadata
std::vector<uint8_t> blob; {
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, public:
LZ4, enum class Format : uint32_t // NOLINT(performance-enum-size)
LZ4HC, {
}; None = 0,
RGBA8,
};
auto save_binary_file(const char *path, const AssetFile &in_file) -> bool; struct Metadata
auto load_binary_file(const char *path, AssetFile &out_file) -> bool; {
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 } // namespace Assets

View file

@ -0,0 +1,14 @@
#pragma once
#include <cstdint>
namespace Assets {
enum class CompressionType : uint32_t // NOLINT(performance-enum-size)
{
None,
LZ4,
LZ4HC,
};
}

View file

@ -2,79 +2,11 @@
#include <lz4.h> #include <lz4.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
// [version], [type] --
// [asset_metadata], [blob_metadata] --
// [blob] --
namespace Assets { 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 } // namespace Assets

View file

@ -1,56 +1,62 @@
#include <asset_parser/parser.hpp> #include <asset_parser/parser.hpp>
#include <format>
#include <fstream> #include <fstream>
#include <istream> #include <utility>
#include <ostream>
namespace Assets { namespace Assets {
auto save_binary_file(const char *path, const AssetFile &file) -> bool // void Asset::unpack(std::byte *destination)
{ // {
std::ofstream outstream(path, std::ios::binary | std::ios::out); // if (!m_stream.is_open())
// {
outstream.write((const char *)&file.version, sizeof(uint32_t)); // throw std::logic_error {
outstream.write((const char *)&file.type, sizeof(AssetFile::Type)); // "Failed to unpack asset: "
// "ifstream is closed",
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)); // switch (m_metadata.blob_compression_type)
// {
outstream.write(file.json.c_str(), json_size); // case CompressionType::None:
outstream.write((const char *)file.blob.data(), blob_size); // if (m_metadata.packed_size != m_metadata.unpacked_size)
// {
outstream.close(); // throw std::logic_error {
// "Failed to unpack asset: "
outstream.close(); // "compression type set to none but packed/unpacked sizes differ",
// };
return true; // }
} //
// m_stream.read(
auto load_binary_file(const char *path, AssetFile &out_file) -> bool // std::bit_cast<char *>(destination),
{ // static_cast<long>(m_metadata.packed_size)
std::ifstream instream(path, std::ios::binary); // );
instream.seekg(0ull); // m_stream.close();
//
if (!instream.is_open()) // case CompressionType::LZ4:
return false; // m_stream.close();
// throw std::logic_error {
instream.read((char *)&out_file.version, sizeof(uint32_t)); // "Failed to unpack asset: "
instream.read((char *)&out_file.type, sizeof(AssetFile::Type)); // "LZ4 compression is not implemented yet",
// };
uint32_t json_size; //
uint32_t blob_size; //
instream.read((char *)&json_size, sizeof(uint32_t)); // case CompressionType::LZ4HC:
instream.read((char *)&blob_size, sizeof(uint32_t)); // m_stream.close();
// throw std::logic_error {
out_file.json.resize(json_size); // "Failed to unpack asset: "
out_file.blob.resize(blob_size); // "LZ4HC compression is not implemented yet",
instream.read((char *)out_file.json.data(), json_size); // };
instream.read((char *)out_file.blob.data(), blob_size); //
// default:
instream.close(); // m_stream.close();
// throw std::logic_error {
return true; // std::format(
} // "Failed to unpack asset: "
// "Compression type was not recognized: {}",
// std::to_underlying(m_metadata.blob_compression_type)
// ),
// };
// }
// }
} // namespace Assets } // namespace Assets

View file

@ -104,7 +104,7 @@ target_link_libraries(
PUBLIC opengl::opengl PUBLIC opengl::opengl
PUBLIC glfw PUBLIC glfw
PUBLIC imgui PUBLIC imgui
PUBLIC stb::stb PUBLIC asset_parser
PUBLIC yaml-cpp::yaml-cpp PUBLIC yaml-cpp::yaml-cpp
PUBLIC EnTT::EnTT PUBLIC EnTT::EnTT
) )

View file

@ -7,7 +7,7 @@ namespace Light {
class BasicFileHandle class BasicFileHandle
{ {
public: public:
virtual ~BasicFileHandle() = default; virtual ~BasicFileHandle() = default;
BasicFileHandle( BasicFileHandle(
uint8_t *data = nullptr, uint8_t *data = nullptr,
uint32_t size = 0ull, uint32_t size = 0ull,
@ -58,13 +58,12 @@ virtual ~BasicFileHandle() = default;
return is_valid(); return is_valid();
} }
protected: private:
// made protected for custom free(): // made protected for custom free():
uint8_t *m_data; uint8_t *m_data;
uint32_t m_size; uint32_t m_size;
private:
const std::string m_path; const std::string m_path;
const std::string m_name; const std::string m_name;
@ -72,68 +71,10 @@ private:
const std::string m_extension; 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 class FileManager
{ {
public: public:
static auto read_text_file(const std::string &path) -> BasicFileHandle; 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 } // namespace Light

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <engine/base/base.hpp> #include <engine/base/base.hpp>
#include <filesystem>
namespace Light { namespace Light {
@ -26,13 +27,9 @@ public:
instance().load_shader_impl(name, vertexPath, pixelPath); instance().load_shader_impl(name, vertexPath, pixelPath);
} }
static void load_texture( static void load_texture(const std::string &name, const std::string &path)
const std::string &name,
const std::string &path,
unsigned int desiredComponents = 4u
)
{ {
instance().load_texture_impl(name, path, desiredComponents); instance().load_texture_impl(name, path);
} }
static void release_texture(const std::string &name) static void release_texture(const std::string &name)
@ -59,11 +56,7 @@ private:
const std::string &pixelPath const std::string &pixelPath
); );
void load_texture_impl( void load_texture_impl(const std::string &name, const std::filesystem::path &path);
const std::string &name,
const std::string &path,
unsigned int desiredComponents = 4u
);
void release_texture_impl(const std::string &name); void release_texture_impl(const std::string &name);

View file

@ -1,7 +1,5 @@
#define STB_IMAGE_IMPLEMENTATION
#include <engine/utils/file_manager.hpp> #include <engine/utils/file_manager.hpp>
#include <utility> #include <utility>
#include <stb_image.h>
namespace Light { namespace Light {
@ -27,7 +25,6 @@ void BasicFileHandle::release()
m_size = 0ull; m_size = 0ull;
} }
auto FileManager::read_text_file(const std::string &path) -> BasicFileHandle auto FileManager::read_text_file(const std::string &path) -> BasicFileHandle
{ {
// parse path info // parse path info
@ -63,52 +60,52 @@ auto FileManager::read_text_file(const std::string &path) -> BasicFileHandle
return { data, static_cast<unsigned int>(size), path, name, extension }; return { data, static_cast<unsigned int>(size), path, name, extension };
} }
auto FileManager::read_image_file(const std::string &path, int32_t desiredComponents) // auto FileManager::read_image_file(const std::string &path, int32_t desiredComponents)
-> ImageFileHandle // -> ImageFileHandle
{ // {
// parse path info // // parse path info
auto name = path.substr(0, path.find('.') + -1); // auto name = path.substr(0, path.find('.') + -1);
auto extension = path.substr(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 // void ImageFileHandle::release()
auto width = 0; // {
auto height = 0; // stbi_image_free(reinterpret_cast<void *>(m_data));
auto fetchedComponents = 0; // m_data = nullptr;
auto *pixels = stbi_load(path.c_str(), &width, &height, &fetchedComponents, desiredComponents); // m_size = 0ull;
// }
// 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<void *>(m_data));
m_data = nullptr;
m_size = 0ull;
}
} // namespace Light } // namespace Light

View file

@ -1,3 +1,5 @@
#include <asset_parser/assets/texture.hpp>
#include <asset_parser/parser.hpp>
#include <engine/graphics/graphics_context.hpp> #include <engine/graphics/graphics_context.hpp>
#include <engine/graphics/shader.hpp> #include <engine/graphics/shader.hpp>
#include <engine/graphics/texture.hpp> #include <engine/graphics/texture.hpp>
@ -12,49 +14,44 @@ void ResourceManager::load_shader_impl(
const std::string &pixelPath const std::string &pixelPath
) )
{ {
// check
lt_assert(!vertexPath.empty(), "Empty 'vertexPath'"); lt_assert(!vertexPath.empty(), "Empty 'vertexPath'");
lt_assert(!pixelPath.empty(), "Empty 'pixelPath'"); lt_assert(!pixelPath.empty(), "Empty 'pixelPath'");
// load files
auto vertexFile = FileManager::read_text_file(vertexPath); auto vertexFile = FileManager::read_text_file(vertexPath);
auto pixelFile = FileManager::read_text_file(pixelPath); auto pixelFile = FileManager::read_text_file(pixelPath);
// check
lt_assert(vertexFile.is_valid(), "Failed to read vertex file: {}", vertexPath); lt_assert(vertexFile.is_valid(), "Failed to read vertex file: {}", vertexPath);
lt_assert(pixelFile.is_valid(), "Failed to read vertex file: {}", pixelPath); lt_assert(pixelFile.is_valid(), "Failed to read vertex file: {}", pixelPath);
// create shader
m_shaders[name] = Ref<Shader>( m_shaders[name] = Ref<Shader>(
Shader::create(vertexFile, pixelFile, GraphicsContext::get_shared_context()) Shader::create(vertexFile, pixelFile, GraphicsContext::get_shared_context())
); );
// free file
vertexFile.release(); vertexFile.release();
pixelFile.release(); pixelFile.release();
} }
void ResourceManager::load_texture_impl( void ResourceManager::load_texture_impl(const std::string &name, const std::filesystem::path &path)
const std::string &name,
const std::string &path,
unsigned int desiredComponents /* = 4u */
)
{ {
// load file log_trc("Loading texture:");
auto imgFile = FileManager::read_image_file(path, desiredComponents); 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());
// create texture
m_textures[name] = Ref<Texture>(Texture::create( m_textures[name] = Ref<Texture>(Texture::create(
imgFile.get_width(), metadata.pixel_size[0],
imgFile.get_height(), metadata.pixel_size[1],
imgFile.get_components(), metadata.num_components,
imgFile.get_data(), std::bit_cast<unsigned char *>(blob.data()),
GraphicsContext::get_shared_context(), GraphicsContext::get_shared_context(),
path path
)); ));
// free file
imgFile.release();
} }
void ResourceManager::release_texture_impl(const std::string &name) void ResourceManager::release_texture_impl(const std::string &name)

View file

@ -28,7 +28,7 @@ EditorLayer::EditorLayer(const std::string &name)
m_camera_entity = m_scene->create_entity("Camera"); m_camera_entity = m_scene->create_entity("Camera");
m_camera_entity.add_component<CameraComponent>(SceneCamera(), true); m_camera_entity.add_component<CameraComponent>(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", {}) }; auto entity = Entity { m_scene->create_entity("Awesomeface", {}) };
entity.add_component<SpriteRendererComponent>( entity.add_component<SpriteRendererComponent>(

View file

@ -10,10 +10,10 @@ AssetBrowserPanel::AssetBrowserPanel(Ref<Scene> active_scene)
, m_assets_path("./data/assets") , m_assets_path("./data/assets")
, m_active_scene(std::move(active_scene)) , m_active_scene(std::move(active_scene))
{ {
ResourceManager::load_texture("_Assets_Directory", "data/engine/icons/asset/dir.png"); ResourceManager::load_texture("_Assets_Directory", "data/engine/icons/asset/dir.asset");
ResourceManager::load_texture("_Assets_Scene", "data/engine/icons/asset/scene.png"); ResourceManager::load_texture("_Assets_Scene", "data/engine/icons/asset/scene.asset");
ResourceManager::load_texture("_Assets_Image", "data/engine/icons/asset/img.png"); ResourceManager::load_texture("_Assets_Image", "data/engine/icons/asset/img.asset");
ResourceManager::load_texture("_Assets_Text", "data/engine/icons/asset/txt.png"); ResourceManager::load_texture("_Assets_Text", "data/engine/icons/asset/txt.asset");
m_directory_texture = ResourceManager::get_texture("_Assets_Directory"); m_directory_texture = ResourceManager::get_texture("_Assets_Directory");
m_scene_texture = ResourceManager::get_texture("_Assets_Scene"); m_scene_texture = ResourceManager::get_texture("_Assets_Scene");