From 441eb8e8dac786ec2f399fb0e3c17dfb7a86048c Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 10 Feb 2016 15:09:04 +0100 Subject: [PATCH] + support of colors per vertex in obj mesh format --- src/Mod/Mesh/App/Core/MeshIO.cpp | 124 +++++++++++++++++++++++-------- 1 file changed, 92 insertions(+), 32 deletions(-) diff --git a/src/Mod/Mesh/App/Core/MeshIO.cpp b/src/Mod/Mesh/App/Core/MeshIO.cpp index cf60bd6d70..183188fb7a 100644 --- a/src/Mod/Mesh/App/Core/MeshIO.cpp +++ b/src/Mod/Mesh/App/Core/MeshIO.cpp @@ -232,6 +232,10 @@ bool MeshInput::LoadOBJ (std::istream &rstrIn) boost::regex rx_p("^v\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)\\s*$"); + boost::regex rx_c("^v\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" + "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" + "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" + "\\s+(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s*$"); boost::regex rx_f3("^f\\s+([0-9]+)/?[0-9]*/?[0-9]*" "\\s+([0-9]+)/?[0-9]*/?[0-9]*" "\\s+([0-9]+)/?[0-9]*/?[0-9]*\\s*$"); @@ -258,6 +262,7 @@ bool MeshInput::LoadOBJ (std::istream &rstrIn) if (!buf) return false; + MeshIO::Binding rgb_value = MeshIO::OVERALL; bool readvertices=false; while (std::getline(rstrIn, line)) { for (std::string::iterator it = line.begin(); it != line.end(); ++it) @@ -269,6 +274,21 @@ bool MeshInput::LoadOBJ (std::istream &rstrIn) fZ = (float)std::atof(what[7].first); meshPoints.push_back(MeshPoint(Base::Vector3f(fX, fY, fZ))); } + else if (boost::regex_match(line.c_str(), what, rx_c)) { + readvertices = true; + fX = (float)std::atof(what[1].first); + fY = (float)std::atof(what[4].first); + fZ = (float)std::atof(what[7].first); + float r = std::min(std::atof(what[10].first),255) / 255.0f; + float g = std::min(std::atof(what[11].first),255) / 255.0f; + float b = std::min(std::atof(what[12].first),255) / 255.0f; + meshPoints.push_back(MeshPoint(Base::Vector3f(fX, fY, fZ))); + + App::Color c(r,g,b); + unsigned long prop = static_cast(c.getPackedValue()); + meshPoints.back().SetProperty(prop); + rgb_value = MeshIO::PER_VERTEX; + } else if (boost::regex_match(line.c_str(), what, rx_f3)) { // starts a new segment if (readvertices) { @@ -307,26 +327,22 @@ bool MeshInput::LoadOBJ (std::istream &rstrIn) } } - this->_rclMesh.Clear(); // remove all data before - // Don't use Assign() because Merge() checks which points are really needed. - // This method sets already the correct neighbourhood - unsigned long ct = meshPoints.size(); - std::list removeFaces; - for (MeshFacetArray::_TConstIterator it = meshFacets.begin(); it != meshFacets.end(); ++it) { - bool ok = true; - for (int i=0;i<3;i++) { - if (it->_aulPoints[i] >= ct) { - Base::Console().Warning("Face index %lu out of range\n", it->_aulPoints[i]); - ok = false; + // now get back the colors from the vertex property + if (rgb_value == MeshIO::PER_VERTEX) { + if (_material) { + _material->binding = MeshIO::PER_VERTEX; + _material->diffuseColor.reserve(meshPoints.size()); + + for (MeshPointArray::iterator it = meshPoints.begin(); it != meshPoints.end(); ++it) { + unsigned long prop = it->_ulProp; + App::Color c; + c.setPackedValue(static_cast(prop)); + _material->diffuseColor.push_back(c); } } - - if (!ok) - removeFaces.push_front(it-meshFacets.begin()); } - for (std::list::iterator it = removeFaces.begin(); it != removeFaces.end(); ++it) - meshFacets.erase(meshFacets.begin() + *it); + this->_rclMesh.Clear(); // remove all data before MeshKernel tmp; tmp.Adopt(meshPoints,meshFacets); @@ -1736,36 +1752,80 @@ bool MeshOutput::SaveBinarySTL (std::ostream &rstrOut) const } /** Saves an OBJ file. */ -bool MeshOutput::SaveOBJ (std::ostream &rstrOut) const +bool MeshOutput::SaveOBJ (std::ostream &out) const { const MeshPointArray& rPoints = _rclMesh.GetPoints(); const MeshFacetArray& rFacets = _rclMesh.GetFacets(); - if (!rstrOut || rstrOut.bad() == true) + if (!out || out.bad() == true) return false; - Base::SequencerLauncher seq("saving...", _rclMesh.CountPoints() + _rclMesh.CountFacets()); + Base::SequencerLauncher seq("saving...", _rclMesh.CountPoints() + _rclMesh.CountFacets()); + bool exportColor = false; + if (_material) { + if (_material->binding == MeshIO::PER_FACE) { + Base::Console().Warning("Cannot export color information because it's defined per face"); + } + else if (_material->binding == MeshIO::PER_VERTEX) { + if (_material->diffuseColor.size() != rPoints.size()) { + Base::Console().Warning("Cannot export color information because there is a different number of points and colors"); + } + else { + exportColor = true; + } + } + else if (_material->binding == MeshIO::OVERALL) { + if (_material->diffuseColor.empty()) { + Base::Console().Warning("Cannot export color information because there is no color defined"); + } + else { + exportColor = true; + } + } + } + + // Header + out << "# Created by FreeCAD " << std::endl; + out.precision(6); + out.setf(std::ios::fixed | std::ios::showpoint); // vertices - if (this->apply_transform) { - Base::Vector3f pt; - for (MeshPointArray::_TConstIterator it = rPoints.begin(); it != rPoints.end(); ++it) { + Base::Vector3f pt; + std::size_t index = 0; + for (MeshPointArray::_TConstIterator it = rPoints.begin(); it != rPoints.end(); ++it, ++index) { + if (this->apply_transform) { pt = this->_transform * *it; - rstrOut << "v " << pt.x << " " << pt.y << " " << pt.z << std::endl; - seq.next(true); // allow to cancel } - } - else { - for (MeshPointArray::_TConstIterator it = rPoints.begin(); it != rPoints.end(); ++it) { - rstrOut << "v " << it->x << " " << it->y << " " << it->z << std::endl; - seq.next(true); // allow to cancel + else { + pt.Set(it->x, it->y, it->z); } + + if (exportColor) { + App::Color c; + if (_material->binding == MeshIO::PER_VERTEX) { + c = _material->diffuseColor[index]; + } + else { + c = _material->diffuseColor.front(); + } + + int r = static_cast(c.r * 255.0f); + int g = static_cast(c.g * 255.0f); + int b = static_cast(c.b * 255.0f); + + out << "v " << pt.x << " " << pt.y << " " << pt.z << " " << r << " " << g << " " << b << std::endl; + } + else { + out << "v " << pt.x << " " << pt.y << " " << pt.z << std::endl; + } + seq.next(true); // allow to cancel } + // facet indices (no texture and normal indices) for (MeshFacetArray::_TConstIterator it = rFacets.begin(); it != rFacets.end(); ++it) { - rstrOut << "f " << it->_aulPoints[0]+1 << " " - << it->_aulPoints[1]+1 << " " - << it->_aulPoints[2]+1 << std::endl; + out << "f " << it->_aulPoints[0]+1 << " " + << it->_aulPoints[1]+1 << " " + << it->_aulPoints[2]+1 << std::endl; seq.next(true); // allow to cancel }