Files
openmesh/src/OpenMesh/Apps/Unsupported/OsgViewer/osgviewer.cc

523 lines
15 KiB
C++
Raw Normal View History

/*===========================================================================*\
* *
* OpenMesh *
* Copyright (C) 2001-2014 by Computer Graphics Group, RWTH Aachen *
* www.openmesh.org *
* *
*---------------------------------------------------------------------------*
* This file is part of OpenMesh. *
* *
* OpenMesh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of *
* the License, or (at your option) any later version with the *
* following exceptions: *
* *
* If other files instantiate templates or use macros *
* or inline functions from this file, or you compile this file and *
* link it with other files to produce an executable, this file does *
* not by itself cause the resulting executable to be covered by the *
* GNU Lesser General Public License. This exception does not however *
* invalidate any other reasons why the executable file might be *
* covered by the GNU Lesser General Public License. *
* *
* OpenMesh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU LesserGeneral Public *
* License along with OpenMesh. If not, *
* see <http://www.gnu.org/licenses/>. *
* *
\*===========================================================================*/
/*===========================================================================*\
* *
* $Revision$ *
* $Date$ *
* *
\*===========================================================================*/
// -------------------- STL
#include <memory>
#include <iostream>
#include <iomanip>
#include <stdexcept>
// -------------------- OpenSG
#include <GL/glut.h>
#include <OpenSG/OSGConfig.h>
#include <OpenSG/OSGGLUTWindow.h>
#include <OpenSG/OSGSimpleSceneManager.h>
#include <OpenSG/OSGSceneFileHandler.h>
#include <OpenSG/OSGTriangleIterator.h>
#include <OpenSG/OSGFaceIterator.h>
// -------------------- OpenMesh
#include <OpenMesh/Core/IO/MeshIO.hh> // always before kernel type
#include <OpenMesh/Tools/Kernel_OSG/TriMesh_OSGArrayKernelT.hh>
#include <OpenMesh/Tools/Kernel_OSG/bindT.hh>
#include <OpenMesh/Tools/Utils/Timer.hh>
#include <OpenMesh/Tools/Subdivider/Uniform/LoopT.hh>
// --------------------
#include <OpenMesh/Tools/Smoother/JacobiLaplaceSmootherT.hh>
// ----------------------------------------------------------- namespace -----
OSG_USING_NAMESPACE
// ------------------------------------------------------------- OpenMesh ----
struct MeshTraits : public OpenMesh::Kernel_OSG::Traits
{
HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge);
VertexAttributes ( OpenMesh::Attributes::Normal |
OpenMesh::Attributes::Color );
FaceAttributes ( OpenMesh::Attributes::Normal );
};
typedef OpenMesh::Kernel_OSG::TriMesh_OSGArrayKernelT<MeshTraits> mesh_t;
typedef OpenMesh::Subdivider::Uniform::LoopT< mesh_t > loop_t;
typedef OpenMesh::Smoother::JacobiLaplaceSmootherT< mesh_t > smoother_t;
// --------------------------------------------------------------- globals ----
class MeshContainer
{
public:
typedef std::vector<mesh_t*> meshbag_t;
const size_t InvalidIndex;
public:
MeshContainer() : InvalidIndex(size_t(-1))
{ }
~MeshContainer()
{
meshbag_t::iterator it = meshes_.begin();
for(;it != meshes_.end(); ++it)
delete *it;
}
size_t size() const { return meshes_.size(); }
mesh_t& operator [] ( size_t idx )
{
if (idx < meshes_.size())
return *(meshes_[idx]);
throw std::range_error("Invalid index");
}
const mesh_t& operator [] ( size_t idx ) const
{
if (idx < meshes_.size())
return *(meshes_[idx]);
throw std::range_error("Invalid index");
}
bool bind( osg::GeometryPtr geo )
{
std::auto_ptr<mesh_t> obj(new mesh_t);
return (OpenMesh::Kernel_OSG::bind< mesh_t >( *obj, geo))
? (meshes_.push_back(obj.release()), true)
: false;
}
private:
meshbag_t meshes_;
private: // non-copyable
MeshContainer( const MeshContainer& );
MeshContainer& operator = ( const MeshContainer& );
};
struct Globals
{
// OpenSG specific entities
SimpleSceneManager* mgr;
GLUTWindowPtr gwin;
NodePtr root;
std::vector<GeometryPtr> geos;
size_t sel;
bool statistics;
// OpenMesh specific entities
MeshContainer meshes;
} g;
// -------------------------------------------------------------- forwards ----
void display(void);
void reshape(int width, int height);
void mouse(int button, int state, int x, int y);
void keyboard(unsigned char key, int x, int y);
void motion(int x, int y);
// ---------------------------------------------------------------- helper ----
// setup the GLUT library which handles the windows for us
int setupGLUT(int *argc, char *argv[])
{
glutInit(argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
int winid = glutCreateWindow("OpenMesh within OpenSG");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutKeyboardFunc(keyboard);
return winid;
}
// -------------------------------------------------- locate geometry node ----
/*
This function uses the fact that ::dcast() acts like dynamic_cast. It tries
to dcast the core to a GeometryPtr, and tests the result to see if it
actually was derived from Geometry.
*/
Action::ResultE bindGeo(NodePtr& node)
{
GeometryPtr geo = GeometryPtr::dcast(node->getCore());
if (geo!=NullFC)
{
if ( g.meshes.bind( geo ) )
{
std::cout << " Geometry connected to OpenMesh object\n";
g.geos.push_back(geo);
g.sel = g.meshes.size()-1;
assert( g.geos.size() == g.meshes.size() );
}
else
std::cerr << " Warning! Could not bind the OpenMesh"
<< " object to the geometry!\n";
}
return Action::Continue;
}
// ------------------------------------------------------------------ main ----
int main(int argc, char **argv)
{
// OSG init
osgInit(argc,argv);
int winid = setupGLUT(&argc, argv);
// the connection between GLUT and OpenSG
g.gwin = GLUTWindow::create();
g.gwin->setId(winid);
g.gwin->init();
// -------------------- create root node with core
std::cout << "Create root node with core\n";
g.root = Node::create();
NodeCorePtr core = Group::create();
osg::beginEditCP(g.root);
{
g.root->setCore(core);
}
osg::endEditCP(g.root);
// -------------------- load the scene
std::cout << "Load a scene from '" << argv[1] << "'\n";
NodePtr node = SceneFileHandler::the().read( argv[1] );
if ( node != NullFC )
{
osg::beginEditCP(g.root);
{
g.root->addChild(node);
}
osg::endEditCP(g.root);
}
else
return 1;
// -------------------- bind all geometry nodes to an OpenMesh
std::cout << "Bind all geometry nodes\n";
traverse(g.root,
osgTypedFunctionFunctor1CPtrRef<Action::ResultE,NodePtr>(bindGeo));
if (!g.meshes.size())
{
std::cerr << " No geometry found. Nothing to do!\n";
return 1;
}
else
std::cout << " Number of bound geometry: " << g.meshes.size() << std::endl;
// -------------------- create the SimpleSceneManager helper
std::cout << "Create simple scene manager\n";
g.mgr = new SimpleSceneManager;
// tell the manager what to manage
g.mgr->setWindow(g.gwin);
g.mgr->setRoot (g.root);
//
g.mgr->useOpenSGLogo();
g.mgr->setStatistics(false);
// -------------------- show the whole scene
std::cout << "Display everything\n";
g.mgr->showAll();
glutMainLoop();
return 0;
}
// --------------------------------------------------------------- display ----
void display(void)
{
g.mgr->redraw();
}
// --------------------------------------------------------------- reshape ----
void reshape(int w, int h)
{
g.mgr->resize(w, h);
glutPostRedisplay();
}
// ----------------------------------------------------------------- mouse ----
void mouse(int button, int state, int x, int y)
{
if (state)
{
g.mgr->mouseButtonRelease(button, x, y);
// if ( g.mode & FLYMODE )
// glutIdleFunc(NULL);
}
else
{
g.mgr->mouseButtonPress(button, x, y);
// if ( g.mode & FLYMODE )
// glutIdleFunc(idle);
}
glutPostRedisplay();
}
// -------------------------------------------------------------- keyboard ----
void keyboard(unsigned char key, int x, int y)
{
#define MESH g.meshes[g.sel]
#define GEO g.geos[g.sel]
#define YN(b) (b?"yes":"no")
OpenMesh::Utils::Timer t;
using namespace std;
switch(key)
{
case 27: // escape
exit(0);
break;
case 'i':
{
cout << "OpenMesh information for obj #" << g.sel << ":\n";
cout << " #Vertices: " << MESH.n_vertices() << endl;
cout << " #Faces: " << MESH.n_faces() << endl;
cout << " #Edges: " << MESH.n_edges() << endl;
cout << " v. normal: " << YN(MESH.has_vertex_normals()) << endl;
cout << " v. color: " << YN(MESH.has_vertex_colors()) << endl;
cout << "v. texcoord: " << YN(MESH.has_vertex_texcoords()) << endl;
cout << " f. normal: " << YN(MESH.has_face_normals()) << endl;
cout << " f. color: " << YN(MESH.has_face_colors()) << endl;
break;
}
case 'I':
cout << "Geometry information for obj #" << g.sel << ":\n";
cout << " #Types: " << GEO->getTypes()->size() << endl;
cout << " #Lengths: " << GEO->getLengths()->size() << endl;
cout << " #Indices: " << GEO->getIndices()->size() << endl;
cout << "#Positions: " << GEO->getPositions()->size() << endl;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if ((size_t(key)-size_t('0')) < g.meshes.size())
{
g.sel = (size_t(key)-size_t('0'));
cout << "Selected geometry #" << g.sel << endl;
}
break;
case '+':
g.sel = ++g.sel % g.meshes.size();
cout << "Selected geometry #" << g.sel << endl;
break;
case '-':
g.sel = (g.sel + g.meshes.size()-1) % g.meshes.size();
cout << "Selected geometry #" << g.sel << endl;
break;
case 'S':
g.mgr->setStatistics( g.statistics=!g.statistics );
g.statistics
? cout << "Statistics enabled.\n"
: cout << "Statistics disabled.\n";
glutPostRedisplay();
break;
case 'w':
{
OpenMesh::IO::Options opt;
if (MESH.has_vertex_colors())
opt += OpenMesh::IO::Options::VertexColor;
if (MESH.has_face_colors())
opt += OpenMesh::IO::Options::FaceColor;
if (MESH.has_vertex_normals())
opt += OpenMesh::IO::Options::VertexNormal;
std::string ofname;
{
std::stringstream ostr;
ostr << "object-" << g.sel << ".om";
ofname = ostr.str();
}
cout << "Writing OpenMesh of geometry #" << g.sel
<< " to " << ofname << std::endl;
t.start();
bool rc = OpenMesh::IO::write_mesh( MESH, ofname, opt);
t.stop();
rc
? cout << " Done (" << t.as_string() << ")\n"
: cout << " Failed to store OpenMesh\n";
break;
}
case 's':
{
cout << "Appyling two smoothing steps on selected geometry..";
t.start();
smoother_t smoother( g.meshes[g.sel] );
smoother.initialize( smoother_t::Tangential, smoother_t::C1 );
beginEditCP(g.geos[g.sel]);
smoother.smooth(2);
endEditCP(g.geos[g.sel]);
t.stop();
cout << "done. " << t.as_string() << endl;
glutPostRedisplay();
break;
}
case 't':
{
cout << "Applying two smoothing steps on all bound geometry..";
t.start();
for(size_t i = 0; i < g.meshes.size(); ++i)
{
smoother_t smoother( g.meshes[i] );
smoother.initialize( smoother_t::Tangential, smoother_t::C1 );
beginEditCP(g.geos[i]);
smoother.smooth(2);
endEditCP(g.geos[i]);
}
t.stop();
cout << "done. " << t.as_string() << endl;
glutPostRedisplay();
break;
}
case 'c':
{
OpenMesh::IO::Options opt;
if (MESH.has_vertex_colors())
opt += OpenMesh::IO::Options::VertexColor;
if (MESH.has_face_colors())
opt += OpenMesh::IO::Options::FaceColor;
if (MESH.has_vertex_normals())
opt += OpenMesh::IO::Options::VertexNormal;
mesh_t m(MESH);
std::string ofname;
{
std::stringstream ostr;
ostr << "copy-" << g.sel << ".om";
ofname = ostr.str();
}
cout << "Writing copy of geometry #" << g.sel
<< " to " << ofname << std::endl;
t.start();
bool rc = OpenMesh::IO::write_mesh( MESH, ofname, opt);
t.stop();
rc
? cout << " Done (" << t.as_string() << ")\n"
: cout << " Failed to store OpenMesh\n";
OpenMesh::IO::write_mesh( m, ofname );
break;
}
case 'u':
{
cout << "Applying one step of loop subdivision..";
t.start();
loop_t loop;
beginEditCP( GEO );
loop( MESH, 1 );
MESH.update_normals();
endEditCP( GEO );
t.stop();
cout << "done. " << t.as_string() << endl;
glutPostRedisplay();
break;
}
default:
cout << "key [0x" << setw(4) << hex << key << dec << "]\n";
}
#undef YN
#undef MESH
}
//----------------------------------------------------------------- motion ----
void motion(int x, int y)
{
g.mgr->mouseMove(x, y);
glutPostRedisplay();
}