diff --git a/src/OpenMesh/Apps/CMakeLists.txt b/src/OpenMesh/Apps/CMakeLists.txt
index a1ebbd8c..c3a9c71d 100644
--- a/src/OpenMesh/Apps/CMakeLists.txt
+++ b/src/OpenMesh/Apps/CMakeLists.txt
@@ -18,6 +18,7 @@ if (QT4_FOUND AND OPENGL_FOUND AND GLEW_FOUND AND GLUT_FOUND AND NOT BUILD_APPS
add_subdirectory (Decimating/DecimaterGui)
add_subdirectory (QtViewer)
add_subdirectory (Subdivider/SubdividerGui)
+ add_subdirectory (ProgViewer)
else ()
if ( BUILD_APPS STREQUAL OFF )
message ("Building Apps disabled by user.")
diff --git a/src/OpenMesh/Apps/ProgViewer/ACGMakefile b/src/OpenMesh/Apps/ProgViewer/ACGMakefile
new file mode 100644
index 00000000..dd5b34d0
--- /dev/null
+++ b/src/OpenMesh/Apps/ProgViewer/ACGMakefile
@@ -0,0 +1,18 @@
+#== SYSTEM PART -- DON'T TOUCH ==============================================
+include $(ACGMAKE)/Config
+#==============================================================================
+
+CXX_CFLAGS += -DQT_THREAD_SUPPORT
+
+SUBDIRS = $(call find-subdirs)
+
+PACKAGES := qt4 glut opengl x11 math
+
+PROJ_LIBS = OpenMesh/Apps/QtViewer OpenMesh/Tools OpenMesh/Core
+
+MODULES := moc4 cxx
+
+
+#== SYSTEM PART -- DON'T TOUCH ==============================================
+include $(ACGMAKE)/Rules
+#==============================================================================
diff --git a/src/OpenMesh/Apps/ProgViewer/OpenMesh_Apps_ProgViewer.vcproj b/src/OpenMesh/Apps/ProgViewer/OpenMesh_Apps_ProgViewer.vcproj
new file mode 100644
index 00000000..0ae89add
--- /dev/null
+++ b/src/OpenMesh/Apps/ProgViewer/OpenMesh_Apps_ProgViewer.vcproj
@@ -0,0 +1,274 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/OpenMesh/Apps/ProgViewer/ProgViewerWidget.cc b/src/OpenMesh/Apps/ProgViewer/ProgViewerWidget.cc
new file mode 100644
index 00000000..8b2df60a
--- /dev/null
+++ b/src/OpenMesh/Apps/ProgViewer/ProgViewerWidget.cc
@@ -0,0 +1,332 @@
+/*===========================================================================*\
+ * *
+ * OpenMesh *
+ * Copyright (C) 2001-2009 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 . *
+ * *
+\*===========================================================================*/
+
+/*===========================================================================*\
+ * *
+ * $Revision$ *
+ * $Date$ *
+ * *
+\*===========================================================================*/
+
+
+//== INCLUDES =================================================================
+
+#ifdef _MSC_VER
+# pragma warning(disable: 4267 4311)
+#endif
+
+#include
+#include
+// --------------------
+#include
+#include
+#include
+// --------------------
+#include
+#include
+#include
+#include
+#include
+// --------------------
+#ifdef ARCH_DARWIN
+# include
+#else
+# include
+#endif
+
+using namespace Qt;
+//== IMPLEMENTATION ==========================================================
+
+
+void
+ProgViewerWidget::open_prog_mesh(const char* _filename)
+{
+ MyMesh::Point p;
+ unsigned int i, i0, i1, i2;
+ unsigned int v1, vl, vr;
+ char c[10];
+
+ std::ifstream ifs(_filename, std::ios::binary);
+ if (!ifs)
+ {
+ std::cerr << "read error\n";
+ exit(1);
+ }
+
+ //
+ bool swap = OpenMesh::Endian::local() != OpenMesh::Endian::LSB;
+
+ // read header
+ ifs.read(c, 8); c[8] = '\0';
+ if (std::string(c) != std::string("ProgMesh"))
+ {
+ std::cerr << "Wrong file format.\n";
+ exit(1);
+ }
+ OpenMesh::IO::binary::restore( ifs, n_base_vertices_, swap );
+ OpenMesh::IO::binary::restore( ifs, n_base_faces_, swap );
+ OpenMesh::IO::binary::restore( ifs, n_detail_vertices_, swap );
+
+ n_max_vertices_ = n_base_vertices_ + n_detail_vertices_;
+
+ // load base mesh
+ mesh_.clear();
+
+ for (i=0; i::restore( ifs, p, swap );
+ mesh_.add_vertex(p);
+ }
+
+ for (i=0; i::restore( ifs, i0, swap);
+ OpenMesh::IO::binary::restore( ifs, i1, swap);
+ OpenMesh::IO::binary::restore( ifs, i2, swap);
+ mesh_.add_face(mesh_.vertex_handle(i0),
+ mesh_.vertex_handle(i1),
+ mesh_.vertex_handle(i2));
+ }
+
+
+ // load progressive detail
+ for (i=0; i::restore( ifs, p, swap );
+ OpenMesh::IO::binary::restore( ifs, v1, swap );
+ OpenMesh::IO::binary::restore( ifs, vl, swap );
+ OpenMesh::IO::binary::restore( ifs, vr, swap );
+
+ PMInfo pminfo;
+ pminfo.p0 = p;
+ pminfo.v1 = MyMesh::VertexHandle(v1);
+ pminfo.vl = MyMesh::VertexHandle(vl);
+ pminfo.vr = MyMesh::VertexHandle(vr);
+ pminfos_.push_back(pminfo);
+ }
+ pmiter_ = pminfos_.begin();
+
+
+ // update face and vertex normals
+ mesh_.update_face_normals();
+ mesh_.update_vertex_normals();
+
+ // bounding box
+ MyMesh::ConstVertexIter
+ vIt(mesh_.vertices_begin()),
+ vEnd(mesh_.vertices_end());
+
+ MyMesh::Point bbMin, bbMax;
+
+ bbMin = bbMax = mesh_.point(vIt);
+ for (; vIt!=vEnd; ++vIt)
+ {
+ bbMin.minimize(mesh_.point(vIt));
+ bbMax.maximize(mesh_.point(vIt));
+ }
+
+ // set center and radius
+ set_scene_pos(0.5f*(bbMin + bbMax), 0.5*(bbMin - bbMax).norm());
+
+ // info
+ std::cerr << mesh_.n_vertices() << " vertices, "
+ << mesh_.n_edges() << " edge, "
+ << mesh_.n_faces() << " faces, "
+ << n_detail_vertices_ << " detail vertices\n";
+
+ setWindowTitle( QFileInfo(_filename).fileName() );
+}
+
+
+//-----------------------------------------------------------------------------
+
+
+void ProgViewerWidget::refine(unsigned int _n)
+{
+ size_t n_vertices = mesh_.n_vertices();
+
+ while (n_vertices < _n && pmiter_ != pminfos_.end())
+ {
+ pmiter_->v0 = mesh_.add_vertex(pmiter_->p0);
+ mesh_.vertex_split(pmiter_->v0,
+ pmiter_->v1,
+ pmiter_->vl,
+ pmiter_->vr);
+ ++pmiter_;
+ ++n_vertices;
+ }
+
+ mesh_.update_face_normals();
+ mesh_.update_vertex_normals();
+
+ std::cerr << n_vertices << " vertices\n";
+}
+
+
+//-----------------------------------------------------------------------------
+
+
+void ProgViewerWidget::coarsen(unsigned int _n)
+{
+ size_t n_vertices = mesh_.n_vertices();
+
+ while (n_vertices > _n && pmiter_ != pminfos_.begin())
+ {
+ --pmiter_;
+
+ MyMesh::HalfedgeHandle hh =
+ mesh_.find_halfedge(pmiter_->v0, pmiter_->v1);
+
+ mesh_.collapse(hh);
+
+ --n_vertices;
+ }
+
+ mesh_.garbage_collection();
+ mesh_.update_face_normals();
+ mesh_.update_vertex_normals();
+
+ std::cerr << n_vertices << " vertices\n";
+}
+
+
+//-----------------------------------------------------------------------------
+
+void ProgViewerWidget::keyPressEvent(QKeyEvent* _event)
+{
+ switch (_event->key())
+ {
+ case Key_Minus:
+ if ( _event->modifiers() & ShiftModifier)
+ coarsen(mesh_.n_vertices()-1);
+ else
+ coarsen((unsigned int)(0.9*mesh_.n_vertices()));
+ updateGL();
+ break;
+
+ case Key_Plus:
+ if (_event->modifiers() & ShiftModifier)
+ refine(mesh_.n_vertices()+1);
+ else
+ refine((unsigned int)(std::max( 1.1*mesh_.n_vertices(),
+ mesh_.n_vertices()+1.0) ));
+ updateGL();
+ break;
+
+ case Key_Home:
+ coarsen(n_base_vertices_);
+ updateGL();
+ break;
+
+ case Key_A:
+ if (timer_->isActive())
+ {
+ timer_->stop();
+ std::cout << "animation stopped!" << std::endl;
+ }
+ else
+ {
+ timer_->setSingleShot(true);
+ timer_->start(0);
+ std::cout << "animation started!" << std::endl;
+ }
+ break;
+
+ case Key_End:
+ refine(n_base_vertices_ + n_detail_vertices_);
+ updateGL();
+ break;
+
+ case Key_P:
+ {
+ const size_t refine_max = 100000;
+ const size_t n_loop = 5;
+
+ OpenMesh::Utils::Timer t;
+ size_t count;
+
+ coarsen(0); count = mesh_.n_vertices();
+ refine(refine_max); count = mesh_.n_vertices() - count;
+
+ t.start();
+ for (size_t i=0; iBase::keyPressEvent(_event);
+ }
+}
+
+void ProgViewerWidget::animate( void )
+{
+ if (animateRefinement_)
+ {
+ refine((unsigned int)( 1.1*(mesh_.n_vertices()+1) ));
+ if ( mesh_.n_vertices() > n_base_vertices_+(0.5*n_detail_vertices_))
+ animateRefinement_ = false;
+ }
+ else
+ {
+ coarsen((unsigned int)(0.9*(mesh_.n_vertices()-1)));
+ if ( mesh_.n_vertices() == n_base_vertices_ )
+ animateRefinement_ = true;
+ }
+ updateGL();
+ timer_->setSingleShot(true);
+ timer_->start(300);
+}
+
+//=============================================================================
diff --git a/src/OpenMesh/Apps/ProgViewer/ProgViewerWidget.hh b/src/OpenMesh/Apps/ProgViewer/ProgViewerWidget.hh
new file mode 100644
index 00000000..36f49ab6
--- /dev/null
+++ b/src/OpenMesh/Apps/ProgViewer/ProgViewerWidget.hh
@@ -0,0 +1,148 @@
+/*===========================================================================*\
+ * *
+ * OpenMesh *
+ * Copyright (C) 2001-2009 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 . *
+ * *
+\*===========================================================================*/
+
+/*===========================================================================*\
+ * *
+ * $Revision$ *
+ * $Date$ *
+ * *
+\*===========================================================================*/
+
+
+#ifndef OPENMESHAPPS_PROGVIEWERWIDGET_HH
+#define OPENMESHAPPS_PROGVIEWERWIDGET_HH
+
+
+//== INCLUDES =================================================================
+
+#include
+#include
+#include
+#include
+#include
+
+
+
+//== CLASS DEFINITION =========================================================
+
+
+using namespace OpenMesh;
+using namespace OpenMesh::Attributes;
+
+
+struct MyTraits : public OpenMesh::DefaultTraits
+{
+ VertexAttributes ( OpenMesh::Attributes::Normal |
+ OpenMesh::Attributes::Status );
+ EdgeAttributes ( OpenMesh::Attributes::Status );
+ HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge );
+ FaceAttributes ( OpenMesh::Attributes::Normal |
+ OpenMesh::Attributes::Status );
+};
+
+
+typedef OpenMesh::TriMesh_ArrayKernelT MyMesh;
+typedef MeshViewerWidgetT MeshViewerWidget;
+
+
+//== CLASS DEFINITION =========================================================
+
+
+
+class ProgViewerWidget : public MeshViewerWidget
+{
+ Q_OBJECT
+
+public:
+
+ typedef MeshViewerWidget Base;
+ typedef ProgViewerWidget This;
+
+
+public:
+ /// default constructor
+ ProgViewerWidget(QWidget* _parent=0)
+ : MeshViewerWidget(_parent)
+ {
+ timer_ = new QTimer(this);
+
+ connect( timer_, SIGNAL(timeout()), SLOT(animate()) );
+ }
+
+ /// destructor
+ ~ProgViewerWidget()
+ {
+ delete timer_;
+ }
+
+ /// open progressive mesh
+ void open_prog_mesh(const char* _filename);
+
+protected slots:
+
+void animate( void );
+
+private:
+
+ QTimer *timer_;
+
+ struct PMInfo
+ {
+ MyMesh::Point p0;
+ MyMesh::VertexHandle v0, v1, vl, vr;
+ };
+ typedef std::vector PMInfoContainer;
+ typedef PMInfoContainer::iterator PMInfoIter;
+
+ /// refine mesh up to _n vertices
+ void refine(unsigned int _n);
+
+ /// coarsen mesh down to _n vertices
+ void coarsen(unsigned int _n);
+
+ virtual void keyPressEvent(QKeyEvent* _event);
+
+ // mesh data
+ bool animateRefinement_;
+ PMInfoContainer pminfos_;
+ PMInfoIter pmiter_;
+ size_t n_base_vertices_, n_base_faces_, n_detail_vertices_;
+ size_t n_max_vertices_;
+};
+
+
+//=============================================================================
+#endif // OPENMESHAPPS_PROGVIEWERWIDGET_HH defined
+//=============================================================================
+
diff --git a/src/OpenMesh/Apps/ProgViewer/progviewer.cc b/src/OpenMesh/Apps/ProgViewer/progviewer.cc
new file mode 100644
index 00000000..1367ee11
--- /dev/null
+++ b/src/OpenMesh/Apps/ProgViewer/progviewer.cc
@@ -0,0 +1,89 @@
+/*===========================================================================*\
+ * *
+ * OpenMesh *
+ * Copyright (C) 2001-2009 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 . *
+ * *
+\*===========================================================================*/
+
+/*===========================================================================*\
+ * *
+ * $Revision$ *
+ * $Date$ *
+ * *
+\*===========================================================================*/
+
+#ifdef _MSC_VER
+# pragma warning(disable: 4267 4311)
+#endif
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+int main(int argc, char **argv)
+{
+ // OpenGL check
+ QApplication::setColorSpec( QApplication::CustomColor );
+ QApplication app(argc,argv);
+
+ glutInit(&argc,argv);
+
+ if ( !QGLFormat::hasOpenGL() ) {
+ std::cerr << "This system has no OpenGL support.\n";
+ return -1;
+ }
+
+
+ // create widget
+ ProgViewerWidget w(0);
+ w.resize(400, 400);
+ w.show();
+
+ // load scene
+ if (argc > 1) w.open_prog_mesh(argv[1]);
+
+
+ // print usage info
+ std::cout << "\n\n"
+ << "Press Minus : Coarsen mesh\n"
+ << " Plus : Refine mesh\n"
+ << " Home : Coarsen down to base mesh\n"
+ << " End : Refine up to finest mesh\n"
+ << "\n";
+
+
+ return app.exec();
+}