- Changes in Cat functions
- Using gmtime_s and gmtime_r as a thread-safe functions
- ZFill() that is used for padding
- Option for ZipWriter to pad LocalFileHeaders(it is used to properly run tests)
- ZipWriter::IsOpen()
- Moved material creation away from WriteObjContents
- Using MemMappedFile instead of ReadFile
- Scoping files and adding them to archive
- UsdEncoder refactoring
This commit is contained in:
Vladyslav Baranovskyi
2024-11-27 20:21:14 +02:00
parent ba8574f537
commit 34bfebbdd3
5 changed files with 85 additions and 70 deletions

View File

@@ -106,54 +106,64 @@ namespace
static_assert(sizeof(EndOfCentralDirectoryHeader) == 22, "Well packed struct");
static_assert(sizeof(NtfsExtraField) == 36, "Well packed struct");
uint32_t Cat(std::vector<uint8_t>& dest, size_t size, uint8_t* thing)
uint32_t Cat(std::vector<uint8_t>& dest, size_t size, const uint8_t* thing)
{
uint32_t startOffset = dest.size();
dest.insert(dest.end(), (uint8_t*)thing, (uint8_t*)(thing + size));
dest.insert(dest.end(), thing, thing + size);
return startOffset;
}
template<typename T>
uint32_t Cat(std::vector<uint8_t>& dest, T* thing)
uint32_t Cat(std::vector<uint8_t>& dest, const T* thing)
{
return Cat(dest, sizeof(T), reinterpret_cast<uint8_t*>(thing));
return Cat(dest, sizeof(T), reinterpret_cast<const uint8_t*>(thing));
}
uint32_t Cat(std::vector<uint8_t>& dest, const std::vector<uint8_t>& thing)
{
return Cat(dest, thing.size(), const_cast<uint8_t*>(thing.data()));
return Cat(dest, thing.size(), thing.data());
}
std::pair<uint16_t, uint16_t> ConvertToDosTimeDate(time_t time)
std::pair<uint16_t, uint16_t> ConvertToDosTimeDate(const time_t time)
{
std::tm* tm = std::gmtime(&time);
if (tm)
{
uint16_t dosTime = 0;
dosTime |= (tm->tm_sec / 2) & 0x1F; // Seconds divided by 2 (Bits 00-04)
dosTime |= (tm->tm_min & 0x3F) << 5; // Minutes (Bits 05-10)
dosTime |= (tm->tm_hour & 0x1F) << 11; // Hours (Bits 11-15)
std::tm tm;
#if _MSC_VER >= 1400
if (gmtime_s(&tm, &time) != 0) [[unlikely]]
throw std::runtime_error("gmtime_s() failed");
#else
if (gmtime_r(&time, &tm) == nullptr) [[unlikely]]
throw std::runtime_error("gmtime_r() failed");
#endif
uint16_t dosTime = 0;
dosTime |= (tm.tm_sec / 2) & 0x1F; // Seconds divided by 2 (Bits 00-04)
dosTime |= (tm.tm_min & 0x3F) << 5; // Minutes (Bits 05-10)
dosTime |= (tm.tm_hour & 0x1F) << 11; // Hours (Bits 11-15)
uint16_t dosDate = 0;
dosDate |= (tm->tm_mday & 0x1F); // Day (Bits 00-04)
dosDate |= ((tm->tm_mon + 1) & 0x0F) << 5; // Month (Bits 05-08)
dosDate |= ((tm->tm_year - 80) & 0x7F) << 9; // Year from 1980 (Bits 09-15)
return { dosTime, dosDate };
}
uint16_t dosDate = 0;
dosDate |= (tm.tm_mday & 0x1F); // Day (Bits 00-04)
dosDate |= ((tm.tm_mon + 1) & 0x0F) << 5; // Month (Bits 05-08)
dosDate |= ((tm.tm_year - 80) & 0x7F) << 9; // Year from 1980 (Bits 09-15)
return { dosTime, dosDate };
}
return {};
template<int MAX_PADDING_SIZE = 64>
void ZFill(FILE *handle, size_t num)
{
uint8_t zeros[MAX_PADDING_SIZE] = {};
fwrite(&zeros, num, 1, handle);
}
}
namespace OpenVulkano
{
ZipWriter::ZipWriter(const std::filesystem::path& filePath)
ZipWriter::ZipWriter(const std::filesystem::path& filePath, bool alignHeadersby64)
{
m_file = fopen(filePath.string().c_str(), "wb");
if (!m_file)
{
throw std::runtime_error("Unable to open file for writing: " + filePath.string());
}
m_pad = alignHeadersby64;
}
void ZipWriter::AddFile(const FileDescription& description, const void* buffer)
@@ -169,6 +179,13 @@ namespace OpenVulkano
time_t accessTime = modTime; // FileDescription doesn't have this field
auto [dosTime, dosDate] = ConvertToDosTimeDate(modTime);
if (m_pad)
{
size_t headerSize = sizeof(LocalFileHeader) + fileNameLength;
size_t padding = 64 - ((ftell(m_file) + headerSize) & 63);
ZFill<64>(m_file, padding);
}
LocalFileHeader lfh;
lfh.fileLastModTime = dosTime;
lfh.fileLastModDate = dosDate;
@@ -209,7 +226,7 @@ namespace OpenVulkano
ZipWriter::~ZipWriter()
{
if (m_file)
if (IsOpen())
{
int centralDirsOffset = 0;
if (m_numFiles)

View File

@@ -17,12 +17,15 @@ namespace OpenVulkano
{
std::vector<uint8_t> m_centralDirs;
int m_numFiles = 0;
bool m_pad = false;
FILE* m_file;
public:
ZipWriter(const std::filesystem::path& filePath);
ZipWriter(const std::filesystem::path& filePath, bool alignHeadersby64 = false);
~ZipWriter();
bool IsOpen() const { return m_file != nullptr; }
void AddFile(const FileDescription& description, const void* buffer);
void AddFile(const std::filesystem::path& fileName, const char* inArchiveName);
};

View File

@@ -5,6 +5,7 @@
*/
#include "MeshWriter.hpp"
#include "IO/MemMappedFile.hpp"
#include "Scene/Geometry.hpp"
#include "Scene/Vertex.hpp"
#include "Scene/UsdEncoder.hpp"
@@ -24,8 +25,7 @@ namespace OpenVulkano::Scene
if (!file.is_open())
throw std::runtime_error("Failed to open file '" + filePath + "' for writing!");
std::stringstream dummy;
WriteObjContents(geometry, "", file, dummy);
WriteObjContents(geometry, "", file);
file.close();
}
@@ -42,18 +42,25 @@ namespace OpenVulkano::Scene
{
OpenVulkano::ArchiveWriter zipWriter(zipPath.c_str());
std::stringstream objContents, mtlContents;
WriteObjContents(geometry, texturePath, objContents, mtlContents);
auto objDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("model.obj", objContents.str().size());
zipWriter.AddFile(objDesc, objContents.str().data());
auto mtlDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("material.mtl", mtlContents.str().size());
zipWriter.AddFile(mtlDesc, mtlContents.str().data());
const char* materialName = "Material0";
{
std::stringstream objContents;
WriteObjContents(geometry, materialName, objContents);
auto objContentsStr = objContents.str();
auto objDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("model.obj", objContentsStr.size());
zipWriter.AddFile(objDesc, objContentsStr.data());
}
{
std::stringstream mtlContents;
mtlContents << "newmtl " << materialName << "\n" << ObjMaterialContents;
auto mtlContentsStr = mtlContents.str();
auto mtlDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("material.mtl", mtlContentsStr.size());
zipWriter.AddFile(mtlDesc, mtlContentsStr.data());
}
if (!texturePath.empty() && std::filesystem::exists(texturePath))
{
auto textureFile = Utils::ReadFile(texturePath);
auto textureFile = MemMappedFile(texturePath);
auto texDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("texture.png", textureFile.Size());
zipWriter.AddFile(texDesc, textureFile.Data());
}
@@ -61,16 +68,19 @@ namespace OpenVulkano::Scene
void MeshWriter::WriteAsUSDZ(Geometry* geometry, const std::string& texturePath, const std::string& usdzPath)
{
OpenVulkano::ZipWriter zipWriter(usdzPath);
OpenVulkano::ZipWriter zipWriter(usdzPath);// NOCHECKIN, true);
std::stringstream usdFile;
WriteUsdContents(usdFile, geometry);
auto usdDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("geometry.usda", usdFile.str().size());
zipWriter.AddFile(usdDesc, usdFile.str().data());
{
std::stringstream usdFile;
WriteUsdContents(usdFile, geometry);
auto usdFileStr = usdFile.str();
auto usdDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("geometry.usda", usdFileStr.size());
zipWriter.AddFile(usdDesc, usdFileStr.data());
}
if (!texturePath.empty() && std::filesystem::exists(texturePath))
{
auto textureFile = Utils::ReadFile(texturePath);
auto textureFile = MemMappedFile(texturePath);
auto texDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("texture.png", textureFile.Size());
zipWriter.AddFile(texDesc, textureFile.Data());
}

View File

@@ -14,22 +14,22 @@
namespace OpenVulkano::Scene
{
void WriteObjContents(Geometry* geometry, const std::string& texturePath, std::ostream& objContent, std::ostream& mtlContent)
{
bool useTexture = texturePath.size() != 0;
objContent << "# OBJ file generated by OpenVulkanoCpp\n";
if (useTexture)
{
mtlContent << R"(newmtl Material0
static constexpr std::string_view ObjMaterialContents = R"(
Ka 1.000 1.000 1.000
Kd 1.000 1.000 1.000
Ks 0.000 0.000 0.000
map_Ka texture.png
map_Kd texture.png
)";
objContent << "mtllib material.mtl\nusemtl Material0\n";
void WriteObjContents(Geometry* geometry, const std::string& materialName, std::ostream& objContent)
{
objContent << "# OBJ file generated by OpenVulkanoCpp\n";
if (materialName.size() != 0)
{
objContent << "mtllib material.mtl\n";
objContent << "usemtl " << materialName << "\n";
}
for (int i = 0; i < geometry->vertexCount; ++i)

View File

@@ -50,11 +50,8 @@ def Xform "root" (
{
if ((i + 1) % 3 == 0)
{
if (i > 2) output << ", ";
output << "3";
if (i < geometry->indexCount - 1)
{
output << ", ";
}
}
}
@@ -63,11 +60,8 @@ def Xform "root" (
for (size_t i = 0; i < geometry->indexCount; ++i)
{
if (i > 0) output << ", ";
output << geometry->GetIndex(i);
if (i < geometry->indexCount - 1)
{
output << ", ";
}
}
output << R"(]
@@ -78,11 +72,8 @@ def Xform "root" (
for (size_t i = 0; i < geometry->vertexCount; ++i)
{
const auto& v = geometry->vertices[i];
if (i > 0) output << ", ";
output << "(" << v.normal.x << ", " << v.normal.y << ", " << v.normal.z << ")";
if (i < geometry->vertexCount - 1)
{
output << ", ";
}
}
output << R"(] (
@@ -93,11 +84,8 @@ def Xform "root" (
for (size_t i = 0; i < geometry->vertexCount; ++i)
{
const auto& v = geometry->vertices[i];
if (i > 0) output << ", ";
output << "(" << v.position.x << ", " << v.position.y << ", " << v.position.z << ")";
if (i < geometry->vertexCount - 1)
{
output << ", ";
}
}
output << R"(]
@@ -109,11 +97,8 @@ def Xform "root" (
{
const size_t vertexIndex = geometry->GetIndex(i);
const auto& v = geometry->vertices[vertexIndex];
if (i > 0) output << ", ";
output << "(" << v.textureCoordinates.x << ", " << v.textureCoordinates.y << ")";
if (i < geometry->indexCount - 1)
{
output << ", ";
}
}
output << R"(] (