150 lines
5.0 KiB
C++
150 lines
5.0 KiB
C++
#include "../libslic3r.h"
|
|
#include "../Model.hpp"
|
|
#include "../TriangleMesh.hpp"
|
|
|
|
#include "OBJ.hpp"
|
|
#include "objparser.hpp"
|
|
|
|
#include <string>
|
|
|
|
#include <boost/log/trivial.hpp>
|
|
|
|
#ifdef _WIN32
|
|
#define DIR_SEPARATOR '\\'
|
|
#else
|
|
#define DIR_SEPARATOR '/'
|
|
#endif
|
|
|
|
//Translation
|
|
#include "I18N.hpp"
|
|
#define _L(s) Slic3r::I18N::translate(s)
|
|
|
|
namespace Slic3r {
|
|
|
|
bool load_obj(const char *path, TriangleMesh *meshptr, std::string &message)
|
|
{
|
|
if (meshptr == nullptr)
|
|
return false;
|
|
|
|
// Parse the OBJ file.
|
|
ObjParser::ObjData data;
|
|
if (! ObjParser::objparse(path, data)) {
|
|
BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path;
|
|
message = _L("load_obj: failed to parse");
|
|
return false;
|
|
}
|
|
|
|
// Count the faces and verify, that all faces are triangular.
|
|
size_t num_faces = 0;
|
|
size_t num_quads = 0;
|
|
for (size_t i = 0; i < data.vertices.size(); ++ i) {
|
|
// Find the end of face.
|
|
size_t j = i;
|
|
for (; j < data.vertices.size() && data.vertices[j].coordIdx != -1; ++ j) ;
|
|
if (size_t num_face_vertices = j - i; num_face_vertices > 0) {
|
|
if (num_face_vertices > 4) {
|
|
// Non-triangular and non-quad faces are not supported as of now.
|
|
BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path << ". The file contains polygons with more than 4 vertices.";
|
|
message = _L("The file contains polygons with more than 4 vertices.");
|
|
return false;
|
|
} else if (num_face_vertices < 3) {
|
|
// Non-triangular and non-quad faces are not supported as of now.
|
|
BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path << ". The file contains polygons with less than 2 vertices.";
|
|
message = _L("The file contains polygons with less than 2 vertices.");
|
|
return false;
|
|
}
|
|
if (num_face_vertices == 4)
|
|
++ num_quads;
|
|
++ num_faces;
|
|
i = j;
|
|
}
|
|
}
|
|
|
|
// Convert ObjData into indexed triangle set.
|
|
indexed_triangle_set its;
|
|
size_t num_vertices = data.coordinates.size() / 4;
|
|
its.vertices.reserve(num_vertices);
|
|
its.indices.reserve(num_faces + num_quads);
|
|
for (size_t i = 0; i < num_vertices; ++ i) {
|
|
size_t j = i << 2;
|
|
its.vertices.emplace_back(data.coordinates[j], data.coordinates[j + 1], data.coordinates[j + 2]);
|
|
}
|
|
int indices[4];
|
|
for (size_t i = 0; i < data.vertices.size();)
|
|
if (data.vertices[i].coordIdx == -1)
|
|
++ i;
|
|
else {
|
|
int cnt = 0;
|
|
while (i < data.vertices.size())
|
|
if (const ObjParser::ObjVertex &vertex = data.vertices[i ++]; vertex.coordIdx == -1) {
|
|
break;
|
|
} else {
|
|
assert(cnt < 4);
|
|
if (vertex.coordIdx < 0 || vertex.coordIdx >= int(its.vertices.size())) {
|
|
BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path << ". The file contains invalid vertex index.";
|
|
message = _L("The file contains invalid vertex index.");
|
|
return false;
|
|
}
|
|
indices[cnt ++] = vertex.coordIdx;
|
|
}
|
|
if (cnt) {
|
|
assert(cnt == 3 || cnt == 4);
|
|
// Insert one or two faces (triangulate a quad).
|
|
its.indices.emplace_back(indices[0], indices[1], indices[2]);
|
|
if (cnt == 4)
|
|
its.indices.emplace_back(indices[0], indices[2], indices[3]);
|
|
}
|
|
}
|
|
|
|
*meshptr = TriangleMesh(std::move(its));
|
|
if (meshptr->empty()) {
|
|
BOOST_LOG_TRIVIAL(error) << "load_obj: This OBJ file couldn't be read because it's empty. " << path;
|
|
message = _L("This OBJ file couldn't be read because it's empty.");
|
|
return false;
|
|
}
|
|
if (meshptr->volume() < 0)
|
|
meshptr->flip_triangles();
|
|
return true;
|
|
}
|
|
|
|
bool load_obj(const char *path, Model *model, std::string &message, const char *object_name_in)
|
|
{
|
|
TriangleMesh mesh;
|
|
|
|
bool ret = load_obj(path, &mesh, message);
|
|
|
|
if (ret) {
|
|
std::string object_name;
|
|
if (object_name_in == nullptr) {
|
|
const char *last_slash = strrchr(path, DIR_SEPARATOR);
|
|
object_name.assign((last_slash == nullptr) ? path : last_slash + 1);
|
|
} else
|
|
object_name.assign(object_name_in);
|
|
|
|
model->add_object(object_name.c_str(), path, std::move(mesh));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool store_obj(const char *path, TriangleMesh *mesh)
|
|
{
|
|
//FIXME returning false even if write failed.
|
|
mesh->WriteOBJFile(path);
|
|
return true;
|
|
}
|
|
|
|
bool store_obj(const char *path, ModelObject *model_object)
|
|
{
|
|
TriangleMesh mesh = model_object->mesh();
|
|
return store_obj(path, &mesh);
|
|
}
|
|
|
|
bool store_obj(const char *path, Model *model)
|
|
{
|
|
TriangleMesh mesh = model->mesh();
|
|
return store_obj(path, &mesh);
|
|
}
|
|
|
|
}; // namespace Slic3r
|