2025-07-07 15:35:17 +03:30
|
|
|
#include <asset_parser/assets/texture.hpp>
|
2025-07-07 15:17:13 +03:30
|
|
|
#include <lz4.h>
|
|
|
|
|
2025-07-09 15:30:54 +03:30
|
|
|
namespace Assets {
|
2025-07-07 15:17:13 +03:30
|
|
|
|
2025-07-09 21:30:17 +03:30
|
|
|
/* 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 *)¤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<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)
|
|
|
|
{
|
2025-07-11 14:05:59 +03:30
|
|
|
throw std::runtime_error(
|
|
|
|
"Failed to unpack blob from TextureAsset: "
|
|
|
|
"compressed/uncompressed size mismatch for no compression "
|
|
|
|
"type"
|
|
|
|
);
|
2025-07-09 21:30:17 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
if (m_pixel_blob_metadata.uncompressed_size > destination_capacity)
|
|
|
|
{
|
2025-07-11 14:05:59 +03:30
|
|
|
throw std::runtime_error(
|
|
|
|
"Failed to unpack blob from TextureAsset: "
|
|
|
|
"uncompressed_size > destination_capacity, unpacking "
|
|
|
|
"would result in segfault"
|
|
|
|
);
|
2025-07-09 21:30:17 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_stream.is_open())
|
|
|
|
{
|
2025-07-11 14:05:59 +03:30
|
|
|
throw std::runtime_error(
|
|
|
|
"Failed to unpack blob from TextureAsset: ifstream is "
|
|
|
|
"closed"
|
|
|
|
);
|
2025-07-09 21:30:17 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
m_stream.read(
|
|
|
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
|
|
|
(char *)destination,
|
|
|
|
static_cast<long>(m_pixel_blob_metadata.uncompressed_size)
|
|
|
|
);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
2025-07-11 14:05:59 +03:30
|
|
|
throw std::runtime_error(
|
|
|
|
std::format(
|
|
|
|
"Failed to unpack blob from TextureAsset: unsupported "
|
|
|
|
"compression type: {}",
|
|
|
|
std::to_underlying(m_pixel_blob_metadata.compression_type)
|
|
|
|
)
|
|
|
|
);
|
2025-07-09 21:30:17 +03:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[[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;
|
|
|
|
}
|
2025-07-07 15:17:13 +03:30
|
|
|
|
|
|
|
} // namespace Assets
|