From 371e68c5284359daea0446dfc674473a1461614a Mon Sep 17 00:00:00 2001 From: skal Date: Thu, 5 Feb 2026 16:41:14 +0100 Subject: feat(assets): Add Texture Asset support (Task #18.0 prep) - Integrated stb_image for image decompression in asset_packer. - Added GetTextureAsset helper in asset_manager. - Updated procedural asset generation to include dimensions header for consistency. - Updated test_assets to verify new asset format. --- tools/asset_packer.cc | 53 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 7 deletions(-) (limited to 'tools/asset_packer.cc') diff --git a/tools/asset_packer.cc b/tools/asset_packer.cc index 004561b..39169e4 100644 --- a/tools/asset_packer.cc +++ b/tools/asset_packer.cc @@ -10,6 +10,14 @@ #include #include +#define STB_IMAGE_IMPLEMENTATION +#define STBI_NO_LINEAR // Don't apply gamma correction, we want raw bytes +#define STBI_ONLY_PNG +#define STBI_ONLY_JPEG +#define STBI_ONLY_TGA +#define STBI_ONLY_BMP +#include "stb_image.h" + #include "procedural/generator.h" // For ProcGenFunc and procedural functions #include "util/asset_manager.h" // For AssetRecord and AssetId @@ -21,6 +29,13 @@ static const std::map kAssetPackerProcGenFuncMap = { {"make_periodic", procedural::make_periodic}, }; +static bool HasImageExtension(const std::string& filename) { + std::string ext = filename.substr(filename.find_last_of(".") + 1); + // simple case-insensitive check (assuming lowercase for simplicity or just basic checks) + if (ext == "png" || ext == "jpg" || ext == "jpeg" || ext == "tga" || ext == "bmp") return true; + return false; +} + // Helper struct to hold all information about an asset during parsing struct AssetBuildInfo { std::string name; @@ -207,14 +222,38 @@ int main(int argc, char* argv[]) { if (!info.is_procedural) { std::string base_dir = assets_txt_path.substr(0, assets_txt_path.find_last_of("/\\") + 1); - std::ifstream asset_file(base_dir + info.filename, std::ios::binary); - if (!asset_file.is_open()) { - fprintf(stderr, "Error: Could not open asset file: %s\n", - (base_dir + info.filename).c_str()); - return 1; + std::string full_path = base_dir + info.filename; + + std::vector buffer; + bool is_image = HasImageExtension(info.filename); + + if (is_image) { + int w, h, channels; + unsigned char* img_data = stbi_load(full_path.c_str(), &w, &h, &channels, 4); // Force 4 channels (RGBA) + if (!img_data) { + fprintf(stderr, "Error: Could not load image file: %s (Reason: %s)\n", full_path.c_str(), stbi_failure_reason()); + return 1; + } + + // Format: [Width(4)][Height(4)][Pixels...] + buffer.resize(sizeof(uint32_t) * 2 + w * h * 4); + uint32_t* header = reinterpret_cast(buffer.data()); + header[0] = (uint32_t)w; + header[1] = (uint32_t)h; + std::memcpy(buffer.data() + sizeof(uint32_t) * 2, img_data, w * h * 4); + + stbi_image_free(img_data); + printf("Processed image asset %s: %dx%d RGBA\n", info.name.c_str(), w, h); + } else { + std::ifstream asset_file(full_path, std::ios::binary); + if (!asset_file.is_open()) { + fprintf(stderr, "Error: Could not open asset file: %s\n", full_path.c_str()); + return 1; + } + buffer.assign((std::istreambuf_iterator(asset_file)), + std::istreambuf_iterator()); } - std::vector buffer((std::istreambuf_iterator(asset_file)), - std::istreambuf_iterator()); + size_t original_size = buffer.size(); buffer.push_back(0); // Null terminator for safety -- cgit v1.2.3