/* Crafter®.Asset Copyright (C) 2026 Catcrafts® catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3.0 as published by the Free Software Foundation; This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ export module Crafter.Asset:Compression; import std; export namespace Crafter::Compression { // Hard-aborts the process after printing `msg`. Used in place of // `throw std::runtime_error(...)` so the module is buildable under // `-fno-exceptions` (wasm targets ship without the C++ unwinding // runtime). Asset-loading errors are unrecoverable in practice — a // bad magic, version mismatch, or stream-size mismatch always means // the build's data is inconsistent with the binary. [[noreturn]] inline void Fatal(std::string_view msg) { std::println(std::cerr, "Crafter.Asset fatal: {}", msg); std::abort(); } // One independently-decompressable GDeflate stream inside CompressedBlob::bytes. // Layout matches what VK_EXT_memory_decompression's VkDecompressMemoryRegionEXT // expects, minus the device addresses (which the consumer fills in). struct RegionMeta { std::uint64_t srcOffset; std::uint64_t compressedSize; std::uint64_t decompressedSize; }; struct CompressedBlob { std::vector bytes; std::vector regions; std::uint64_t TotalDecompressedSize() const noexcept { std::uint64_t sum = 0; for (const RegionMeta& r : regions) sum += r.decompressedSize; return sum; } }; // Compresses each input span as its own GDeflate tile-stream; concatenates // them into one byte buffer with a parallel region table. Streams are // independent and can be addressed individually by VkDecompressMemoryRegionEXT // entries on the GPU path. CompressedBlob CompressStreams(std::span> streams); // CPU fallback decoder. outputs.size() must equal blob.regions.size(); // outputs[i].size() must equal blob.regions[i].decompressedSize. void DecompressCPU(const CompressedBlob& blob, std::span> outputs); // Length-prefixed serialization of a CompressedBlob. Used by per-asset // SaveCompressed/LoadCompressed implementations after they've written // their own type-specific header. void WriteBlob(std::ostream& file, const CompressedBlob& blob); CompressedBlob ReadBlob(std::istream& file); }