From ad0e30841a91eeea55cff08eddd97d246eaace8e Mon Sep 17 00:00:00 2001 From: Martin Gerhardy Date: Sun, 22 May 2022 18:37:20 +0200 Subject: [PATCH] VOXELFORMAT: hopefully fixed uv coordinates for palettes that don't have 256 colors --- src/modules/voxelformat/FBXFormat.cpp | 2 +- src/modules/voxelformat/GLTFFormat.cpp | 2 +- src/modules/voxelformat/OBJFormat.cpp | 72 +++++++++++++++----------- src/modules/voxelformat/OBJFormat.h | 3 +- src/modules/voxelformat/PLYFormat.cpp | 2 +- 5 files changed, 47 insertions(+), 34 deletions(-) diff --git a/src/modules/voxelformat/FBXFormat.cpp b/src/modules/voxelformat/FBXFormat.cpp index 249b6d79b..e08931fcf 100644 --- a/src/modules/voxelformat/FBXFormat.cpp +++ b/src/modules/voxelformat/FBXFormat.cpp @@ -152,7 +152,7 @@ Objects: { if (withTexCoords) { // 1 x 256 is the texture format that we are using for our palette - const float texcoord = 1.0f / (float)palette.colorCount; + const float texcoord = 1.0f / (float)voxel::PaletteMaxColors; // it is only 1 pixel high - sample the middle const float v1 = 0.5f; wrapBool(stream.writeString("\t\tLayerElementUV: 0 {\n", false)) diff --git a/src/modules/voxelformat/GLTFFormat.cpp b/src/modules/voxelformat/GLTFFormat.cpp index a4aa981d7..daf4033eb 100644 --- a/src/modules/voxelformat/GLTFFormat.cpp +++ b/src/modules/voxelformat/GLTFFormat.cpp @@ -160,7 +160,7 @@ bool GLTFFormat::saveMeshes(const core::Map &meshIdxNodeMap, const Sce continue; } // 1 x 256 is the texture format that we are using for our palette - const float texcoord = 1.0f / (float)palette.colorCount; + const float texcoord = 1.0f / (float)voxel::PaletteMaxColors; int meshExtIdx = 0; meshIdxNodeMap.get(nodeId, meshExtIdx); diff --git a/src/modules/voxelformat/OBJFormat.cpp b/src/modules/voxelformat/OBJFormat.cpp index cf4006749..a5c63efff 100644 --- a/src/modules/voxelformat/OBJFormat.cpp +++ b/src/modules/voxelformat/OBJFormat.cpp @@ -33,24 +33,18 @@ namespace voxelformat { return false; \ } -bool OBJFormat::writeMtlFile(const core::String &mtlName, const core::String &paletteName) const { - const io::FilePtr &file = io::filesystem()->open(mtlName, io::FileMode::SysWrite); - if (!file->validHandle()) { - Log::error("Failed to create mtl file at %s", file->name().c_str()); +bool OBJFormat::writeMtlFile(io::SeekableWriteStream &stream, const core::String &mtlId, const core::String &mapKd) const { + if (!stream.writeStringFormat(false, "\nnewmtl %s\n", mtlId.c_str())) { + Log::error("Failed to write obj newmtl"); return false; } - io::FileStream stream(file); - wrapBool(stream.writeStringFormat(false, "# version " PROJECT_VERSION " github.com/mgerhardy/vengi\n")) - wrapBool(stream.writeStringFormat(false, "\n")) - wrapBool(stream.writeStringFormat(false, "newmtl palette\n")) - wrapBool(stream.writeStringFormat(false, "Ka 1.000000 1.000000 1.000000\n")) - wrapBool(stream.writeStringFormat(false, "Kd 1.000000 1.000000 1.000000\n")) - wrapBool(stream.writeStringFormat(false, "Ks 0.000000 0.000000 0.000000\n")) - wrapBool(stream.writeStringFormat(false, "Tr 1.000000\n")) - wrapBool(stream.writeStringFormat(false, "illum 1\n")) - wrapBool(stream.writeStringFormat(false, "Ns 0.000000\n")) - const core::String& paletteFilename = core::string::extractFilenameWithExtension(paletteName); - if (!stream.writeStringFormat(false, "map_Kd %s\n", paletteFilename.c_str())) { + wrapBool(stream.writeString("Ka 1.000000 1.000000 1.000000\n", false)) + wrapBool(stream.writeString("Kd 1.000000 1.000000 1.000000\n", false)) + wrapBool(stream.writeString("Ks 0.000000 0.000000 0.000000\n", false)) + wrapBool(stream.writeString("Tr 1.000000\n", false)) + wrapBool(stream.writeString("illum 1\n", false)) + wrapBool(stream.writeString("Ns 0.000000\n", false)) + if (!stream.writeStringFormat(false, "map_Kd %s\n", mapKd.c_str())) { Log::error("Failed to write obj map_Kd"); return false; } @@ -66,6 +60,21 @@ bool OBJFormat::saveMeshes(const core::Map &, const SceneGraph &sceneG Log::debug("Exporting %i layers", (int)meshes.size()); + core::String mtlname = core::string::stripExtension(filename); + mtlname.append(".mtl"); + Log::debug("Use mtl file: %s", mtlname.c_str()); + + const io::FilePtr &file = io::filesystem()->open(mtlname, io::FileMode::SysWrite); + if (!file->validHandle()) { + Log::error("Failed to create mtl file at %s", file->name().c_str()); + return false; + } + io::FileStream matlstream(file); + wrapBool(matlstream.writeString("# version " PROJECT_VERSION " github.com/mgerhardy/vengi\n", false)) + wrapBool(matlstream.writeString("\n", false)) + + core::Map paletteMaterialIndices((int)sceneGraph.size()); + int idxOffset = 0; int texcoordOffset = 0; for (const auto &meshExt : meshes) { @@ -80,17 +89,10 @@ bool OBJFormat::saveMeshes(const core::Map &, const SceneGraph &sceneG const SceneGraphNode &graphNode = sceneGraph.node(meshExt.nodeId); const voxel::Palette &palette = graphNode.palette(); - core::String mtlname = core::string::stripExtension(filename); - mtlname.append(core::String::format("%" PRIu64, palette.hash())); - mtlname.append(".mtl"); - const core::String hashId = core::String::format("%" PRIu64, palette.hash()); - core::String palettename = core::string::stripExtension(filename); - palettename.append(hashId); - palettename.append(".png"); // 1 x 256 is the texture format that we are using for our palette - const float texcoord = 1.0f / (float)palette.colorCount; + const float texcoord = 1.0f / (float)voxel::PaletteMaxColors; // it is only 1 pixel high - sample the middle const float v1 = 0.5f; const glm::vec3 offset(mesh->getOffset()); @@ -102,7 +104,10 @@ bool OBJFormat::saveMeshes(const core::Map &, const SceneGraph &sceneG } stream.writeStringFormat(false, "o %s\n", objectName); stream.writeStringFormat(false, "mtllib %s\n", core::string::extractFilenameWithExtension(mtlname).c_str()); - wrapBool(stream.writeStringFormat(false, "usemtl palette\n")) + if (!stream.writeStringFormat(false, "usemtl %s\n", hashId.c_str())) { + Log::error("Failed to write obj usemtl %s\n", hashId.c_str()); + return false; + } for (int i = 0; i < nv; ++i) { const voxel::VoxelVertex &v = vertices[i]; @@ -175,11 +180,18 @@ bool OBJFormat::saveMeshes(const core::Map &, const SceneGraph &sceneG } idxOffset += nv; - if (!writeMtlFile(mtlname, palettename)) { - return false; - } - if (!palette.save(palettename.c_str())) { - return false; + if (paletteMaterialIndices.find(palette.hash()) == paletteMaterialIndices.end()) { + core::String palettename = core::string::stripExtension(filename); + palettename.append(hashId); + palettename.append(".png"); + paletteMaterialIndices.put(palette.hash(), 1); + const core::String &mapKd = core::string::extractFilenameWithExtension(palettename); + if (!writeMtlFile(matlstream, hashId, mapKd)) { + return false; + } + if (!palette.save(palettename.c_str())) { + return false; + } } } return true; diff --git a/src/modules/voxelformat/OBJFormat.h b/src/modules/voxelformat/OBJFormat.h index a41fa66f2..ff27bbd78 100644 --- a/src/modules/voxelformat/OBJFormat.h +++ b/src/modules/voxelformat/OBJFormat.h @@ -5,6 +5,7 @@ #pragma once #include "MeshFormat.h" +#include "io/Stream.h" namespace tinyobj { struct mesh_t; @@ -18,7 +19,7 @@ namespace voxelformat { */ class OBJFormat : public MeshFormat { private: - bool writeMtlFile(const core::String& mtlName, const core::String &paletteName) const; + bool writeMtlFile(io::SeekableWriteStream &stream, const core::String &mtlId, const core::String &mapKd) const; static void calculateAABB(const tinyobj::mesh_t &mesh, const tinyobj::attrib_t &attrib, glm::vec3 &mins, glm::vec3 &maxs); static void subdivideShape(const tinyobj::mesh_t &mesh, const core::StringMap &textures, diff --git a/src/modules/voxelformat/PLYFormat.cpp b/src/modules/voxelformat/PLYFormat.cpp index 451674a55..32a34c638 100644 --- a/src/modules/voxelformat/PLYFormat.cpp +++ b/src/modules/voxelformat/PLYFormat.cpp @@ -65,7 +65,7 @@ bool PLYFormat::saveMeshes(const core::Map &, const SceneGraph &sceneG const SceneGraphNode &graphNode = sceneGraph.node(meshExt.nodeId); const voxel::Palette &palette = graphNode.palette(); // 1 x 256 is the texture format that we are using for our palette - const float texcoord = 1.0f / (float)palette.colorCount; + const float texcoord = 1.0f / (float)voxel::PaletteMaxColors; // it is only 1 pixel high - sample the middle const float v1 = 0.5f;