#include #include #include #include // #include #include #include #include #include struct MyTraits : public OpenMesh::DefaultTraits { VertexAttributes ( OpenMesh::Attributes::Normal | OpenMesh::Attributes::Color | OpenMesh::Attributes::TexCoord2D ); HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge ); FaceAttributes ( OpenMesh::Attributes::Normal | OpenMesh::Attributes::Color ); }; typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; void usage_and_exit(int xcode) { using std::cout; using std::endl; cout << "\nUsage: mconvert [option] []\n\n"; cout << " Convert from one 3D geometry format to another.\n" << " Or simply display some information about the object\n" << " stored in .\n" << endl; cout << "Options:\n" << endl; cout << " -b\tUse binary mode if supported by target format.\n" << endl; cout << " -l\tStore least significant bit first (LSB, little endian).\n" << endl; cout << " -m\tStore most significant bit first (MSB, big endian).\n" << endl; cout << " -s\tSwap byte order.\n" << endl; cout << " -B\tUse binary mode if supported by source format.\n" << endl; cout << " -S\tSwap byte order of input data.\n" << endl; cout << " -c\tCopy vertex color if provided by input.\n" << endl; cout << " -d\tCopy face color if provided by input.\n" << endl; cout << " -C\tTranslate object in its center-of-gravity.\n" << endl; cout << " -n\tCopy vertex normals if provided by input. Else compute normals.\n" << endl; cout << " -N\tReverse normal directions.\n" << endl; cout << " -t\tCopy vertex texture coordinates if provided by input file.\n" << endl; cout << " -T \"x y z\"\tTranslate object by vector (x, y, z)'\"\n" << std::endl; cout << endl; exit(xcode); } // ---------------------------------------------------------------------------- template struct Option : std::pair< T, bool > { typedef std::pair< T, bool > Base; Option() { Base::second = false; } bool is_valid() const { return Base::second; } bool is_empty() const { return !Base::second; } operator T& () { return Base::first; } operator const T& () const { return Base::first; } Option& operator = ( const T& _rhs ) { Base::first = _rhs; Base::second=true; return *this; } bool operator == ( const T& _rhs ) const { return Base::first == _rhs; } bool operator != ( const T& _rhs ) const { return Base::first != _rhs; } }; template std::ostream& operator << (std::ostream& _os, const Option& _opt ) { if (_opt.second) _os << _opt.first; else _os << ""; return _os; } template std::istream& operator >> (std::istream& _is, Option& _opt ) { _is >> _opt.first; _opt.second = true; return _is; } // ---------------------------------------------------------------------------- int main(int argc, char *argv[] ) { // ------------------------------------------------------------ command line int c; std::string ifname, ofname; bool rev_normals = false; bool obj_center = false; OpenMesh::IO::Options opt, ropt; Option< MyMesh::Point > tvec; while ( (c=getopt(argc, argv, "bBcdCi:hlmnNo:sStT:"))!=-1 ) { switch(c) { case 'b': opt += OpenMesh::IO::Options::Binary; break; case 'B': ropt += OpenMesh::IO::Options::Binary; break; case 'l': opt += OpenMesh::IO::Options::LSB; break; case 'm': opt += OpenMesh::IO::Options::MSB; break; case 's': opt += OpenMesh::IO::Options::Swap; break; case 'S': ropt += OpenMesh::IO::Options::Swap; break; case 'n': opt += OpenMesh::IO::Options::VertexNormal; break; case 'N': rev_normals = true; break; case 'C': obj_center = true; break; case 'c': opt += OpenMesh::IO::Options::VertexColor; break; case 'd': opt += OpenMesh::IO::Options::FaceColor; break; case 't': opt += OpenMesh::IO::Options::VertexTexCoord; break; case 'T': { std::cout << optarg << std::endl; std::stringstream str; str << optarg; str >> tvec; std::cout << tvec << std::endl; break; } case 'i': ifname = optarg; break; case 'o': ofname = optarg; break; case 'h': usage_and_exit(0); case '?': default: usage_and_exit(1); } } if (ifname.empty()) { if (optind < argc) ifname = argv[optind++]; else usage_and_exit(1); } MyMesh mesh; OpenMesh::Utils::Timer timer; // ------------------------------------------------------------ read std::cout << "reading.." << std::endl; { bool rc; timer.start(); rc = OpenMesh::IO::read_mesh( mesh, ifname, ropt ); timer.stop(); if (rc) std::cout << " read in " << timer.as_string() << std::endl; else { std::cout << " read failed\n" << std::endl; return 1; } timer.reset(); } // ---------------------------------------- some information about input std::cout << (ropt.check(OpenMesh::IO::Options::Binary) ? " source is binary\n" : " source is ascii\n"); std::cout << " #V " << mesh.n_vertices() << std::endl; std::cout << " #E " << mesh.n_edges() << std::endl; std::cout << " #F " << mesh.n_faces() << std::endl; if (ropt.vertex_has_texcoord()) std::cout << " has texture coordinates" << std::endl; if (ropt.vertex_has_normal()) std::cout << " has vertex normals" << std::endl; if (ropt.vertex_has_color()) std::cout << " has vertex colors" << std::endl; if (ropt.face_has_normal()) std::cout << " has face normals" << std::endl; if (ropt.face_has_color()) std::cout << " has face colors" << std::endl; // if (ofname.empty()) { if ( optind < argc ) ofname = argv[optind++]; else return 0; } // ------------------------------------------------------------ features // ---------------------------------------- compute normal feature if ( opt.vertex_has_normal() && !ropt.vertex_has_normal()) { std::cout << "compute normals" << std::endl; timer.start(); mesh.update_face_normals(); timer.stop(); std::cout << " " << mesh.n_faces() << " face normals in " << timer.as_string() << std::endl; timer.reset(); timer.start(); mesh.update_vertex_normals(); timer.stop(); std::cout << " " << mesh.n_vertices() << " vertex normals in " << timer.as_string() << std::endl; timer.reset(); } // ---------------------------------------- reverse normal feature if ( rev_normals && ropt.vertex_has_normal() ) { std::cout << "reverse normal directions" << std::endl; timer.start(); MyMesh::VertexIter vit = mesh.vertices_begin(); for (; vit != mesh.vertices_end(); ++vit) mesh.set_normal( vit.handle(), -mesh.normal( vit.handle() ) ); timer.stop(); std::cout << " " << mesh.n_vertices() << " vertex normals in " << timer.as_string() << std::endl; timer.reset(); } // ---------------------------------------- centering feature if ( obj_center ) { OpenMesh::Vec3f cog(0,0,0); size_t nv; std::cout << "center object" << std::endl; timer.start(); MyMesh::VertexIter vit = mesh.vertices_begin(); for (; vit != mesh.vertices_end(); ++vit) cog += mesh.point( vit ); timer.stop(); nv = mesh.n_vertices(); cog *= 1.0f/mesh.n_vertices(); std::cout << " cog = [" << cog << "]'" << std::endl; if (cog.sqrnorm() > 0.8) // actually one should consider the size of object { vit = mesh.vertices_begin(); timer.cont(); for (; vit != mesh.vertices_end(); ++vit) mesh.set_point( vit , mesh.point( vit )-cog ); timer.stop(); nv += mesh.n_vertices(); } else std::cout << " already centered!" << std::endl; std::cout << " visited " << nv << " vertices in " << timer.as_string() << std::endl; timer.reset(); } // ---------------------------------------- translate feature if ( tvec.is_valid() ) { std::cout << "Translate object by " << tvec << std::endl; timer.start(); MyMesh::VertexIter vit = mesh.vertices_begin(); for (; vit != mesh.vertices_end(); ++vit) mesh.set_point( vit , mesh.point( vit ) + tvec.first ); timer.stop(); std::cout << " moved " << mesh.n_vertices() << " vertices in " << timer.as_string() << std::endl; } // ---------------------------------------- color vertices feature if ( opt.check( OpenMesh::IO::Options::VertexColor ) && !ropt.check( OpenMesh::IO::Options::VertexColor ) ) { std::cout << "Color vertices" << std::endl; double d = 256.0/double(mesh.n_vertices()); double d2 = d/2.0; double r = 0.0, g = 0.0, b = 255.0; timer.start(); MyMesh::VertexIter vit = mesh.vertices_begin(); for (; vit != mesh.vertices_end(); ++vit) { mesh.set_color( vit , MyMesh::Color( std::min((int)(r+0.5),255), std::min((int)(g+0.5),255), std::max((int)(b+0.5),0) ) ); r += d; g += d2; b -= d; } timer.stop(); std::cout << " colored " << mesh.n_vertices() << " vertices in " << timer.as_string() << std::endl; } // ---------------------------------------- color faces feature if ( opt.check( OpenMesh::IO::Options::FaceColor ) && !ropt.check( OpenMesh::IO::Options::FaceColor ) ) { std::cout << "Color faces" << std::endl; double d = 256.0/double(mesh.n_faces()); double d2 = d/2.0; double r = 0.0, g = 50.0, b = 255.0; timer.start(); MyMesh::FaceIter it = mesh.faces_begin(); for (; it != mesh.faces_end(); ++it) { mesh.set_color( it , MyMesh::Color( std::min((int)(r+0.5),255), std::min((int)(g+0.5),255), std::max((int)(b+0.5),0) ) ); r += d2; // g += d2; b -= d; } timer.stop(); std::cout << " colored " << mesh.n_faces() << " faces in " << timer.as_string() << std::endl; } // ------------------------------------------------------------ write std::cout << "writing.." << std::endl; { bool rc; timer.start(); rc = OpenMesh::IO::write_mesh( mesh, ofname, opt ); timer.stop(); if (!rc) { std::cerr << " error writing mesh!" << std::endl; return 1; } // -------------------------------------- write output and some info if ( opt.check(OpenMesh::IO::Options::Binary) ) { std::cout << " " << OpenMesh::IO::binary_size(mesh, ofname, opt) << std::endl; } if ( opt.vertex_has_normal() ) std::cout << " with vertex normals" << std::endl; if ( opt.vertex_has_color() ) std::cout << " with vertex colors" << std::endl; if ( opt.vertex_has_texcoord() ) std::cout << " with vertex texcoord" << std::endl; if ( opt.face_has_normal() ) std::cout << " with face normals" << std::endl; if ( opt.face_has_color() ) std::cout << " with face colors" << std::endl; std::cout << " wrote in " << timer.as_string() << std::endl; timer.reset(); } return 0; }