Summary:
- 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:
@@ -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::tm* tm = std::gmtime(&time);
|
||||
if (tm)
|
||||
std::pair<uint16_t, uint16_t> ConvertToDosTimeDate(const time_t time)
|
||||
{
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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());
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"(] (
|
||||
|
||||
Reference in New Issue
Block a user