From f4e85127d6e904c321a8360b995dc3d62b2bd589 Mon Sep 17 00:00:00 2001 From: EvilSpirit Date: Mon, 4 Jul 2016 12:02:30 +0600 Subject: [PATCH] Wavefront OBJ: export mesh color as well. --- CHANGELOG.md | 2 ++ src/dsc.h | 5 ++++ src/export.cpp | 74 +++++++++++++++++++++++++++++++++--------------- src/solvespace.h | 2 +- 4 files changed, 59 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a9a854..2cbda8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ Changelog New export/import features: * Three.js: allow configuring projection for exported model, and initially use the current viewport projection. + * Wavefront OBJ: a material file is exported alongside the model, containing + mesh color information. New rendering features: * The "Show/hide hidden lines" button is now a tri-state button that allows diff --git a/src/dsc.h b/src/dsc.h index d8d76fb..3a895b4 100644 --- a/src/dsc.h +++ b/src/dsc.h @@ -532,7 +532,12 @@ public: (int)((bgra) & 0xff), (int)(255 - ((bgra >> 24) & 0xff))); } +}; +struct RgbaColorCompare { + bool operator()(RgbaColor a, RgbaColor b) const { + return a.ToARGB32() < b.ToARGB32(); + } }; class BBox { diff --git a/src/export.cpp b/src/export.cpp index a604fec..f95d197 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -816,7 +816,18 @@ void SolveSpaceUI::ExportMeshTo(const std::string &filename) { if(FilenameHasExtension(filename, ".stl")) { ExportMeshAsStlTo(f, m); } else if(FilenameHasExtension(filename, ".obj")) { - ExportMeshAsObjTo(f, m); + std::string mtlFilename = filename.substr(0, filename.length() - 4) + ".mtl"; + FILE *fMtl = ssfopen(mtlFilename, "wb"); + if(!fMtl) { + Error("Couldn't write to '%s'", filename.c_str()); + return; + } + + std::string mtlBasename = mtlFilename.substr(mtlFilename.rfind(PATH_SEP) + 1); + fprintf(f, "mtllib %s\n", mtlBasename.c_str()); + ExportMeshAsObjTo(f, fMtl, m); + + fclose(fMtl); } else if(FilenameHasExtension(filename, ".js") || FilenameHasExtension(filename, ".html")) { SOutlineList *e = &(SK.GetGroup(SS.GW.activeGroup)->displayOutlines); @@ -872,34 +883,51 @@ void SolveSpaceUI::ExportMeshAsStlTo(FILE *f, SMesh *sm) { // Export the mesh as Wavefront OBJ format. This requires us to reduce all the // identical vertices to the same identifier, so do that first. //----------------------------------------------------------------------------- -void SolveSpaceUI::ExportMeshAsObjTo(FILE *f, SMesh *sm) { - SPointList spl = {}; - STriangle *tr; - for(tr = sm->l.First(); tr; tr = sm->l.NextAfter(tr)) { - spl.IncrementTagFor(tr->a); - spl.IncrementTagFor(tr->b); - spl.IncrementTagFor(tr->c); +void SolveSpaceUI::ExportMeshAsObjTo(FILE *fObj, FILE *fMtl, SMesh *sm) { + std::map colors; + for(const STriangle &t : sm->l) { + RgbaColor color = t.meta.color; + if(colors.find(color) == colors.end()) { + std::string id = ssprintf("h%02x%02x%02x", + color.red, + color.green, + color.blue); + colors.emplace(color, id); + } + for(int i = 0; i < 3; i++) { + fprintf(fObj, "v %.10f %.10f %.10f\n", + CO(t.vertices[i].ScaledBy(1 / SS.exportScale))); + } } - // Output all the vertices. - SPoint *sp; - for(sp = spl.l.First(); sp; sp = spl.l.NextAfter(sp)) { - fprintf(f, "v %.10f %.10f %.10f\r\n", - sp->p.x / SS.exportScale, - sp->p.y / SS.exportScale, - sp->p.z / SS.exportScale); + for(auto &it : colors) { + fprintf(fMtl, "newmtl %s\n", + it.second.c_str()); + fprintf(fMtl, "Kd %.3f %.3f %.3f\n", + it.first.redF(), it.first.greenF(), it.first.blueF()); } - // And now all the triangular faces, in terms of those vertices. The - // file format counts from 1, not 0. - for(tr = sm->l.First(); tr; tr = sm->l.NextAfter(tr)) { - fprintf(f, "f %d %d %d\r\n", - spl.IndexForPoint(tr->a) + 1, - spl.IndexForPoint(tr->b) + 1, - spl.IndexForPoint(tr->c) + 1); + for(const STriangle &t : sm->l) { + for(int i = 0; i < 3; i++) { + Vector n = t.normals[i].WithMagnitude(1.0); + fprintf(fObj, "vn %.10f %.10f %.10f\n", + CO(n)); + } } - spl.Clear(); + RgbaColor currentColor = {}; + for(int i = 0; i < sm->l.n; i++) { + const STriangle &t = sm->l.elem[i]; + if(!currentColor.Equals(t.meta.color)) { + currentColor = t.meta.color; + fprintf(fObj, "usemtl %s\n", colors[currentColor].c_str()); + } + + fprintf(fObj, "f %d//%d %d//%d %d//%d\n", + i * 3 + 1, i * 3 + 1, + i * 3 + 2, i * 3 + 2, + i * 3 + 3, i * 3 + 3); + } } //----------------------------------------------------------------------------- diff --git a/src/solvespace.h b/src/solvespace.h index 9b8a10f..8249047 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -815,7 +815,7 @@ public: void ExportAsPngTo(const std::string &filename); void ExportMeshTo(const std::string &filename); void ExportMeshAsStlTo(FILE *f, SMesh *sm); - void ExportMeshAsObjTo(FILE *f, SMesh *sm); + void ExportMeshAsObjTo(FILE *fObj, FILE *fMtl, SMesh *sm); void ExportMeshAsThreeJsTo(FILE *f, const std::string &filename, SMesh *sm, SOutlineList *sol); void ExportViewOrWireframeTo(const std::string &filename, bool exportWireframe);