diff --git a/openVulkanoCpp/IO/Archive/ZipWriter.cpp b/openVulkanoCpp/IO/Archive/ZipWriter.cpp index 037c6b1..a9c1375 100644 --- a/openVulkanoCpp/IO/Archive/ZipWriter.cpp +++ b/openVulkanoCpp/IO/Archive/ZipWriter.cpp @@ -11,6 +11,7 @@ */ #include "ZipWriter.hpp" +#include "Base/Utils.hpp" #include "Math/CRC32.hpp" #include @@ -91,22 +92,6 @@ namespace static_assert(sizeof(EndOfCentralDirectoryHeader) == 22, "Well packed struct"); static_assert(sizeof(NtfsExtraField) == 36, "Well packed struct"); - std::vector ReadEntireFile(const std::string& fname) - { - FILE *file = fopen(fname.c_str(), "rb"); - std::vector buffer; - if(file) - { - fseek(file, 0, SEEK_END); - size_t size = ftell(file); - fseek(file, 0, SEEK_SET); - buffer.resize(size); - fread(buffer.data(), size, 1, file); - fclose(file); - } - return buffer; - } - template uint32_t Cat(std::vector& dest, T* thing) { @@ -157,6 +142,15 @@ namespace namespace OpenVulkano { + ZipWriter::ZipWriter(const std::filesystem::path& filePath) + { + m_file = fopen(filePath.string().c_str(), "wb"); + if (!m_file) + { + throw std::runtime_error("Unable to open file for writing: " + filePath.string()); + } + } + void ZipWriter::AddFile(const FileDescription& description, const void* buffer) { size_t fileSize = description.size; @@ -177,9 +171,10 @@ namespace OpenVulkano lfh.compressedSize = lfh.uncompressedSize = fileSize; lfh.fileNameLength = fileNameLength; - size_t headerOffset = Cat(m_headers, &lfh); - Cat(m_headers, fileNameLength, fileName); - Cat(m_headers, description.size, (uint8_t *)buffer); + size_t headerOffset = ftell(m_file); + fwrite(&lfh, sizeof(lfh), 1, m_file); + fwrite(fileName, fileNameLength, 1, m_file); + fwrite(buffer, fileSize, 1, m_file); CentalDirectoryFileHeader cdfh; cdfh.fileLastModTime = dosTime; @@ -203,41 +198,28 @@ namespace OpenVulkano m_numFiles += 1; } - std::vector ZipWriter::GetMemory() + void ZipWriter::AddFile(const std::filesystem::path& fileName, const char* inArchiveName) { - std::vector buffer = m_headers; - + auto data = Utils::ReadFile(fileName.string()); + auto desc = OpenVulkano::FileDescription::MakeDescriptionForFile(inArchiveName, data.Size()); + AddFile(desc, data.Data()); + } + + void ZipWriter::Close() + { + int centralDirsOffset = 0; if (m_numFiles) { - int centralDirsOffset = Cat(buffer, m_centralDirs); + centralDirsOffset = ftell(m_file); + fwrite(m_centralDirs.data(), m_centralDirs.size(), 1, m_file); + m_centralDirs.clear(); } EndOfCentralDirectoryHeader eocd; eocd.centralDirectoryEntries = eocd.totalCentralDirectoryEntries = m_numFiles; - eocd.centralDirectoryOffset = m_headers.size(); + eocd.centralDirectoryOffset = centralDirsOffset; - Cat(buffer, &eocd); - - return buffer; - } - - void ZipWriter::AddFile(const std::filesystem::path& fileName, const char* inArchiveName) - { - auto data = ReadEntireFile(fileName.string()); - auto desc = OpenVulkano::FileDescription::MakeDescriptionForFile(inArchiveName, data.size()); - AddFile(desc, data.data()); - } - - bool ZipWriter::Write(const std::filesystem::path& archivePath) - { - FILE* file = fopen(archivePath.string().c_str(), "wb"); - if (file) - { - auto mem = GetMemory(); - fwrite(mem.data(), mem.size(), 1, file); - fclose(file); - return true; - } - return false; + fwrite(&eocd, sizeof(eocd), 1, m_file); + fclose(m_file); } } \ No newline at end of file diff --git a/openVulkanoCpp/IO/Archive/ZipWriter.hpp b/openVulkanoCpp/IO/Archive/ZipWriter.hpp index c0f4649..722a9de 100644 --- a/openVulkanoCpp/IO/Archive/ZipWriter.hpp +++ b/openVulkanoCpp/IO/Archive/ZipWriter.hpp @@ -15,15 +15,15 @@ namespace OpenVulkano { class ZipWriter { - std::vector m_headers; std::vector m_centralDirs; int m_numFiles = 0; + FILE *m_file; public: + ZipWriter(const std::filesystem::path& filePath); + void AddFile(const FileDescription& description, const void* buffer); void AddFile(const std::filesystem::path& fileName, const char* inArchiveName); - - bool Write(const std::filesystem::path& archivePath); - std::vector GetMemory(); + void Close(); }; } \ No newline at end of file diff --git a/openVulkanoCpp/Scene/Geometry.cpp b/openVulkanoCpp/Scene/Geometry.cpp index a05f0b2..7a780f5 100644 --- a/openVulkanoCpp/Scene/Geometry.cpp +++ b/openVulkanoCpp/Scene/Geometry.cpp @@ -153,4 +153,29 @@ namespace OpenVulkano::Scene vertices = nullptr; indices = nullptr; } + + uint32_t Geometry::GetIndex(int index) const + { + uint32_t result = 0; + + if (index >= indexCount) + throw std::out_of_range("Index is out of range"); + + if (indexType == OpenVulkano::Scene::VertexIndexType::UINT16) + { + uint16_t* indices = GetIndices16(); + result = indices[index]; + } + else if (indexType == OpenVulkano::Scene::VertexIndexType::UINT32) + { + uint32_t* indices = GetIndices32(); + result = indices[index]; + } + else + { + throw std::runtime_error("Invalid geometry index type"); + } + + return result; + } } diff --git a/openVulkanoCpp/Scene/Geometry.hpp b/openVulkanoCpp/Scene/Geometry.hpp index c5c1159..8653a52 100644 --- a/openVulkanoCpp/Scene/Geometry.hpp +++ b/openVulkanoCpp/Scene/Geometry.hpp @@ -57,6 +57,7 @@ namespace OpenVulkano Vertex* GetVertices() const { return vertices; } void* GetIndices() const { return indices; } + uint32_t GetIndex(int index) const; uint16_t* GetIndices16() const { return static_cast(indices); } uint32_t* GetIndices32() const { return static_cast(indices); } uint32_t GetIndexCount() const { return indexCount; } diff --git a/openVulkanoCpp/Scene/MeshWriter.cpp b/openVulkanoCpp/Scene/MeshWriter.cpp index 7eaeabe..afa03c0 100644 --- a/openVulkanoCpp/Scene/MeshWriter.cpp +++ b/openVulkanoCpp/Scene/MeshWriter.cpp @@ -7,6 +7,8 @@ #include "MeshWriter.hpp" #include "Scene/Geometry.hpp" #include "Scene/Vertex.hpp" +#include "Scene/UsdEncoder.hpp" +#include "Scene/ObjEncoder.hpp" #include "IO/Archive/ArchiveWriter.hpp" #include "IO/Archive/ZipWriter.hpp" #include @@ -22,268 +24,6 @@ #include #include -namespace -{ - uint32_t GetIndexFromGeometry(OpenVulkano::Scene::Geometry* geometry, int index) - { - uint32_t result = 0; - - if (geometry->indexType == OpenVulkano::Scene::VertexIndexType::UINT16) - { - uint16_t *indices = static_cast(geometry->indices); - result = indices[index]; - } - else if (geometry->indexType == OpenVulkano::Scene::VertexIndexType::UINT32) - { - uint32_t *indices = static_cast(geometry->indices); - result = indices[index]; - } - else - { - throw std::runtime_error("Invalid geometry index type"); - } - - return result; - } - - std::string ReadEntireFile(const std::string& fname) - { - FILE *file = fopen(fname.c_str(), "rb"); - std::string buffer; - if(file) - { - fseek(file, 0, SEEK_END); - size_t size = ftell(file); - fseek(file, 0, SEEK_SET); - buffer = std::string(size, ' '); - fread(&buffer[0], size, 1, file); - fclose(file); - } - return buffer; - } - - void WriteGeometryWithoutTexturesUsingTinyusdz(OpenVulkano::Scene::Geometry* geometry, const std::string& filePath) - { - tinyusdz::Stage stage; - tinyusdz::Xform xform; - tinyusdz::GeomMesh mesh; - mesh.name = "TheMesh"; - - std::vector pts(geometry->vertexCount); - std::vector indices(geometry->indexCount); - tinyusdz::Attribute uvAttr; - std::vector uvs(geometry->vertexCount); - - for (uint32_t i = 0; i < geometry->vertexCount; ++i) - { - const OpenVulkano::Vertex& v = geometry->vertices[i]; - pts[i].x = v.position.x; - pts[i].y = v.position.y; - pts[i].z = v.position.z; - uvs[i] = { v.textureCoordinates.x, v.textureCoordinates.y }; - } - - mesh.points.set_value(pts); - uvAttr.set_value(uvs); - - std::vector counts(geometry->indexCount / 3, 3); // NOTE(vb): The value 3 is kind of arbitrary, but this array must be in the mesh! - mesh.faceVertexCounts.set_value(counts); - - for (uint32_t i = 0; i < geometry->indexCount; ++i) - { - uint32_t index = GetIndexFromGeometry(geometry, i); - indices[i] = index; - } - mesh.faceVertexIndices.set_value(indices); - - uvAttr.metas().interpolation = tinyusdz::Interpolation::FaceVarying; - tinyusdz::Property uvProp(uvAttr); - mesh.props.emplace("primvars:UVMap", uvProp); - - tinyusdz::Prim xformPrim(xform); - tinyusdz::Prim meshPrim(mesh); - std::string err; - if (!xformPrim.add_child(std::move(meshPrim), true, &err)) - { - throw std::runtime_error("Failed to construct scene: " + err); - } - - if (!stage.add_root_prim(std::move(xformPrim))) - { - throw std::runtime_error("Failed to add prim to stage root: " + stage.get_error()); - } - - stage.metas().defaultPrim = tinyusdz::value::token(xformPrim.element_name()); - stage.metas().comment = "Generated by OpenVulkanoCpp"; - if (!stage.commit()) - { - throw std::runtime_error("Failed to commit stage: " + stage.get_error()); - } - - std::ofstream file(filePath); - if (!file.is_open()) - throw std::runtime_error("Failed to open file '" + filePath + "' for writing!"); - std::string scene = to_string(stage); - file << scene << "\n"; - file.close(); - } - - std::vector ConvertToUSDC(const std::string& contents) - { - std::vector result; - tinyusdz::Stage stage; - std::string warn, err; - assert(tinyusdz::LoadUSDAFromMemory((const uint8_t *)contents.data(), (const size_t)contents.size(), "", &stage, &warn, &err)); - bool ret = tinyusdz::usdc::SaveAsUSDCToMemory(stage, &result, &warn, &err); // As for now, this reports that it's not implemented... - return result; - } - - std::string GetUsdContents(OpenVulkano::Scene::Geometry* geometry, const std::string texturePath = "") - { - std::ostringstream file; - std::ostringstream points, normals, indices, texCoords, faceCounts; - points << std::fixed << std::setprecision(6); - normals << std::fixed << std::setprecision(6); - - for (size_t i = 0; i < geometry->vertexCount; ++i) - { - const auto& v = geometry->vertices[i]; - points << "(" << v.position.x << ", " << v.position.y << ", " << v.position.z << ")"; - normals << "(" << v.normal.x << ", " << v.normal.y << ", " << v.normal.z << ")"; - if (i < geometry->vertexCount - 1) - { - points << ", "; - normals << ", "; - } - } - - for (size_t i = 0; i < geometry->indexCount; ++i) - { - indices << GetIndexFromGeometry(geometry, i); - if (i < geometry->indexCount - 1) - { - indices << ", "; - } - if ((i + 1) % 3 == 0) - { - faceCounts << "3"; - if (i < geometry->indexCount - 1) - { - faceCounts << ", "; - } - } - } - - texCoords << std::fixed << std::setprecision(6); - - for (size_t i = 0; i < geometry->indexCount; ++i) - { - const size_t vertexIndex = GetIndexFromGeometry(geometry, i); - const auto& v = geometry->vertices[vertexIndex]; - texCoords << "(" << v.textureCoordinates.x << ", " << v.textureCoordinates.y << ")"; - if (i < geometry->indexCount - 1) - { - texCoords << ", "; - } - } - - file << R"(#usda 1.0 -( - defaultPrim = "root" - doc = "Exported from OpenVulkano" - metersPerUnit = 1 - upAxis = "Z" -) - -def Xform "root" ( - customData = { - dictionary Blender = { - bool generated = 1 - } - } -) -{ - def Xform "model" - { - custom string userProperties:blender:object_name = "model" - float3 xformOp:rotateXYZ = (89.99999, -0, 0) - float3 xformOp:scale = (1, 1, 1) - double3 xformOp:translate = (0, 0, 0) - uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] - - def Mesh "model" ( - active = true - prepend apiSchemas = ["MaterialBindingAPI"] - ) - { - uniform bool doubleSided = 1 - float3[] extent = [(-0.5, -0.5, 0), (0.5, 0.5, 0)] - int[] faceVertexCounts = [)" - << faceCounts.str() << R"(] - int[] faceVertexIndices = [)" - << indices.str() << R"(] - rel material:binding = - normal3f[] normals = [)" - << normals.str() << R"(] ( - interpolation = "faceVarying" - ) - point3f[] points = [)" - << points.str() << R"(] - texCoord2f[] primvars:st = [)" - << texCoords.str() << R"(] ( - interpolation = "faceVarying" - ) - uniform token subdivisionScheme = "none" - custom string userProperties:blender:data_name = "model" - } - } - - def Scope "_materials" - { - def Material "Material0" - { - token outputs:surface.connect = - custom string userProperties:blender:data_name = "Material0" - - def Shader "Principled_BSDF" - { - uniform token info:id = "UsdPreviewSurface" - float inputs:clearcoat = 0 - float inputs:clearcoatRoughness = 0.03 - color3f inputs:diffuseColor.connect = - float inputs:ior = 1.5 - float inputs:metallic = 0 - float inputs:opacity = 1 - float inputs:roughness = 1 - float inputs:specular = 0 - token outputs:surface - } - - def Shader "Image_Texture" - { - uniform token info:id = "UsdUVTexture" - asset inputs:file = @./texture.png@ - token inputs:sourceColorSpace = "sRGB" - float2 inputs:st.connect = - token inputs:wrapS = "repeat" - token inputs:wrapT = "repeat" - float3 outputs:rgb - } - - def Shader "uvmap" - { - uniform token info:id = "UsdPrimvarReader_float2" - string inputs:varname = "st" - float2 outputs:result - } - } - } -} -)"; - return file.str(); - } -} - namespace OpenVulkano::Scene { void MeshWriter::WriteAsOBJ(Geometry* geometry, const std::string& filePath) @@ -293,43 +33,8 @@ namespace OpenVulkano::Scene if (!file.is_open()) throw std::runtime_error("Failed to open file '" + filePath + "' for writing!"); - // Vertices - for (int i = 0; i < geometry->vertexCount; ++i) - { - const OpenVulkano::Vertex& v = geometry->vertices[i]; - std::string line; - line = fmt::format("v {} {} {}\n", v.position.x, v.position.y, v.position.z); - file << line; - } - - // Normals - for (int i = 0; i < geometry->vertexCount; ++i) - { - const OpenVulkano::Vertex& v = geometry->vertices[i]; - std::string line; - line = fmt::format("vn {} {} {}\n", v.normal.x, v.normal.y, v.normal.z); - file << line; - } - - // TexCoords - for (int i = 0; i < geometry->vertexCount; ++i) - { - const OpenVulkano::Vertex& v = geometry->vertices[i]; - std::string line; - line = fmt::format("vt {} {}\n", v.textureCoordinates.x, v.textureCoordinates.y); - file << line; - } - - // Indices - for (int i = 0; i < geometry->indexCount; i += 3) - { - uint32_t i0 = GetIndexFromGeometry(geometry, i + 0) + 1; - uint32_t i1 = GetIndexFromGeometry(geometry, i + 1) + 1; - uint32_t i2 = GetIndexFromGeometry(geometry, i + 2) + 1; - std::string line = fmt::format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", i0, i1, i2); - file << line; - } - + auto [objContents, mtlContents] = GetObjContents(geometry, ""); + file << objContents; file.close(); } @@ -345,64 +50,27 @@ namespace OpenVulkano::Scene void MeshWriter::WriteObjAsZip(Geometry* geometry, const std::string& zipPath, const std::string& texturePath) { - std::stringstream mtlContent; - std::string materialName = "Material0"; - mtlContent << "newmtl " << materialName << "\n"; - mtlContent << "Ka 1.000 1.000 1.000\n"; // Ambient - mtlContent << "Kd 1.000 1.000 1.000\n"; // Diffuse - mtlContent << "Ks 0.000 0.000 0.000\n"; // Specular - if (!texturePath.empty()) - { - mtlContent << "map_Ka texture.png\n"; // Ambient map - mtlContent << "map_Kd texture.png\n"; // Texture map - } - - std::stringstream objContent; - objContent << "# OBJ file generated by OpenVulkanoCpp\n"; - objContent << "mtllib material.mtl\n"; - objContent << "usemtl " << materialName << "\n"; - for (int i = 0; i < geometry->vertexCount; ++i) - { - const auto& v = geometry->vertices[i]; - objContent << fmt::format("v {} {} {}\n", v.position.x, v.position.y, v.position.z); - } - for (int i = 0; i < geometry->vertexCount; ++i) - { - const auto& v = geometry->vertices[i]; - objContent << fmt::format("vn {} {} {}\n", v.normal.x, v.normal.y, v.normal.z); - } - for (int i = 0; i < geometry->vertexCount; ++i) - { - const auto& v = geometry->vertices[i]; - objContent << fmt::format("vt {} {}\n", v.textureCoordinates.x, v.textureCoordinates.y); - } - for (int i = 0; i < geometry->indexCount; i += 3) - { - uint32_t i0 = GetIndexFromGeometry(geometry, i) + 1; - uint32_t i1 = GetIndexFromGeometry(geometry, i + 1) + 1; - uint32_t i2 = GetIndexFromGeometry(geometry, i + 2) + 1; - objContent << fmt::format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", i0, i1, i2); - } - OpenVulkano::ArchiveWriter zipWriter(zipPath.c_str()); - auto objDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("model.obj", objContent.str().size()); - zipWriter.AddFile(objDesc, objContent.str().data()); + auto [objContents, mtlContents] = GetObjContents(geometry, texturePath); - auto mtlDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("material.mtl", mtlContent.str().size()); - zipWriter.AddFile(mtlDesc, mtlContent.str().data()); + auto objDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("model.obj", objContents.size()); + zipWriter.AddFile(objDesc, objContents.data()); + + auto mtlDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("material.mtl", mtlContents.size()); + zipWriter.AddFile(mtlDesc, mtlContents.data()); if (!texturePath.empty() && std::filesystem::exists(texturePath)) { - auto textureFileSize = std::filesystem::file_size(texturePath); - auto texDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("texture.png", textureFileSize); - zipWriter.AddFile(texDesc, ReadEntireFile(texturePath).c_str()); + auto textureFile = Utils::ReadFile(texturePath); + auto texDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("texture.png", textureFile.Size()); + zipWriter.AddFile(texDesc, textureFile.Data()); } } void MeshWriter::WriteAsUSDZ(Geometry* geometry, const std::string& usdzPath, const std::string& texturePath) { - OpenVulkano::ZipWriter zipWriter; + OpenVulkano::ZipWriter zipWriter(usdzPath); std::string usd = GetUsdContents(geometry, texturePath); auto usdDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("geometry.usda", usd.size()); @@ -410,14 +78,11 @@ namespace OpenVulkano::Scene if (!texturePath.empty() && std::filesystem::exists(texturePath)) { - auto textureFileSize = std::filesystem::file_size(texturePath); - auto texDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("texture.png", textureFileSize); - zipWriter.AddFile(texDesc, ReadEntireFile(texturePath).c_str()); + auto textureFile = Utils::ReadFile(texturePath); + auto texDesc = OpenVulkano::FileDescription::MakeDescriptionForFile("texture.png", textureFile.Size()); + zipWriter.AddFile(texDesc, textureFile.Data()); } - if(!zipWriter.Write(usdzPath)) - { - throw std::runtime_error("Unable to write to USDZ file " + usdzPath); - } + zipWriter.Close(); } } \ No newline at end of file diff --git a/openVulkanoCpp/Scene/ObjEncoder.hpp b/openVulkanoCpp/Scene/ObjEncoder.hpp new file mode 100644 index 0000000..0b7b660 --- /dev/null +++ b/openVulkanoCpp/Scene/ObjEncoder.hpp @@ -0,0 +1,69 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include +#include +#include +#include +#include "Scene/Geometry.hpp" + +namespace OpenVulkano::Scene +{ + // Returns [objContents, mtlContents] + std::pair GetObjContents(Geometry* geometry, const std::string& texturePath) + { + std::pair result; + + bool useTexture = texturePath.size() != 0; + + std::stringstream objContent; + objContent << "# OBJ file generated by OpenVulkanoCpp\n"; + + if (useTexture) + { + std::stringstream mtlContent; + std::string materialName = "Material0"; + mtlContent << "newmtl " << materialName << 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 " << materialName << "\n"; + + result.second = mtlContent.str(); + } + + for (int i = 0; i < geometry->vertexCount; ++i) + { + const auto& v = geometry->vertices[i]; + objContent << fmt::format("v {} {} {}\n", v.position.x, v.position.y, v.position.z); + } + for (int i = 0; i < geometry->vertexCount; ++i) + { + const auto& v = geometry->vertices[i]; + objContent << fmt::format("vn {} {} {}\n", v.normal.x, v.normal.y, v.normal.z); + } + for (int i = 0; i < geometry->vertexCount; ++i) + { + const auto& v = geometry->vertices[i]; + objContent << fmt::format("vt {} {}\n", v.textureCoordinates.x, v.textureCoordinates.y); + } + for (int i = 0; i < geometry->indexCount; i += 3) + { + uint32_t i0 = geometry->GetIndex(i + 0) + 1; + uint32_t i1 = geometry->GetIndex(i + 1) + 1; + uint32_t i2 = geometry->GetIndex(i + 2) + 1; + objContent << fmt::format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", i0, i1, i2); + } + + result.first = objContent.str(); + + return result; + } +} \ No newline at end of file diff --git a/openVulkanoCpp/Scene/UsdEncoder.hpp b/openVulkanoCpp/Scene/UsdEncoder.hpp new file mode 100644 index 0000000..6f7effc --- /dev/null +++ b/openVulkanoCpp/Scene/UsdEncoder.hpp @@ -0,0 +1,158 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include + +#include "Scene/Geometry.hpp" + +namespace OpenVulkano::Scene +{ + std::string GetUsdContents(OpenVulkano::Scene::Geometry* geometry, const std::string texturePath = "") + { + std::ostringstream result; + std::ostringstream points, normals, indices, texCoords, faceCounts; + points << std::fixed << std::setprecision(6); + normals << std::fixed << std::setprecision(6); + + for (size_t i = 0; i < geometry->vertexCount; ++i) + { + const auto& v = geometry->vertices[i]; + points << "(" << v.position.x << ", " << v.position.y << ", " << v.position.z << ")"; + normals << "(" << v.normal.x << ", " << v.normal.y << ", " << v.normal.z << ")"; + if (i < geometry->vertexCount - 1) + { + points << ", "; + normals << ", "; + } + } + + for (size_t i = 0; i < geometry->indexCount; ++i) + { + indices << geometry->GetIndex(i); + if (i < geometry->indexCount - 1) + { + indices << ", "; + } + if ((i + 1) % 3 == 0) + { + faceCounts << "3"; + if (i < geometry->indexCount - 1) + { + faceCounts << ", "; + } + } + } + + texCoords << std::fixed << std::setprecision(6); + + for (size_t i = 0; i < geometry->indexCount; ++i) + { + const size_t vertexIndex = geometry->GetIndex(i); + const auto& v = geometry->vertices[vertexIndex]; + texCoords << "(" << v.textureCoordinates.x << ", " << v.textureCoordinates.y << ")"; + if (i < geometry->indexCount - 1) + { + texCoords << ", "; + } + } + + result << R"(#usda 1.0 +( + defaultPrim = "root" + doc = "Exported from OpenVulkano" + metersPerUnit = 1 + upAxis = "Y" +) + +def Xform "root" ( + customData = { + dictionary Blender = { + bool generated = 1 + } + } +) +{ + def Xform "model" + { + custom string userProperties:blender:object_name = "model" + float3 xformOp:rotateXYZ = (90, -0, 0) + float3 xformOp:scale = (1, 1, 1) + double3 xformOp:translate = (0, 0, 0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + + def Mesh "model" ( + active = true + prepend apiSchemas = ["MaterialBindingAPI"] + ) + { + uniform bool doubleSided = 1 + float3[] extent = [(-0.5, -0.5, 0), (0.5, 0.5, 0)] + int[] faceVertexCounts = [)" + << faceCounts.str() << R"(] + int[] faceVertexIndices = [)" + << indices.str() << R"(] + rel material:binding = + normal3f[] normals = [)" + << normals.str() << R"(] ( + interpolation = "faceVarying" + ) + point3f[] points = [)" + << points.str() << R"(] + texCoord2f[] primvars:st = [)" + << texCoords.str() << R"(] ( + interpolation = "faceVarying" + ) + uniform token subdivisionScheme = "none" + custom string userProperties:blender:data_name = "model" + } + } + + def Scope "_materials" + { + def Material "Material0" + { + token outputs:surface.connect = + custom string userProperties:blender:data_name = "Material0" + + def Shader "Principled_BSDF" + { + uniform token info:id = "UsdPreviewSurface" + float inputs:clearcoat = 0 + float inputs:clearcoatRoughness = 0.03 + color3f inputs:diffuseColor.connect = + float inputs:ior = 1.5 + float inputs:metallic = 0 + float inputs:opacity = 1 + float inputs:roughness = 1 + float inputs:specular = 0 + token outputs:surface + } + + def Shader "Image_Texture" + { + uniform token info:id = "UsdUVTexture" + asset inputs:file = @./texture.png@ + token inputs:sourceColorSpace = "sRGB" + float2 inputs:st.connect = + token inputs:wrapS = "repeat" + token inputs:wrapT = "repeat" + float3 outputs:rgb + } + + def Shader "uvmap" + { + uniform token info:id = "UsdPrimvarReader_float2" + string inputs:varname = "st" + float2 outputs:result + } + } + } +} +)"; + return result.str(); + } +} \ No newline at end of file diff --git a/tests/IO/Archive/ZipWriterTest.cpp b/tests/IO/Archive/ZipWriterTest.cpp index 9e1a115..9fa99e8 100644 --- a/tests/IO/Archive/ZipWriterTest.cpp +++ b/tests/IO/Archive/ZipWriterTest.cpp @@ -10,25 +10,31 @@ #include #include +#include "Base/Utils.hpp" #include "IO/Archive/ZipWriter.hpp" +#include "IO/AppFolders.hpp" using namespace OpenVulkano; TEST_CASE("Empty zip file", "[ZipWriter]") { - ZipWriter writer; - auto mem = writer.GetMemory(); - + const auto emptyZipPath = AppFolders::GetAppTempDir() / "empty.zip"; + ZipWriter writer(emptyZipPath); + writer.Close(); + auto mem = Utils::ReadFile(emptyZipPath); const int expectSize = 22; - std::vector expect = {0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + Array expect = {0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - CHECK(mem.size() == expectSize); + CHECK(mem.Size() == expectSize); CHECK(mem == expect); + + std::filesystem::remove(emptyZipPath); } TEST_CASE("Zip with one file(AAA.txt that has 'AAA')", "[ZipWriter]") { - ZipWriter writer; + const auto oneFileZipPath = AppFolders::GetAppTempDir() / "one_file.zip"; + ZipWriter writer(oneFileZipPath); FileDescription desc = FileDescription::MakeDescriptionForFile("AAA.txt", 3); desc.modTime = {}; @@ -36,11 +42,12 @@ TEST_CASE("Zip with one file(AAA.txt that has 'AAA')", "[ZipWriter]") char buffer[] = {'A', 'A', 'A'}; writer.AddFile(desc, buffer); + writer.Close(); - auto mem = writer.GetMemory(); + auto mem = Utils::ReadFile(oneFileZipPath); const int expectSize = 151; - std::vector expect = + Array expect = { 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xec, 0xa7, 0x31, 0xa0, 0x66, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x2e, 0x74, 0x78, 0x74, 0x41, 0x41, 0x41, 0x50, 0x4b, 0x01, 0x02, 0x1f, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xec, @@ -50,14 +57,17 @@ TEST_CASE("Zip with one file(AAA.txt that has 'AAA')", "[ZipWriter]") 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00 }; - CHECK(mem.size() == expectSize); + CHECK(mem.Size() == expectSize); CHECK(mem == expect); + + std::filesystem::remove(oneFileZipPath); } TEST_CASE("Zip with two files(AAA.txt that has 'AAA', BBB.bin that has 'BBB')", "[ZipWriter]") { - ZipWriter writer; + const auto twoFilesZipPath = AppFolders::GetAppTempDir() / "two_files.zip"; + ZipWriter writer(twoFilesZipPath); FileDescription aaa = FileDescription::MakeDescriptionForFile("AAA.txt", 3); aaa.modTime = {}; @@ -71,11 +81,12 @@ TEST_CASE("Zip with two files(AAA.txt that has 'AAA', BBB.bin that has 'BBB')", writer.AddFile(aaa, aaaBuffer); writer.AddFile(bbb, bbbBuffer); + writer.Close(); - auto mem = writer.GetMemory(); + auto mem = Utils::ReadFile(twoFilesZipPath); const int expectSize = 280; - std::vector expect = + Array expect = { 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xec, 0xa7, 0x31, 0xa0, 0x66, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x2e, 0x74, 0x78, 0x74, 0x41, 0x41, 0x41, 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xec, 0x87, 0x8d, @@ -89,8 +100,10 @@ TEST_CASE("Zip with two files(AAA.txt that has 'AAA', BBB.bin that has 'BBB')", 0x3e, 0xd5, 0xde, 0xb1, 0x9d, 0x01, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00 }; - CHECK(mem.size() == expectSize); + CHECK(mem.Size() == expectSize); CHECK(mem == expect); + + std::filesystem::remove(twoFilesZipPath); }