feat(assetpacker): add asset packing
This commit is contained in:
parent
4797f0a832
commit
9f6271f9ba
@ -104,19 +104,15 @@ set(ENGINE_SOURCES
|
||||
src/enet_client.cpp
|
||||
src/enet_server.cpp
|
||||
|
||||
src/components/sprite_component.cpp
|
||||
src/Logger.cpp
|
||||
src/Logger.h
|
||||
src/components/transform_component.h
|
||||
|
||||
src/components/sprite_component.cpp
|
||||
src/components/physics_component.cpp
|
||||
src/components/physics_component.h
|
||||
src/components/input_component.cpp
|
||||
src/components/input_component.h
|
||||
src/components/health_component.h
|
||||
src/components/ui_component.cpp
|
||||
src/components/ui_component.h
|
||||
|
||||
src/scene_manager.cpp
|
||||
src/components/layer_component.h
|
||||
src/filepacker.cpp
|
||||
)
|
||||
|
||||
add_library(IsoEngine ${ENGINE_SOURCES})
|
||||
|
193
src/filepacker.cpp
Normal file
193
src/filepacker.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
//
|
||||
// Created by illyum on 9/13/2024.
|
||||
//
|
||||
|
||||
#include "filepacker.h"
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
bool FilePacker::Pack(const std::string &directoryPath, const std::string &outputBapFile) {
|
||||
BapHeader header;
|
||||
std::ofstream outputFile(outputBapFile, std::ios::binary);
|
||||
|
||||
if (!outputFile) {
|
||||
Logger::GetInstance().LogError("FilePacker::Pack(): Failed to open output file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::memcpy(header.magic, static_cast<const char*>("BAP"), 3);
|
||||
header.version = PACKER_VERSION;
|
||||
header.fileCount = 0;
|
||||
|
||||
std::vector<std::pair<FileEntry, std::vector<char>>> filesData;
|
||||
size_t headerSize = 3 + sizeof(header.version) + sizeof(header.fileCount);
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(directoryPath)) {
|
||||
if (entry.is_regular_file()) {
|
||||
FileEntry fileEntry;
|
||||
fileEntry.filePath = entry.path().string();
|
||||
|
||||
// TODO: Implement filetype detection
|
||||
fileEntry.fileType = RAWBINARY;
|
||||
fileEntry.compressedSize = COMPRESSION_NONE;
|
||||
|
||||
std::ifstream inputFile(entry.path(), std::ios::binary | std::ios::ate);
|
||||
if (!inputFile) {
|
||||
Logger::GetInstance().LogError("FilePacker::Pack(): Failed to open file for packing: " + entry.path().string());
|
||||
return false;
|
||||
}
|
||||
fileEntry.dataSize = inputFile.tellg();
|
||||
inputFile.seekg(0, std::ios::beg);
|
||||
std::vector<char> fileData(fileEntry.dataSize);
|
||||
inputFile.read(fileData.data(), fileEntry.dataSize);
|
||||
inputFile.close();
|
||||
|
||||
// TODO: Implement data compression
|
||||
std::vector<char> compressedData = CompressData(fileData, fileEntry.compression);
|
||||
fileEntry.compressedSize = compressedData.size();
|
||||
|
||||
filesData.emplace_back(fileEntry, std::move(compressedData));
|
||||
size_t pathLength = fileEntry.filePath.size();
|
||||
size_t metadataLength = fileEntry.metadata.size();
|
||||
|
||||
headerSize += sizeof(pathLength) + pathLength + sizeof(fileEntry.fileType) + sizeof(fileEntry.compression)
|
||||
+ sizeof(fileEntry.dataSize) + sizeof(fileEntry.compressedSize) + sizeof(fileEntry.dataOffset)
|
||||
+ sizeof(metadataLength) + metadataLength;
|
||||
|
||||
header.fileEntries.push_back(fileEntry);
|
||||
header.fileCount++;
|
||||
}
|
||||
}
|
||||
outputFile.seekp(headerSize, std::ios::beg);
|
||||
for (size_t i = 0; i < filesData.size(); ++i) {
|
||||
auto& fileEntry = header.fileEntries[i];
|
||||
const auto& compressedData = filesData[i].second;
|
||||
fileEntry.dataOffset = outputFile.tellp();
|
||||
outputFile.write(compressedData.data(), compressedData.size());
|
||||
}
|
||||
|
||||
outputFile.seekp(0, std::ios::beg);
|
||||
WriteHeader(outputFile, header);
|
||||
outputFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<FileEntry> FilePacker::listFiles(const std::string& bapFile) {
|
||||
std::ifstream inputFile(bapFile, std::ios::binary);
|
||||
if (!inputFile) {
|
||||
Logger::GetInstance().LogCritical("Failed to open .bap file for listing: " + bapFile);
|
||||
throw std::runtime_error("File could not be opened");
|
||||
}
|
||||
|
||||
BapHeader header = ReadHeader(inputFile);
|
||||
inputFile.close();
|
||||
return header.fileEntries;
|
||||
}
|
||||
|
||||
bool FilePacker::ExtractFile(const std::string& bapFile, const std::string& fileName, const std::string& outputPath) {
|
||||
std::ifstream inputFile(bapFile, std::ios::binary);
|
||||
if (!inputFile) {
|
||||
Logger::GetInstance().LogError("Failed to open .bap file for extraction: " + bapFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
BapHeader header = ReadHeader(inputFile);
|
||||
for (const auto& fileEntry : header.fileEntries) {
|
||||
if (fileEntry.filePath == fileName) {
|
||||
std::ofstream outFile(outputPath, std::ios::binary);
|
||||
if (!outFile) {
|
||||
Logger::GetInstance().LogError("Failed to create output file: " + outputPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<char> compressedData(fileEntry.compressedSize);
|
||||
inputFile.seekg(fileEntry.dataOffset, std::ios::beg);
|
||||
inputFile.read(compressedData.data(), compressedData.size());
|
||||
std::vector<char> decompressedData = DecompressData(compressedData, fileEntry.compression);
|
||||
outFile.write(decompressedData.data(), decompressedData.size());
|
||||
outFile.close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Logger::GetInstance().LogError("File not found in .bap archive: " + fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
void FilePacker::WriteHeader(std::ofstream& outFile, const BapHeader& header) {
|
||||
outFile.write(header.magic, 3);
|
||||
outFile.write(reinterpret_cast<const char*>(&header.version), sizeof(header.version));
|
||||
outFile.write(reinterpret_cast<const char*>(&header.fileCount), sizeof(header.fileCount));
|
||||
|
||||
for (const auto& fileEntry : header.fileEntries) {
|
||||
size_t pathLength = fileEntry.filePath.size();
|
||||
outFile.write(reinterpret_cast<const char*>(&pathLength), sizeof(pathLength));
|
||||
outFile.write(fileEntry.filePath.c_str(), pathLength);
|
||||
outFile.write(reinterpret_cast<const char*>(&fileEntry.fileType), sizeof(fileEntry.fileType));
|
||||
outFile.write(reinterpret_cast<const char*>(&fileEntry.compression), sizeof(fileEntry.compression));
|
||||
outFile.write(reinterpret_cast<const char*>(&fileEntry.dataSize), sizeof(fileEntry.dataSize));
|
||||
outFile.write(reinterpret_cast<const char*>(&fileEntry.compressedSize), sizeof(fileEntry.compressedSize));
|
||||
outFile.write(reinterpret_cast<const char*>(&fileEntry.dataOffset), sizeof(fileEntry.dataOffset));
|
||||
|
||||
size_t metadataLength = fileEntry.metadata.size();
|
||||
outFile.write(reinterpret_cast<const char*>(&metadataLength), sizeof(metadataLength));
|
||||
outFile.write(fileEntry.metadata.c_str(), metadataLength);
|
||||
}
|
||||
}
|
||||
|
||||
BapHeader FilePacker::ReadHeader(std::ifstream& inFile) {
|
||||
BapHeader header;
|
||||
|
||||
inFile.read(header.magic, 3);
|
||||
inFile.read(reinterpret_cast<char*>(&header.version), sizeof(header.version));
|
||||
inFile.read(reinterpret_cast<char*>(&header.fileCount), sizeof(header.fileCount));
|
||||
|
||||
if (header.version != PACKER_VERSION) {
|
||||
Logger::GetInstance().LogCritical("FilePacker::ReadHeader(): Wrong .bap file version.");
|
||||
throw std::runtime_error("Invalid bap file version");
|
||||
}
|
||||
|
||||
for (int i = 0; i < header.fileCount; ++i) {
|
||||
FileEntry fileEntry;
|
||||
|
||||
size_t pathLength;
|
||||
inFile.read(reinterpret_cast<char*>(&pathLength), sizeof(pathLength));
|
||||
|
||||
fileEntry.filePath.resize(pathLength);
|
||||
inFile.read(fileEntry.filePath.data(), pathLength);
|
||||
|
||||
inFile.read(reinterpret_cast<char*>(&fileEntry.fileType), sizeof(fileEntry.fileType));
|
||||
inFile.read(reinterpret_cast<char*>(&fileEntry.compression), sizeof(fileEntry.compression));
|
||||
inFile.read(reinterpret_cast<char*>(&fileEntry.dataSize), sizeof(fileEntry.dataSize));
|
||||
inFile.read(reinterpret_cast<char*>(&fileEntry.compressedSize), sizeof(fileEntry.compressedSize));
|
||||
inFile.read(reinterpret_cast<char*>(&fileEntry.dataOffset), sizeof(fileEntry.dataOffset));
|
||||
|
||||
size_t metadataLength;
|
||||
inFile.read(reinterpret_cast<char*>(&metadataLength), sizeof(metadataLength));
|
||||
|
||||
fileEntry.metadata.resize(metadataLength);
|
||||
inFile.read(fileEntry.metadata.data(), metadataLength);
|
||||
|
||||
header.fileEntries.push_back(fileEntry);
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
std::vector<char> FilePacker::CompressData(const std::vector<char>& input, CompressionType compression) {
|
||||
// IMPL: Implement actual compression on a per file basis
|
||||
if (compression == COMPRESSION_NONE) {
|
||||
return input;
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
std::vector<char> FilePacker::DecompressData(const std::vector<char>& input, CompressionType compression) {
|
||||
// IMPL: Implement decompression on a per file basis
|
||||
if (compression == COMPRESSION_NONE) {
|
||||
return input;
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
55
src/filepacker.h
Normal file
55
src/filepacker.h
Normal file
@ -0,0 +1,55 @@
|
||||
//
|
||||
// Created by illyum on 9/13/2024.
|
||||
//
|
||||
|
||||
#ifndef FILEPACKER_H
|
||||
#define FILEPACKER_H
|
||||
|
||||
#include <IsoEnginePCH.h>
|
||||
|
||||
#define BAP_MAGIC "BAP"
|
||||
#define PACKER_VERSION 1
|
||||
|
||||
enum CompressionType {
|
||||
COMPRESSION_NONE,
|
||||
COMPRESSION_LZMA
|
||||
};
|
||||
|
||||
enum FileType {
|
||||
PNG,
|
||||
RAWTEXT,
|
||||
RAWBINARY
|
||||
};
|
||||
|
||||
struct FileEntry {
|
||||
std::string filePath;
|
||||
FileType fileType;
|
||||
CompressionType compression;
|
||||
size_t dataSize;
|
||||
size_t compressedSize;
|
||||
std::string metadata;
|
||||
size_t dataOffset;
|
||||
};
|
||||
|
||||
struct BapHeader {
|
||||
char magic[3];
|
||||
int version;
|
||||
int fileCount;
|
||||
std::vector<FileEntry> fileEntries;
|
||||
};
|
||||
|
||||
class FilePacker {
|
||||
public:
|
||||
bool Pack(const std::string& directoryPath, const std::string& outputBapFile);
|
||||
bool Unpack(const std::string& bapFile, const std::string& outputDirectory);
|
||||
std::vector<FileEntry> listFiles(const std::string& bapFile);
|
||||
bool ExtractFile(const std::string& bapFile, const std::string& fileName, const std::string& outputPath);
|
||||
|
||||
private:
|
||||
void WriteHeader(std::ofstream& outFile, const BapHeader& header);
|
||||
BapHeader ReadHeader(std::ifstream& inFile);
|
||||
std::vector<char> CompressData(const std::vector<char>& input, CompressionType compression);
|
||||
std::vector<char> DecompressData(const std::vector<char>& input, CompressionType compression);
|
||||
};
|
||||
|
||||
#endif //FILEPACKER_H
|
Loading…
x
Reference in New Issue
Block a user