Mesh: Improve OBJ mesh import
This change allows it to load OBJ files created by Blender. Fixes https://github.com/FreeCAD/FreeCAD/issues/19456
This commit is contained in:
@@ -22,14 +22,18 @@
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
#include <istream>
|
||||
#include <map>
|
||||
#endif
|
||||
|
||||
#include "Core/MeshIO.h"
|
||||
#include "Core/MeshKernel.h"
|
||||
#include <Base/Color.h>
|
||||
#include <Base/FileInfo.h>
|
||||
#include <Base/Stream.h>
|
||||
#include <Base/Tools.h>
|
||||
|
||||
#include "ReaderOBJ.h"
|
||||
@@ -37,47 +41,322 @@
|
||||
|
||||
using namespace MeshCore;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class ReaderOBJImp
|
||||
{
|
||||
public:
|
||||
using string_list = std::vector<std::string>;
|
||||
|
||||
explicit ReaderOBJImp(Material* material)
|
||||
: _material {material}
|
||||
{}
|
||||
|
||||
void Load(const std::string& line)
|
||||
{
|
||||
if (Ignore(line)) {
|
||||
return;
|
||||
}
|
||||
|
||||
boost::char_separator<char> sep(" /\t");
|
||||
boost::tokenizer<boost::char_separator<char>> tokens(line, sep);
|
||||
token_results.assign(tokens.begin(), tokens.end());
|
||||
if (token_results.size() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (MatchVertex(token_results)) {
|
||||
LoadVertex(token_results);
|
||||
}
|
||||
else if (MatchVertexWithColor(token_results)) {
|
||||
LoadVertexWithColor(token_results);
|
||||
}
|
||||
else if (MatchGroup(token_results)) {
|
||||
LoadGroup(token_results);
|
||||
}
|
||||
else if (MatchLibrary(token_results)) {
|
||||
LoadLibrary(token_results);
|
||||
}
|
||||
else if (MatchUseMaterial(token_results)) {
|
||||
LoadUseMaterial(token_results);
|
||||
}
|
||||
else if (MatchFace(token_results)) {
|
||||
LoadFace(token_results);
|
||||
}
|
||||
else if (MatchQuad(token_results)) {
|
||||
LoadQuad(token_results);
|
||||
}
|
||||
}
|
||||
|
||||
void SetupMaterial()
|
||||
{
|
||||
// Add the last added material name
|
||||
if (!materialName.empty()) {
|
||||
_materialNames.emplace_back(materialName, countMaterialFacets);
|
||||
}
|
||||
|
||||
// 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 (const auto& it : meshPoints) {
|
||||
unsigned long prop = it._ulProp;
|
||||
Base::Color c;
|
||||
c.setPackedValue(static_cast<uint32_t>(prop));
|
||||
_material->diffuseColor.push_back(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!materialName.empty()) {
|
||||
// At this point the materials from the .mtl file are not known and will be read-in by
|
||||
// the calling instance but the color list is pre-filled with a default value
|
||||
if (_material) {
|
||||
_material->binding = MeshIO::PER_FACE;
|
||||
const float rgb = 0.8F;
|
||||
_material->diffuseColor.resize(meshFacets.size(), Base::Color(rgb, rgb, rgb));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool Ignore(const std::string& line) const
|
||||
{
|
||||
// clang-format off
|
||||
return boost::starts_with(line, "vn ") ||
|
||||
boost::starts_with(line, "vt ") ||
|
||||
boost::starts_with(line, "s ") ||
|
||||
boost::starts_with(line, "o ") ||
|
||||
boost::starts_with(line, "#");
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
bool MatchVertex(const string_list& tokens) const
|
||||
{
|
||||
return tokens[0] == "v" && tokens.size() == 4;
|
||||
}
|
||||
|
||||
void LoadVertex(const string_list& tokens)
|
||||
{
|
||||
float x = std::stof(tokens[1]);
|
||||
float y = std::stof(tokens[2]);
|
||||
float z = std::stof(tokens[3]);
|
||||
meshPoints.push_back(MeshPoint(Base::Vector3f(x, y, z)));
|
||||
}
|
||||
|
||||
bool MatchVertexWithColor(const string_list& tokens) const
|
||||
{
|
||||
return tokens[0] == "v" && tokens.size() == 7; // NOLINT
|
||||
}
|
||||
|
||||
void LoadVertexWithColor(const string_list& tokens)
|
||||
{
|
||||
LoadVertex(tokens);
|
||||
|
||||
// NOLINTBEGIN
|
||||
float r = std::stof(tokens[4]);
|
||||
float g = std::stof(tokens[5]);
|
||||
float b = std::stof(tokens[6]);
|
||||
if (r > 1.0F || g > 1.0F || b > 1.0F) {
|
||||
r /= 255.0F;
|
||||
g /= 255.0F;
|
||||
b /= 255.0F;
|
||||
}
|
||||
// NOLINTEND
|
||||
|
||||
SetVertexColor(Base::Color(r, g, b));
|
||||
}
|
||||
|
||||
void SetVertexColor(const Base::Color& c)
|
||||
{
|
||||
unsigned long prop = static_cast<uint32_t>(c.getPackedValue());
|
||||
meshPoints.back().SetProperty(prop);
|
||||
rgb_value = MeshIO::PER_VERTEX;
|
||||
}
|
||||
|
||||
bool MatchGroup(const string_list& tokens) const
|
||||
{
|
||||
return tokens[0] == "g" && tokens.size() == 2;
|
||||
}
|
||||
|
||||
void LoadGroup(const string_list& tokens)
|
||||
{
|
||||
new_segment = true;
|
||||
groupName = Base::Tools::escapedUnicodeToUtf8(tokens[1]);
|
||||
}
|
||||
|
||||
bool MatchLibrary(const string_list& tokens) const
|
||||
{
|
||||
return tokens[0] == "mtllib" && tokens.size() == 2;
|
||||
}
|
||||
|
||||
void LoadLibrary(const string_list& tokens)
|
||||
{
|
||||
if (_material) {
|
||||
_material->library = Base::Tools::escapedUnicodeToUtf8(tokens[1]);
|
||||
}
|
||||
}
|
||||
|
||||
bool MatchUseMaterial(const string_list& tokens) const
|
||||
{
|
||||
return tokens[0] == "usemtl" && tokens.size() == 2;
|
||||
}
|
||||
|
||||
void LoadUseMaterial(const string_list& tokens)
|
||||
{
|
||||
if (!materialName.empty()) {
|
||||
_materialNames.emplace_back(materialName, countMaterialFacets);
|
||||
}
|
||||
materialName = Base::Tools::escapedUnicodeToUtf8(tokens[1]);
|
||||
countMaterialFacets = 0;
|
||||
}
|
||||
|
||||
bool MatchFace(const string_list& tokens) const
|
||||
{
|
||||
// NOLINTBEGIN
|
||||
const auto num = tokens.size();
|
||||
return tokens[0] == "f" && (num == 4 || num == 7 || num == 10);
|
||||
// NOLINTEND
|
||||
}
|
||||
|
||||
void LoadFace(const string_list& tokens)
|
||||
{
|
||||
StartNewSegment();
|
||||
|
||||
// NOLINTBEGIN
|
||||
int index1 = 1;
|
||||
int index2 = 2;
|
||||
int index3 = 3;
|
||||
if (tokens.size() == 7) {
|
||||
index2 = 3;
|
||||
index3 = 5;
|
||||
}
|
||||
else if (tokens.size() == 10) {
|
||||
index2 = 4;
|
||||
index3 = 7;
|
||||
}
|
||||
// NOLINTEND
|
||||
|
||||
// 3-vertex face
|
||||
int i1 = std::atoi(tokens[index1].c_str());
|
||||
i1 = i1 > 0 ? i1 - 1 : i1 + static_cast<int>(meshPoints.size());
|
||||
int i2 = std::atoi(tokens[index2].c_str());
|
||||
i2 = i2 > 0 ? i2 - 1 : i2 + static_cast<int>(meshPoints.size());
|
||||
int i3 = std::atoi(tokens[index3].c_str());
|
||||
i3 = i3 > 0 ? i3 - 1 : i3 + static_cast<int>(meshPoints.size());
|
||||
|
||||
AddFace(i1, i2, i3);
|
||||
}
|
||||
|
||||
bool MatchQuad(const string_list& tokens) const
|
||||
{
|
||||
// NOLINTBEGIN
|
||||
const auto num = tokens.size();
|
||||
return tokens[0] == "f" && (num == 5 || num == 9 || num == 13);
|
||||
// NOLINTEND
|
||||
}
|
||||
|
||||
void LoadQuad(const string_list& tokens)
|
||||
{
|
||||
StartNewSegment();
|
||||
|
||||
// NOLINTBEGIN
|
||||
int index1 = 1;
|
||||
int index2 = 2;
|
||||
int index3 = 3;
|
||||
int index4 = 4;
|
||||
if (tokens.size() == 9) {
|
||||
index2 = 3;
|
||||
index3 = 5;
|
||||
index4 = 7;
|
||||
}
|
||||
else if (tokens.size() == 13) {
|
||||
index2 = 4;
|
||||
index3 = 7;
|
||||
index4 = 10;
|
||||
}
|
||||
// NOLINTEND
|
||||
|
||||
// 4-vertex face
|
||||
int i1 = std::atoi(tokens[index1].c_str());
|
||||
i1 = i1 > 0 ? i1 - 1 : i1 + static_cast<int>(meshPoints.size());
|
||||
int i2 = std::atoi(tokens[index2].c_str());
|
||||
i2 = i2 > 0 ? i2 - 1 : i2 + static_cast<int>(meshPoints.size());
|
||||
int i3 = std::atoi(tokens[index3].c_str());
|
||||
i3 = i3 > 0 ? i3 - 1 : i3 + static_cast<int>(meshPoints.size());
|
||||
int i4 = std::atoi(tokens[index4].c_str());
|
||||
i4 = i4 > 0 ? i4 - 1 : i4 + static_cast<int>(meshPoints.size());
|
||||
|
||||
AddFace(i1, i2, i3);
|
||||
AddFace(i3, i4, i1);
|
||||
}
|
||||
|
||||
void StartNewSegment()
|
||||
{
|
||||
// starts a new segment
|
||||
if (new_segment) {
|
||||
if (!groupName.empty()) {
|
||||
_groupNames.push_back(groupName);
|
||||
groupName.clear();
|
||||
}
|
||||
new_segment = false;
|
||||
segment++;
|
||||
}
|
||||
}
|
||||
|
||||
void AddFace(int i, int j, int k)
|
||||
{
|
||||
MeshFacet item;
|
||||
item.SetVertices(i, j, k);
|
||||
item.SetProperty(segment);
|
||||
meshFacets.push_back(item);
|
||||
countMaterialFacets++;
|
||||
}
|
||||
|
||||
public:
|
||||
// NOLINTBEGIN
|
||||
MeshPointArray meshPoints;
|
||||
MeshFacetArray meshFacets;
|
||||
// NOLINTEND
|
||||
|
||||
using MaterialPerSegment = std::pair<std::string, unsigned long>;
|
||||
std::vector<MaterialPerSegment> GetMaterialNames() const
|
||||
{
|
||||
return _materialNames;
|
||||
}
|
||||
|
||||
private:
|
||||
string_list token_results;
|
||||
MeshIO::Binding rgb_value = MeshIO::OVERALL;
|
||||
unsigned long countMaterialFacets = 0;
|
||||
unsigned long segment = 0;
|
||||
bool new_segment = true;
|
||||
|
||||
std::string groupName;
|
||||
std::string materialName;
|
||||
Material* _material;
|
||||
std::vector<std::string> _groupNames;
|
||||
std::vector<MaterialPerSegment> _materialNames;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ReaderOBJ::ReaderOBJ(MeshKernel& kernel, Material* material)
|
||||
: _kernel(kernel)
|
||||
, _material(material)
|
||||
{}
|
||||
|
||||
bool ReaderOBJ::Load(const std::string& file)
|
||||
{
|
||||
Base::FileInfo fi(file);
|
||||
Base::ifstream str(fi, std::ios::in);
|
||||
return Load(str);
|
||||
}
|
||||
|
||||
bool ReaderOBJ::Load(std::istream& str)
|
||||
{
|
||||
boost::regex rx_m("^mtllib\\s+(.+)\\s*$");
|
||||
boost::regex rx_u(R"(^usemtl\s+([\x21-\x7E]+)\s*$)");
|
||||
boost::regex rx_g(R"(^g\s+([\x21-\x7E]+)\s*$)");
|
||||
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_t("^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+([-+]?[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_f3("^f\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
|
||||
"\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
|
||||
"\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*\\s*$");
|
||||
boost::regex rx_f4("^f\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
|
||||
"\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
|
||||
"\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
|
||||
"\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*\\s*$");
|
||||
boost::cmatch what;
|
||||
|
||||
unsigned long segment = 0;
|
||||
MeshPointArray meshPoints;
|
||||
MeshFacetArray meshFacets;
|
||||
|
||||
std::string line;
|
||||
float fX {}, fY {}, fZ {};
|
||||
int i1 = 1, i2 = 1, i3 = 1, i4 = 1;
|
||||
MeshFacet item;
|
||||
|
||||
if (!str || str.bad()) {
|
||||
return false;
|
||||
}
|
||||
@@ -87,161 +366,30 @@ bool ReaderOBJ::Load(std::istream& str)
|
||||
return false;
|
||||
}
|
||||
|
||||
MeshIO::Binding rgb_value = MeshIO::OVERALL;
|
||||
bool new_segment = true;
|
||||
std::string groupName;
|
||||
std::string materialName;
|
||||
unsigned long countMaterialFacets = 0;
|
||||
|
||||
ReaderOBJImp reader(_material);
|
||||
std::string line;
|
||||
while (std::getline(str, line)) {
|
||||
if (boost::regex_match(line.c_str(), what, rx_p)) {
|
||||
fX = (float)std::atof(what[1].first);
|
||||
fY = (float)std::atof(what[4].first);
|
||||
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)) {
|
||||
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<int>(std::atof(what[10].first), 255) / 255.0F;
|
||||
float g = std::min<int>(std::atof(what[11].first), 255) / 255.0F;
|
||||
float b = std::min<int>(std::atof(what[12].first), 255) / 255.0F;
|
||||
meshPoints.push_back(MeshPoint(Base::Vector3f(fX, fY, fZ)));
|
||||
|
||||
Base::Color c(r, g, b);
|
||||
unsigned long prop = static_cast<uint32_t>(c.getPackedValue());
|
||||
meshPoints.back().SetProperty(prop);
|
||||
rgb_value = MeshIO::PER_VERTEX;
|
||||
}
|
||||
else if (boost::regex_match(line.c_str(), what, rx_t)) {
|
||||
fX = (float)std::atof(what[1].first);
|
||||
fY = (float)std::atof(what[4].first);
|
||||
fZ = (float)std::atof(what[7].first);
|
||||
float r = static_cast<float>(std::atof(what[10].first));
|
||||
float g = static_cast<float>(std::atof(what[13].first));
|
||||
float b = static_cast<float>(std::atof(what[16].first));
|
||||
meshPoints.push_back(MeshPoint(Base::Vector3f(fX, fY, fZ)));
|
||||
|
||||
Base::Color c(r, g, b);
|
||||
unsigned long prop = static_cast<uint32_t>(c.getPackedValue());
|
||||
meshPoints.back().SetProperty(prop);
|
||||
rgb_value = MeshIO::PER_VERTEX;
|
||||
}
|
||||
else if (boost::regex_match(line.c_str(), what, rx_g)) {
|
||||
new_segment = true;
|
||||
groupName = Base::Tools::escapedUnicodeToUtf8(what[1].first);
|
||||
}
|
||||
else if (boost::regex_match(line.c_str(), what, rx_m)) {
|
||||
if (_material) {
|
||||
_material->library = Base::Tools::escapedUnicodeToUtf8(what[1].first);
|
||||
}
|
||||
}
|
||||
else if (boost::regex_match(line.c_str(), what, rx_u)) {
|
||||
if (!materialName.empty()) {
|
||||
_materialNames.emplace_back(materialName, countMaterialFacets);
|
||||
}
|
||||
materialName = Base::Tools::escapedUnicodeToUtf8(what[1].first);
|
||||
countMaterialFacets = 0;
|
||||
}
|
||||
else if (boost::regex_match(line.c_str(), what, rx_f3)) {
|
||||
// starts a new segment
|
||||
if (new_segment) {
|
||||
if (!groupName.empty()) {
|
||||
_groupNames.push_back(groupName);
|
||||
groupName.clear();
|
||||
}
|
||||
new_segment = false;
|
||||
segment++;
|
||||
}
|
||||
|
||||
// 3-vertex face
|
||||
i1 = std::atoi(what[1].first);
|
||||
i1 = i1 > 0 ? i1 - 1 : i1 + static_cast<int>(meshPoints.size());
|
||||
i2 = std::atoi(what[2].first);
|
||||
i2 = i2 > 0 ? i2 - 1 : i2 + static_cast<int>(meshPoints.size());
|
||||
i3 = std::atoi(what[3].first);
|
||||
i3 = i3 > 0 ? i3 - 1 : i3 + static_cast<int>(meshPoints.size());
|
||||
item.SetVertices(i1, i2, i3);
|
||||
item.SetProperty(segment);
|
||||
meshFacets.push_back(item);
|
||||
countMaterialFacets++;
|
||||
}
|
||||
else if (boost::regex_match(line.c_str(), what, rx_f4)) {
|
||||
// starts a new segment
|
||||
if (new_segment) {
|
||||
if (!groupName.empty()) {
|
||||
_groupNames.push_back(groupName);
|
||||
groupName.clear();
|
||||
}
|
||||
new_segment = false;
|
||||
segment++;
|
||||
}
|
||||
|
||||
// 4-vertex face
|
||||
i1 = std::atoi(what[1].first);
|
||||
i1 = i1 > 0 ? i1 - 1 : i1 + static_cast<int>(meshPoints.size());
|
||||
i2 = std::atoi(what[2].first);
|
||||
i2 = i2 > 0 ? i2 - 1 : i2 + static_cast<int>(meshPoints.size());
|
||||
i3 = std::atoi(what[3].first);
|
||||
i3 = i3 > 0 ? i3 - 1 : i3 + static_cast<int>(meshPoints.size());
|
||||
i4 = std::atoi(what[4].first);
|
||||
i4 = i4 > 0 ? i4 - 1 : i4 + static_cast<int>(meshPoints.size());
|
||||
|
||||
item.SetVertices(i1, i2, i3);
|
||||
item.SetProperty(segment);
|
||||
meshFacets.push_back(item);
|
||||
countMaterialFacets++;
|
||||
|
||||
item.SetVertices(i3, i4, i1);
|
||||
item.SetProperty(segment);
|
||||
meshFacets.push_back(item);
|
||||
countMaterialFacets++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the last added material name
|
||||
if (!materialName.empty()) {
|
||||
_materialNames.emplace_back(materialName, countMaterialFacets);
|
||||
}
|
||||
|
||||
// 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 (const auto& it : meshPoints) {
|
||||
unsigned long prop = it._ulProp;
|
||||
Base::Color c;
|
||||
c.setPackedValue(static_cast<uint32_t>(prop));
|
||||
_material->diffuseColor.push_back(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!materialName.empty()) {
|
||||
// At this point the materials from the .mtl file are not known and will be read-in by the
|
||||
// calling instance but the color list is pre-filled with a default value
|
||||
if (_material) {
|
||||
_material->binding = MeshIO::PER_FACE;
|
||||
_material->diffuseColor.resize(meshFacets.size(), Base::Color(0.8F, 0.8F, 0.8F));
|
||||
}
|
||||
boost::trim(line);
|
||||
reader.Load(line);
|
||||
}
|
||||
reader.SetupMaterial();
|
||||
_materialNames = reader.GetMaterialNames();
|
||||
|
||||
_kernel.Clear(); // remove all data before
|
||||
|
||||
MeshCleanup meshCleanup(meshPoints, meshFacets);
|
||||
MeshCleanup meshCleanup(reader.meshPoints, reader.meshFacets);
|
||||
if (_material) {
|
||||
meshCleanup.SetMaterial(_material);
|
||||
}
|
||||
meshCleanup.RemoveInvalids();
|
||||
MeshPointFacetAdjacency meshAdj(meshPoints.size(), meshFacets);
|
||||
MeshPointFacetAdjacency meshAdj(reader.meshPoints.size(), reader.meshFacets);
|
||||
meshAdj.SetFacetNeighbourhood();
|
||||
_kernel.Adopt(meshPoints, meshFacets);
|
||||
_kernel.Adopt(reader.meshPoints, reader.meshFacets);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
bool ReaderOBJ::LoadMaterial(std::istream& str)
|
||||
{
|
||||
std::string line;
|
||||
@@ -272,13 +420,13 @@ bool ReaderOBJ::LoadMaterial(std::istream& str)
|
||||
auto readColor = [](const std::vector<std::string>& tokens) -> Base::Color {
|
||||
if (tokens.size() == 2) {
|
||||
// If only R is given then G and B will be equal
|
||||
float r = boost::lexical_cast<float>(tokens[1]);
|
||||
float r = std::stof(tokens[1]);
|
||||
return Base::Color(r, r, r);
|
||||
}
|
||||
if (tokens.size() == 4) {
|
||||
float r = boost::lexical_cast<float>(tokens[1]);
|
||||
float g = boost::lexical_cast<float>(tokens[2]);
|
||||
float b = boost::lexical_cast<float>(tokens[3]);
|
||||
float r = std::stof(tokens[1]);
|
||||
float g = std::stof(tokens[2]);
|
||||
float b = std::stof(tokens[3]);
|
||||
return Base::Color(r, g, b);
|
||||
}
|
||||
|
||||
@@ -297,7 +445,7 @@ bool ReaderOBJ::LoadMaterial(std::istream& str)
|
||||
materialName = Base::Tools::escapedUnicodeToUtf8(token_results[1]);
|
||||
}
|
||||
else if (token_results[0] == "d") {
|
||||
float a = boost::lexical_cast<float>(token_results[1]);
|
||||
float a = std::stof(token_results[1]);
|
||||
materialTransparency[materialName] = 1.0F - a;
|
||||
}
|
||||
// If only R is given then G and B will be equal
|
||||
@@ -312,8 +460,6 @@ bool ReaderOBJ::LoadMaterial(std::istream& str)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const boost::bad_lexical_cast&) {
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,11 @@ public:
|
||||
* \brief ReaderOBJ
|
||||
*/
|
||||
explicit ReaderOBJ(MeshKernel& kernel, Material*);
|
||||
/*!
|
||||
* \brief Load the mesh from the file
|
||||
* \return true on success and false otherwise
|
||||
*/
|
||||
bool Load(const std::string& file);
|
||||
/*!
|
||||
* \brief Load the mesh from the input stream
|
||||
* \return true on success and false otherwise
|
||||
|
||||
Reference in New Issue
Block a user