23#ifndef VCL_IO_MESH_OBJ_SAVE_H
24#define VCL_IO_MESH_OBJ_SAVE_H
28#include <vclib/io/file_info.h>
29#include <vclib/io/image/save.h>
30#include <vclib/io/mesh/settings.h>
31#include <vclib/io/write.h>
33#include <vclib/space/complex.h>
34#include <vclib/space/core.h>
40template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
41std::vector<std::string> saveObjMaterials(
43 const std::string& meshBasePath,
47 std::vector<std::string> materials;
48 if constexpr (HasMaterials<MeshType>) {
49 materials.reserve(m.materialsNumber());
50 for (uint i = 0; i < m.materialsNumber(); ++i) {
51 const Material& mat = m.material(i);
52 ObjMaterial omat(mat, i);
53 std::string matName = mat.name();
54 if (matName.empty()) {
55 matName =
"MATERIAL_" + std::to_string(i);
56 omat.matName = matName;
59 mtlfp <<
"newmtl " << matName << std::endl;
60 mtlfp << omat << std::endl;
61 materials.push_back(matName);
67template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
70 const std::string& filename,
74 const SaveSettings& settings = SaveSettings(),
86 if (!settings.info.isEmpty())
87 meshInfo = settings.info.intersect(meshInfo);
92 if (meshInfo.hasPerVertexTexCoord() &&
93 meshInfo.hasPerFaceWedgeTexCoords()) {
94 meshInfo.setPerVertexTexCoord(
false);
97 std::ofstream mtlftmp;
99 std::vector<std::string> materialNames;
101 bool useMtl = meshInfo.hasMaterials();
104 std::string mtlFileName =
107 mtlftmp = openOutputFileStream(
111 fp <<
"mtllib ./" << mtlFileName << std::endl;
113 else if (mtlfp ==
nullptr) {
119 materialNames = saveObjMaterials(m, meshBasePath, *mtlfp, log);
125 using VertexType = MeshType::VertexType;
127 fp << std::endl <<
"# Vertices" << std::endl;
129 for (
const VertexType& v : m.
vertices()) {
131 io::writeDouble(fp, v.position().x(),
false);
132 io::writeDouble(fp, v.position().y(),
false);
133 io::writeDouble(fp, v.position().z(),
false);
134 if constexpr (HasPerVertexColor<MeshType>) {
135 if (meshInfo.hasPerVertexColor()) {
136 io::writeFloat(fp, v.color().redF(),
false);
137 io::writeFloat(fp, v.color().greenF(),
false);
138 io::writeFloat(fp, v.color().blueF(),
false);
143 if constexpr (HasPerVertexNormal<MeshType>) {
144 if (meshInfo.hasPerVertexNormal()) {
146 io::writeDouble(fp, v.normal().x(),
false);
147 io::writeDouble(fp, v.normal().y(),
false);
148 io::writeDouble(fp, v.normal().z(),
false);
152 if constexpr (HasPerVertexTexCoord<MeshType>) {
153 if (meshInfo.hasPerVertexTexCoord()) {
155 io::writeFloat(fp, v.texCoord().u(),
false);
156 io::writeFloat(fp, v.texCoord().v(),
false);
163 if constexpr (HasFaces<MeshType>) {
164 using VertexType = MeshType::VertexType;
165 using FaceType = MeshType::FaceType;
167 if (meshInfo.hasFaces()) {
168 fp << std::endl <<
"# Faces" << std::endl;
171 std::vector<uint> vIndices = m.vertexCompactIndices();
173 uint wedgeTexCoord = 1;
174 for (
const FaceType& f : m.
faces()) {
175 if constexpr (HasMaterials<MeshType>) {
177 if (f.materialIndex() != lastMaterial) {
178 lastMaterial = f.materialIndex();
179 fp <<
"usemtl " << materialNames[lastMaterial]
184 if constexpr (HasPerFaceWedgeTexCoords<MeshType>) {
185 if (meshInfo.hasPerFaceWedgeTexCoords()) {
186 using WedgeTexCoordType = FaceType::WedgeTexCoordType;
187 for (
const WedgeTexCoordType wt : f.wedgeTexCoords()) {
189 io::writeFloat(fp, wt.u(),
false);
190 io::writeFloat(fp, wt.v(),
false);
197 for (
const VertexType* v : f.
vertices()) {
198 fp << vIndices[m.index(v)] + 1;
199 if constexpr (HasPerVertexTexCoord<MeshType>) {
202 if (meshInfo.hasPerVertexTexCoord()) {
203 fp <<
"/" << vIndices[m.index(v)] + 1;
206 if constexpr (HasPerFaceWedgeTexCoords<MeshType>) {
210 if (meshInfo.hasPerFaceWedgeTexCoords()) {
211 fp <<
"/" << wedgeTexCoord++;
221 if constexpr (HasEdges<MeshType>) {
222 using VertexType = MeshType::VertexType;
223 using EdgeType = MeshType::EdgeType;
225 if (meshInfo.hasEdges()) {
226 fp << std::endl <<
"# Edges" << std::endl;
229 std::vector<uint> vIndices = m.vertexCompactIndices();
231 for (
const EdgeType& e : m.
edges()) {
233 fp << vIndices[m.index(e.vertex(0))] + 1 <<
" ";
234 fp << vIndices[m.index(e.vertex(1))] + 1 << std::endl;
239 if constexpr (HasMaterials<MeshType>) {
240 if (useMtl && settings.saveTextureImages) {
242 saveTextureImages(m, meshBasePath, {BASE_COLOR, EMISSIVE}, log);
249template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
254 const SaveSettings& settings,
257 detail::saveObj(m,
"materials", fp, &mtlfp,
false, settings, log);
260template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
264 const SaveSettings& settings,
267 detail::saveObj(m,
"", fp,
nullptr,
false, settings, log);
270template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
273 const std::string& filename,
274 const SaveSettings& settings,
277 std::ofstream fp = openOutputFileStream(filename,
"obj");
279 detail::saveObj(m, filename, fp,
nullptr,
true, settings, log);
static std::string fileNameWithExtension(const std::string &fullpath)
Get the filename with extension of a file.
Definition file_info.h:240
static std::string pathWithoutFileName(const std::string &fullpath)
Get the path of a file.
Definition file_info.h:200
TextureType
Defines the types of textures used in the PBR material model.
Definition material.h:62
NullLogger nullLogger
The nullLogger object is an object of type NullLogger that is used as default argument in the functio...
Definition null_logger.h:123
constexpr uint UINT_NULL
The UINT_NULL value represent a null value of uint that is the maximum value that can be represented ...
Definition base.h:48
constexpr detail::FacesView faces
A view that allows to iterate overt the Face elements of an object.
Definition face.h:84
constexpr detail::EdgesView edges
A view that allows to iterate overt the Edge elements of an object.
Definition edge.h:84
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:92