23#ifndef VCL_LOAD_SAVE_OBJ_SAVE_H
24#define VCL_LOAD_SAVE_OBJ_SAVE_H
28#include <vclib/exceptions/io.h>
29#include <vclib/io/file_info.h>
30#include <vclib/io/write.h>
31#include <vclib/load_save/settings.h>
32#include <vclib/misc/logger.h>
33#include <vclib/space/complex/mesh_info.h>
34#include <vclib/space/core/texture.h>
42template<VertexConcept VertexType, MeshConcept MeshType>
43ObjMaterial objMaterialFromVertex(
49 if constexpr (HasPerVertexColor<MeshType>) {
50 if (fi.hasVertexColors()) {
52 mat.Kd.x() = v.color().redF();
53 mat.Kd.y() = v.color().greenF();
54 mat.Kd.z() = v.color().blueF();
57 if constexpr (HasPerVertexTexCoord<MeshType>) {
58 if (fi.hasVertexTexCoords()) {
59 mat.hasTexture =
true;
60 if constexpr (HasTexturePaths<MeshType>) {
61 mat.map_Kd = m.texturePath(v.texCoord().index());
68template<FaceConcept FaceType, MeshConcept MeshType>
69ObjMaterial objMaterialFromFace(
75 if constexpr (HasPerFaceColor<MeshType>) {
76 if (fi.hasFaceColors()) {
78 mat.Kd.x() = f.color().redF();
79 mat.Kd.y() = f.color().greenF();
80 mat.Kd.z() = f.color().blueF();
83 if constexpr (HasPerFaceWedgeTexCoords<MeshType>) {
84 if (fi.hasFaceWedgeTexCoords()) {
85 mat.hasTexture =
true;
86 if constexpr (HasTexturePaths<MeshType>) {
87 mat.map_Kd = m.texturePath(f.textureIndex());
94template<EdgeConcept EdgeType, MeshConcept MeshType>
95ObjMaterial objMaterialFromEdge(
const EdgeType& e,
const MeshInfo& fi)
98 if constexpr (HasPerEdgeColor<MeshType>) {
99 if (fi.hasEdgeColors()) {
101 mat.Kd.x() = e.color().redF();
102 mat.Kd.y() = e.color().greenF();
103 mat.Kd.z() = e.color().blueF();
110 ElementConcept ElementType,
111 MeshConcept MeshType,
112 LoggerConcept LogType = NullLogger>
113void writeElementObjMaterial(
114 const ElementType& e,
117 ObjMaterial& lastMaterial,
118 std::map<ObjMaterial, std::string>& materialMap,
121 const SaveSettings& settings,
125 constexpr bool EL_IS_VERTEX = ElementType::ELEMENT_ID == ElemId::VERTEX;
126 constexpr bool EL_IS_FACE = ElementType::ELEMENT_ID == ElemId::FACE;
127 constexpr bool EL_IS_EDGE = ElementType::ELEMENT_ID == ElemId::EDGE;
129 if constexpr (EL_IS_VERTEX) {
130 mat = objMaterialFromVertex<typename MeshType::VertexType, MeshType>(
133 if constexpr (EL_IS_FACE) {
134 mat = objMaterialFromFace(e, m, fi);
136 if constexpr (EL_IS_EDGE) {
137 mat = objMaterialFromEdge<typename MeshType::EdgeType, MeshType>(e, fi);
139 if (!mat.isEmpty()) {
140 static const std::string MATERIAL_PREFIX =
"MATERIAL_";
142 auto it = materialMap.find(mat);
143 if (it == materialMap.end()) {
145 mname = MATERIAL_PREFIX + std::to_string(materialMap.size());
146 materialMap[mat] = mname;
148 mtlfp <<
"newmtl " << mname << std::endl;
149 mtlfp << mat << std::endl;
150 if constexpr (HasTextureImages<MeshType>) {
151 if (settings.saveTextureImages && mat.hasTexture) {
155 uint textureIndex = 0;
156 if constexpr (EL_IS_FACE) {
157 textureIndex = e.textureIndex();
159 const Texture& t = m.texture(textureIndex);
161 t.image().save(m.meshBasePath() + mat.map_Kd);
163 catch (
const std::runtime_error& e) {
164 log.log(e.what(), LogType::WARNING_LOG);
174 if (mat != lastMaterial) {
176 fp <<
"usemtl " << mname << std::endl;
181template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
184 const std::string& filename,
189 const SaveSettings& settings = SaveSettings())
191 MeshInfo meshInfo(m);
197 if (!settings.info.isEmpty())
198 meshInfo = settings.info.intersect(meshInfo);
203 if (meshInfo.hasVertexTexCoords() && meshInfo.hasFaceWedgeTexCoords()) {
204 meshInfo.setVertexTexCoords(
false);
207 std::ofstream mtlftmp;
208 std::map<detail::ObjMaterial, std::string> materialMap;
211 meshInfo.hasVertexColors() || meshInfo.hasFaceColors() ||
212 (meshInfo.hasTextures() &&
213 (meshInfo.hasVertexTexCoords() || meshInfo.hasFaceWedgeTexCoords()));
216 std::string mtlFileName =
219 mtlftmp = openOutputFileStream(
223 fp <<
"mtllib ./" << mtlFileName << std::endl;
225 else if (mtlfp ==
nullptr) {
230 detail::ObjMaterial lastMaterial;
233 using VertexType = MeshType::VertexType;
235 fp << std::endl <<
"# Vertices" << std::endl;
237 for (
const VertexType& v : m.
vertices()) {
239 detail::writeElementObjMaterial<VertexType, MeshType>(
251 io::writeDouble(fp, v.coord().x(),
false);
252 io::writeDouble(fp, v.coord().y(),
false);
253 io::writeDouble(fp, v.coord().z(),
false);
256 if constexpr (HasPerVertexNormal<MeshType>) {
257 if (meshInfo.hasVertexNormals()) {
259 io::writeDouble(fp, v.normal().x(),
false);
260 io::writeDouble(fp, v.normal().y(),
false);
261 io::writeDouble(fp, v.normal().z(),
false);
265 if constexpr (HasPerVertexTexCoord<MeshType>) {
266 if (meshInfo.hasVertexTexCoords()) {
268 io::writeFloat(fp, v.texCoord().u(),
false);
269 io::writeFloat(fp, v.texCoord().v(),
false);
276 if constexpr (HasFaces<MeshType>) {
277 using VertexType = MeshType::VertexType;
278 using FaceType = MeshType::FaceType;
280 fp << std::endl <<
"# Faces" << std::endl;
283 std::vector<uint> vIndices = m.vertexCompactIndices();
285 uint wedgeTexCoord = 1;
286 for (
const FaceType& f : m.
faces()) {
288 detail::writeElementObjMaterial(
299 if constexpr (HasPerFaceWedgeTexCoords<MeshType>) {
300 if (meshInfo.hasFaceWedgeTexCoords()) {
301 using WedgeTexCoordType = FaceType::WedgeTexCoordType;
302 for (
const WedgeTexCoordType wt : f.wedgeTexCoords()) {
304 io::writeFloat(fp, wt.u(),
false);
305 io::writeFloat(fp, wt.v(),
false);
312 for (
const VertexType* v : f.
vertices()) {
313 fp << vIndices[m.index(v)] + 1;
314 if constexpr (HasPerVertexTexCoord<MeshType>) {
317 if (meshInfo.hasVertexTexCoords()) {
318 fp <<
"/" << vIndices[m.index(v)] + 1;
321 if constexpr (HasPerFaceWedgeTexCoords<MeshType>) {
325 if (meshInfo.hasFaceWedgeTexCoords()) {
326 fp <<
"/" << wedgeTexCoord++;
335 if constexpr (HasEdges<MeshType>) {
336 using VertexType = MeshType::VertexType;
337 using EdgeType = MeshType::EdgeType;
339 fp << std::endl <<
"# Edges" << std::endl;
342 std::vector<uint> vIndices = m.vertexCompactIndices();
344 for (
const EdgeType& e : m.
edges()) {
346 detail::writeElementObjMaterial(
358 fp << vIndices[m.index(e.vertex(0))] + 1 <<
" ";
359 fp << vIndices[m.index(e.vertex(1))] + 1 << std::endl;
366template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
371 const SaveSettings& settings,
374 detail::saveObj(m,
"materials", fp, &mtlfp,
false, log, settings);
377template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
383 const SaveSettings& settings = SaveSettings())
385 detail::saveObj(m,
"materials", fp, &mtlfp,
false, log, settings);
388template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
392 const SaveSettings& settings,
395 detail::saveObj(m,
"", fp,
nullptr,
false, log, settings);
398template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
403 const SaveSettings& settings = SaveSettings())
405 detail::saveObj(m,
"", fp,
nullptr,
false, log, settings);
408template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
411 const std::string& filename,
412 const SaveSettings& settings,
415 std::ofstream fp = openOutputFileStream(filename,
"obj");
417 detail::saveObj(m, filename, fp,
nullptr,
true, log, settings);
420template<MeshConcept MeshType, LoggerConcept LogType = NullLogger>
423 const std::string& filename,
425 const SaveSettings& settings = SaveSettings())
427 std::ofstream fp = openOutputFileStream(filename,
"obj");
429 detail::saveObj(m, filename, fp,
nullptr,
true, log, settings);
static std::string fileNameWithExtension(const std::string &fullpath)
Get the filename with extension of a file.
Definition file_info.h:237
static std::string pathWithoutFileName(const std::string &fullpath)
Get the path of a file.
Definition file_info.h:197
NullLogger nullLogger
The nullLogger object is an object of type NullLogger that is used as default argument in the functio...
Definition null_logger.h:125
constexpr detail::FacesView faces
A view that allows to iterate overt the Face elements of an object.
Definition face.h:52
constexpr detail::EdgesView edges
A view that allows to iterate overt the Edge elements of an object.
Definition edge.h:52
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:60