23
#include "PreCompiled.h"
25
#include <boost/lexical_cast.hpp>
26
#include <boost/regex.hpp>
27
#include <boost/tokenizer.hpp>
31
#include "Core/MeshIO.h"
32
#include "Core/MeshKernel.h"
33
#include <Base/Tools.h>
38
using namespace MeshCore;
40
ReaderOBJ::ReaderOBJ(MeshKernel& kernel, Material* material)
45
bool ReaderOBJ::Load(std::istream& str)
47
boost::regex rx_m("^mtllib\\s+(.+)\\s*$");
48
boost::regex rx_u(R"(^usemtl\s+([\x21-\x7E]+)\s*$)");
49
boost::regex rx_g(R"(^g\s+([\x21-\x7E]+)\s*$)");
50
boost::regex rx_p("^v\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
51
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
52
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)\\s*$");
53
boost::regex rx_c("^v\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
54
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
55
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
56
"\\s+(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s*$");
57
boost::regex rx_t("^v\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
58
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
59
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
60
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
61
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
62
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)\\s*$");
63
boost::regex rx_f3("^f\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
64
"\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
65
"\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*\\s*$");
66
boost::regex rx_f4("^f\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
67
"\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
68
"\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
69
"\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*\\s*$");
72
unsigned long segment = 0;
73
MeshPointArray meshPoints;
74
MeshFacetArray meshFacets;
77
float fX {}, fY {}, fZ {};
78
int i1 = 1, i2 = 1, i3 = 1, i4 = 1;
81
if (!str || str.bad()) {
85
std::streambuf* buf = str.rdbuf();
90
MeshIO::Binding rgb_value = MeshIO::OVERALL;
91
bool new_segment = true;
92
std::string groupName;
93
std::string materialName;
94
unsigned long countMaterialFacets = 0;
96
while (std::getline(str, line)) {
97
if (boost::regex_match(line.c_str(), what, rx_p)) {
98
fX = (float)std::atof(what[1].first);
99
fY = (float)std::atof(what[4].first);
100
fZ = (float)std::atof(what[7].first);
101
meshPoints.push_back(MeshPoint(Base::Vector3f(fX, fY, fZ)));
103
else if (boost::regex_match(line.c_str(), what, rx_c)) {
104
fX = (float)std::atof(what[1].first);
105
fY = (float)std::atof(what[4].first);
106
fZ = (float)std::atof(what[7].first);
107
float r = std::min<int>(std::atof(what[10].first), 255) / 255.0f;
108
float g = std::min<int>(std::atof(what[11].first), 255) / 255.0f;
109
float b = std::min<int>(std::atof(what[12].first), 255) / 255.0f;
110
meshPoints.push_back(MeshPoint(Base::Vector3f(fX, fY, fZ)));
112
App::Color c(r, g, b);
113
unsigned long prop = static_cast<uint32_t>(c.getPackedValue());
114
meshPoints.back().SetProperty(prop);
115
rgb_value = MeshIO::PER_VERTEX;
117
else if (boost::regex_match(line.c_str(), what, rx_t)) {
118
fX = (float)std::atof(what[1].first);
119
fY = (float)std::atof(what[4].first);
120
fZ = (float)std::atof(what[7].first);
121
float r = static_cast<float>(std::atof(what[10].first));
122
float g = static_cast<float>(std::atof(what[13].first));
123
float b = static_cast<float>(std::atof(what[16].first));
124
meshPoints.push_back(MeshPoint(Base::Vector3f(fX, fY, fZ)));
126
App::Color c(r, g, b);
127
unsigned long prop = static_cast<uint32_t>(c.getPackedValue());
128
meshPoints.back().SetProperty(prop);
129
rgb_value = MeshIO::PER_VERTEX;
131
else if (boost::regex_match(line.c_str(), what, rx_g)) {
133
groupName = Base::Tools::escapedUnicodeToUtf8(what[1].first);
135
else if (boost::regex_match(line.c_str(), what, rx_m)) {
137
_material->library = Base::Tools::escapedUnicodeToUtf8(what[1].first);
140
else if (boost::regex_match(line.c_str(), what, rx_u)) {
141
if (!materialName.empty()) {
142
_materialNames.emplace_back(materialName, countMaterialFacets);
144
materialName = Base::Tools::escapedUnicodeToUtf8(what[1].first);
145
countMaterialFacets = 0;
147
else if (boost::regex_match(line.c_str(), what, rx_f3)) {
150
if (!groupName.empty()) {
151
_groupNames.push_back(groupName);
159
i1 = std::atoi(what[1].first);
160
i1 = i1 > 0 ? i1 - 1 : i1 + static_cast<int>(meshPoints.size());
161
i2 = std::atoi(what[2].first);
162
i2 = i2 > 0 ? i2 - 1 : i2 + static_cast<int>(meshPoints.size());
163
i3 = std::atoi(what[3].first);
164
i3 = i3 > 0 ? i3 - 1 : i3 + static_cast<int>(meshPoints.size());
165
item.SetVertices(i1, i2, i3);
166
item.SetProperty(segment);
167
meshFacets.push_back(item);
168
countMaterialFacets++;
170
else if (boost::regex_match(line.c_str(), what, rx_f4)) {
173
if (!groupName.empty()) {
174
_groupNames.push_back(groupName);
182
i1 = std::atoi(what[1].first);
183
i1 = i1 > 0 ? i1 - 1 : i1 + static_cast<int>(meshPoints.size());
184
i2 = std::atoi(what[2].first);
185
i2 = i2 > 0 ? i2 - 1 : i2 + static_cast<int>(meshPoints.size());
186
i3 = std::atoi(what[3].first);
187
i3 = i3 > 0 ? i3 - 1 : i3 + static_cast<int>(meshPoints.size());
188
i4 = std::atoi(what[4].first);
189
i4 = i4 > 0 ? i4 - 1 : i4 + static_cast<int>(meshPoints.size());
191
item.SetVertices(i1, i2, i3);
192
item.SetProperty(segment);
193
meshFacets.push_back(item);
194
countMaterialFacets++;
196
item.SetVertices(i3, i4, i1);
197
item.SetProperty(segment);
198
meshFacets.push_back(item);
199
countMaterialFacets++;
204
if (!materialName.empty()) {
205
_materialNames.emplace_back(materialName, countMaterialFacets);
209
if (rgb_value == MeshIO::PER_VERTEX) {
211
_material->binding = MeshIO::PER_VERTEX;
212
_material->diffuseColor.reserve(meshPoints.size());
214
for (const auto& it : meshPoints) {
215
unsigned long prop = it._ulProp;
217
c.setPackedValue(static_cast<uint32_t>(prop));
218
_material->diffuseColor.push_back(c);
222
else if (!materialName.empty()) {
226
_material->binding = MeshIO::PER_FACE;
227
_material->diffuseColor.resize(meshFacets.size(), App::Color(0.8f, 0.8f, 0.8f));
233
MeshCleanup meshCleanup(meshPoints, meshFacets);
235
meshCleanup.SetMaterial(_material);
237
meshCleanup.RemoveInvalids();
238
MeshPointFacetAdjacency meshAdj(meshPoints.size(), meshFacets);
239
meshAdj.SetFacetNeighbourhood();
240
_kernel.Adopt(meshPoints, meshFacets);
245
bool ReaderOBJ::LoadMaterial(std::istream& str)
253
if (!str || str.bad()) {
257
std::streambuf* buf = str.rdbuf();
262
std::map<std::string, App::Color> materialAmbientColor;
263
std::map<std::string, App::Color> materialDiffuseColor;
264
std::map<std::string, App::Color> materialSpecularColor;
265
std::map<std::string, float> materialTransparency;
266
std::string materialName;
267
std::vector<App::Color> ambientColor;
268
std::vector<App::Color> diffuseColor;
269
std::vector<App::Color> specularColor;
270
std::vector<float> transparency;
272
auto readColor = [](const std::vector<std::string>& tokens) -> App::Color {
273
if (tokens.size() == 2) {
275
float r = boost::lexical_cast<float>(tokens[1]);
276
return App::Color(r, r, r);
278
else if (tokens.size() == 4) {
279
float r = boost::lexical_cast<float>(tokens[1]);
280
float g = boost::lexical_cast<float>(tokens[2]);
281
float b = boost::lexical_cast<float>(tokens[3]);
282
return App::Color(r, g, b);
285
throw std::length_error("Unexpected number of tokens");
288
while (std::getline(str, line)) {
289
boost::char_separator<char> sep(" ");
290
boost::tokenizer<boost::char_separator<char>> tokens(line, sep);
291
std::vector<std::string> token_results;
292
token_results.assign(tokens.begin(), tokens.end());
295
if (token_results.size() >= 2) {
296
if (token_results[0] == "newmtl") {
297
materialName = Base::Tools::escapedUnicodeToUtf8(token_results[1]);
299
else if (token_results[0] == "d") {
300
float a = boost::lexical_cast<float>(token_results[1]);
301
materialTransparency[materialName] = 1.0f - a;
304
else if (token_results[0] == "Ka") {
305
materialAmbientColor[materialName] = readColor(token_results);
307
else if (token_results[0] == "Kd") {
308
materialDiffuseColor[materialName] = readColor(token_results);
310
else if (token_results[0] == "Ks") {
311
materialSpecularColor[materialName] = readColor(token_results);
315
catch (const boost::bad_lexical_cast&) {
317
catch (const std::exception&) {
321
for (const auto& it : _materialNames) {
323
auto jt = materialAmbientColor.find(it.first);
324
if (jt != materialAmbientColor.end()) {
325
std::vector<App::Color> mat(it.second, jt->second);
326
ambientColor.insert(ambientColor.end(), mat.begin(), mat.end());
330
auto jt = materialDiffuseColor.find(it.first);
331
if (jt != materialDiffuseColor.end()) {
332
std::vector<App::Color> mat(it.second, jt->second);
333
diffuseColor.insert(diffuseColor.end(), mat.begin(), mat.end());
337
auto jt = materialSpecularColor.find(it.first);
338
if (jt != materialSpecularColor.end()) {
339
std::vector<App::Color> mat(it.second, jt->second);
340
specularColor.insert(specularColor.end(), mat.begin(), mat.end());
344
auto jt = materialTransparency.find(it.first);
345
if (jt != materialTransparency.end()) {
346
std::vector<float> transp(it.second, jt->second);
347
transparency.insert(transparency.end(), transp.begin(), transp.end());
352
if (diffuseColor.size() == _material->diffuseColor.size()) {
353
_material->binding = MeshIO::PER_FACE;
354
_material->ambientColor.swap(ambientColor);
355
_material->diffuseColor.swap(diffuseColor);
356
_material->specularColor.swap(specularColor);
357
_material->transparency.swap(transparency);
361
_material->binding = MeshIO::OVERALL;
362
_material->ambientColor.clear();
363
_material->diffuseColor.clear();
364
_material->specularColor.clear();
365
_material->transparency.clear();