- 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(EndOfCentralDirectoryHeader) == 22, "Well packed struct");
static_assert(sizeof(NtfsExtraField) == 36, "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(); 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; return startOffset;
} }
template<typename T> 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) 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); std::tm tm;
if (tm) #if _MSC_VER >= 1400
{ if (gmtime_s(&tm, &time) != 0) [[unlikely]]
uint16_t dosTime = 0; throw std::runtime_error("gmtime_s() failed");
dosTime |= (tm->tm_sec / 2) & 0x1F; // Seconds divided by 2 (Bits 00-04) #else
dosTime |= (tm->tm_min & 0x3F) << 5; // Minutes (Bits 05-10) if (gmtime_r(&time, &tm) == nullptr) [[unlikely]]
dosTime |= (tm->tm_hour & 0x1F) << 11; // Hours (Bits 11-15) 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; uint16_t dosDate = 0;
dosDate |= (tm->tm_mday & 0x1F); // Day (Bits 00-04) dosDate |= (tm.tm_mday & 0x1F); // Day (Bits 00-04)
dosDate |= ((tm->tm_mon + 1) & 0x0F) << 5; // Month (Bits 05-08) dosDate |= ((tm.tm_mon + 1) & 0x0F) << 5; // Month (Bits 05-08)
dosDate |= ((tm->tm_year - 80) & 0x7F) << 9; // Year from 1980 (Bits 09-15) dosDate |= ((tm.tm_year - 80) & 0x7F) << 9; // Year from 1980 (Bits 09-15)
return { dosTime, dosDate }; 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 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"); m_file = fopen(filePath.string().c_str(), "wb");
if (!m_file) if (!m_file)
{ {
throw std::runtime_error("Unable to open file for writing: " + filePath.string()); throw std::runtime_error("Unable to open file for writing: " + filePath.string());
} }
m_pad = alignHeadersby64;
} }
void ZipWriter::AddFile(const FileDescription& description, const void* buffer) 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 time_t accessTime = modTime; // FileDescription doesn't have this field
auto [dosTime, dosDate] = ConvertToDosTimeDate(modTime); 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; LocalFileHeader lfh;
lfh.fileLastModTime = dosTime; lfh.fileLastModTime = dosTime;
lfh.fileLastModDate = dosDate; lfh.fileLastModDate = dosDate;
@@ -209,7 +226,7 @@ namespace OpenVulkano
ZipWriter::~ZipWriter() ZipWriter::~ZipWriter()
{ {
if (m_file) if (IsOpen())
{ {
int centralDirsOffset = 0; int centralDirsOffset = 0;
if (m_numFiles) if (m_numFiles)

View File

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

View File

@@ -5,6 +5,7 @@
*/ */
#include "MeshWriter.hpp" #include "MeshWriter.hpp"
#include "IO/MemMappedFile.hpp"
#include "Scene/Geometry.hpp" #include "Scene/Geometry.hpp"
#include "Scene/Vertex.hpp" #include "Scene/Vertex.hpp"
#include "Scene/UsdEncoder.hpp" #include "Scene/UsdEncoder.hpp"
@@ -24,8 +25,7 @@ namespace OpenVulkano::Scene
if (!file.is_open()) if (!file.is_open())
throw std::runtime_error("Failed to open file '" + filePath + "' for writing!"); throw std::runtime_error("Failed to open file '" + filePath + "' for writing!");
std::stringstream dummy; WriteObjContents(geometry, "", file);
WriteObjContents(geometry, "", file, dummy);
file.close(); file.close();
} }
@@ -42,18 +42,25 @@ namespace OpenVulkano::Scene
{ {
OpenVulkano::ArchiveWriter zipWriter(zipPath.c_str()); OpenVulkano::ArchiveWriter zipWriter(zipPath.c_str());
std::stringstream objContents, mtlContents; const char* materialName = "Material0";
WriteObjContents(geometry, texturePath, objContents, mtlContents); {
std::stringstream objContents;
auto objDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("model.obj", objContents.str().size()); WriteObjContents(geometry, materialName, objContents);
zipWriter.AddFile(objDesc, objContents.str().data()); auto objContentsStr = objContents.str();
auto objDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("model.obj", objContentsStr.size());
auto mtlDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("material.mtl", mtlContents.str().size()); zipWriter.AddFile(objDesc, objContentsStr.data());
zipWriter.AddFile(mtlDesc, mtlContents.str().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)) 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()); auto texDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("texture.png", textureFile.Size());
zipWriter.AddFile(texDesc, textureFile.Data()); 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) 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); std::stringstream usdFile;
auto usdDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("geometry.usda", usdFile.str().size()); WriteUsdContents(usdFile, geometry);
zipWriter.AddFile(usdDesc, usdFile.str().data()); 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)) 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()); auto texDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("texture.png", textureFile.Size());
zipWriter.AddFile(texDesc, textureFile.Data()); zipWriter.AddFile(texDesc, textureFile.Data());
} }

View File

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

View File

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