OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
ObjParser Namespace Reference

Classes

struct  ObjVertex
struct  ObjUseMtl
struct  ObjNewMtl
struct  ObjObject
struct  ObjGroup
struct  ObjSmoothingGroup
struct  ObjData
struct  MtlData

Functions

static bool obj_parseline (const char *line, ObjData &data)
static bool mtl_is_space (char c)
static const char * mtl_skip_ws (const char *line)
static const char * mtl_skip_token (const char *line)
static bool mtl_token_equals (const char *begin, const char *end, const char *token)
static std::string mtl_trim_value (const char *line)
static bool mtl_skip_numeric_token (const char *&line)
static bool mtl_skip_required_tokens (const char *&line, int count)
static std::string mtl_parse_texture_name (const char *line)
static bool mtl_parseline (const char *line, MtlData &data)
bool objparse (const char *path, ObjData &data)
bool mtlparse (const char *path, MtlData &data)
bool objparse (std::istream &stream, ObjData &data)
template<typename T>
bool savevector (FILE *pFile, const std::vector< T > &v)
bool savevector (FILE *pFile, const std::vector< std::string > &v)
template<typename T>
bool savevectornameidx (FILE *pFile, const std::vector< T > &v)
template<typename T>
bool loadvector (FILE *pFile, std::vector< T > &v)
bool loadvector (FILE *pFile, std::vector< std::string > &v)
template<typename T>
bool loadvectornameidx (FILE *pFile, std::vector< T > &v)
bool objbinsave (const char *path, const ObjData &data)
bool objbinload (const char *path, ObjData &data)
template<typename T>
bool vectorequal (const std::vector< T > &v1, const std::vector< T > &v2)
bool vectorequal (const std::vector< std::string > &v1, const std::vector< std::string > &v2)
bool objequal (const ObjData &data1, const ObjData &data2)
bool operator== (const ObjVertex &v1, const ObjVertex &v2)
bool operator== (const ObjUseMtl &v1, const ObjUseMtl &v2)
bool operator== (const ObjObject &v1, const ObjObject &v2)
bool operator== (const ObjGroup &v1, const ObjGroup &v2)
bool operator== (const ObjSmoothingGroup &v1, const ObjSmoothingGroup &v2)

Variables

static std::string cur_mtl_name = ""

Class Documentation

◆ ObjParser::ObjVertex

struct ObjParser::ObjVertex
Class Members
int coordIdx
int normalIdx
int textureCoordIdx

◆ ObjParser::ObjUseMtl

struct ObjParser::ObjUseMtl
Collaboration diagram for ObjParser::ObjUseMtl:
Class Members
int face_end {-1}
int face_start
string name
int vertexIdxEnd {-1}
int vertexIdxFirst

◆ ObjParser::ObjNewMtl

struct ObjParser::ObjNewMtl
Collaboration diagram for ObjParser::ObjNewMtl:
Class Members
float d
float illum
array< float, 3 > Ka
array< float, 3 > Kd
array< float, 3 > Ke
array< float, 3 > Ks
string map_Kd
string name
float Ni
float Ns
array< float, 3 > Tf
float Tr {1.0f}

◆ ObjParser::ObjObject

struct ObjParser::ObjObject
Collaboration diagram for ObjParser::ObjObject:
Class Members
string name
int vertexIdxFirst

◆ ObjParser::ObjGroup

struct ObjParser::ObjGroup
Collaboration diagram for ObjParser::ObjGroup:
Class Members
string name
int vertexIdxFirst

◆ ObjParser::ObjSmoothingGroup

struct ObjParser::ObjSmoothingGroup
Class Members
int smoothingGroupID
int vertexIdxFirst

◆ ObjParser::ObjData

struct ObjParser::ObjData
Collaboration diagram for ObjParser::ObjData:
Class Members
vector< float > coordinates
vector< ObjGroup > groups
bool has_vertex_color {false}
vector< string > mtllibs
vector< float > normals
vector< ObjObject > objects
vector< float > parameters
vector< ObjSmoothingGroup > smoothingGroups
vector< float > textureCoordinates
vector< ObjUseMtl > usemtls
int version
vector< ObjVertex > vertices

◆ ObjParser::MtlData

struct ObjParser::MtlData
Collaboration diagram for ObjParser::MtlData:
Class Members
vector< string > mtl_orders
unordered_map< string, shared_ptr< ObjNewMtl > > new_mtl_unmap
int version

Function Documentation

◆ loadvector() [1/2]

bool ObjParser::loadvector ( FILE * pFile,
std::vector< std::string > & v )
841{
842 v.clear();
843 size_t cnt = 0;
844 if (::fread(&cnt, sizeof(cnt), 1, pFile) != 1)
845 return false;
846 v.reserve(cnt);
847 for (size_t i = 0; i < cnt; ++ i) {
848 size_t len = 0;
849 if (::fread(&len, sizeof(len), 1, pFile) != 1)
850 return false;
851 std::string s(" ", len);
852 if (::fread(s.data(), 1, len, pFile) != len)
853 return false;
854 v.push_back(std::move(s));
855 }
856 return true;
857}

◆ loadvector() [2/2]

template<typename T>
bool ObjParser::loadvector ( FILE * pFile,
std::vector< T > & v )
826{
827 v.clear();
828 size_t cnt = 0;
829 if (::fread(&cnt, sizeof(cnt), 1, pFile) != 1)
830 return false;
831 //FIXME sizeof(T) works for data types leaving no gaps in the allocated vector because of alignment of the T type.
832 if (cnt != 0) {
833 v.assign(cnt, T());
834 if (::fread(&v.front(), sizeof(T), cnt, pFile) != cnt)
835 return false;
836 }
837 return true;
838}

Referenced by objbinload().

Here is the caller graph for this function:

◆ loadvectornameidx()

template<typename T>
bool ObjParser::loadvectornameidx ( FILE * pFile,
std::vector< T > & v )
861{
862 v.clear();
863 size_t cnt = 0;
864 if (::fread(&cnt, sizeof(cnt), 1, pFile) != 1)
865 return false;
866 v.assign(cnt, T());
867 for (size_t i = 0; i < cnt; ++ i) {
868 if (::fread(&v[i].vertexIdxFirst, sizeof(int), 1, pFile) != 1)
869 return false;
870 size_t len = 0;
871 if (::fread(&len, sizeof(len), 1, pFile) != 1)
872 return false;
873 v[i].name.assign(" ", len);
874 if (::fread(v[i].name.data(), 1, len, pFile) != len)
875 return false;
876 }
877 return true;
878}

Referenced by objbinload().

Here is the caller graph for this function:

◆ mtl_is_space()

bool ObjParser::mtl_is_space ( char c)
static
382{
383 return c == ' ' || c == '\t' || c == '\r';
384}

Referenced by mtl_skip_numeric_token(), mtl_skip_token(), mtl_skip_ws(), and mtl_trim_value().

Here is the caller graph for this function:

◆ mtl_parse_texture_name()

std::string ObjParser::mtl_parse_texture_name ( const char * line)
static
441{
442 const char *original = mtl_skip_ws(line);
443 const char *current = original;
444
445 while (*current == '-') {
446 const char *option_begin = current;
447 const char *option_end = mtl_skip_token(current);
448 current = option_end;
449
450 if (mtl_token_equals(option_begin, option_end, "-o") ||
451 mtl_token_equals(option_begin, option_end, "-s") ||
452 mtl_token_equals(option_begin, option_end, "-t")) {
453 int skipped = 0;
454 while (skipped < 3 && mtl_skip_numeric_token(current))
455 ++skipped;
456 if (skipped == 0)
457 return mtl_trim_value(original);
458 continue;
459 }
460
461 int option_args = -1;
462 if (mtl_token_equals(option_begin, option_end, "-mm"))
463 option_args = 2;
464 else if (mtl_token_equals(option_begin, option_end, "-bm") ||
465 mtl_token_equals(option_begin, option_end, "-boost") ||
466 mtl_token_equals(option_begin, option_end, "-texres") ||
467 mtl_token_equals(option_begin, option_end, "-clamp") ||
468 mtl_token_equals(option_begin, option_end, "-blendu") ||
469 mtl_token_equals(option_begin, option_end, "-blendv") ||
470 mtl_token_equals(option_begin, option_end, "-cc") ||
471 mtl_token_equals(option_begin, option_end, "-imfchan") ||
472 mtl_token_equals(option_begin, option_end, "-type"))
473 option_args = 1;
474
475 if (option_args < 0 || !mtl_skip_required_tokens(current, option_args))
476 return mtl_trim_value(original);
477 }
478
479 return mtl_trim_value(current);
480}
static const char * mtl_skip_token(const char *line)
Definition objparser.cpp:393
static bool mtl_token_equals(const char *begin, const char *end, const char *token)
Definition objparser.cpp:400
static const char * mtl_skip_ws(const char *line)
Definition objparser.cpp:386
static bool mtl_skip_required_tokens(const char *&line, int count)
Definition objparser.cpp:428
static bool mtl_skip_numeric_token(const char *&line)
Definition objparser.cpp:415
static std::string mtl_trim_value(const char *line)
Definition objparser.cpp:406

References mtl_skip_numeric_token(), mtl_skip_required_tokens(), mtl_skip_token(), mtl_skip_ws(), mtl_token_equals(), and mtl_trim_value().

Referenced by mtl_parseline().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mtl_parseline()

bool ObjParser::mtl_parseline ( const char * line,
MtlData & data )
static
483{
484 if (*line == 0) return true;
486 // Ignore whitespaces at the beginning of the line.
487 // FIXME is this a good idea?
488 EATWS();
489
490 char c1 = *line++;
491 switch (c1) {
492 case '#': {// Comment, ignore the rest of the line.
493 break;
494 }
495 case 'n': {
496 if (*(line++) != 'e' || *(line++) != 'w' || *(line++) != 'm' || *(line++) != 't' || *(line++) != 'l')
497 return false;
498 EATWS();
499 ObjNewMtl new_mtl;
500 cur_mtl_name = line;
501 data.new_mtl_unmap[cur_mtl_name] = std::make_shared<ObjNewMtl>();
502 data.mtl_orders.emplace_back(cur_mtl_name);
503 break;
504 }
505 case 'm': {
506 if (*(line++) != 'a' || *(line++) != 'p' || *(line++) != '_' || *(line++) != 'K' || *(line++) != 'd') return false;
507 EATWS();
508 if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
510 }
511 break;
512 }
513 case 'N': {
514 char cur_char = *(line++);
515 if (cur_char == 's') {
516 EATWS();
517 char * endptr = 0;
518 double ns = strtod(line, &endptr);
519 if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
520 data.new_mtl_unmap[cur_mtl_name]->Ns = (float) ns;
521 }
522 } else if (cur_char == 'i') {
523 EATWS();
524 char * endptr = 0;
525 double ni = strtod(line, &endptr);
526 if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
527 data.new_mtl_unmap[cur_mtl_name]->Ni = (float) ni;
528 }
529 }
530 break;
531 }
532 case 'K': {
533 char cur_char = *(line++);
534 if (cur_char == 'a') {
535 EATWS();
536 char * endptr = 0;
537 double x = strtod(line, &endptr);
538 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
539 line = endptr;
540 EATWS();
541 double y = strtod(line, &endptr);
542 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
543 line = endptr;
544 EATWS();
545 double z = strtod(line, &endptr);
546 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
547 line = endptr;
548 EATWS();
549 if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
550 data.new_mtl_unmap[cur_mtl_name]->Ka[0] = x;
551 data.new_mtl_unmap[cur_mtl_name]->Ka[1] = y;
552 data.new_mtl_unmap[cur_mtl_name]->Ka[2] = z;
553 }
554 } else if (cur_char == 'd') {
555 EATWS();
556 char * endptr = 0;
557 double x = strtod(line, &endptr);
558 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
559 line = endptr;
560 EATWS();
561 double y = strtod(line, &endptr);
562 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
563 line = endptr;
564 EATWS();
565 double z = strtod(line, &endptr);
566 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
567 line = endptr;
568 EATWS();
569 if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
570 data.new_mtl_unmap[cur_mtl_name]->Kd[0] = x;
571 data.new_mtl_unmap[cur_mtl_name]->Kd[1] = y;
572 data.new_mtl_unmap[cur_mtl_name]->Kd[2] = z;
573 }
574 } else if (cur_char == 's') {
575 EATWS();
576 char * endptr = 0;
577 double x = strtod(line, &endptr);
578 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
579 line = endptr;
580 EATWS();
581 double y = strtod(line, &endptr);
582 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
583 line = endptr;
584 EATWS();
585 double z = strtod(line, &endptr);
586 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
587 line = endptr;
588 EATWS();
589 if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
590 data.new_mtl_unmap[cur_mtl_name]->Ks[0] = x;
591 data.new_mtl_unmap[cur_mtl_name]->Ks[1] = y;
592 data.new_mtl_unmap[cur_mtl_name]->Ks[2] = z;
593 }
594 } else if (cur_char == 'e') {
595 EATWS();
596 char * endptr = 0;
597 double x = strtod(line, &endptr);
598 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
599 line = endptr;
600 EATWS();
601 double y = strtod(line, &endptr);
602 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
603 line = endptr;
604 EATWS();
605 double z = strtod(line, &endptr);
606 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
607 line = endptr;
608 EATWS();
609 if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
610 data.new_mtl_unmap[cur_mtl_name]->Ke[0] = x;
611 data.new_mtl_unmap[cur_mtl_name]->Ke[1] = y;
612 data.new_mtl_unmap[cur_mtl_name]->Ke[2] = z;
613 }
614 }
615 break;
616 }
617 case 'i': {
618 if (*(line++) != 'l' || *(line++) != 'l' || *(line++) != 'u' || *(line++) != 'm')
619 return false;
620 EATWS();
621 char * endptr = 0;
622 double illum = strtod(line, &endptr);
623 if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
624 data.new_mtl_unmap[cur_mtl_name]->illum = (float) illum;
625 }
626 break;
627 }
628 case 'd': {
629 EATWS();
630 char * endptr = 0;
631 double d = strtod(line, &endptr);
632 if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
633 data.new_mtl_unmap[cur_mtl_name]->d = (float) d;
634 }
635 break;
636 }
637 case 'T': {
638 char cur_char = *(line++);
639 if (cur_char == 'r') {
640 EATWS();
641 char * endptr = 0;
642 double tr = strtod(line, &endptr);
643 if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
644 data.new_mtl_unmap[cur_mtl_name]->Tr = (float) tr;
645 }
646 break;
647 } else if (cur_char == 'f') {
648 EATWS();
649 char * endptr = 0;
650 double x = strtod(line, &endptr);
651 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
652 line = endptr;
653 EATWS();
654 double y = strtod(line, &endptr);
655 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t')) return false;
656 line = endptr;
657 EATWS();
658 double z = strtod(line, &endptr);
659 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
660 line = endptr;
661 EATWS();
662 if (data.new_mtl_unmap.find(cur_mtl_name) != data.new_mtl_unmap.end()) {
663 data.new_mtl_unmap[cur_mtl_name]->Tf[0] = x;
664 data.new_mtl_unmap[cur_mtl_name]->Tf[1] = y;
665 data.new_mtl_unmap[cur_mtl_name]->Tf[2] = z;
666 }
667 break;
668 }
669 }
670 }
671 return true;
672}
std::vector< std::string > mtl_orders
Definition objparser.hpp:129
std::unordered_map< std::string, std::shared_ptr< ObjNewMtl > > new_mtl_unmap
Definition objparser.hpp:126
static std::string mtl_parse_texture_name(const char *line)
Definition objparser.cpp:440
static std::string cur_mtl_name
Definition objparser.cpp:380
bool is_decimal_separator_point()
Definition LocalesUtils.cpp:78
#define EATWS()
Definition objparser.cpp:20

References cur_mtl_name, EATWS, Slic3r::is_decimal_separator_point(), ObjParser::MtlData::mtl_orders, mtl_parse_texture_name(), and ObjParser::MtlData::new_mtl_unmap.

Referenced by mtlparse().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mtl_skip_numeric_token()

bool ObjParser::mtl_skip_numeric_token ( const char *& line)
static
416{
417 const char *begin = mtl_skip_ws(line);
418 if (*begin == 0)
419 return false;
420 char *endptr = 0;
421 strtod(begin, &endptr);
422 if (endptr == begin || (!mtl_is_space(*endptr) && *endptr != 0))
423 return false;
424 line = mtl_skip_ws(endptr);
425 return true;
426}
static bool mtl_is_space(char c)
Definition objparser.cpp:381

References mtl_is_space(), and mtl_skip_ws().

Referenced by mtl_parse_texture_name().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mtl_skip_required_tokens()

bool ObjParser::mtl_skip_required_tokens ( const char *& line,
int count )
static
429{
430 for (int i = 0; i < count; ++i) {
431 line = mtl_skip_ws(line);
432 if (*line == 0)
433 return false;
434 line = mtl_skip_token(line);
435 }
436 line = mtl_skip_ws(line);
437 return true;
438}
static unsigned int count
Definition AuxiliaryDataViewModel.cpp:246

References count, mtl_skip_token(), and mtl_skip_ws().

Referenced by mtl_parse_texture_name().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mtl_skip_token()

const char * ObjParser::mtl_skip_token ( const char * line)
static
394{
395 while (*line != 0 && !mtl_is_space(*line))
396 ++line;
397 return line;
398}

References mtl_is_space().

Referenced by mtl_parse_texture_name(), and mtl_skip_required_tokens().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mtl_skip_ws()

const char * ObjParser::mtl_skip_ws ( const char * line)
static
387{
388 while (mtl_is_space(*line))
389 ++line;
390 return line;
391}

References mtl_is_space().

Referenced by mtl_parse_texture_name(), mtl_skip_numeric_token(), mtl_skip_required_tokens(), and mtl_trim_value().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mtl_token_equals()

bool ObjParser::mtl_token_equals ( const char * begin,
const char * end,
const char * token )
static
401{
402 const size_t len = static_cast<size_t>(end - begin);
403 return strlen(token) == len && strncmp(begin, token, len) == 0;
404}

Referenced by mtl_parse_texture_name().

Here is the caller graph for this function:

◆ mtl_trim_value()

std::string ObjParser::mtl_trim_value ( const char * line)
static
407{
408 const char *begin = mtl_skip_ws(line);
409 const char *end = begin + strlen(begin);
410 while (end > begin && mtl_is_space(*(end - 1)))
411 --end;
412 return std::string(begin, end);
413}

References mtl_is_space(), and mtl_skip_ws().

Referenced by mtl_parse_texture_name().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mtlparse()

bool ObjParser::mtlparse ( const char * path,
MtlData & data )
717{
718 Slic3r::CNumericLocalesSetter locales_setter;
719
720 FILE *pFile = boost::nowide::fopen(path, "rt");
721 if (pFile == 0) return false;
722 cur_mtl_name = "";
723 try {
724 char buf[65536 * 2];
725 size_t len = 0;
726 size_t lenPrev = 0;
727 while ((len = ::fread(buf + lenPrev, 1, 65536, pFile)) != 0) {
728 len += lenPrev;
729 size_t lastLine = 0;
730 for (size_t i = 0; i < len; ++i)
731 if (buf[i] == '\r' || buf[i] == '\n') {
732 buf[i] = 0;
733 char *c = buf + lastLine;
734 while (*c == ' ' || *c == '\t') ++c;
735 // FIXME check the return value and exit on error?
736 // Will it break parsing of some obj files?
737 mtl_parseline(c, data);
738 lastLine = i + 1;
739 }
740 lenPrev = len - lastLine;
741 if (lenPrev > 65536) {
742 BOOST_LOG_TRIVIAL(error) << "MtlParser: Excessive line length";
743 ::fclose(pFile);
744 return false;
745 }
746 memmove(buf, buf + lastLine, lenPrev);
747 }
748 } catch (std::bad_alloc &) {
749 BOOST_LOG_TRIVIAL(error) << "MtlParser: Out of memory";
750 }
751 ::fclose(pFile);
752 return true;
753}
Definition LocalesUtils.hpp:19
static bool mtl_parseline(const char *line, MtlData &data)
Definition objparser.cpp:482

References cur_mtl_name, and mtl_parseline().

Referenced by Slic3r::load_obj().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ obj_parseline()

bool ObjParser::obj_parseline ( const char * line,
ObjData & data )
static
22{
23 if (*line == 0)
24 return true;
26 // Ignore whitespaces at the beginning of the line.
27 //FIXME is this a good idea?
28 EATWS();
29
30 char c1 = *line ++;
31 switch (c1) {
32 case '#':
33 // Comment, ignore the rest of the line.
34 break;
35 case 'v':
36 {
37 // Parse vertex geometry (position, normal, texture coordinates)
38 char c2 = *line ++;
39 switch (c2) {
40 case 't':
41 {
42 // vt - vertex texture parameter
43 // u v [w], w == 0 (or w == 1)
44 char c2 = *line ++;
45 if (c2 != ' ' && c2 != '\t')
46 return false;
47 EATWS();
48 char *endptr = 0;
49 double u = strtod(line, &endptr);
50 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
51 return false;
52 line = endptr;
53 EATWS();
54 double v = 0;
55 if (*line != 0) {
56 v = strtod(line, &endptr);
57 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
58 return false;
59 line = endptr;
60 EATWS();
61 }
62 // The optional w is accepted but not stored: only u and v are used.
63 if (*line != 0) {
64 strtod(line, &endptr);
65 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
66 return false;
67 line = endptr;
68 EATWS();
69 }
70 if (*line != 0)
71 return false;
72 data.textureCoordinates.push_back((float)u);
73 data.textureCoordinates.push_back((float)v);
74 break;
75 }
76 case 'n':
77 {
78 // vn - vertex normal
79 // x y z
80 char c2 = *line ++;
81 if (c2 != ' ' && c2 != '\t')
82 return false;
83 EATWS();
84 char *endptr = 0;
85 double x = strtod(line, &endptr);
86 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
87 return false;
88 line = endptr;
89 EATWS();
90 double y = strtod(line, &endptr);
91 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
92 return false;
93 line = endptr;
94 EATWS();
95 double z = strtod(line, &endptr);
96 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
97 return false;
98 line = endptr;
99 EATWS();
100 if (*line != 0)
101 return false;
102 data.normals.push_back((float)x);
103 data.normals.push_back((float)y);
104 data.normals.push_back((float)z);
105 break;
106 }
107 case 'p':
108 {
109 // vp - vertex parameter
110 char c2 = *line ++;
111 if (c2 != ' ' && c2 != '\t')
112 return false;
113 EATWS();
114 char *endptr = 0;
115 double u = strtod(line, &endptr);
116 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
117 return false;
118 line = endptr;
119 EATWS();
120 double v = strtod(line, &endptr);
121 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
122 return false;
123 line = endptr;
124 EATWS();
125 double w = 0;
126 if (*line != 0) {
127 w = strtod(line, &endptr);
128 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
129 return false;
130 line = endptr;
131 EATWS();
132 }
133 if (*line != 0)
134 return false;
135 data.parameters.push_back((float)u);
136 data.parameters.push_back((float)v);
137 data.parameters.push_back((float)w);
138 break;
139 }
140 default:
141 {
142 // v - vertex geometry
143 if (c2 != ' ' && c2 != '\t')
144 return false;
145 EATWS();
146 char *endptr = 0;
147 double x = strtod(line, &endptr);
148 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
149 return false;
150 line = endptr;
151 EATWS();
152 double y = strtod(line, &endptr);
153 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
154 return false;
155 line = endptr;
156 EATWS();
157 double z = strtod(line, &endptr);
158 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
159 return false;
160 line = endptr;
161 EATWS();
162 double color_x = 0.0, color_y = 0.0, color_z = 0.0, color_w = 0.0;//undefine color
163 if (*line != 0) {
164 if (!data.has_vertex_color) {
165 data.has_vertex_color = true;
166 }
167 color_x = strtod(line, &endptr);
168 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
169 return false;
170 line = endptr;
171 EATWS();
172 color_y = strtod(line, &endptr);
173 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
174 return false;
175 line = endptr;
176 EATWS();
177 color_z = strtod(line, &endptr);
178 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
179 return false;
180 line = endptr;
181 EATWS();
182 color_w = 1.0;//default define alpha = 1.0
183 if (*line != 0) {
184 color_w = strtod(line, &endptr);
185 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0)) return false;
186 line = endptr;
187 EATWS();
188 }
189 }
190 // the following check is commented out because there may be obj files containing extra data, as those generated by Meshlab,
191 // see https://dev.prusa3d.com/browse/SPE-1019 for an example,
192 // and this would lead to a crash because no vertex would be stored
193// if (*line != 0)
194// return false;
195 data.coordinates.push_back((float)x);
196 data.coordinates.push_back((float)y);
197 data.coordinates.push_back((float)z);
198 data.coordinates.push_back((float) color_x);
199 data.coordinates.push_back((float) color_y);
200 data.coordinates.push_back((float) color_z);
201 data.coordinates.push_back((float) color_w);
202 break;
203 }
204 }
205 break;
206 }
207 case 'f':
208 {
209 // face
210 EATWS();
211 if (*line == 0)
212 return false;
213
214 // current vertex to be parsed
215 ObjVertex vertex;
216 char *endptr = 0;
217 while (*line != 0) {
218 // Parse a single vertex reference.
219 vertex.coordIdx = 0;
220 vertex.normalIdx = 0;
221 vertex.textureCoordIdx = 0;
222 vertex.coordIdx = strtol(line, &endptr, 10);
223 // Coordinate has to be defined
224 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != '/' && *endptr != 0))
225 return false;
226 line = endptr;
227 if (*line == '/') {
228 ++ line;
229 // Texture coordinate index may be missing after a 1st slash, but then the normal index has to be present.
230 if (*line != '/') {
231 // Parse the texture coordinate index.
232 vertex.textureCoordIdx = strtol(line, &endptr, 10);
233 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != '/' && *endptr != 0))
234 return false;
235 line = endptr;
236 }
237 if (*line == '/') {
238 // Parse normal index.
239 ++ line;
240 vertex.normalIdx = strtol(line, &endptr, 10);
241 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
242 return false;
243 line = endptr;
244 }
245 }
246 if (vertex.coordIdx < 0)
247 vertex.coordIdx += (int) data.coordinates.size() / OBJ_VERTEX_LENGTH;
248 else
249 -- vertex.coordIdx;
250 if (vertex.normalIdx < 0)
251 vertex.normalIdx += (int)data.normals.size() / 3;
252 else
253 -- vertex.normalIdx;
254 if (vertex.textureCoordIdx < 0)
255 vertex.textureCoordIdx += (int)data.textureCoordinates.size() / OBJ_TEXCOORD_LENGTH;
256 else
257 -- vertex.textureCoordIdx;
258 data.vertices.push_back(vertex);
259 EATWS();
260 }
261 if (data.usemtls.size() > 0) {
262 data.usemtls.back().vertexIdxEnd = (int) data.vertices.size();
263 }
264 if (data.usemtls.size() > 0) {
265 int face_index_count = 0;
266 for (int i = data.vertices.size() - 1; i >= 0; i--) {
267 if (data.vertices[i].coordIdx == -1) {
268 break;
269 }
270 face_index_count++;
271 }
272 if (face_index_count >= 3) {
273 data.usemtls.back().face_end += face_index_count - 2;
274 }
275 }
276 vertex.coordIdx = -1;
277 vertex.normalIdx = -1;
278 vertex.textureCoordIdx = -1;
279 data.vertices.push_back(vertex);
280 break;
281 }
282 case 'm':
283 {
284 if (*(line ++) != 't' ||
285 *(line ++) != 'l' ||
286 *(line ++) != 'l' ||
287 *(line ++) != 'i' ||
288 *(line ++) != 'b')
289 return false;
290 // mtllib [external .mtl file name]
291 // printf("mtllib %s\r\n", line);
292 EATWS();
293 data.mtllibs.push_back(std::string(line));
294 break;
295 }
296 case 'u':
297 {
298 if (*(line ++) != 's' ||
299 *(line ++) != 'e' ||
300 *(line ++) != 'm' ||
301 *(line ++) != 't' ||
302 *(line ++) != 'l')
303 return false;
304 // usemtl [material name]
305 // printf("usemtl %s\r\n", line);
306 EATWS();
307 if (data.usemtls.size()>0) {
308 data.usemtls.back().vertexIdxEnd = (int) data.vertices.size();
309 }
310 ObjUseMtl usemtl;
311 usemtl.vertexIdxFirst = (int)data.vertices.size();
312 usemtl.name = line;
313 data.usemtls.push_back(usemtl);
314 if (data.usemtls.size() == 1) {
315 data.usemtls.back().face_start = 0;
316 }
317 else {//>=2
318 auto count = data.usemtls.size();
319 auto& last_usemtl = data.usemtls[count-1];
320 auto& last_last_usemtl = data.usemtls[count - 2];
321 last_usemtl.face_start = last_last_usemtl.face_end + 1;
322 }
323 data.usemtls.back().face_end = data.usemtls.back().face_start - 1;
324 break;
325 }
326 case 'o':
327 {
328 // o [object name]
329 EATWS();
330 while (*line != ' ' && *line != '\t' && *line != 0)
331 ++ line;
332 // copy name to line.
333 EATWS();
334 if (*line != 0)
335 return false;
336 ObjObject object;
337 object.vertexIdxFirst = (int)data.vertices.size();
338 object.name = line;
339 data.objects.push_back(object);
340 break;
341 }
342 case 'g':
343 {
344 // g [group name]
345 // printf("group %s\r\n", line);
346 ObjGroup group;
347 group.vertexIdxFirst = (int)data.vertices.size();
348 group.name = line;
349 data.groups.push_back(group);
350 break;
351 }
352 case 's':
353 {
354 // s 1 / off
355 char c2 = *line ++;
356 if (c2 != ' ' && c2 != '\t')
357 return false;
358 EATWS();
359 char *endptr = 0;
360 long g = strtol(line, &endptr, 10);
361 if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
362 return false;
363 line = endptr;
364 EATWS();
365 if (*line != 0)
366 return false;
367 ObjSmoothingGroup group;
368 group.vertexIdxFirst = (int)data.vertices.size();
369 group.smoothingGroupID = g;
370 data.smoothingGroups.push_back(group);
371 break;
372 }
373 default:
374 BOOST_LOG_TRIVIAL(error) << "ObjParser: Unknown command: " << c1;
375 break;
376 }
377
378 return true;
379}
std::vector< float > normals
Definition objparser.hpp:108
std::vector< ObjGroup > groups
Definition objparser.hpp:115
std::vector< ObjVertex > vertices
Definition objparser.hpp:119
int vertexIdxFirst
Definition objparser.hpp:29
int coordIdx
Definition objparser.hpp:15
std::vector< float > parameters
Definition objparser.hpp:110
std::vector< ObjUseMtl > usemtls
Definition objparser.hpp:113
std::vector< float > coordinates
Definition objparser.hpp:103
std::vector< std::string > mtllibs
Definition objparser.hpp:112
int vertexIdxFirst
Definition objparser.hpp:60
std::vector< float > textureCoordinates
Definition objparser.hpp:106
bool has_vertex_color
Definition objparser.hpp:104
std::vector< ObjObject > objects
Definition objparser.hpp:114
int vertexIdxFirst
Definition objparser.hpp:73
int vertexIdxFirst
Definition objparser.hpp:85
std::vector< ObjSmoothingGroup > smoothingGroups
Definition objparser.hpp:116
Definition objparser.hpp:28
Definition objparser.hpp:84
Definition objparser.hpp:72
Definition objparser.hpp:59
Definition objparser.hpp:14
#define OBJ_TEXCOORD_LENGTH
Definition objparser.hpp:96
#define OBJ_VERTEX_LENGTH
Definition objparser.hpp:95

References ObjParser::ObjVertex::coordIdx, ObjParser::ObjData::coordinates, count, EATWS, ObjParser::ObjData::groups, ObjParser::ObjData::has_vertex_color, Slic3r::is_decimal_separator_point(), ObjParser::ObjData::mtllibs, ObjParser::ObjGroup::name, ObjParser::ObjUseMtl::name, ObjParser::ObjVertex::normalIdx, ObjParser::ObjData::normals, OBJ_TEXCOORD_LENGTH, OBJ_VERTEX_LENGTH, ObjParser::ObjData::objects, ObjParser::ObjData::parameters, ObjParser::ObjSmoothingGroup::smoothingGroupID, ObjParser::ObjData::smoothingGroups, ObjParser::ObjVertex::textureCoordIdx, ObjParser::ObjData::textureCoordinates, ObjParser::ObjData::usemtls, ObjParser::ObjGroup::vertexIdxFirst, ObjParser::ObjObject::vertexIdxFirst, ObjParser::ObjSmoothingGroup::vertexIdxFirst, ObjParser::ObjUseMtl::vertexIdxFirst, and ObjParser::ObjData::vertices.

Referenced by objparse(), and objparse().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ objbinload()

bool ObjParser::objbinload ( const char * path,
ObjData & data )
906{
907 FILE *pFile = boost::nowide::fopen(path, "rb");
908 if (pFile == 0)
909 return false;
910
911 data.version = 0;
912 if (::fread(&data.version, sizeof(data.version), 1, pFile) != 1)
913 return false;
914 if (data.version != 1)
915 return false;
916
917 bool result =
918 loadvector(pFile, data.coordinates) &&
919 loadvector(pFile, data.textureCoordinates) &&
920 loadvector(pFile, data.normals) &&
921 loadvector(pFile, data.parameters) &&
922 loadvector(pFile, data.mtllibs) &&
923 loadvectornameidx(pFile, data.usemtls) &&
924 loadvectornameidx(pFile, data.objects) &&
925 loadvectornameidx(pFile, data.groups) &&
926 loadvector(pFile, data.smoothingGroups) &&
927 loadvector(pFile, data.vertices);
928
929 ::fclose(pFile);
930 return result;
931}
bool loadvectornameidx(FILE *pFile, std::vector< T > &v)
Definition objparser.cpp:860
int version
Definition objparser.hpp:100
bool loadvector(FILE *pFile, std::vector< T > &v)
Definition objparser.cpp:825

References ObjParser::ObjData::coordinates, ObjParser::ObjData::groups, loadvector(), loadvectornameidx(), ObjParser::ObjData::mtllibs, ObjParser::ObjData::normals, ObjParser::ObjData::objects, ObjParser::ObjData::parameters, ObjParser::ObjData::smoothingGroups, ObjParser::ObjData::textureCoordinates, ObjParser::ObjData::usemtls, ObjParser::ObjData::version, and ObjParser::ObjData::vertices.

Here is the call graph for this function:

◆ objbinsave()

bool ObjParser::objbinsave ( const char * path,
const ObjData & data )
881{
882 FILE *pFile = boost::nowide::fopen(path, "wb");
883 if (pFile == 0)
884 return false;
885
886 size_t version = 1;
887 ::fwrite(&version, 1, sizeof(version), pFile);
888
889 bool result =
890 savevector(pFile, data.coordinates) &&
891 savevector(pFile, data.textureCoordinates) &&
892 savevector(pFile, data.normals) &&
893 savevector(pFile, data.parameters) &&
894 savevector(pFile, data.mtllibs) &&
895 savevectornameidx(pFile, data.usemtls) &&
896 savevectornameidx(pFile, data.objects) &&
897 savevectornameidx(pFile, data.groups) &&
898 savevector(pFile, data.smoothingGroups) &&
899 savevector(pFile, data.vertices);
900
901 ::fclose(pFile);
902 return result;
903}
bool savevector(FILE *pFile, const std::vector< T > &v)
Definition objparser.cpp:788
bool savevectornameidx(FILE *pFile, const std::vector< T > &v)
Definition objparser.cpp:811

References ObjParser::ObjData::coordinates, ObjParser::ObjData::groups, ObjParser::ObjData::mtllibs, ObjParser::ObjData::normals, ObjParser::ObjData::objects, ObjParser::ObjData::parameters, savevector(), savevectornameidx(), ObjParser::ObjData::smoothingGroups, ObjParser::ObjData::textureCoordinates, ObjParser::ObjData::usemtls, and ObjParser::ObjData::vertices.

Here is the call graph for this function:

◆ objequal()

bool ObjParser::objequal ( const ObjData & data1,
const ObjData & data2 )
extern
955{
956 //FIXME ignore version number
957 // version;
958
959 return
960 vectorequal(data1.coordinates, data2.coordinates) &&
962 vectorequal(data1.normals, data2.normals) &&
963 vectorequal(data1.parameters, data2.parameters) &&
964 vectorequal(data1.mtllibs, data2.mtllibs) &&
965 vectorequal(data1.usemtls, data2.usemtls) &&
966 vectorequal(data1.objects, data2.objects) &&
967 vectorequal(data1.groups, data2.groups) &&
968 vectorequal(data1.vertices, data2.vertices);
969}
bool vectorequal(const std::vector< T > &v1, const std::vector< T > &v2)
Definition objparser.cpp:934

References ObjParser::ObjData::coordinates, ObjParser::ObjData::groups, ObjParser::ObjData::mtllibs, ObjParser::ObjData::normals, ObjParser::ObjData::objects, ObjParser::ObjData::parameters, ObjParser::ObjData::textureCoordinates, ObjParser::ObjData::usemtls, vectorequal(), and ObjParser::ObjData::vertices.

Here is the call graph for this function:

◆ objparse() [1/2]

bool ObjParser::objparse ( const char * path,
ObjData & data )
675{
676 Slic3r::CNumericLocalesSetter locales_setter;
677
678 FILE *pFile = boost::nowide::fopen(path, "rt");
679 if (pFile == 0)
680 return false;
681
682 try {
683 char buf[65536 * 2];
684 size_t len = 0;
685 size_t lenPrev = 0;
686 while ((len = ::fread(buf + lenPrev, 1, 65536, pFile)) != 0) {
687 len += lenPrev;
688 size_t lastLine = 0;
689 for (size_t i = 0; i < len; ++ i)
690 if (buf[i] == '\r' || buf[i] == '\n') {
691 buf[i] = 0;
692 char *c = buf + lastLine;
693 while (*c == ' ' || *c == '\t')
694 ++ c;
695 //FIXME check the return value and exit on error?
696 // Will it break parsing of some obj files?
697 obj_parseline(c, data);
698 lastLine = i + 1;
699 }
700 lenPrev = len - lastLine;
701 if (lenPrev > 65536) {
702 BOOST_LOG_TRIVIAL(error) << "ObjParser: Excessive line length";
703 ::fclose(pFile);
704 return false;
705 }
706 memmove(buf, buf + lastLine, lenPrev);
707 }
708 }
709 catch (std::bad_alloc&) {
710 BOOST_LOG_TRIVIAL(error) << "ObjParser: Out of memory";
711 }
712 ::fclose(pFile);
713 return true;
714}
static bool obj_parseline(const char *line, ObjData &data)
Definition objparser.cpp:21

References obj_parseline().

Referenced by Slic3r::load_obj().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ objparse() [2/2]

bool ObjParser::objparse ( std::istream & stream,
ObjData & data )
756{
757 Slic3r::CNumericLocalesSetter locales_setter;
758
759 try {
760 char buf[65536 * 2];
761 size_t len = 0;
762 size_t lenPrev = 0;
763 while ((len = size_t(stream.read(buf + lenPrev, 65536).gcount())) != 0) {
764 len += lenPrev;
765 size_t lastLine = 0;
766 for (size_t i = 0; i < len; ++ i)
767 if (buf[i] == '\r' || buf[i] == '\n') {
768 buf[i] = 0;
769 char *c = buf + lastLine;
770 while (*c == ' ' || *c == '\t')
771 ++ c;
772 obj_parseline(c, data);
773 lastLine = i + 1;
774 }
775 lenPrev = len - lastLine;
776 memmove(buf, buf + lastLine, lenPrev);
777 }
778 }
779 catch (std::bad_alloc&) {
780 BOOST_LOG_TRIVIAL(error) << "ObjParser: Out of memory";
781 return false;
782 }
783
784 return true;
785}

References obj_parseline().

Here is the call graph for this function:

◆ operator==() [1/5]

bool ObjParser::operator== ( const ObjGroup & v1,
const ObjGroup & v2 )
inline
78{
79 return v1.vertexIdxFirst == v2.vertexIdxFirst &&
80 v1.name.compare(v2.name) == 0;
81}
std::string name
Definition objparser.hpp:74

References ObjParser::ObjGroup::name, and ObjParser::ObjGroup::vertexIdxFirst.

◆ operator==() [2/5]

bool ObjParser::operator== ( const ObjObject & v1,
const ObjObject & v2 )
inline
65{
66 return
68 v1.name.compare(v2.name) == 0;
69}
std::string name
Definition objparser.hpp:61

References ObjParser::ObjObject::name, and ObjParser::ObjObject::vertexIdxFirst.

◆ operator==() [3/5]

bool ObjParser::operator== ( const ObjSmoothingGroup & v1,
const ObjSmoothingGroup & v2 )
inline

◆ operator==() [4/5]

bool ObjParser::operator== ( const ObjUseMtl & v1,
const ObjUseMtl & v2 )
inline
53{
54 return v1.vertexIdxFirst == v2.vertexIdxFirst &&
55 v1.name.compare(v2.name) == 0;
56}
std::string name
Definition objparser.hpp:33

References ObjParser::ObjUseMtl::name, and ObjParser::ObjUseMtl::vertexIdxFirst.

◆ operator==() [5/5]

bool ObjParser::operator== ( const ObjVertex & v1,
const ObjVertex & v2 )
inline
21{
22 return v1.coordIdx == v2.coordIdx &&
24 v1.normalIdx == v2.normalIdx;
25}
int textureCoordIdx
Definition objparser.hpp:16
int normalIdx
Definition objparser.hpp:17

References ObjParser::ObjVertex::coordIdx, ObjParser::ObjVertex::normalIdx, and ObjParser::ObjVertex::textureCoordIdx.

◆ savevector() [1/2]

bool ObjParser::savevector ( FILE * pFile,
const std::vector< std::string > & v )
799{
800 size_t cnt = v.size();
801 ::fwrite(&cnt, 1, sizeof(cnt), pFile);
802 for (size_t i = 0; i < cnt; ++ i) {
803 size_t len = v[i].size();
804 ::fwrite(&len, 1, sizeof(cnt), pFile);
805 ::fwrite(v[i].c_str(), 1, len, pFile);
806 }
807 return true;
808}

◆ savevector() [2/2]

template<typename T>
bool ObjParser::savevector ( FILE * pFile,
const std::vector< T > & v )
789{
790 size_t cnt = v.size();
791 ::fwrite(&cnt, 1, sizeof(cnt), pFile);
792 //FIXME sizeof(T) works for data types leaving no gaps in the allocated vector because of alignment of the T type.
793 if (! v.empty())
794 ::fwrite(&v.front(), 1, sizeof(T) * cnt, pFile);
795 return true;
796}

Referenced by objbinsave().

Here is the caller graph for this function:

◆ savevectornameidx()

template<typename T>
bool ObjParser::savevectornameidx ( FILE * pFile,
const std::vector< T > & v )
812{
813 size_t cnt = v.size();
814 ::fwrite(&cnt, 1, sizeof(cnt), pFile);
815 for (size_t i = 0; i < cnt; ++ i) {
816 ::fwrite(&v[i].vertexIdxFirst, 1, sizeof(int), pFile);
817 size_t len = v[i].name.size();
818 ::fwrite(&len, 1, sizeof(cnt), pFile);
819 ::fwrite(v[i].name.c_str(), 1, len, pFile);
820 }
821 return true;
822}

Referenced by objbinsave().

Here is the caller graph for this function:

◆ vectorequal() [1/2]

bool ObjParser::vectorequal ( const std::vector< std::string > & v1,
const std::vector< std::string > & v2 )
945{
946 if (v1.size() != v2.size())
947 return false;
948 for (size_t i = 0; i < v1.size(); ++ i)
949 if (v1[i].compare(v2[i]) != 0)
950 return false;
951 return true;
952}

◆ vectorequal() [2/2]

template<typename T>
bool ObjParser::vectorequal ( const std::vector< T > & v1,
const std::vector< T > & v2 )
935{
936 if (v1.size() != v2.size())
937 return false;
938 for (size_t i = 0; i < v1.size(); ++ i)
939 if (! (v1[i] == v2[i]))
940 return false;
941 return true;
942}

Referenced by objequal().

Here is the caller graph for this function:

Variable Documentation

◆ cur_mtl_name

std::string ObjParser::cur_mtl_name = ""
static

Referenced by mtl_parseline(), and mtlparse().