Skip to content

Commit

Permalink
Implemented zlib compression and decompression
Browse files Browse the repository at this point in the history
  • Loading branch information
ChunkTreasure1 committed Mar 2, 2024
1 parent 254ab32 commit 0a7d579
Show file tree
Hide file tree
Showing 28 changed files with 13,213 additions and 21 deletions.
6 changes: 4 additions & 2 deletions Volt/Launcher/premake5.lua
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ project "Launcher"
"%{IncludeDir.fastlz}",

"%{IncludeDir.VulkanSDK}",
"%{IncludeDir.vma}"
"%{IncludeDir.vma}",
"%{IncludeDir.zlib}"
}

links
Expand Down Expand Up @@ -123,7 +124,8 @@ project "Launcher"
"%{Library.discord}",

"%{Library.Vulkan}",
"%{Library.dxc}"
"%{Library.dxc}",
"%{Library.zlib}"
}

debugargs
Expand Down
6 changes: 4 additions & 2 deletions Volt/Sandbox/premake5.lua
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ project "Sandbox"
"%{IncludeDir.VulkanSDK}",
"%{IncludeDir.vma}",

"%{IncludeDir.TGAFbx}"
"%{IncludeDir.TGAFbx}",
"%{IncludeDir.zlib}"
}

links
Expand Down Expand Up @@ -163,7 +164,8 @@ project "Sandbox"
"%{Library.discord}",

"%{Library.Vulkan}",
"%{Library.dxc}"
"%{Library.dxc}",
"%{Library.zlib}"
}

debugargs
Expand Down
4 changes: 3 additions & 1 deletion Volt/Volt/premake5.lua
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ project "Volt"
"%{IncludeDir.vma}",
"%{IncludeDir.VulkanSDK}",
"%{IncludeDir.shaderc_glslc}",
"%{IncludeDir.shaderc_utils}"
"%{IncludeDir.shaderc_utils}",

"%{IncludeDir.zlib}"
}

links
Expand Down
2 changes: 1 addition & 1 deletion Volt/Volt/src/Volt/Asset/AssetManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ namespace Volt
{
Unload(handle);

Ref<Asset> asset;
Ref<Asset> asset = CreateRef<Asset>();
LoadAsset(handle, asset);
}

Expand Down
2 changes: 1 addition & 1 deletion Volt/Volt/src/Volt/Asset/AssetManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ namespace Volt
return nullptr;
}

Ref<Asset> asset;
Ref<Asset> asset = CreateRef<T>();
Get().LoadAsset(assetHandle, asset);

if (asset)
Expand Down
2 changes: 1 addition & 1 deletion Volt/Volt/src/Volt/Asset/ImportersNew/MeshSerializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ namespace Volt
streamWriter.Write(serializationData);

const auto filePath = AssetManager::GetFilesystemPath(metadata.filePath);
streamWriter.WriteToDisk(filePath);
streamWriter.WriteToDisk(filePath, true, sizeof(SerializedAssetMetadata));
}

bool MeshSerializer::Deserialize(const AssetMetadata& metadata, Ref<Asset> destinationAsset) const
Expand Down
14 changes: 14 additions & 0 deletions Volt/Volt/src/Volt/Core/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
#include <GLFW/glfw3.h>
#include <imgui.h>

#include "Volt/Asset/ImportersNew/MeshSerializer.h"

namespace Volt
{
Application::Application(const ApplicationInfo& info)
Expand Down Expand Up @@ -135,6 +137,18 @@ namespace Volt
{
m_steamImplementation = SteamImplementation::Create();
}


Ref<MeshSerializer> serializer = CreateRef<MeshSerializer>();
Ref<Mesh> mesh = AssetManager::GetAsset<Mesh>("Assets/SM_Cube.vtmesh");

AssetMetadata metadata{};
metadata.filePath = "Assets/TestCube.vtasset";

serializer->Serialize(metadata, mesh);

Ref<Mesh> testMesh = CreateRef<Mesh>();
serializer->Deserialize(metadata, testMesh);
}

Application::~Application()
Expand Down
119 changes: 113 additions & 6 deletions Volt/Volt/src/Volt/Utility/FileIO/BinaryStreamReader.cpp
Original file line number Diff line number Diff line change
@@ -1,30 +1,137 @@
#include "vtpch.h"
#include "BinaryStreamReader.h"

#include "zlib.h"

namespace Volt
{
BinaryStreamReader::BinaryStreamReader(const std::filesystem::path& filePath)
{
constexpr size_t compressionEncodingHeaderSize = sizeof(uint8_t) + sizeof(size_t);

std::ifstream stream(filePath, std::ios::in | std::ios::binary);
if (stream)
{
stream.seekg(0, std::ios::end);
m_data.resize(stream.tellg());
stream.seekg(0, std::ios::beg);
stream.read(reinterpret_cast<char*>(m_data.data()), m_data.size());

m_streamValid = true;
}
else
{
return;
}

// Read compression encoding
const uint8_t isCompressed = m_data[0];
const size_t compressedDataOffset = *reinterpret_cast<size_t*>(&m_data[1]) + compressionEncodingHeaderSize;

if (isCompressed)
{
if (!Decompress(compressedDataOffset))
{
m_streamValid = false;
}
}
}

void BinaryStreamReader::ReadData(void* outData, const TypeHeader& serializedTypeHeader, const TypeHeader& constructedTypeHeader)
{
VT_CORE_ASSERT(serializedTypeHeader.baseTypeSize == constructedTypeHeader.baseTypeSize, "Base Type sizes must match!");
m_stream.read(reinterpret_cast<char*>(outData), serializedTypeHeader.totalTypeSize);
memcpy_s(outData, serializedTypeHeader.totalTypeSize, &m_data[m_currentOffset], serializedTypeHeader.totalTypeSize);
m_currentOffset += serializedTypeHeader.totalTypeSize;
}

BinaryStreamReader::BinaryStreamReader(const std::filesystem::path& filePath)
bool BinaryStreamReader::Decompress(size_t compressedDataOffset)
{
m_stream = std::ifstream(filePath, std::ios::in | std::ios::binary);
constexpr uint32_t CHUNK_SIZE = 16384;
constexpr size_t compressionEncodingHeaderSize = sizeof(uint8_t) + sizeof(size_t);

z_stream stream;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
stream.avail_in = 0;
stream.next_in = Z_NULL;

int32_t zLibResult = inflateInit(&stream);
if (zLibResult != Z_OK)
{
return false;
}

uint32_t srcOffset = static_cast<uint32_t>(compressedDataOffset);

std::vector<uint8_t> tempResult{};

do
{
stream.avail_in = std::min(CHUNK_SIZE, static_cast<uint32_t>(m_data.size()) - srcOffset);
if (stream.avail_in == 0)
{
break;
}

uint8_t* bytePtr = &m_data[srcOffset];
srcOffset += stream.avail_in;
stream.next_in = bytePtr;

do
{
size_t dstOffset = tempResult.size();
tempResult.resize(tempResult.size() + CHUNK_SIZE);

stream.avail_out = CHUNK_SIZE;
stream.next_out = &tempResult[dstOffset];

zLibResult = inflate(&stream, Z_NO_FLUSH);
assert(zLibResult != Z_STREAM_ERROR);

switch (zLibResult)
{
case Z_NEED_DICT:
zLibResult = Z_DATA_ERROR;
case Z_DATA_ERROR:
case Z_MEM_ERROR:
{
inflateEnd(&stream);
return false;
}
}

uint32_t actualOutSize = CHUNK_SIZE - stream.avail_out;
tempResult.resize(dstOffset + actualOutSize);

} while (stream.avail_out == 0);

} while (zLibResult != Z_STREAM_END);

inflateEnd(&stream);

if (zLibResult == Z_STREAM_END)
{
m_data.erase(m_data.begin(), m_data.begin() + compressionEncodingHeaderSize);

m_data.resize(compressedDataOffset + tempResult.size() - compressionEncodingHeaderSize);
memcpy_s(&m_data[compressedDataOffset - compressionEncodingHeaderSize], tempResult.size(), tempResult.data(), tempResult.size());
}

return zLibResult == Z_STREAM_END;
}

bool BinaryStreamReader::IsStreamValid() const
{
return m_stream.good();
return m_streamValid;
}

TypeHeader BinaryStreamReader::ReadTypeHeader()
{
constexpr size_t typeHeaderSize = sizeof(TypeHeader);

TypeHeader result{};
m_stream.read(reinterpret_cast<char*>(&result), typeHeaderSize);
TypeHeader result = *reinterpret_cast<TypeHeader*>(&m_data[m_currentOffset]);
m_currentOffset += typeHeaderSize;
return result;
}
}
6 changes: 5 additions & 1 deletion Volt/Volt/src/Volt/Utility/FileIO/BinaryStreamReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ namespace Volt
TypeHeader ReadTypeHeader();
void ReadData(void* outData, const TypeHeader& serializedTypeHeader, const TypeHeader& constructedTypeHeader);

std::ifstream m_stream{};
bool Decompress(size_t compressedDataOffset);

std::vector<uint8_t> m_data;
size_t m_currentOffset = 0;
bool m_streamValid = false;
};

template<typename T>
Expand Down
94 changes: 92 additions & 2 deletions Volt/Volt/src/Volt/Utility/FileIO/BinaryStreamWriter.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,105 @@
#include "vtpch.h"
#include "BinaryStreamWriter.h"

#include "zlib.h"

namespace Volt
{
void BinaryStreamWriter::WriteToDisk(const std::filesystem::path& targetFilepath)
void BinaryStreamWriter::WriteToDisk(const std::filesystem::path& targetFilepath, bool compress, size_t compressedDataOffset)
{
constexpr size_t compressionEncodingHeaderSize = sizeof(uint8_t) + sizeof(size_t);

std::ofstream stream(targetFilepath, std::ios::out | std::ios::binary);
stream.write(reinterpret_cast<const char*>(m_data.data()), m_data.size());

const uint8_t* writePtr = m_data.data();
size_t size = m_data.size();

std::vector<uint8_t> compressedData;
if (compress)
{
compressedData.resize(compressionEncodingHeaderSize);
compressedData[0] = 1; // First byte tells if file is compressed

// Next 8 bytes tells the offset to where the compressed data starts
memcpy_s(&compressedData[1], sizeof(size_t), &compressedDataOffset, sizeof(size_t));

compressedDataOffset += compressionEncodingHeaderSize;

compressedData.resize(compressedDataOffset);
if (GetCompressed(compressedData, compressedDataOffset))
{
memcpy_s(&compressedData[compressionEncodingHeaderSize], compressedDataOffset - compressionEncodingHeaderSize, m_data.data(), compressedDataOffset - compressionEncodingHeaderSize);

writePtr = compressedData.data();
size = compressedData.size();
}
}

if (writePtr == m_data.data())
{
// Insert 0 at beginning to flag that file is uncompressed;
std::array<uint8_t, compressionEncodingHeaderSize> emptyEncodingHeader;
emptyEncodingHeader.fill(0);

m_data.insert(m_data.begin(), emptyEncodingHeader.begin(), emptyEncodingHeader.end());
}

stream.write(reinterpret_cast<const char*>(writePtr), size);
stream.close();
}

bool BinaryStreamWriter::GetCompressed(std::vector<uint8_t>& result, size_t compressedDataOffset)
{
constexpr uint32_t CHUNK_SIZE = 16384;
constexpr size_t compressionEncodingHeaderSize = sizeof(uint8_t) + sizeof(size_t);

z_stream stream;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;

int32_t zLibResult = deflateInit(&stream, Z_DEFAULT_COMPRESSION);
if (zLibResult != Z_OK)
{
return false;
}

int32_t shouldFlush;
uint32_t srcOffset = static_cast<uint32_t>(compressedDataOffset - compressionEncodingHeaderSize);

do
{
stream.avail_in = std::min(CHUNK_SIZE, static_cast<uint32_t>(m_data.size()) - srcOffset);
uint8_t* bytePtr = &m_data[srcOffset];
srcOffset += stream.avail_in;

shouldFlush = srcOffset == m_data.size() ? Z_FINISH : Z_NO_FLUSH;
stream.next_in = bytePtr;

do
{
size_t dstOffset = result.size();
result.resize(result.size() + CHUNK_SIZE);

stream.avail_out = CHUNK_SIZE;
stream.next_out = &result[dstOffset];

zLibResult = deflate(&stream, shouldFlush);
assert(zLibResult != Z_STREAM_ERROR);

uint32_t actualOutSize = CHUNK_SIZE - stream.avail_out;
result.resize(dstOffset + actualOutSize);

} while (stream.avail_out == 0);
assert(stream.avail_in == 0);

} while (shouldFlush != Z_FINISH);
assert(zLibResult == Z_STREAM_END);

deflateEnd(&stream);
return true;
}

void BinaryStreamWriter::WriteData(const void* data, const size_t size, const TypeHeader& typeHeader)
{
constexpr size_t typeHeaderSize = sizeof(TypeHeader);
Expand Down
Loading

0 comments on commit 0a7d579

Please sign in to comment.