Эх сурвалжийг харах

Merge branch 'master' of https://github.com/libigl/libigl

Conflicts:
	build/Makefile_xml
	include/igl/viewer/Viewer.cpp

Former-commit-id: 11ebbb961006aa8f4cef2657e872a4ca1ec17536
Olga Diamanti 10 жил өмнө
parent
commit
b7a17460f1
63 өөрчлөгдсөн 4256 нэмэгдсэн , 556 устгасан
  1. 1 0
      .gitignore
  2. 1 1
      README.md
  3. 2 1
      build/Makefile.conf
  4. 12 9
      build/Makefile_xml
  5. 1 0
      google-soc/collapse-split-flip.ai.REMOVED.git-id
  6. 1 0
      google-soc/collapse-split-flip.jpg.REMOVED.git-id
  7. 46 0
      google-soc/google-soc.md
  8. 67 0
      google-soc/index.html
  9. 1 0
      google-soc/libigl-logo-python-matlab.ai.REMOVED.git-id
  10. 1 0
      google-soc/libigl-logo-python-matlab.jpg.REMOVED.git-id
  11. 7 1
      include/igl/angles.h
  12. 9 1
      include/igl/boolean/mesh_boolean.cpp
  13. 12 18
      include/igl/boundary_loop.cpp
  14. 1 1
      include/igl/cat.cpp
  15. 1 0
      include/igl/cgal/SelfIntersectMesh.h
  16. 1 1
      include/igl/doublearea.cpp
  17. 277 104
      include/igl/embree/EmbreeIntersector.h
  18. 3 1
      include/igl/embree/Hit.h
  19. 5 2
      include/igl/embree/unproject_onto_mesh.cpp
  20. 7 6
      include/igl/file_dialog_open.cpp
  21. 1 3
      include/igl/file_dialog_save.cpp
  22. 1 1
      include/igl/internal_angles.cpp
  23. 154 33
      include/igl/outer_hull.cpp
  24. 16 0
      include/igl/outer_hull.h
  25. 27 2
      include/igl/peel_outer_hull_layers.cpp
  26. 13 0
      include/igl/peel_outer_hull_layers.h
  27. 39 6
      include/igl/png/texture_from_png.cpp
  28. 24 9
      include/igl/png/texture_from_png.h
  29. 756 0
      include/igl/serialize.cpp
  30. 361 0
      include/igl/serialize.h
  31. 1 1
      include/igl/slice.cpp
  32. 1 1
      include/igl/svd3x3/arap_dof.cpp
  33. 1 0
      include/igl/viewer/OpenGL_state.cpp
  34. 85 100
      include/igl/viewer/Viewer.cpp
  35. 18 23
      include/igl/viewer/Viewer.h
  36. 71 47
      include/igl/viewer/ViewerCore.cpp
  37. 0 3
      include/igl/viewer/ViewerCore.h
  38. 52 36
      include/igl/viewer/ViewerData.cpp
  39. 0 8
      include/igl/viewer/ViewerData.h
  40. 36 14
      include/igl/viewer/ViewerPlugin.h
  41. 13 9
      include/igl/xml/ReAntTweakBarXMLSerialization.h
  42. 0 51
      include/igl/xml/XMLSerializable.h
  43. 0 1
      include/igl/xml/XMLSerializer.h.REMOVED.git-id
  44. 259 0
      include/igl/xml/old_version/ReAntTweakBarXMLSerialization.h
  45. 49 0
      include/igl/xml/old_version/XMLSerializable.h
  46. 4 8
      include/igl/xml/old_version/XMLSerialization.h
  47. 1 5
      include/igl/xml/old_version/XMLSerializationTest.h
  48. 1 0
      include/igl/xml/old_version/XMLSerializer.h.REMOVED.git-id
  49. 485 0
      include/igl/xml/serialization_test.cpp
  50. 970 0
      include/igl/xml/serialize_xml.cpp
  51. 259 0
      include/igl/xml/serialize_xml.h
  52. 3 3
      index.html
  53. 9 0
      scripts/update_gh-pages.sh
  54. 1 0
      tutorial/402_PolyharmonicDeformation/main.cpp
  55. 1 0
      tutorial/403_BoundedBiharmonicWeights/main.cpp
  56. 1 1
      tutorial/501_HarmonicParam/main.cpp
  57. 61 27
      tutorial/601_Serialization/main.cpp
  58. 4 4
      tutorial/701_Statistics/main.cpp
  59. 7 2
      tutorial/CMakeLists.shared
  60. 1 0
      tutorial/cmake/FindEIGEN.cmake
  61. 12 10
      tutorial/cmake/FindEMBREE.cmake
  62. 1 1
      tutorial/tutorial.html.REMOVED.git-id
  63. 1 1
      tutorial/tutorial.md.REMOVED.git-id

+ 1 - 0
.gitignore

@@ -69,3 +69,4 @@ external/glfw/build
 *buildXcode*
 tutorial/build*
 tutorial/*/*.mexmaci64
+external/libpng/build

+ 1 - 1
README.md

@@ -6,7 +6,7 @@
 
 libigl is a simple C++ geometry processing library. We have a wide
 functionality including construction of sparse discrete differential geometry
-operators and finite-elements matrices such as the contangent Laplacian and
+operators and finite-elements matrices such as the cotangent Laplacian and
 diagonalized mass matrix, simple facet and edge-based topology data structures,
 mesh-viewing utilities for OpenGL and GLSL, and many core functions for matrix
 manipulation which make [Eigen](http://eigen.tuxfamily.org) feel a lot more

+ 2 - 1
build/Makefile.conf

@@ -106,8 +106,9 @@ endif
 
 ifeq ($(IGL_USERNAME),daniele)
 	IGL_WITH_MATLAB=0
+	IGL_WITH_XML=1
 	AFLAGS=-m64
-	GG=g++-4.8
+	GG=g++-4.8 -Wfatal-errors
 	EIGEN3_INC=-I/usr/local/include/eigen3
 endif
 

+ 12 - 9
build/Makefile_xml

@@ -1,10 +1,10 @@
 include Makefile.conf
 
 .PHONY: all
-all:
-debug:
-#all: libiglxml
-#debug: libiglxml
+#all:
+#debug:
+all: libiglxml
+debug: libiglxml
 
 include Makefile.conf
 all: CFLAGS += -O3 -DNDEBUG
@@ -13,8 +13,9 @@ debug: CFLAGS += -g -Wall
 .PHONY: libiglxml
 libiglxml: obj ../lib/libiglxml.a
 
-SRC_DIR=../include/igl/xml/
-CPP_FILES=$(wildcard $(SRC_DIR)*.cpp)
+#SRC_DIR=../include/igl/xml/
+#CPP_FILES=$(wildcard $(SRC_DIR)*.cpp)
+CPP_FILES=$(wildcard ../include/igl/xml/*.cpp)
 OBJ_FILES=$(addprefix obj/,$(notdir $(CPP_FILES:.cpp=.o)))
 
 # include igl headers
@@ -23,7 +24,9 @@ INC+=-I../include/
 # EXPECTS THAT CFLAGS IS ALREADY SET APPROPRIATELY
 
 # Eigen dependency
-EIGEN3_INC=-I$(DEFAULT_PREFIX)/include/eigen3 -I$(DEFAULT_PREFIX)/include/eigen3/unsupported
+ifndef EIGEN3_INC
+	EIGEN3_INC=-I$(DEFAULT_PREFIX)/include/eigen3 -I$(DEFAULT_PREFIX)/include/eigen3/unsupported
+endif
 INC+=$(EIGEN3_INC)
 
 #AntTweakbar dependency
@@ -49,8 +52,8 @@ obj:
 	rm -f $@
 	ar cqs $@ $(OBJ_FILES)
 
-obj/%.o: $(SRC_DIR)/%.cpp $(SRC_DIR)/%.h
-	g++ $(AFLAGS) $(CFLAGS) -c -o $@ $< $(INC)
+obj/%.o: ../include/igl/xml/%.cpp 
+	$(GG) $(AFLAGS) $(CFLAGS) -c -o $@ $< $(INC)
 
 clean:
 	rm -f $(OBJ_FILES)

+ 1 - 0
google-soc/collapse-split-flip.ai.REMOVED.git-id

@@ -0,0 +1 @@
+df9f72b3e478619e1ea66fe679d1c5b4cfa13fb2

+ 1 - 0
google-soc/collapse-split-flip.jpg.REMOVED.git-id

@@ -0,0 +1 @@
+4a6e9ced0bd70bfe81d27bc663e0205225d1ab51

+ 46 - 0
google-soc/google-soc.md

@@ -0,0 +1,46 @@
+# [libigl](./index.html) - Google Summer of Code 2015 Project Ideas
+
+## Automatic Generation of Python/MATLAB bindings
+
+![](./libigl-logo-python-matlab.jpg)
+
+Libigl is a C++ library, but its functional interface make it very friendly to
+wrapping individual functions for popular scripting languages like Python or
+MATLAB. Since many libigl functions have the form "mesh in" --> "mesh out" or
+"mesh with scalar field in" --> "scalar field out", we would like to develop an
+_automatic_ routine for generating Python and MATLAB bindings for libigl
+functions. This project has three parts: 1) determining the necessary mark up
+(e.g. comments) inside libigl header files to determine the Python interface,
+2) writing a program to parse this mark up and generate valid Python bindings
+and compilation instructions, and 3) validating and testing these results on a
+variety of functions in the library.
+
+Student: [apply](https://www.google-melange.com/gsoc/homepage/google/gsoc2015)
+
+Mentors: Alec Jacobson & Daniele Panozzo
+
+## Topological Mesh Operations
+
+![](./collapse-split-flip.jpg)
+
+Libigl avoids complicated mesh data-structures to ensure that its interface is
+clean and easy to port into users' existing projects. Our mesh format is a
+simple list of vertices and list of face indices to those vertices: `V` and
+`F`.  We have a number of functions for _deforming_ a mesh: that is, modifying
+the entries in `V`, but currently lack functions for _modifying_ the mesh's
+topology: that is, modifying `F` and/or modifying the _size_ of `V`. This
+project entails implementing _efficient_ routines for: edge collapse, edge
+splitting, and edge flipping. The project will culminate in a routine combining
+these core functions for surface remeshing.
+
+Student: [apply](https://www.google-melange.com/gsoc/homepage/google/gsoc2015)
+
+Mentors: Alec Jacobson & Daniele Panozzo
+
+## Contact
+
+Google Summer of Code projects with libigl are mentored by [Alec
+Jacobson](http://www.cs.columbia.edu/~jacobson/) and [Daniele
+Panozzo](http://www.inf.ethz.ch/personal/dpanozzo/). Please [contact
+us](mailto:alecjacobson@gmail.com,daniele.panozzo@gmail.com) if you have
+questions, comments or other ideas for a fun summer of hacking on libigl.

+ 67 - 0
google-soc/index.html

@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<meta charset="utf-8"/>
+	<title>libigl</title>
+	<meta name="author" content="Alec Jacobson and Daniele Panozzo and others"/>
+	<link type="text/css" rel="stylesheet" href="../tutorial/style.css"/>
+<script type='text/javascript' src='http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'></script>
+<link rel='stylesheet' href='http://yandex.st/highlightjs/7.3/styles/default.min.css'>
+<script src='http://yandex.st/highlightjs/7.3/highlight.min.js'></script>
+<script>hljs.initHighlightingOnLoad();</script>
+</head>
+<body>
+
+<h1 id="libigl-googlesummerofcode2015projectideas"><a href="./index.html">libigl</a> - Google Summer of Code 2015 Project Ideas</h1>
+
+<h2 id="automaticgenerationofpythonmatlabbindings">Automatic Generation of Python/MATLAB bindings</h2>
+
+<figure>
+<img src="./libigl-logo-python-matlab.jpg" alt="" />
+</figure>
+
+<p>Libigl is a C++ library, but its functional interface make it very friendly to
+wrapping individual functions for popular scripting languages like Python or
+MATLAB. Since many libigl functions have the form &#8220;mesh in&#8221; &#8211;&gt; &#8220;mesh out&#8221; or
+&#8220;mesh with scalar field in&#8221; &#8211;&gt; &#8220;scalar field out&#8221;, we would like to develop an
+<em>automatic</em> routine for generating Python and MATLAB bindings for libigl
+functions. This project has three parts: 1) determining the necessary mark up
+(e.g. comments) inside libigl header files to determine the Python interface,
+2) writing a program to parse this mark up and generate valid Python bindings
+and compilation instructions, and 3) validating and testing these results on a
+variety of functions in the library.</p>
+
+<p>Student: <a href="https://www.google-melange.com/gsoc/homepage/google/gsoc2015">apply</a></p>
+
+<p>Mentors: Alec Jacobson &amp; Daniele Panozzo</p>
+
+<h2 id="topologicalmeshoperations">Topological Mesh Operations</h2>
+
+<figure>
+<img src="./collapse-split-flip.jpg" alt="" />
+</figure>
+
+<p>Libigl avoids complicated mesh data-structures to ensure that its interface is
+clean and easy to port into users&#8217; existing projects. Our mesh format is a
+simple list of vertices and list of face indices to those vertices: <code>V</code> and
+<code>F</code>. We have a number of functions for <em>deforming</em> a mesh: that is, modifying
+the entries in <code>V</code>, but currently lack functions for <em>modifying</em> the mesh&#8217;s
+topology: that is, modifying <code>F</code> and/or modifying the <em>size</em> of <code>V</code>. This
+project entails implementing <em>efficient</em> routines for: edge collapse, edge
+splitting, and edge flipping. The project will culminate in a routine combining
+these core functions for surface remeshing.</p>
+
+<p>Student: <a href="https://www.google-melange.com/gsoc/homepage/google/gsoc2015">apply</a></p>
+
+<p>Mentors: Alec Jacobson &amp; Daniele Panozzo</p>
+
+<h2 id="contact">Contact</h2>
+
+<p>Google Summer of Code projects with libigl are mentored by <a href="http://www.cs.columbia.edu/~jacobson/">Alec
+Jacobson</a> and <a href="http://www.inf.ethz.ch/personal/dpanozzo/">Daniele
+Panozzo</a>. Please <a href="&#109;&#97;&#105;&#108;&#x74;&#111;&#x3a;&#x61;&#x6c;&#101;&#x63;&#x6a;&#x61;&#x63;&#111;&#98;&#115;&#111;&#110;&#64;&#103;&#109;&#x61;&#105;&#108;&#x2e;&#x63;&#x6f;&#x6d;&#44;&#x64;&#x61;&#110;&#105;&#101;&#x6c;&#101;&#x2e;&#x70;&#x61;&#110;&#x6f;&#122;&#x7a;&#x6f;&#64;&#x67;&#x6d;&#x61;&#x69;&#x6c;&#x2e;&#99;&#x6f;&#x6d;">&#99;&#x6f;&#x6e;&#116;&#x61;&#99;&#x74;
+&#117;&#115;</a> if you have
+questions, comments or other ideas for a fun summer of hacking on libigl.</p>
+
+</body>
+</html>

+ 1 - 0
google-soc/libigl-logo-python-matlab.ai.REMOVED.git-id

@@ -0,0 +1 @@
+3aee7373f24e4e55c0e9996326581446109ddbaa

+ 1 - 0
google-soc/libigl-logo-python-matlab.jpg.REMOVED.git-id

@@ -0,0 +1 @@
+f8623f70e91e4bbc5ed229da96191cb7bce86765

+ 7 - 1
include/igl/angles.h

@@ -7,7 +7,13 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #ifndef IGL_ANGLES_H
 #define IGL_ANGLES_H
-#warning "Deprecated. Use igl/internal_angles.h instead"
+#ifdef _WIN32
+ #pragma message ( "Deprecated. Use igl/internal_angles.h instead" )
+#else
+ #warning "Deprecated. Use igl/internal_angles.h instead"
+#endif
+
+
 #include "igl_inline.h"
 #include <Eigen/Core>
 namespace igl

+ 9 - 1
include/igl/boolean/mesh_boolean.cpp

@@ -1,5 +1,6 @@
 #include "mesh_boolean.h"
 #include <igl/peel_outer_hull_layers.h>
+#include <igl/per_face_normals.h>
 #include <igl/cgal/remesh_self_intersections.h>
 #include <igl/remove_unreferenced.h>
 #include <igl/unique_simplices.h>
@@ -167,6 +168,13 @@ IGL_INLINE void igl::mesh_boolean(
     J = CJ;
     return;
   }
+  MatrixX3S N,CN;
+  per_face_normals(V,F,N);
+  CN.resize(CF.rows(),3);
+  for(size_t f = 0;f<(size_t)CN.rows();f++)
+  {
+    CN.row(f) = N.row(CJ(f));
+  }
 
 #ifdef IGL_MESH_BOOLEAN_DEBUG
   cout<<"peel..."<<endl;
@@ -175,7 +183,7 @@ IGL_INLINE void igl::mesh_boolean(
   // peel layers keeping track of odd and even flips
   Matrix<bool,Dynamic,1> odd;
   Matrix<bool,Dynamic,1> flip;
-  peel_outer_hull_layers(CV,CF,odd,flip);
+  peel_outer_hull_layers(CV,CF,CN,odd,flip);
 
 #ifdef IGL_MESH_BOOLEAN_DEBUG
   cout<<"categorize..."<<endl;

+ 12 - 18
include/igl/boundary_loop.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2014 Stefan Brugger <stefanbrugger@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "boundary_loop.h"
 #include "slice.h"
@@ -14,14 +14,14 @@
 
 template <typename DerivedF, typename Index>
 IGL_INLINE void igl::boundary_loop(
-    const Eigen::PlainObjectBase<DerivedF> & F, 
+    const Eigen::PlainObjectBase<DerivedF> & F,
     std::vector<std::vector<Index> >& L)
 {
   using namespace std;
   using namespace Eigen;
   using namespace igl;
 
-  MatrixXd Vdummy(F.maxCoeff(),1);
+  MatrixXd Vdummy(F.maxCoeff()+1,1);
   MatrixXi TT,TTi;
   vector<std::vector<int> > VF, VFi;
   triangle_triangle_adjacency(Vdummy,F,TT,TTi);
@@ -63,16 +63,10 @@ IGL_INLINE void igl::boundary_loop(
           if (F(fid,1) == v) vLoc = 1;
           if (F(fid,2) == v) vLoc = 2;
 
-          int vPrev = F(fid,(vLoc + F.cols()-1) % F.cols());
           int vNext = F(fid,(vLoc + 1) % F.cols());
 
-          bool newBndEdge = false;
-          if (unvisited[vPrev] && TT(fid,(vLoc+2) % F.cols()) < 0)
-          {
-            next = vPrev;
-            newBndEdge = true;
-          }
-          else if (unvisited[vNext] && TT(fid,vLoc) < 0)
+          newBndEdge = false;
+          if (unvisited[vNext] && TT(fid,vLoc) < 0)
           {
             next = vNext;
             newBndEdge = true;
@@ -95,7 +89,7 @@ IGL_INLINE void igl::boundary_loop(
 
 template <typename DerivedF, typename Index>
 IGL_INLINE void igl::boundary_loop(
-  const Eigen::PlainObjectBase<DerivedF>& F, 
+  const Eigen::PlainObjectBase<DerivedF>& F,
   std::vector<Index>& L)
 {
   using namespace Eigen;
@@ -113,7 +107,7 @@ IGL_INLINE void igl::boundary_loop(
       maxLen = Lall[i].size();
       idxMax = i;
     }
-  }   
+  }
 
   L.resize(Lall[idxMax].size());
   for (int i = 0; i < Lall[idxMax].size(); ++i)
@@ -122,7 +116,7 @@ IGL_INLINE void igl::boundary_loop(
 
 template <typename DerivedF, typename DerivedL>
 IGL_INLINE void igl::boundary_loop(
-  const Eigen::PlainObjectBase<DerivedF>& F, 
+  const Eigen::PlainObjectBase<DerivedF>& F,
   Eigen::PlainObjectBase<DerivedL>& L)
 {
   using namespace Eigen;
@@ -134,4 +128,4 @@ IGL_INLINE void igl::boundary_loop(
   L.resize(Lvec.size());
   for (int i = 0; i < Lvec.size(); ++i)
     L(i) = Lvec[i];
-}
+}

+ 1 - 1
include/igl/cat.cpp

@@ -36,7 +36,7 @@ IGL_INLINE void igl::cat(
     return;
   }
 
-  DynamicSparseMatrix<Scalar, RowMajor> dyn_C;
+  SparseMatrix<Scalar, RowMajor> dyn_C;
   if(dim == 1)
   {
     assert(A.cols() == B.cols());

+ 1 - 0
include/igl/cgal/SelfIntersectMesh.h

@@ -913,6 +913,7 @@ inline bool igl::SelfIntersectMesh<
     // Construct intersection
     try
     {
+      // This can fail for Epick but not Epeck
       CGAL::Object result = CGAL::intersection(A,B);
       if(!result.empty())
       {

+ 1 - 1
include/igl/doublearea.cpp

@@ -132,7 +132,7 @@ IGL_INLINE void igl::doublearea(
   #  define IGL_OMP_MIN_VALUE 1000
   #endif
   #pragma omp parallel for if (m>IGL_OMP_MIN_VALUE)
-  for(size_t i = 0;i<m;i++)
+  for(long int i = 0;i<m;i++)
   {
     //// Heron's formula for area
     //const typename Derivedl::Scalar arg =

+ 277 - 104
include/igl/embree/EmbreeIntersector.h

@@ -1,23 +1,26 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // 
 // Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//               2014 Christian Schüller <schuellchr@gmail.com>
 // 
 // This Source Code Form is subject to the terms of the Mozilla Public License 
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can 
 // obtain one at http://mozilla.org/MPL/2.0/.
-// igl function interface for Embree2.0
+// igl function interface for Embree2.2
 //
 // Necessary changes to switch from previous Embree versions:
 // * Use igl:Hit instead of embree:Hit (where id0 -> id)
-// * Embree2.0 finds now also back face intersections
+// * For Embree2.2
+// * Uncomment #define __USE_RAY_MASK__ in platform.h to enable masking
 
 #ifndef IGL_EMBREE_INTERSECTOR_H
 #define IGL_EMBREE_INTERSECTOR_H
 
-#include "Hit.h"
 #include <Eigen/Core>
-#include "Embree_convenience.h"
 #include <vector>
+#include <embree2/rtcore.h>
+#include <embree2/rtcore_ray.h>
+#include "Hit.h"
 
 namespace igl
 {
@@ -29,14 +32,12 @@ namespace igl
     // to call more than once.
     static inline void global_init();
   private:
-    // Deinitialize the embree engine. This should probably never be called by
-    // the user. Hence it's private. Do you really want to do this?
+    // Deinitialize the embree engine.
     static inline void global_deinit();
   public:
-    typedef Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic> PointMatrixType;
-    typedef Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>  FaceMatrixType;
-    typedef Eigen::Matrix<float,1,3> RowVector3;
-  public:
+    typedef Eigen::Matrix<float,Eigen::Dynamic,3> PointMatrixType;
+    typedef Eigen::Matrix<int,Eigen::Dynamic,3> FaceMatrixType;
+  public: 
     inline EmbreeIntersector();
   private:
     // Copying and assignment are not allowed.
@@ -44,7 +45,7 @@ namespace igl
     inline EmbreeIntersector & operator=(const EmbreeIntersector &);
   public:
     virtual inline ~EmbreeIntersector();
-      
+    
     // Initialize with a given mesh.
     //
     // Inputs:
@@ -53,11 +54,22 @@ namespace igl
     // Side effects:
     //   The first time this is ever called the embree engine is initialized.
     inline void init(
-      const PointMatrixType & V,
-      const FaceMatrixType & F,
-      const char* structure = "default",
-      const char* builder = "default",
-      const char* traverser = "default");
+      const PointMatrixType& V,
+      const FaceMatrixType& F);
+
+    // Initialize with a given mesh.
+    //
+    // Inputs:
+    //   V  vector of #V by 3 list of vertex positions for each geometry
+    //   F  vector of #F by 3 list of Oriented triangles for each geometry
+    //   masks  a 32 bit mask to identify active geometries.
+    // Side effects:
+    //   The first time this is ever called the embree engine is initialized.
+    inline void init(
+      const std::vector<const PointMatrixType*>& V,
+      const std::vector<const FaceMatrixType*>& F,
+      const std::vector<int>& masks);
+
     // Deinitialize embree datasctructures for current mesh.  Also called on
     // destruction: no need to call if you just want to init() once and
     // destroy.
@@ -68,32 +80,65 @@ namespace igl
     // Inputs:
     //   origin     3d origin point of ray
     //   direction  3d (not necessarily normalized) direction vector of ray
+    //   tnear      start of ray segment
+    //   tfar       end of ray segment
+    //   masks      a 32 bit mask to identify active geometries.
     // Output:
     //   hit        information about hit
     // Returns true if and only if there was a hit
     inline bool intersectRay(
-      const RowVector3& origin, 
-      const RowVector3& direction,
+      const Eigen::RowVector3f& origin, 
+      const Eigen::RowVector3f& direction,
       Hit& hit,
       float tnear = 0,
-      float tfar = embree::inf) const;
+      float tfar = -1,
+      int mask = 0xFFFFFFFF) const;
 
-    // Given a ray find the all hits in order
+    // Given a ray find the first hit
+    // This is a conservative hit test where multiple rays within a small radius
+    // will be tested and only the closesest hit is returned.
     // 
     // Inputs:
     //   origin     3d origin point of ray
     //   direction  3d (not necessarily normalized) direction vector of ray
+    //   tnear      start of ray segment
+    //   tfar       end of ray segment
+    //   masks      a 32 bit mask to identify active geometries.
+    //   geoId      id of geometry mask (default -1 if no: no masking)
+    //   closestHit true for gets closest hit, false for furthest hit
+    // Output:
+    //   hit        information about hit
+    // Returns true if and only if there was a hit
+    inline bool intersectBeam(
+      const Eigen::RowVector3f& origin,
+      const Eigen::RowVector3f& direction,
+      Hit& hit,
+      float tnear = 0,
+      float tfar = -1,
+      int mask = 0xFFFFFFFF,
+      int geoId = -1,
+      bool closestHit = true) const;
+
+    // Given a ray find all hits in order
+    // 
+    // Inputs:
+    //   origin     3d origin point of ray
+    //   direction  3d (not necessarily normalized) direction vector of ray
+    //   tnear      start of ray segment
+    //   tfar       end of ray segment
+    //   masks      a 32 bit mask to identify active geometries.
     // Output:
     //   hit        information about hit
     //   num_rays   number of rays shot (at least one)
     // Returns true if and only if there was a hit
     inline bool intersectRay(
-      const RowVector3& origin,
-      const RowVector3& direction,
+      const Eigen::RowVector3f& origin,
+      const Eigen::RowVector3f& direction,
       std::vector<Hit > &hits,
       int& num_rays,
       float tnear = 0,
-      float tfar = embree::inf) const;
+      float tfar = std::numeric_limits<float>::infinity(),
+      int mask = 0xFFFFFFFF) const;
 
     // Given a ray find the first hit
     // 
@@ -103,14 +148,30 @@ namespace igl
     // Output:
     //   hit  information about hit
     // Returns true if and only if there was a hit
-    inline bool intersectSegment(const RowVector3& a, const RowVector3& ab, Hit &hit) const;
+    inline bool intersectSegment(
+      const Eigen::RowVector3f& a,
+      const Eigen::RowVector3f& ab,
+      Hit &hit,
+      int mask = 0xFFFFFFFF) const;
     
   private:
-    embree::RTCGeometry* mesh;
-    embree::RTCTriangle* triangles;
-    embree::RTCVertex *vertices;
-    embree::Intersector1 *intersector;
+
+    struct Vertex   {float x,y,z,a;};
+    struct Triangle {int v0, v1, v2;};
+
+    RTCScene scene;
+    unsigned geomID;
+    Vertex* vertices;
+    Triangle* triangles;
     bool initialized;
+
+    inline void createRay(
+      RTCRay& ray,
+      const Eigen::RowVector3f& origin,
+      const Eigen::RowVector3f& direction,
+      float tnear,
+      float tfar,
+      int mask) const;
   };
 }
 
@@ -127,18 +188,17 @@ namespace igl
   static bool EmbreeIntersector_inited = false;
 }
 
-template <typename RowVector3>
-inline embree::Vector3f toVector3f(const RowVector3 &p) { return embree::Vector3f((float)p[0], (float)p[1], (float)p[2]); }
-
 inline void igl::EmbreeIntersector::global_init()
 {
   if(!EmbreeIntersector_inited)
   {
-    embree::rtcInit();
+    rtcInit();
+    if(rtcGetError() != RTC_NO_ERROR)
+      std::cerr << "Embree: An error occured while initialiting embree core!" << std::endl;
 #ifdef IGL_VERBOSE
-    embree::rtcSetVerbose(3);
+    else
+      std::cerr << "Embree: core initialized." << std::endl;
 #endif
-    embree::rtcStartThreads();
     EmbreeIntersector_inited = true;
   }
 }
@@ -146,50 +206,59 @@ inline void igl::EmbreeIntersector::global_init()
 inline void igl::EmbreeIntersector::global_deinit()
 {
   EmbreeIntersector_inited = false;
-  embree::rtcStopThreads();
-  embree::rtcExit();
-  embree::rtcFreeMemory();
+  rtcExit();
 }
 
 inline igl::EmbreeIntersector::EmbreeIntersector()
   :
-  mesh(NULL),
+  //scene(NULL),
+  geomID(0),
   triangles(NULL),
   vertices(NULL),
-  intersector(NULL),
   initialized(false)
 {
 }
 
 inline igl::EmbreeIntersector::EmbreeIntersector(
-  const EmbreeIntersector & /*that*/)
+  const EmbreeIntersector &)
   :// To make -Weffc++ happy
-  mesh(NULL),
+  //scene(NULL),
+  geomID(0),
   triangles(NULL),
   vertices(NULL),
-  intersector(NULL),
   initialized(false)
 {
-  assert(false && "Copying EmbreeIntersector is not allowed");
+  assert(false && "Embree: Copying EmbreeIntersector is not allowed");
 }
 
 inline igl::EmbreeIntersector & igl::EmbreeIntersector::operator=(
-  const EmbreeIntersector & /*that*/)
+  const EmbreeIntersector &)
 {
-  assert(false && "Assigning an EmbreeIntersector is not allowed");
+  assert(false && "Embree: Assigning an EmbreeIntersector is not allowed");
   return *this;
 }
 
 
 inline void igl::EmbreeIntersector::init(
-  const PointMatrixType & V,
-  const FaceMatrixType & F,
-  const char* structure,
-  const char* builder,
-  const char* traverser)
+  const PointMatrixType& V,
+  const FaceMatrixType& F)
+{
+  std::vector<const PointMatrixType*> Vtemp;
+  std::vector<const FaceMatrixType*> Ftemp;
+  std::vector<int> masks;
+  Vtemp.push_back(&V);
+  Ftemp.push_back(&F);
+  masks.push_back(0xFFFFFFFF);
+  init(Vtemp,Ftemp,masks);
+}
+
+inline void igl::EmbreeIntersector::init(
+  const std::vector<const PointMatrixType*>& V,
+  const std::vector<const FaceMatrixType*>& F,
+  const std::vector<int>& masks)
 {
   
-  if (initialized)
+  if(initialized)
     deinit();
   
   using namespace std;
@@ -197,61 +266,94 @@ inline void igl::EmbreeIntersector::init(
 
   if(V.size() == 0 || F.size() == 0)
   {
+    std::cerr << "Embree: No geometry specified!";
     return;
   }
   
-  mesh = embree::rtcNewTriangleMesh(F.rows(),V.rows(),structure);
+  // create a scene
+  scene = rtcNewScene(RTC_SCENE_ROBUST | RTC_SCENE_HIGH_QUALITY,RTC_INTERSECT1);
 
-  // fill vertex buffer
-  vertices = embree::rtcMapPositionBuffer(mesh);
-  for(int i=0;i<(int)V.rows();i++)
+  for(int g=0;g<V.size();g++)
   {
-    vertices[i] = embree::RTCVertex((float)V(i,0),(float)V(i,1),(float)V(i,2));
-  }
-  embree::rtcUnmapPositionBuffer(mesh);
+    // create triangle mesh geometry in that scene
+    geomID = rtcNewTriangleMesh(scene,RTC_GEOMETRY_STATIC,F[g]->rows(),V[g]->rows(),1);
 
-  // fill triangle buffer
-  triangles = embree::rtcMapTriangleBuffer(mesh);
-  for(int i=0;i<(int)F.rows();i++)
-  {
-    triangles[i] = embree::RTCTriangle((int)F(i,0),(int)F(i,1),(int)F(i,2),i);
+    // fill vertex buffer
+    vertices = (Vertex*)rtcMapBuffer(scene,geomID,RTC_VERTEX_BUFFER);
+    for(int i=0;i<(int)V[g]->rows();i++)
+    {
+      vertices[i].x = (float)V[g]->coeff(i,0);
+      vertices[i].y = (float)V[g]->coeff(i,1);
+      vertices[i].z = (float)V[g]->coeff(i,2);
+    }
+    rtcUnmapBuffer(scene,geomID,RTC_VERTEX_BUFFER);
+
+    // fill triangle buffer
+    triangles = (Triangle*) rtcMapBuffer(scene,geomID,RTC_INDEX_BUFFER);
+    for(int i=0;i<(int)F[g]->rows();i++)
+    {
+      triangles[i].v0 = (int)F[g]->coeff(i,0);
+      triangles[i].v1 = (int)F[g]->coeff(i,1);
+      triangles[i].v2 = (int)F[g]->coeff(i,2);
+    }
+    rtcUnmapBuffer(scene,geomID,RTC_INDEX_BUFFER);
+
+    rtcSetMask(scene,geomID,masks[g]);
   }
-  embree::rtcUnmapTriangleBuffer(mesh);
 
-  embree::rtcBuildAccel(mesh,builder);
-  embree::rtcCleanupGeometry(mesh);
-  
-  intersector = embree::rtcQueryIntersector1(mesh,traverser);
+  rtcCommit(scene);
   
+  if(rtcGetError() != RTC_NO_ERROR)
+      std::cerr << "Embree: An error occured while initializing the provided geometry!" << endl;
+#ifdef IGL_VERBOSE
+  else
+    std::cerr << "Embree: geometry added." << endl;
+#endif
+
   initialized = true;
 }
 
 igl::EmbreeIntersector
 ::~EmbreeIntersector()
 {
-  if (initialized)
+  if(initialized)
     deinit();
 }
 
 void igl::EmbreeIntersector::deinit()
 {
-  embree::rtcDeleteIntersector1(intersector);
-  embree::rtcDeleteGeometry(mesh);
+  rtcDeleteScene(scene);
+
+  if(rtcGetError() != RTC_NO_ERROR)
+      std::cerr << "Embree: An error occured while resetting!" << std::endl;
+#ifdef IGL_VERBOSE
+  else
+    std::cerr << "Embree: geometry removed." << std::endl;
+#endif
 }
 
 inline bool igl::EmbreeIntersector::intersectRay(
-  const RowVector3& origin,
-  const RowVector3& direction,
+  const Eigen::RowVector3f& origin,
+  const Eigen::RowVector3f& direction,
   Hit& hit,
   float tnear,
-  float tfar) const
+  float tfar,
+  int mask) const
 {
-  embree::Ray ray(toVector3f(origin), toVector3f(direction), tnear, tfar);
-  intersector->intersect(ray);
+  RTCRay ray;
+  createRay(ray, origin,direction,tnear,std::numeric_limits<float>::infinity(),mask);
   
-  if(ray)
+  // shot ray
+  rtcIntersect(scene,ray);
+#ifdef IGL_VERBOSE
+  if(rtcGetError() != RTC_NO_ERROR)
+      std::cerr << "Embree: An error occured while resetting!" << std::endl;
+#endif
+  
+  if(ray.geomID != RTC_INVALID_GEOMETRY_ID)
   {
-    hit.id = ray.id0;
+    hit.id = ray.primID;
+    hit.gid = ray.geomID;
     hit.u = ray.u;
     hit.v = ray.v;
     hit.t = ray.tfar;
@@ -261,15 +363,60 @@ inline bool igl::EmbreeIntersector::intersectRay(
   return false;
 }
 
+inline bool igl::EmbreeIntersector::intersectBeam(
+      const Eigen::RowVector3f& origin, 
+      const Eigen::RowVector3f& direction,
+      Hit& hit,
+      float tnear,
+      float tfar,
+      int mask,
+      int geoId,
+      bool closestHit) const
+{
+  bool hasHit = false;
+  Hit bestHit;
+
+  if(closestHit)
+    bestHit.t = std::numeric_limits<float>::max();
+  else
+    bestHit.t = 0;
+
+  if(hasHit = (intersectRay(origin,direction,hit,tnear,tfar,mask) && (hit.gid == geoId || geoId == -1)))
+    bestHit = hit;
+  
+  // sample points around actual ray (conservative hitcheck)
+  float eps= 1e-5;
+  int density = 4;
+        
+  Eigen::RowVector3f up(0,1,0);
+  Eigen::RowVector3f offset = direction.cross(up).normalized();
+
+  Eigen::Matrix3f rot = Eigen::AngleAxis<float>(2*3.14159265358979/density,direction).toRotationMatrix();
+        
+  for(int r=0;r<density;r++)
+  {
+    if(intersectRay(origin+offset*eps,direction,hit,tnear,tfar,mask) && ((closestHit && (hit.t < bestHit.t)) || (!closestHit && (hit.t > bestHit.t))) && (hit.gid == geoId || geoId == -1))
+    {
+      bestHit = hit;
+      hasHit = true;
+    }
+    offset = rot*offset.transpose();
+  }
+
+  hit = bestHit;
+  return hasHit;
+}
+
 inline bool 
 igl::EmbreeIntersector
 ::intersectRay(
-  const RowVector3& origin, 
-  const RowVector3& direction,
+  const Eigen::RowVector3f& origin, 
+  const Eigen::RowVector3f& direction,
   std::vector<Hit > &hits,
   int& num_rays,
   float tnear,
-  float tfar) const
+  float tfar,
+  int mask) const
 {
   using namespace std;
   num_rays = 0;
@@ -282,26 +429,29 @@ igl::EmbreeIntersector
   const double eps = FLOAT_EPS;
   double min_t = tnear;
   bool large_hits_warned = false;
-  embree::Ray ray(toVector3f(origin),toVector3f(direction));
+  RTCRay ray;
+  createRay(ray,origin,direction,tnear,std::numeric_limits<float>::infinity(),mask);
 
   while(true)
   {
     ray.tnear = min_t;
     ray.tfar = tfar;
-    ray.id0 = -1;
+    ray.geomID = RTC_INVALID_GEOMETRY_ID;
+    ray.primID = RTC_INVALID_GEOMETRY_ID;
+    ray.instID = RTC_INVALID_GEOMETRY_ID;
     num_rays++;
-    intersector->intersect(ray);
-    if(ray)
+    rtcIntersect(scene,ray);
+    if(ray.geomID != RTC_INVALID_GEOMETRY_ID)
     {
       // Hit self again, progressively advance
-      if(ray.id0 == last_id0 || ray.tfar <= min_t)
+      if(ray.primID == last_id0 || ray.tfar <= min_t)
       {
         // push min_t a bit more
         //double t_push = pow(2.0,self_hits-4)*(hit.t<eps?eps:hit.t);
         double t_push = pow(2.0,self_hits)*eps;
-#ifdef IGL_VERBOSE
-        cout<<"  t_push: "<<t_push<<endl;
-#endif
+        #ifdef IGL_VERBOSE
+        std::cerr<<"  t_push: "<<t_push<<endl;
+        #endif
         //o = o+t_push*d;
         min_t += t_push;
         self_hits++;
@@ -309,13 +459,14 @@ igl::EmbreeIntersector
       else
       {
         Hit hit;
-        hit.id = ray.id0;
+        hit.id = ray.primID;
+        hit.gid = ray.geomID;
         hit.u = ray.u;
         hit.v = ray.v;
         hit.t = ray.tfar;
         hits.push_back(hit);
 #ifdef IGL_VERBOSE
-        cout<<"  t: "<<hit.t<<endl;
+        std::cerr<<"  t: "<<hit.t<<endl;
 #endif
         // Instead of moving origin, just change min_t. That way calculations
         // all use exactly same origin values
@@ -324,29 +475,29 @@ igl::EmbreeIntersector
         // reset t_scale
         self_hits = 0;
       }
-      last_id0 = ray.id0;
+      last_id0 = ray.primID;
     }
     else
       break; // no more hits
     
     if(hits.size()>1000 && !large_hits_warned)
     {
-      cerr<<"Warning: Large number of hits..."<<endl;
-      cerr<<"[ ";
+      std::cout<<"Warning: Large number of hits..."<<endl;
+      std::cout<<"[ ";
       for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end();hit++)
       {
-        cerr<<(hit->id+1)<<" ";
+        std::cout<<(hit->id+1)<<" ";
       }
       
-      cerr.precision(std::numeric_limits< double >::digits10);
-      cerr<<"[ ";
+      std::cout.precision(std::numeric_limits< double >::digits10);
+      std::cout<<"[ ";
       
       for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end(); hit++)
       {
-        cerr<<(hit->t)<<endl;;
+        std::cout<<(hit->t)<<endl;;
       }
 
-      cerr<<"]"<<endl;
+      std::cout<<"]"<<endl;
       large_hits_warned = true;
 
       return hits.empty();
@@ -358,14 +509,17 @@ igl::EmbreeIntersector
 
 inline bool 
 igl::EmbreeIntersector
-::intersectSegment(const RowVector3& a, const RowVector3& ab, Hit &hit) const
+::intersectSegment(const Eigen::RowVector3f& a, const Eigen::RowVector3f& ab, Hit &hit, int mask) const
 {
-  embree::Ray ray(toVector3f(a), toVector3f(ab), embree::zero, embree::one);
-  intersector->intersect(ray);
+  RTCRay ray;
+  createRay(ray,a,ab,0,1.0,mask);
+  
+  rtcIntersect(scene,ray);
 
-  if(ray)
+  if(ray.geomID != RTC_INVALID_GEOMETRY_ID)
   {
-    hit.id = ray.id0;
+    hit.id = ray.primID;
+    hit.gid = ray.geomID;
     hit.u = ray.u;
     hit.v = ray.v;
     hit.t = ray.tfar;
@@ -375,4 +529,23 @@ igl::EmbreeIntersector
   return false;
 }
 
+inline void
+igl::EmbreeIntersector
+::createRay(RTCRay& ray, const Eigen::RowVector3f& origin, const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
+{
+  ray.org[0] = origin[0];
+  ray.org[1] = origin[1];
+  ray.org[2] = origin[2];
+  ray.dir[0] = direction[0];
+  ray.dir[1] = direction[1];
+  ray.dir[2] = direction[2];
+  ray.tnear = tnear;
+  ray.tfar = tfar;
+  ray.geomID = RTC_INVALID_GEOMETRY_ID;
+  ray.primID = RTC_INVALID_GEOMETRY_ID;
+  ray.instID = RTC_INVALID_GEOMETRY_ID;
+  ray.mask = mask;
+  ray.time = 0.0f;
+}
+
 #endif //EMBREE_INTERSECTOR_H

+ 3 - 1
include/igl/embree/Hit.h

@@ -1,7 +1,8 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // 
 // Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
-// 
+//               2014 Christian Schüller <schuellchr@gmail.com> 
+//
 // This Source Code Form is subject to the terms of the Mozilla Public License 
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can 
 // obtain one at http://mozilla.org/MPL/2.0/.
@@ -14,6 +15,7 @@ namespace igl
   struct Hit
   {
     int id; // primitive id
+    int gid; // geometry id
     float u,v; // barycentric coordinates
     float t; // distance = direction*t to intersection
   };

+ 5 - 2
include/igl/embree/unproject_onto_mesh.cpp

@@ -52,8 +52,11 @@ IGL_INLINE bool igl::unproject_onto_mesh(
   Eigen::Vector3f bc;
   bool hit = unproject_onto_mesh(pos,F,model,proj,viewport,ei,fid,bc);
   int i;
-  bc.maxCoeff(&i);
-  vid = F(fid,i);
+  if (hit)
+  {
+    bc.maxCoeff(&i);
+    vid = F(fid,i);
+  }
   return hit;
 }
 

+ 7 - 6
include/igl/file_dialog_open.cpp

@@ -9,9 +9,12 @@
 #include <cstdio>
 #include <cstring>
 
-
 #ifdef _WIN32
- #include <Commdlg.h>
+  #include <windows.h>
+  #undef max
+  #undef min
+  
+  #include <Commdlg.h>
 #endif
 
 IGL_INLINE std::string igl::file_dialog_open()
@@ -32,20 +35,18 @@ IGL_INLINE std::string igl::file_dialog_open()
   while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL )
   {
   }
-#elif _WIN32
+#elif defined _WIN32
   
   // Use native windows file dialog box
   // (code contributed by Tino Weinkauf)
 
   OPENFILENAME ofn;       // common dialog box structure
   char szFile[260];       // buffer for file name
-  HWND hwnd;              // owner window
-  HANDLE hf;              // file handle
 
   // Initialize OPENFILENAME
   ZeroMemory(&ofn, sizeof(ofn));
   ofn.lStructSize = sizeof(ofn);
-  ofn.hwndOwner = NULL;//hwnd;
+  ofn.hwndOwner = NULL;
   ofn.lpstrFile = new char[100];
   // Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
   // use the contents of szFile to initialize itself.

+ 1 - 3
include/igl/file_dialog_save.cpp

@@ -34,15 +34,13 @@ IGL_INLINE std::string igl::file_dialog_save()
   while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL )
   {
   }
-#elif _WIN32
+#elif defined _WIN32
 
   // Use native windows file dialog box
   // (code contributed by Tino Weinkauf)
 
   OPENFILENAME ofn;       // common dialog box structure
   char szFile[260];       // buffer for file name
-  HWND hwnd;              // owner window
-  HANDLE hf;              // file handle
 
   // Initialize OPENFILENAME
   ZeroMemory(&ofn, sizeof(ofn));

+ 1 - 1
include/igl/internal_angles.cpp

@@ -48,7 +48,7 @@ IGL_INLINE void igl::internal_angles(
   #  define IGL_OMP_MIN_VALUE 1000
   #endif
   #pragma omp parallel for if (m>IGL_OMP_MIN_VALUE)
-  for(size_t f = 0;f<m;f++)
+  for(long int f = 0;f<m;f++)
   {
     for(size_t d = 0;d<3;d++)
     {

+ 154 - 33
include/igl/outer_hull.cpp

@@ -1,5 +1,6 @@
 #include "outer_hull.h"
 #include "outer_facet.h"
+#include "sort.h"
 #include "facet_components.h"
 #include "winding_number.h"
 #include "triangle_triangle_adjacency.h"
@@ -20,12 +21,14 @@
 template <
   typename DerivedV,
   typename DerivedF,
+  typename DerivedN,
   typename DerivedG,
   typename DerivedJ,
   typename Derivedflip>
 IGL_INLINE void igl::outer_hull(
   const Eigen::PlainObjectBase<DerivedV> & V,
   const Eigen::PlainObjectBase<DerivedF> & F,
+  const Eigen::PlainObjectBase<DerivedN> & N,
   Eigen::PlainObjectBase<DerivedG> & G,
   Eigen::PlainObjectBase<DerivedJ> & J,
   Eigen::PlainObjectBase<Derivedflip> & flip)
@@ -55,6 +58,65 @@ IGL_INLINE void igl::outer_hull(
   vector<vector<typename DerivedF::Index> > uE2E;
   unique_edge_map(F,E,uE,EMAP,uE2E);
 
+  // TODO:
+  // uE --> face-edge index, sorted CCW around edge according to normal
+  // uE --> sorted order index 
+  // uE --> bool, whether needed to flip face to make "consistent" with unique
+  //   edge
+  VectorXI diIM(3*m);
+  vector<vector<typename DerivedV::Scalar> > di(uE2E.size());
+  // For each list of face-edges incide on a unique edge
+  for(size_t ui = 0;ui<(size_t)uE.rows();ui++)
+  {
+    const typename DerivedF::Scalar ud = uE(ui,1);
+    const typename DerivedF::Scalar us = uE(ui,0);
+    // Base normal vector to orient against
+    const auto fe0 = uE2E[ui][0];
+    const auto & eVp = N.row(fe0%m);
+    di[ui].resize(uE2E[ui].size());
+
+    const typename DerivedF::Scalar d = F(fe0%m,((fe0/m)+2)%3);
+    const typename DerivedF::Scalar s = F(fe0%m,((fe0/m)+1)%3);
+    // Edge vector
+    //const auto & eV = (V.row(ud)-V.row(us)).normalized();
+    const auto & eV = (V.row(d)-V.row(s)).normalized();
+
+    // Loop over incident face edges
+    for(size_t fei = 0;fei<uE2E[ui].size();fei++)
+    {
+      const auto & fe = uE2E[ui][fei];
+      const auto f = fe % m;
+      const auto c = fe / m;
+      // source should match destination to be consistent
+      const bool cons = (d == F(f,(c+1)%3));
+      assert(cons ||  (d == F(f,(c+2)%3)));
+      assert(!cons || (s == F(f,(c+2)%3)));
+      assert(!cons || (d == F(f,(c+1)%3)));
+      // Angle between n and f
+      const auto & n = N.row(f);
+      di[ui][fei] = M_PI - atan2( eVp.cross(n).dot(eV), eVp.dot(n));
+      if(!cons)
+      {
+        di[ui][fei] = di[ui][fei] + M_PI;
+        if(di[ui][fei]>2.*M_PI)
+        {
+          di[ui][fei] = di[ui][fei] - 2.*M_PI;
+        }
+      }
+    }
+    vector<size_t> IM;
+    igl::sort(di[ui],true,di[ui],IM);
+    // copy old list
+    vector<typename DerivedF::Index> temp = uE2E[ui];
+    for(size_t fei = 0;fei<uE2E[ui].size();fei++)
+    {
+      uE2E[ui][fei] = temp[IM[fei]];
+      const auto & fe = uE2E[ui][fei];
+      diIM(fe) = fei;
+    }
+
+  }
+
   vector<vector<vector<Index > > > TT,_1;
   triangle_triangle_adjacency(E,EMAP,uE2E,false,TT,_1);
   VectorXI counts;
@@ -67,15 +129,6 @@ IGL_INLINE void igl::outer_hull(
   G.resize(0,F.cols());
   J.resize(0,1);
   flip.setConstant(m,1,false);
-  // precompute face normals
-  typename Eigen::Matrix<
-    typename DerivedV::Scalar,
-    DerivedF::RowsAtCompileTime,
-    3> N;
-#ifdef IGL_OUTER_HULL_DEBUG
-  cout<<"normals..."<<endl;
-#endif
-  per_face_normals(V,F,N);
 
 #ifdef IGL_OUTER_HULL_DEBUG
   cout<<"reindex..."<<endl;
@@ -107,7 +160,7 @@ IGL_INLINE void igl::outer_hull(
   barycenter(V,F,BC);
 
 #ifdef IGL_OUTER_HULL_DEBUG
-  cout<<"loop over CCs..."<<endl;
+  cout<<"loop over CCs (="<<ncc<<")..."<<endl;
 #endif
   for(Index id = 0;id<(Index)ncc;id++)
   {
@@ -127,6 +180,7 @@ IGL_INLINE void igl::outer_hull(
     Q.push(f+1*m);
     Q.push(f+2*m);
     flip(f) = f_flip;
+    //cout<<"flip("<<f<<") = "<<(flip(f)?"true":"false")<<endl;
 #ifdef IGL_OUTER_HULL_DEBUG
   cout<<"BFS..."<<endl;
 #endif
@@ -153,44 +207,93 @@ IGL_INLINE void igl::outer_hull(
       }
       // find overlapping face-edges
       const auto & neighbors = uE2E[EMAP(e)];
+      // normal after possible flipping 
       const auto & fN = (flip(f)?-1.:1.)*N.row(f);
       // source of edge according to f
       const int fs = flip(f)?F(f,(c+2)%3):F(f,(c+1)%3);
       // destination of edge according to f
       const int fd = flip(f)?F(f,(c+1)%3):F(f,(c+2)%3);
+      // Edge vector according to f's (flipped) orientation.
       const auto & eV = (V.row(fd)-V.row(fs)).normalized();
+      // edge valence
+      const size_t val = uE2E[EMAP(e)].size();
+      const auto ui = EMAP(e);
+      const auto fe0 = uE2E[ui][0];
+      const auto es = F(fe0%m,((fe0/m)+1)%3);
+      const int e_cons = (fs == es?-1:1);
+      const int nfei = (diIM(e) + val + e_cons*(flip(f)?-1:1))%val;
+      const int max_ne_2 = uE2E[EMAP(e)][nfei];
       // Loop over and find max dihedral angle
-      typename DerivedV::Scalar max_di = -1;
       int max_ne = -1;
-      typename Eigen::Matrix< typename DerivedV::Scalar, 1, 3> max_nN;
-      for(const auto & ne : neighbors)
-      {
-        const int nf = ne%m;
-        if(nf == f)
-        {
-          continue;
-        }
-        const int nc = ne/m;
-        // are faces consistently oriented
-        //const int ns = F(nf,(nc+1)%3);
-        const int nd = F(nf,(nc+2)%3);
-        const bool cons = (flip(f)?fd:fs) == nd;
-        const auto & nN = (cons? (flip(f)?-1:1.) : (flip(f)?1.:-1.) )*N.row(nf);
-        const auto & ndi = M_PI - atan2( fN.cross(nN).dot(eV), fN.dot(nN));
-        if(ndi>=max_di)
-        {
-          max_ne = ne;
-          max_di = ndi;
-          max_nN = nN;
-        }
-      }
+      // // SAVE THIS OLD IMPLEMENTATION FOR NOW
+      //typename DerivedV::Scalar max_di = -1;
+      //for(const auto & ne : neighbors)
+      //{
+      //  const int nf = ne%m;
+      //  if(nf == f)
+      //  {
+      //    continue;
+      //  }
+      //  // Corner of neighbor
+      //  const int nc = ne/m;
+      //  // Is neighbor oriented consistently with (flipped) f?
+      //  //const int ns = F(nf,(nc+1)%3);
+      //  const int nd = F(nf,(nc+2)%3);
+      //  const bool cons = (flip(f)?fd:fs) == nd;
+      //  // Normal after possibly flipping to match flip or orientation of f
+      //  const auto & nN = (cons? (flip(f)?-1:1.) : (flip(f)?1.:-1.) )*N.row(nf);
+      //  // Angle between n and f
+      //  const auto & ndi = M_PI - atan2( fN.cross(nN).dot(eV), fN.dot(nN));
+      //  if(ndi>=max_di)
+      //  {
+      //    max_ne = ne;
+      //    max_di = ndi;
+      //  }
+      //}
+      ////cout<<(max_ne != max_ne_2)<<" =?= "<<e_cons<<endl;
+      //if(max_ne != max_ne_2)
+      //{
+      //  cout<<(f+1)<<" ---> "<<(max_ne%m)+1<<" != "<<(max_ne_2%m)+1<<" ... "<<e_cons<<endl;
+      //  typename DerivedV::Scalar max_di = -1;
+      //  for(size_t nei = 0;nei<neighbors.size();nei++)
+      //  {
+      //    const auto & ne = neighbors[nei];
+      //    const int nf = ne%m;
+      //    if(nf == f)
+      //    {
+      //      cout<<"  "<<(ne%m)+1<<": "<<0<<" "<<di[EMAP[e]][nei]<<" "<<diIM(ne)<<endl;
+      //      continue;
+      //    }
+      //    // Corner of neighbor
+      //    const int nc = ne/m;
+      //    // Is neighbor oriented consistently with (flipped) f?
+      //    //const int ns = F(nf,(nc+1)%3);
+      //    const int nd = F(nf,(nc+2)%3);
+      //    const bool cons = (flip(f)?fd:fs) == nd;
+      //    // Normal after possibly flipping to match flip or orientation of f
+      //    const auto & nN = (cons? (flip(f)?-1:1.) : (flip(f)?1.:-1.) )*N.row(nf);
+      //    // Angle between n and f
+      //    const auto & ndi = M_PI - atan2( fN.cross(nN).dot(eV), fN.dot(nN));
+      //    cout<<"  "<<(ne%m)+1<<": "<<ndi<<" "<<di[EMAP[e]][nei]<<" "<<diIM(ne)<<endl;
+      //    if(ndi>=max_di)
+      //    {
+      //      max_ne = ne;
+      //      max_di = ndi;
+      //    }
+      //  }
+      //}
+      max_ne = max_ne_2;
+
       if(max_ne>=0)
       {
+        // face of neighbor
         const int nf = max_ne%m;
+        // corner of neighbor
         const int nc = max_ne/m;
         const int nd = F(nf,(nc+2)%3);
         const bool cons = (flip(f)?fd:fs) == nd;
         flip(nf) = (cons ? flip(f) : !flip(f));
+        //cout<<"flip("<<nf<<") = "<<(flip(nf)?"true":"false")<<endl;
         const int ne1 = nf+((nc+1)%3)*m;
         const int ne2 = nf+((nc+2)%3)*m;
         if(!EH[ne1])
@@ -323,6 +426,24 @@ IGL_INLINE void igl::outer_hull(
     }
   }
 }
+template <
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedG,
+  typename DerivedJ,
+  typename Derivedflip>
+IGL_INLINE void igl::outer_hull(
+  const Eigen::PlainObjectBase<DerivedV> & V,
+  const Eigen::PlainObjectBase<DerivedF> & F,
+  Eigen::PlainObjectBase<DerivedG> & G,
+  Eigen::PlainObjectBase<DerivedJ> & J,
+  Eigen::PlainObjectBase<Derivedflip> & flip)
+{
+  Eigen::Matrix<typename DerivedV::Scalar,DerivedF::RowsAtCompileTime,3> N;
+  per_face_normals(V,F,N);
+  return outer_hull(V,F,N,G,J,flip);
+}
+
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template specialization
 template void igl::outer_hull<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&);

+ 16 - 0
include/igl/outer_hull.h

@@ -16,11 +16,26 @@ namespace igl
   // Inputs:
   //   V  #V by 3 list of vertex positions
   //   F  #F by 3 list of triangle indices into V
+  //   N  #F by 3 list of per-face normals
   // Outputs:
   //   G  #G by 3 list of output triangle indices into V
   //   J  #G list of indices into F
   //   flip  #F list of whether facet was added to G **and** flipped orientation
   //     (false for faces not added to G)
+  template <
+    typename DerivedV,
+    typename DerivedF,
+    typename DerivedN,
+    typename DerivedG,
+    typename DerivedJ,
+    typename Derivedflip>
+  IGL_INLINE void outer_hull(
+    const Eigen::PlainObjectBase<DerivedV> & V,
+    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::PlainObjectBase<DerivedN> & N,
+    Eigen::PlainObjectBase<DerivedG> & G,
+    Eigen::PlainObjectBase<DerivedJ> & J,
+    Eigen::PlainObjectBase<Derivedflip> & flip);
   template <
     typename DerivedV,
     typename DerivedF,
@@ -34,6 +49,7 @@ namespace igl
     Eigen::PlainObjectBase<DerivedJ> & J,
     Eigen::PlainObjectBase<Derivedflip> & flip);
 }
+
 #ifndef IGL_STATIC_LIBRARY
 #  include "outer_hull.cpp"
 #endif

+ 27 - 2
include/igl/peel_outer_hull_layers.cpp

@@ -1,10 +1,11 @@
 #include "peel_outer_hull_layers.h"
+#include "per_face_normals.h"
 #include "outer_hull.h"
-#include "writePLY.h"
 #include <vector>
 #include <iostream>
 //#define IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
 #ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
+#include "writePLY.h"
 #include "STR.h"
 #endif
 
@@ -12,11 +13,13 @@ using namespace std;
 template <
   typename DerivedV,
   typename DerivedF,
+  typename DerivedN,
   typename Derivedodd,
   typename Derivedflip>
 IGL_INLINE size_t igl::peel_outer_hull_layers(
   const Eigen::PlainObjectBase<DerivedV > & V,
   const Eigen::PlainObjectBase<DerivedF > & F,
+  const Eigen::PlainObjectBase<DerivedN > & N,
   Eigen::PlainObjectBase<Derivedodd > & odd,
   Eigen::PlainObjectBase<Derivedflip > & flip)
 {
@@ -24,6 +27,7 @@ IGL_INLINE size_t igl::peel_outer_hull_layers(
   using namespace std;
   typedef typename DerivedF::Index Index;
   typedef Matrix<typename DerivedF::Scalar,Dynamic,DerivedF::ColsAtCompileTime> MatrixXF;
+  typedef Matrix<typename DerivedN::Scalar,Dynamic,DerivedN::ColsAtCompileTime> MatrixXN;
   typedef Matrix<Index,Dynamic,1> MatrixXI;
   typedef Matrix<typename Derivedflip::Scalar,Dynamic,Derivedflip::ColsAtCompileTime> MatrixXflip;
   const Index m = F.rows();
@@ -36,6 +40,7 @@ IGL_INLINE size_t igl::peel_outer_hull_layers(
 #endif
   // keep track of iteration parity and whether flipped in hull
   MatrixXF Fr = F;
+  MatrixXN Nr = N;
   odd.resize(m,1);
   flip.resize(m,1);
   // Keep track of index map
@@ -55,7 +60,7 @@ IGL_INLINE size_t igl::peel_outer_hull_layers(
   cout<<"calling outer hull..."<<endl;
   writePLY(STR("outer-hull-input-"<<iter<<".ply"),V,Fr);
 #endif
-    outer_hull(V,Fr,Fo,Jo,flipr);
+    outer_hull(V,Fr,Nr,Fo,Jo,flipr);
 #ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
   writePLY(STR("outer-hull-output-"<<iter<<".ply"),V,Fo);
   cout<<"reindex, flip..."<<endl;
@@ -73,8 +78,10 @@ IGL_INLINE size_t igl::peel_outer_hull_layers(
     // Fr = Fr - Fo
     // update IM
     MatrixXF prev_Fr = Fr;
+    MatrixXN prev_Nr = Nr;
     MatrixXI prev_IM = IM;
     Fr.resize(prev_Fr.rows() - Fo.rows(),F.cols());
+    Nr.resize(Fr.rows(),3);
     IM.resize(Fr.rows());
     {
       Index g = 0;
@@ -83,6 +90,7 @@ IGL_INLINE size_t igl::peel_outer_hull_layers(
         if(!in_outer[f])
         {
           Fr.row(g) = prev_Fr.row(f);
+          Nr.row(g) = prev_Nr.row(f);
           IM(g) = prev_IM(f);
           g++;
         }
@@ -94,8 +102,25 @@ IGL_INLINE size_t igl::peel_outer_hull_layers(
   return iter;
 }
 
+template <
+  typename DerivedV,
+  typename DerivedF,
+  typename Derivedodd,
+  typename Derivedflip>
+IGL_INLINE size_t igl::peel_outer_hull_layers(
+  const Eigen::PlainObjectBase<DerivedV > & V,
+  const Eigen::PlainObjectBase<DerivedF > & F,
+  Eigen::PlainObjectBase<Derivedodd > & odd,
+  Eigen::PlainObjectBase<Derivedflip > & flip)
+{
+  Eigen::Matrix<typename DerivedV::Scalar,DerivedF::RowsAtCompileTime,3> N;
+  per_face_normals(V,F,N);
+  return peel_outer_hull_layers(V,F,N,odd,flip);
+}
+
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template specialization
 template size_t igl::peel_outer_hull_layers<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&);
+template size_t igl::peel_outer_hull_layers<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&);
 #endif

+ 13 - 0
include/igl/peel_outer_hull_layers.h

@@ -11,12 +11,25 @@ namespace igl
   // Inputs:
   //   V  #V by 3 list of vertex positions
   //   F  #F by 3 list of triangle indices into V
+  //   N  #F by 3 list of per-face normals
   // Outputs:
   //   odd  #F list of whether facet belongs to an odd iteration peel (otherwise
   //     an even iteration peel)
   //   flip  #F list of whether a facet's orientation was flipped when facet
   //     "peeled" into its associated outer hull layer.
   // Returns number of peels
+  template <
+    typename DerivedV,
+    typename DerivedF,
+    typename DerivedN,
+    typename Derivedodd,
+    typename Derivedflip>
+  IGL_INLINE size_t peel_outer_hull_layers(
+    const Eigen::PlainObjectBase<DerivedV > & V,
+    const Eigen::PlainObjectBase<DerivedF > & F,
+    const Eigen::PlainObjectBase<DerivedN > & N,
+    Eigen::PlainObjectBase<Derivedodd > & odd,
+    Eigen::PlainObjectBase<Derivedflip > & flip);
   template <
     typename DerivedV,
     typename DerivedF,

+ 39 - 6
include/igl/png/texture_from_png.cpp

@@ -1,16 +1,17 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "texture_from_png.h"
-#ifndef IGL_NO_OPENGL
 
 #include <YImage.hpp>
 #include <igl/report_gl_error.h>
 
+#ifndef IGL_NO_OPENGL
+
 IGL_INLINE bool igl::texture_from_png(const std::string png_file, GLuint & id)
 {
   YImage yimg;
@@ -27,7 +28,7 @@ IGL_INLINE bool igl::texture_from_png(const std::string png_file, GLuint & id)
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexImage2D(
-    GL_TEXTURE_2D, 0, GL_RGB, 
+    GL_TEXTURE_2D, 0, GL_RGB,
     yimg.width(), yimg.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, yimg.data());
   glBindTexture(GL_TEXTURE_2D, 0);
   return true;
@@ -35,3 +36,35 @@ IGL_INLINE bool igl::texture_from_png(const std::string png_file, GLuint & id)
 
 #endif
 
+IGL_INLINE bool igl::texture_from_png(
+  const std::string png_file,
+  Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& R,
+  Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& G,
+  Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& B,
+  Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& A
+)
+{
+  YImage yimg;
+  if(!yimg.load(png_file.c_str()))
+  {
+    return false;
+  }
+
+  R.resize(yimg.height(),yimg.width());
+  G.resize(yimg.height(),yimg.width());
+  B.resize(yimg.height(),yimg.width());
+  A.resize(yimg.height(),yimg.width());
+
+  for (unsigned j=0; j<yimg.height(); ++j)
+  {
+    for (unsigned i=0; i<yimg.width(); ++i)
+    {
+      R(i,j) = yimg.at(yimg.width()-1-i,yimg.height()-1-j).r;
+      G(i,j) = yimg.at(yimg.width()-1-i,yimg.height()-1-j).g;
+      B(i,j) = yimg.at(yimg.width()-1-i,yimg.height()-1-j).b;
+      //1A(i,j) = yimg.at(yimg.width()-1-i,yimg.height()-1-j).a;
+    }
+  }
+
+  return true;
+}

+ 24 - 9
include/igl/png/texture_from_png.h

@@ -1,19 +1,18 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 #ifndef IGL_TEXTURE_FROM_PNG_H
 #define IGL_TEXTURE_FROM_PNG_H
-#ifndef IGL_NO_OPENGL
 #include "../igl_inline.h"
+#include <string>
 
+#ifndef IGL_NO_OPENGL
 #include "../OpenGL_convenience.h"
 
-#include <string>
-
 namespace igl
 {
   // Read an image from a .png file and use it as a texture
@@ -25,11 +24,27 @@ namespace igl
   // Returns true on success, false on failure
   IGL_INLINE bool texture_from_png(const std::string png_file, GLuint & id);
 }
+#endif
+
+namespace igl
+{
+  // Read an image from a .png file and use it as a texture
+  //
+  // Input:
+  //  png_file  path to .png file
+  // Output:
+  //  R,G,B,A texture channels
+  // Returns true on success, false on failure
+  IGL_INLINE bool texture_from_png(const std::string png_file,
+  Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& R,
+  Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& G,
+  Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& B,
+  Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& A
+  );
+}
 
 #ifndef IGL_STATIC_LIBRARY
 #  include "texture_from_png.cpp"
 #endif
 
 #endif
-#endif
-

+ 756 - 0
include/igl/serialize.cpp

@@ -0,0 +1,756 @@
+//
+// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "serialize.h"
+
+namespace igl
+{
+  template <typename T>
+  IGL_INLINE bool serialize(const T& obj,const std::string& filename)
+  {
+    return serialize(obj,"obj",filename,true);
+  }
+
+  template <typename T>
+  IGL_INLINE bool serialize(const T& obj,const std::string& objectName,const std::string& filename,bool overwrite)
+  {
+    bool success = false;
+
+    std::vector<char> buffer;
+
+    std::ios_base::openmode mode = std::ios::out | std::ios::binary;
+
+    if(overwrite)
+      mode |= std::ios::trunc;
+    else
+      mode |= std::ios::app;
+
+    std::ofstream file(filename.c_str(),mode);
+
+    if(file.is_open())
+    {
+      serialize(obj,objectName,buffer);
+
+      file.write(&buffer[0],buffer.size());
+
+      file.close();
+
+      success = true;
+    }
+    else
+    {
+      std::cerr << "saving binary serialization failed!" << std::endl;
+    }
+
+    return success;
+  }
+
+  template <typename T>
+  IGL_INLINE bool serialize(const T& obj,const std::string& objectName,std::vector<char>& buffer)
+  {
+    // serialize object data
+    size_t size = serialization::getByteSize(obj);
+    std::vector<char> tmp(size);
+    auto it = tmp.begin();
+    serialization::serialize(obj,tmp,it);
+
+    std::string objectType(typeid(obj).name());
+    size_t newObjectSize = tmp.size();
+    size_t newHeaderSize = serialization::getByteSize(objectName) + serialization::getByteSize(objectType) + sizeof(size_t);
+    size_t curSize = buffer.size();
+    size_t newSize = curSize + newHeaderSize + newObjectSize;
+
+    buffer.resize(newSize);
+
+    std::vector<char>::iterator iter = buffer.begin()+curSize;
+
+    // serialize object header (name/type/size)
+    serialization::serialize(objectName,buffer,iter);
+    serialization::serialize(objectType,buffer,iter);
+    serialization::serialize(newObjectSize,buffer,iter);
+
+    // copy serialized data to buffer
+    iter = std::copy(tmp.begin(),tmp.end(),iter);
+
+    return true;
+  }
+
+  template <typename T>
+  IGL_INLINE bool deserialize(T& obj,const std::string& filename)
+  {
+    return deserialize(obj,"obj",filename);
+  }
+
+  template <typename T>
+  IGL_INLINE bool deserialize(T& obj,const std::string& objectName,const std::string& filename)
+  {
+    bool success = false;
+
+    std::ifstream file(filename.c_str(),std::ios::binary);
+
+    if(file.is_open())
+    {
+      file.seekg(0,std::ios::end);
+      std::streamoff size = file.tellg();
+      file.seekg(0,std::ios::beg);
+
+      std::vector<char> buffer(size);
+      file.read(&buffer[0],size);
+
+      deserialize(obj,objectName,buffer);
+      file.close();
+
+      success = true;
+    }
+    else
+    {
+      std::cerr << "Loading binary serialization failed!" << std::endl;
+    }
+
+    return success;
+  }
+
+  template <typename T>
+  IGL_INLINE bool deserialize(T& obj,const std::string& objectName,const std::vector<char>& buffer)
+  {
+    bool success = false;
+
+    // find suitable object header
+    auto objectIter = buffer.cend();
+    auto iter = buffer.cbegin();
+    while(iter != buffer.end())
+    {
+      std::string name;
+      std::string type;
+      size_t size;
+      serialization::deserialize(name,iter);
+      serialization::deserialize(type,iter);
+      serialization::deserialize(size,iter);
+
+      if(name == objectName && type == typeid(obj).name())
+      {
+        objectIter = iter;
+        //break; // find first suitable object header
+      }
+
+      iter+=size;
+    }
+
+    if(objectIter != buffer.end())
+    {
+      serialization::deserialize(obj,objectIter);
+      success = true;
+    }
+    else
+    {
+      obj = T();
+    }
+
+    return success;
+  }
+
+  // Wrapper function which combines both, de- and serialization
+  template <typename T>
+  IGL_INLINE bool serializer(bool s,T& obj,std::string& filename)
+  {
+    return s ? serialize(obj,filename) : deserialize(obj,filename);
+  }
+
+  template <typename T>
+  IGL_INLINE bool serializer(bool s,T& obj,std::string& objectName,const std::string& filename,bool overwrite)
+  {
+    return s ? serialize(obj,objectName,filename,overwrite) : deserialize(obj,objectName,filename);
+  }
+
+  template <typename T>
+  IGL_INLINE bool serializer(bool s,T& obj,std::string& objectName,std::vector<char>& buffer)
+  {
+    return s ? serialize(obj,objectName,buffer) : deserialize(obj,objectName,buffer);
+  }
+
+  IGL_INLINE bool Serializable::PreSerialization() const
+  {
+    return true;
+  }
+
+  IGL_INLINE void Serializable::PostSerialization() const
+  {
+  }
+
+  IGL_INLINE bool Serializable::PreDeserialization()
+  {
+    return true;
+  }
+
+  IGL_INLINE void Serializable::PostDeserialization()
+  {
+  }
+
+  IGL_INLINE void Serializable::Serialize(std::vector<char>& buffer) const
+  {
+    if(this->PreSerialization())
+    {
+      if(initialized == false)
+      {
+        objects.clear();
+        (const_cast<Serializable*>(this))->InitSerialization();
+        initialized = true;
+      }
+
+      for(const auto& v : objects)
+      {
+        v->Serialize(buffer);
+      }
+
+      this->PostSerialization();
+    }
+  }
+
+  IGL_INLINE void Serializable::Deserialize(const std::vector<char>& buffer)
+  {
+    if(this->PreDeserialization())
+    {
+      if(initialized == false)
+      {
+        objects.clear();
+        (const_cast<Serializable*>(this))->InitSerialization();
+        initialized = true;
+      }
+
+      for(auto& v : objects)
+      {
+        v->Deserialize(buffer);
+      }
+
+      this->PostDeserialization();
+    }
+  }
+
+  IGL_INLINE Serializable::Serializable()
+  {
+    initialized = false;
+  }
+
+  IGL_INLINE Serializable::Serializable(const Serializable& obj)
+  {
+    initialized = false;
+    objects.clear();
+  }
+
+  IGL_INLINE Serializable::~Serializable()
+  {
+    initialized = false;
+    objects.clear();
+  }
+
+  IGL_INLINE Serializable& Serializable::operator=(const Serializable& obj)
+  {
+    if(this != &obj)
+    {
+      if(initialized)
+      {
+        initialized = false;
+        objects.clear();
+      }
+    }
+    return *this;
+  }
+
+  template <typename T>
+  IGL_INLINE void Serializable::Add(T& obj,std::string name,bool binary)
+  {
+    auto object = new SerializationObject<T>();
+    object->Binary = binary;
+    object->Name = name;
+    object->Object = std::unique_ptr<T>(&obj);
+
+    objects.push_back(object);
+  }
+
+  namespace serialization
+  {
+    // not serializable
+    template <typename T>
+    IGL_INLINE typename std::enable_if<!is_serializable<T>::value,size_t>::type getByteSize(const T& obj)
+    {
+      return sizeof(std::vector<char>::size_type);
+    }
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<!is_serializable<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+      // data
+      std::vector<char> tmp;
+      serialize(obj,tmp);
+
+      // size
+      size_t size = buffer.size();
+      serialization::serialize(tmp.size(),buffer,iter);
+      size_t cur = iter - buffer.begin();
+
+      buffer.resize(size+tmp.size());
+      iter = buffer.begin()+cur;
+      iter = std::copy(tmp.begin(),tmp.end(),iter);
+    }
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<!is_serializable<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter)
+    {
+      std::vector<char>::size_type size;
+      serialization::deserialize(size,iter);
+
+      std::vector<char> tmp;
+      tmp.resize(size);
+      std::copy(iter,iter+size,tmp.begin());
+
+      deserialize(obj,tmp);
+      iter += size;
+    }
+
+    // fundamental types
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value,size_t>::type getByteSize(const T& obj)
+    {
+      return sizeof(T);
+    }
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+      //serialization::updateMemoryMap(obj,sizeof(T),memoryMap);
+      const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&obj);
+      iter = std::copy(ptr,ptr+sizeof(T),iter);
+    }
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter)
+    {
+      uint8_t* ptr = reinterpret_cast<uint8_t*>(&obj);
+      std::copy(iter,iter+sizeof(T),ptr);
+      iter += sizeof(T);
+    }
+
+    // std::string
+
+    IGL_INLINE size_t getByteSize(const std::string& obj)
+    {
+      return getByteSize(obj.length())+obj.length()*sizeof(uint8_t);
+    }
+
+    IGL_INLINE void serialize(const std::string& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+      serialization::serialize(obj.length(),buffer,iter);
+      for(const auto& cur : obj)
+      {
+        serialization::serialize(cur,buffer,iter);
+      }
+    }
+
+    IGL_INLINE void deserialize(std::string& obj,std::vector<char>::const_iterator& iter)
+    {
+      size_t size;
+      serialization::deserialize(size,iter);
+
+      std::string str(size,'\0');
+      for(size_t i=0; i<size; ++i)
+      {
+        serialization::deserialize(str.at(i),iter);
+      }
+
+      obj = str;
+    }
+
+    // SerializableBase
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_base_of<SerializableBase,T>::value,size_t>::type getByteSize(const T& obj)
+    {
+      return sizeof(std::vector<char>::size_type);
+    }
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_base_of<SerializableBase,T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+      // data
+      std::vector<char> tmp;
+      obj.Serialize(tmp);
+
+      // size
+      size_t size = buffer.size();
+      serialization::serialize(tmp.size(),buffer,iter);
+      size_t cur = iter - buffer.begin();
+
+      buffer.resize(size+tmp.size());
+      iter = buffer.begin()+cur;
+      iter = std::copy(tmp.begin(),tmp.end(),iter);
+    }
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_base_of<SerializableBase,T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter)
+    {
+      std::vector<char>::size_type size;
+      serialization::deserialize(size,iter);
+
+      std::vector<char> tmp;
+      tmp.resize(size);
+      std::copy(iter,iter+size,tmp.begin());
+
+      obj.Deserialize(tmp);
+      iter += size;
+    }
+
+    // STL containers
+
+    // std::pair
+
+    template <typename T1,typename T2>
+    IGL_INLINE size_t getByteSize(const std::pair<T1,T2>& obj)
+    {
+      return getByteSize(obj.first)+getByteSize(obj.second);
+    }
+
+    template <typename T1,typename T2>
+    IGL_INLINE void serialize(const std::pair<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+      serialization::serialize(obj.first,buffer,iter);
+      serialization::serialize(obj.second,buffer,iter);
+    }
+
+    template <typename T1,typename T2>
+    IGL_INLINE void deserialize(std::pair<T1,T2>& obj,std::vector<char>::const_iterator& iter)
+    {
+      serialization::deserialize(obj.first,iter);
+      serialization::deserialize(obj.second,iter);
+    }
+
+    // std::vector
+
+    template <typename T1,typename T2>
+    IGL_INLINE size_t getByteSize(const std::vector<T1,T2>& obj)
+    {
+      return std::accumulate(obj.begin(),obj.end(),sizeof(size_t),[](const size_t& acc,const T1& cur) { return acc+getByteSize(cur); });
+    }
+
+    template <typename T1,typename T2>
+    IGL_INLINE void serialize(const std::vector<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+      size_t size = obj.size();
+      serialization::serialize(size,buffer,iter);
+      for(const auto& cur : obj)
+      {
+        serialization::serialize(cur,buffer,iter);
+      }
+    }
+
+    template <typename T1,typename T2>
+    IGL_INLINE void deserialize(std::vector<T1,T2>& obj,std::vector<char>::const_iterator& iter)
+    {
+      size_t size;
+      serialization::deserialize(size,iter);
+
+      obj.resize(size);
+      for(auto& v : obj)
+      {
+        serialization::deserialize(v,iter);
+      }
+    }
+
+    //std::set
+
+    template <typename T>
+    IGL_INLINE size_t getByteSize(const std::set<T>& obj)
+    {
+      return std::accumulate(obj.begin(),obj.end(),getByteSize(obj.size()),[](const size_t& acc,const T& cur) { return acc+getByteSize(cur); });
+    }
+
+    template <typename T>
+    IGL_INLINE void serialize(const std::set<T>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+      serialization::serialize(obj.size(),buffer,iter);
+      for(const auto& cur : obj)
+      {
+        serialization::serialize(cur,buffer,iter);
+      }
+    }
+
+    template <typename T>
+    IGL_INLINE void deserialize(std::set<T>& obj,std::vector<char>::const_iterator& iter)
+    {
+      size_t size;
+      serialization::deserialize(size,iter);
+
+      obj.clear();
+      for(size_t i=0; i<size; ++i)
+      {
+        T val;
+        serialization::deserialize(val,iter);
+        obj.insert(val);
+      }
+    }
+
+    // std::map
+
+    template <typename T1,typename T2>
+    IGL_INLINE size_t getByteSize(const std::map<T1,T2>& obj)
+    {
+      return std::accumulate(obj.begin(),obj.end(),sizeof(size_t),[](const size_t& acc,const std::pair<T1,T2>& cur) { return acc+getByteSize(cur); });
+    }
+
+    template <typename T1,typename T2>
+    IGL_INLINE void serialize(const std::map<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+      serialization::serialize(obj.size(),buffer,iter);
+      for(const auto& cur : obj)
+      {
+        serialization::serialize(cur,buffer,iter);
+      }
+    }
+
+    template <typename T1,typename T2>
+    IGL_INLINE void deserialize(std::map<T1,T2>& obj,std::vector<char>::const_iterator& iter)
+    {
+      size_t size;
+      serialization::deserialize(size,iter);
+
+      obj.clear();
+      for(size_t i=0; i<size; ++i)
+      {
+        std::pair<T1,T2> pair;
+        serialization::deserialize(pair,iter);
+        obj.insert(pair);
+      }
+    }
+
+    // Eigen types
+    template<typename T,int R,int C,int P,int MR,int MC>
+    IGL_INLINE size_t getByteSize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj)
+    {
+      // space for numbers of rows,cols and data
+      return 2*sizeof(typename Eigen::Matrix<T,R,C,P,MR,MC>::Index)+sizeof(T)*obj.rows()*obj.cols();
+    }
+
+    template<typename T,int R,int C,int P,int MR,int MC>
+    IGL_INLINE void serialize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+      serialization::serialize(obj.rows(),buffer,iter);
+      serialization::serialize(obj.cols(),buffer,iter);
+      size_t size = sizeof(T)*obj.rows()*obj.cols();
+      auto ptr = reinterpret_cast<const uint8_t*>(obj.data());
+      iter = std::copy(ptr,ptr+size,iter);
+    }
+
+    template<typename T,int R,int C,int P,int MR,int MC>
+    IGL_INLINE void deserialize(Eigen::Matrix<T,R,C,P,MR,MC>& obj,std::vector<char>::const_iterator& iter)
+    {
+      typename Eigen::Matrix<T,R,C,P,MR,MC>::Index rows,cols;
+      serialization::deserialize(rows,iter);
+      serialization::deserialize(cols,iter);
+      size_t size = sizeof(T)*rows*cols;
+      obj.resize(rows,cols);
+      auto ptr = reinterpret_cast<uint8_t*>(obj.data());
+      std::copy(iter,iter+size,ptr);
+      iter+=size;
+    }
+
+    template<typename T,int P,typename I>
+    IGL_INLINE size_t getByteSize(const Eigen::SparseMatrix<T,P,I>& obj)
+    {
+      // space for numbers of rows,cols,nonZeros and tripplets with data (rowIdx,colIdx,value)
+      size_t size = sizeof(Eigen::SparseMatrix<T,P,I>::Index);
+      return 3*size+(sizeof(T)+2*size)*obj.nonZeros();
+    }
+
+    template<typename T,int P,typename I>
+    IGL_INLINE void serialize(const Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+      serialization::serialize(obj.rows(),buffer,iter);
+      serialization::serialize(obj.cols(),buffer,iter);
+      serialization::serialize(obj.nonZeros(),buffer,iter);
+
+      for(int k=0;k<obj.outerSize();++k)
+      {
+        for(typename Eigen::SparseMatrix<T,P,I>::InnerIterator it(obj,k);it;++it)
+        {
+          serialization::serialize(it.row(),buffer,iter);
+          serialization::serialize(it.col(),buffer,iter);
+          serialization::serialize(it.value(),buffer,iter);
+        }
+      }
+    }
+
+    template<typename T,int P,typename I>
+    IGL_INLINE void deserialize(Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>::const_iterator& iter)
+    {
+      typename Eigen::SparseMatrix<T,P,I>::Index rows,cols,nonZeros;
+      serialization::deserialize(rows,iter);
+      serialization::deserialize(cols,iter);
+      serialization::deserialize(nonZeros,iter);
+
+      obj.resize(rows,cols);
+      obj.setZero();
+
+      std::vector<Eigen::Triplet<T,I> > triplets;
+      for(int i=0;i<nonZeros;i++)
+      {
+        typename Eigen::SparseMatrix<T,P,I>::Index rowId,colId;
+        serialization::deserialize(rowId,iter);
+        serialization::deserialize(colId,iter);
+        T value;
+        serialization::deserialize(value,iter);
+        triplets.push_back(Eigen::Triplet<T,I>(rowId,colId,value));
+      }
+      obj.setFromTriplets(triplets.begin(),triplets.end());
+    }
+
+    // pointers
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_pointer<T>::value,size_t>::type getByteSize(const T& obj)
+    {
+      size_t size = sizeof(bool);
+
+      if(obj)
+        size += getByteSize(*obj);
+
+      return size;
+    }
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+      serialization::serialize(obj == nullptr,buffer,iter);
+
+      if(obj)
+        serialization::serialize(*obj,buffer,iter);
+    }
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter)
+    {
+      bool isNullPtr;
+      serialization::deserialize(isNullPtr,iter);
+
+      if(isNullPtr)
+      {
+        if(obj)
+        {
+          std::cout << "deserialization: possible memory leak for '" << typeid(obj).name() << "'" << std::endl;
+          obj = nullptr;
+        }
+      }
+      else
+      {
+        if(obj)
+          std::cout << "deserialization: possible memory leak for '" << typeid(obj).name() << "'" << std::endl;
+
+        obj = new typename std::remove_pointer<T>::type();
+        serialization::deserialize(*obj,iter);
+      }
+    }
+
+    // std::shared_ptr and std::unique_ptr
+
+    /*template <typename T>
+    IGL_INLINE typename std::enable_if<serialization::is_smart_ptr<T>::value,size_t>::type getByteSize(const T& obj)
+    {
+      return getByteSize(obj.get());
+    }
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<serialization::is_smart_ptr<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+      serialize(obj.get(),buffer,iter);
+    }
+
+    template <template<typename> class T0,typename T1>
+    IGL_INLINE typename std::enable_if<serialization::is_smart_ptr<T0<T1> >::value>::type deserialize(T0<T1>& obj,std::vector<char>::const_iterator& iter)
+    {
+      bool isNullPtr;
+      serialization::deserialize(isNullPtr,iter);
+
+      if(isNullPtr)
+      {
+        obj.reset();
+      }
+      else
+      {
+        obj = T0<T1>(new T1());
+        serialization::deserialize(*obj,iter);
+      }
+    }
+
+    // std::weak_ptr
+
+    template <typename T>
+    IGL_INLINE size_t getByteSize(const std::weak_ptr<T>& obj)
+    {
+      return sizeof(size_t);
+    }
+
+    template <typename T>
+    IGL_INLINE void serialize(const std::weak_ptr<T>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+
+    }
+
+    template <typename T>
+    IGL_INLINE void deserialize(std::weak_ptr<T>& obj,std::vector<char>::const_iterator& iter)
+    {
+
+    }*/
+
+    // functions to overload for non-intrusive serialization
+    template <typename T>
+    IGL_INLINE void serialize(const T& obj,std::vector<char>& buffer)
+    {
+      std::cerr << typeid(obj).name() << " is not serializable: derive from igl::Serializable or overload the function igl::serialization::serialize(const T& obj,std::vector<char>& buffer)" << std::endl;
+    }
+
+    template <typename T>
+    IGL_INLINE void deserialize(T& obj,const std::vector<char>& buffer)
+    {
+      std::cerr << typeid(obj).name() << " is not drserializable: derive from igl::Serializable or overload the function igl::serialization::deserialize(T& obj, const std::vector<char>& buffer)" << std::endl;
+    }
+
+    // helper functions
+
+    template <typename T>
+    IGL_INLINE void updateMemoryMap(T& obj,size_t size,std::map<std::uintptr_t,IndexedPointerBase*>& memoryMap)
+    {
+      // check if object is already serialized
+      auto startPtr = new IndexedPointer<T>();
+      startPtr->Object = &obj;
+      auto startBasePtr = static_cast<IndexedPointerBase*>(startPtr);
+      startBasePtr->Type = IndexedPointerBase::BEGIN;
+      auto startAddress = reinterpret_cast<std::uintptr_t>(&obj);
+      auto p = std::pair<std::uintptr_t,IndexedPointerBase*>(startAddress,startBasePtr);
+
+      auto el = memoryMap.insert(p);
+      auto iter = ++el.first; // next elememt
+      if(el.second && (iter == memoryMap.end() || iter->second->Type != IndexedPointerBase::END))
+      {
+        // not yet serialized
+        auto endPtr = new IndexedPointer<T>();
+        auto endBasePtr = static_cast<IndexedPointerBase*>(endPtr);
+        endBasePtr->Type = IndexedPointerBase::END;
+        auto endAddress = reinterpret_cast<std::uintptr_t>(&obj) + size - 1;
+        auto p = std::pair<std::uintptr_t,IndexedPointerBase*>(endAddress,endBasePtr);
+
+        // insert end address
+        memoryMap.insert(el.first,p);
+      }
+      else
+      {
+        // already serialized
+
+        // remove inserted address
+        memoryMap.erase(el.first);
+      }
+    }
+  }
+}

+ 361 - 0
include/igl/serialize.h

@@ -0,0 +1,361 @@
+//
+// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+// -----------------------------------------------------------------------------
+// Functions to save and load a serialization of fundamental c++ data types to
+// and from a binary file. STL containers, Eigen matrix types and nested data
+// structures are also supported. To serialize a user defined class implement
+// the interface Serializable or SerializableBase.
+//
+// See also: xml/serialize_xml.h
+// -----------------------------------------------------------------------------
+// TODOs:
+// * non-intrusive serialization example
+// * arbitrary pointer graph structures
+// * cross-platform compatibility (big-, little-endian)
+// -----------------------------------------------------------------------------
+
+#ifndef IGL_SERIALIZE_H
+#define IGL_SERIALIZE_H
+
+#include <type_traits>
+#include <iostream>
+#include <fstream>
+#include <cstdint>
+#include <numeric>
+#include <vector>
+#include <set>
+#include <map>
+#include <memory>
+#include <cstdint>
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+#include "igl_inline.h"
+
+// non-intrusive serialization helper macros
+
+#define SERIALIZE_TYPE(Type,Params) \
+namespace igl { namespace serialization { \
+  void _serialization(bool s,Type& obj,std::vector<char>& buffer) {Params} \
+  void serialize(const Type& obj,std::vector<char>& buffer) { \
+    _serialization(true,const_cast<Type&>(obj),buffer); \
+    } \
+  void deserialize(Type& obj,const std::vector<char>& buffer) { \
+    _serialization(false,obj,const_cast<std::vector<char>&>(buffer)); \
+    } \
+}}
+
+#define SERIALIZE_MEMBER(Object) ::igl::serializer(s,obj.##Object,std::string(#Object),buffer);
+#define SERIALIZE_MEMBER_NAME(Object,Name) ::igl::serializer(s,obj.##Object,std::string(Name),buffer);
+
+namespace igl
+{
+  struct IndexedPointerBase;
+
+  // Serializes the given object either to a file or to a provided buffer
+  // Templates:
+  //   T  type of the object to serialize
+  // Inputs:
+  //   obj        object to serialize
+  //   objectName unique object name,used for the identification
+  //   overwrite  set to true to overwrite an existing file
+  //   filename   name of the file containing the serialization
+  // Outputs:
+  //   buffer     binary serialization
+  //
+  template <typename T>
+  IGL_INLINE bool serialize(const T& obj,const std::string& filename);
+  template <typename T>
+  IGL_INLINE bool serialize(const T& obj,const std::string& objectName,const std::string& filename,bool overwrite = false);
+  template <typename T>
+  IGL_INLINE bool serialize(const T& obj,const std::string& objectName,std::vector<char>& buffer);
+
+  // Deserializes the given data from a file or buffer back to the provided object
+  //
+  // Templates:
+  //   T  type of the object to serialize
+  // Inputs:
+  //   buffer     binary serialization
+  //   objectName unique object name, used for the identification
+  //   filename   name of the file containing the serialization
+  // Outputs:
+  //   obj        object to load back serialization to
+  //
+  template <typename T>
+  IGL_INLINE bool deserialize(T& obj,const std::string& filename);
+  template <typename T>
+  IGL_INLINE bool deserialize(T& obj,const std::string& objectName,const std::string& filename);
+  template <typename T>
+  IGL_INLINE bool deserialize(T& obj,const std::string& objectName,const std::vector<char>& buffer);
+
+  // Wrapper to expose both, the de- and serialization as one function
+  //
+  template <typename T>
+  IGL_INLINE bool serializer(bool serialize,T& obj,std::string& filename);
+  template <typename T>
+  IGL_INLINE bool serializer(bool serialize,T& obj,std::string& objectName,const std::string& filename,bool overwrite = false);
+  template <typename T>
+  IGL_INLINE bool serializer(bool serialize,T& obj,std::string& objectName,std::vector<char>& buffer);
+
+  // User defined types have to either overload the function igl::serialization::serialize()
+  // and igl::serialization::deserialize() for their type (non-intrusive serialization):
+  //
+  // namespace igl { namespace serialization 
+  // {
+  //   IGL_INLINE void serialize(const UserType& obj,std::vector<char>& buffer) {
+  //     ::igl::serialize(obj.var,"var",buffer);
+  //   }
+  //     
+  //   IGL_INLINE void deserialize(UserType& obj,const std::vector<char>& buffer) {
+  //     ::igl::deserialize(obj.var,"var",buffer);
+  //   }
+  // }}
+  //
+  // or use this macro for convenience:
+  //
+  // SERIALIZE_TYPE(UserType,
+  //   SERIALIZE_MEMBER(var)
+  // )
+  //
+  // or to derive from the class Serializable and add their the members
+  // in InitSerialization like the following:
+  //
+  // class UserType : public igl::Serializable {
+  //
+  //   int var;
+  //
+  //   void InitSerialization() {
+  //     this->Add(var,"var");
+  //   }
+  // };
+
+  // Base interface for user defined types
+  struct SerializableBase
+  {
+    virtual void Serialize(std::vector<char>& buffer) const = 0;
+    virtual void Deserialize(const std::vector<char>& buffer) = 0;
+  };
+
+  // Convenient interface for user defined types
+  class Serializable: public SerializableBase
+  {
+  private:
+
+    template <typename T>
+    struct SerializationObject : public SerializableBase
+    {
+      bool Binary;
+      std::string Name;
+      std::unique_ptr<T> Object;
+
+      void Serialize(std::vector<char>& buffer) const override {
+        igl::serialize(*Object,Name,buffer);
+      }
+
+      void Deserialize(const std::vector<char>& buffer) override {
+        igl::deserialize(*Object,Name,buffer);
+      }
+    };
+
+    mutable bool initialized;
+    mutable std::vector<SerializableBase*> objects;
+
+  public:
+
+    // Override this function to add your member variables which should be serialized
+    IGL_INLINE virtual void InitSerialization() = 0;
+
+    // Following functions can be overridden to handle the specific events.
+    // Return false to prevent the de-/serialization of an object.
+    IGL_INLINE virtual bool PreSerialization() const;
+    IGL_INLINE virtual void PostSerialization() const;
+    IGL_INLINE virtual bool PreDeserialization();
+    IGL_INLINE virtual void PostDeserialization();
+
+    // Default implementation of SerializableBase interface
+    IGL_INLINE void Serialize(std::vector<char>& buffer) const override final;
+    IGL_INLINE void Deserialize(const std::vector<char>& buffer) override final;
+
+    // Default constructor, destructor, assignment and copy constructor
+    IGL_INLINE Serializable();
+    IGL_INLINE Serializable(const Serializable& obj);
+    IGL_INLINE ~Serializable();
+    IGL_INLINE Serializable& operator=(const Serializable& obj);
+
+    // Use this function to add your variables which should be serialized
+    template <typename T>
+    IGL_INLINE void Add(T& obj,std::string name,bool binary = false);
+  };
+
+  // structure for pointer handling
+  struct IndexedPointerBase
+  {
+    enum { BEGIN,END } Type;
+    size_t Index;
+  };
+  template<typename T>
+  struct IndexedPointer: public IndexedPointerBase
+  {
+    const T* Object;
+  };
+
+  // internal functions
+  namespace serialization
+  {
+    // compile time type checks
+    template <typename T>
+    struct is_stl_container { static const bool value = false; };
+    template <typename T1,typename T2>
+    struct is_stl_container<std::pair<T1,T2> > { static const bool value = true; };
+    template <typename T1,typename T2>
+    struct is_stl_container<std::vector<T1,T2> > { static const bool value = true; };
+    template <typename T>
+    struct is_stl_container<std::set<T> > { static const bool value = true; };
+    template <typename T1,typename T2>
+    struct is_stl_container<std::map<T1,T2> > { static const bool value = true; };
+
+    template <typename T>
+    struct is_eigen_type { static const bool value = false; };
+    template <typename T,int R,int C,int P,int MR,int MC>
+    struct is_eigen_type<Eigen::Matrix<T,R,C,P,MR,MC> > { static const bool value = true; };
+    template <typename T,int P,typename I>
+    struct is_eigen_type<Eigen::SparseMatrix<T,P,I> > { static const bool value = true; };
+
+    template <typename T>
+    struct is_smart_ptr { static const bool value = false; };
+    template <typename T>
+    struct is_smart_ptr<std::shared_ptr<T> > { static const bool value = true; };
+    template <typename T>
+    struct is_smart_ptr<std::unique_ptr<T> > { static const bool value = true; };
+    template <typename T>
+    struct is_smart_ptr<std::weak_ptr<T> > { static const bool value = true; };
+
+    template <typename T>
+    struct is_serializable {
+      static const bool value = std::is_fundamental<T>::value || std::is_same<std::string,T>::value || std::is_base_of<SerializableBase,T>::value
+        || is_stl_container<T>::value || is_eigen_type<T>::value || std::is_pointer<T>::value || serialization::is_smart_ptr<T>::value;
+    };
+
+    // non serializable types
+    template <typename T>
+    IGL_INLINE typename std::enable_if<!is_serializable<T>::value,size_t>::type getByteSize(const T& obj);
+    template <typename T>
+    IGL_INLINE typename std::enable_if<!is_serializable<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T>
+    IGL_INLINE typename std::enable_if<!is_serializable<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);
+
+    // fundamental types
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value,size_t>::type getByteSize(const T& obj);
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);
+
+    // std::string
+    IGL_INLINE size_t getByteSize(const std::string& obj);
+    IGL_INLINE void serialize(const std::string& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    IGL_INLINE void deserialize(std::string& obj,std::vector<char>::const_iterator& iter);
+
+    // SerializableBase
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_base_of<SerializableBase,T>::value,size_t>::type getByteSize(const T& obj);
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_base_of<SerializableBase,T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_base_of<SerializableBase,T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);    
+
+    // stl containers
+    // std::pair
+    template <typename T1,typename T2>
+    IGL_INLINE size_t getByteSize(const std::pair<T1,T2>& obj);
+    template <typename T1,typename T2>
+    IGL_INLINE void serialize(const std::pair<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T1,typename T2>
+    IGL_INLINE void deserialize(std::pair<T1,T2>& obj,std::vector<char>::const_iterator& iter);
+
+    // std::vector
+    template <typename T1,typename T2>
+    IGL_INLINE size_t getByteSize(const std::vector<T1,T2>& obj);
+    template <typename T1,typename T2>
+    IGL_INLINE void serialize(const std::vector<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T1,typename T2>
+    IGL_INLINE void deserialize(std::vector<T1,T2>& obj,std::vector<char>::const_iterator& iter);
+
+    // std::set
+    template <typename T>
+    IGL_INLINE size_t getByteSize(const std::set<T>& obj);
+    template <typename T>
+    IGL_INLINE void serialize(const std::set<T>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T>
+    IGL_INLINE void deserialize(std::set<T>& obj,std::vector<char>::const_iterator& iter);
+
+    // std::map
+    template <typename T1,typename T2>
+    IGL_INLINE size_t getByteSize(const std::map<T1,T2>& obj);
+    template <typename T1,typename T2>
+    IGL_INLINE void serialize(const std::map<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T1,typename T2>
+    IGL_INLINE void deserialize(std::map<T1,T2>& obj,std::vector<char>::const_iterator& iter);
+
+    // Eigen types
+    template<typename T,int R,int C,int P,int MR,int MC>
+    IGL_INLINE size_t getByteSize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj);
+    template<typename T,int R,int C,int P,int MR,int MC>
+    IGL_INLINE void serialize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template<typename T,int R,int C,int P,int MR,int MC>
+    IGL_INLINE void deserialize(Eigen::Matrix<T,R,C,P,MR,MC>& obj,std::vector<char>::const_iterator& iter);
+
+    template<typename T,int P,typename I>
+    IGL_INLINE size_t getByteSize(const Eigen::SparseMatrix<T,P,I>& obj);
+    template<typename T,int P,typename I>
+    IGL_INLINE void serialize(const Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template<typename T,int P,typename I>
+    IGL_INLINE void deserialize(Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>::const_iterator& iter);
+
+    // raw pointers
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_pointer<T>::value,size_t>::type getByteSize(const T& obj);
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);
+
+    // std::shared_ptr and std::unique_ptr
+    /*template <typename T>
+    IGL_INLINE typename std::enable_if<serialization::is_smart_ptr<T>::value,size_t>::type getByteSize(const T& obj);
+    template <typename T>
+    IGL_INLINE typename std::enable_if<serialization::is_smart_ptr<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <template<typename> class T0, typename T1>
+    IGL_INLINE typename std::enable_if<serialization::is_smart_ptr<T0<T1> >::value>::type deserialize(T0<T1>& obj,std::vector<char>::const_iterator& iter);
+
+    // std::weak_ptr
+    template <typename T>
+    IGL_INLINE size_t getByteSize(const std::weak_ptr<T>& obj);
+    template <typename T>
+    IGL_INLINE void serialize(const std::weak_ptr<T>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T>
+    IGL_INLINE void deserialize(std::weak_ptr<T>& obj,std::vector<char>::const_iterator& iter);*/
+
+    // functions to overload for non-intrusive serialization
+    template <typename T>
+    IGL_INLINE void serialize(const T& obj,std::vector<char>& buffer);
+    template <typename T>
+    IGL_INLINE void deserialize(T& obj,const std::vector<char>& buffer);
+
+    // helper functions
+    template <typename T>
+    IGL_INLINE void updateMemoryMap(T& obj,size_t size,std::map<std::uintptr_t,IndexedPointerBase*>& memoryMap);
+  }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+  #include "serialize.cpp"
+#endif
+
+#endif

+ 1 - 1
include/igl/slice.cpp

@@ -53,7 +53,7 @@ IGL_INLINE void igl::slice(
     CI[C(i)].push_back(i);
   }
   // Resize output
-  Eigen::DynamicSparseMatrix<T, Eigen::RowMajor> dyn_Y(ym,yn);
+  Eigen::SparseMatrix<T, Eigen::RowMajor> dyn_Y(ym,yn);
   // Take a guess at the number of nonzeros (this assumes uniform distribution
   // not banded or heavily diagonal)
   dyn_Y.reserve((X.nonZeros()/(X.rows()*X.cols())) * (ym*yn));

+ 1 - 1
include/igl/svd3x3/arap_dof.cpp

@@ -739,7 +739,7 @@ IGL_INLINE bool igl::arap_dof_update(
 #ifdef __SSE__ // fit_rotations_SSE will convert to float if necessary
       fit_rotations_SSE(S,R);
 #else
-      fit_rotations(S,R);
+      fit_rotations(S,false,R);
 #endif
     }
 

+ 1 - 0
include/igl/viewer/OpenGL_state.cpp

@@ -293,6 +293,7 @@ IGL_INLINE void igl::OpenGL_state::bind_mesh()
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_u, tex_v, 0, GL_RGB, GL_UNSIGNED_BYTE, tex.data());
   }
   glUniform1i(shader_mesh.uniform("tex"), 0);

+ 85 - 100
include/igl/viewer/Viewer.cpp

@@ -6,6 +6,8 @@
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 
+// TODO: save_scene()/load_scene()
+
 #include "Viewer.h"
 #include <igl/get_seconds.h>
 
@@ -27,9 +29,6 @@
 #   include <OpenGL/gl3.h>
 #   define __gl_h_ /* Prevent inclusion of the old gl.h */
 #else
-#   ifdef _WIN32
-#       include <windows.h>
-#   endif
 #   include <GL/gl.h>
 #endif
 
@@ -51,10 +50,6 @@
 #include <limits>
 #include <cassert>
 
-#ifdef ENABLE_XML_SERIALIZATION
-  #include "igl/xml/XMLSerializer.h"
-#endif
-
 #include <igl/readOBJ.h>
 #include <igl/readOFF.h>
 #include <igl/adjacency_list.h>
@@ -70,26 +65,27 @@
 #include <igl/unproject.h>
 #include <igl/viewer/TextRenderer.h>
 
+#ifdef ENABLE_SERIALIZATION
+#include <igl/serialize.h>
+#endif
+
 // Internal global variables used for glfw event handling
 static igl::Viewer * __viewer;
 static double highdpi = 1;
 static double scroll_x = 0;
 static double scroll_y = 0;
+static int global_KMod = 0;
 
 namespace {
-  #ifndef NO_TBAR
-  void TW_CALL copy_str(std::string& dst, const std::string& src)
+void TW_CALL copy_str(std::string& dst, const std::string& src)
 {
   dst = src;
 }
-#endif
 }
 
 static void glfw_mouse_press(GLFWwindow* window, int button, int action, int modifier)
 {
-  #ifndef NO_TBAR
   bool tw_used = TwEventMouseButtonGLFW(button, action);
-  #endif
   igl::Viewer::MouseButton mb;
 
   if (button == GLFW_MOUSE_BUTTON_1)
@@ -101,12 +97,10 @@ static void glfw_mouse_press(GLFWwindow* window, int button, int action, int mod
 
   if (action == GLFW_PRESS)
   {
-    #ifndef NO_TBAR
     if(!tw_used)
     {
       __viewer->mouse_down(mb,modifier);
     }
-    #endif
   } else
   {
     // Always call mouse_up on up
@@ -120,10 +114,7 @@ static void glfw_error_callback(int error, const char* description)
   fputs(description, stderr);
 }
 
-int global_KMod = 0;
-#ifndef NO_TBAR
-
-int TwEventKeyGLFW3(int glfwKey, int glfwAction)
+IGL_INLINE int TwEventKeyGLFW3(int glfwKey, int glfwAction)
 {
   int handled = 0;
 
@@ -264,21 +255,19 @@ int TwEventKeyGLFW3(int glfwKey, int glfwAction)
 
   return handled;
 }
-#endif
+
 static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int modifier)
 {
   if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
     glfwSetWindowShouldClose(window, GL_TRUE);
 
-    #ifndef NO_TBAR
-    if (!TwEventKeyGLFW3(key,action))
+  if (!TwEventKeyGLFW3(key,action))
   {
     if (action == GLFW_PRESS)
       __viewer->key_down(key, modifier);
     else
       __viewer->key_up(key, modifier);
   }
-  #endif
 }
 
 static void glfw_window_size(GLFWwindow* window, int width, int height)
@@ -288,7 +277,6 @@ static void glfw_window_size(GLFWwindow* window, int width, int height)
 
   __viewer->resize(w, h);
 
-#ifndef NO_TBAR
   TwWindowSize(w, h);
   const auto & bar = __viewer->bar;
   // Keep AntTweakBar on right side of screen and height == opengl height
@@ -304,18 +292,15 @@ static void glfw_window_size(GLFWwindow* window, int width, int height)
   size[1] = highdpi*(height-pos[1]-10);
   TwSetParam(bar, NULL, "position", TW_PARAM_INT32, 2, pos);
   TwSetParam(bar, NULL, "size", TW_PARAM_INT32, 2,size);
-#endif
 }
 
 static void glfw_mouse_move(GLFWwindow* window, double x, double y)
 {
-  #ifndef NO_TBAR
   if(!TwEventMousePosGLFW(x*highdpi,y*highdpi) || __viewer->down)
   {
     // Call if TwBar hasn't used or if down
     __viewer->mouse_move(x*highdpi, y*highdpi);
   }
-  #endif
 }
 
 static void glfw_mouse_scroll(GLFWwindow* window, double x, double y)
@@ -324,25 +309,20 @@ static void glfw_mouse_scroll(GLFWwindow* window, double x, double y)
   scroll_x += x;
   scroll_y += y;
 
-  #ifndef NO_TBAR
   if (!TwEventMouseWheelGLFW(scroll_y))
     __viewer->mouse_scroll(y);
-    #endif
 }
 
 static void glfw_char_callback(GLFWwindow* window, unsigned int c)
 {
-  #ifndef NO_TBAR
   if ((c & 0xff00)==0)
     TwKeyPressed(c, global_KMod);
-    #endif
 }
 
 namespace igl
 {
-  void Viewer::init()
+  IGL_INLINE void Viewer::init()
   {
-    #ifndef NO_TBAR
     // Create a tweak bar
     bar = TwNewBar("libIGL-Viewer");
     TwDefine(" libIGL-Viewer help='This is a simple 3D mesh viewer.' "); // Message added to the help bar->
@@ -352,7 +332,7 @@ namespace igl
 
     // ---------------------- LOADING ----------------------
 
-    #ifdef ENABLE_XML_SERIALIZATION
+    #ifdef ENABLE_SERIALIZATION
     TwAddButton(bar,"Load Scene", load_scene_cb,    this, "group='Workspace'");
     TwAddButton(bar,"Save Scene", save_scene_cb,    this, "group='Workspace'");
     #endif
@@ -426,7 +406,7 @@ namespace igl
                " group='Overlays'"
                " label='Show Faces Labels' key='CTRL+;' help='Toggle face"
                " indices'");
-#endif
+
     core.init();
 
     if (callback_init)
@@ -436,7 +416,7 @@ namespace igl
     init_plugins();
   }
 
-  Viewer::Viewer()
+  IGL_INLINE Viewer::Viewer()
   {
 
     // Temporary variables initialization
@@ -470,24 +450,24 @@ namespace igl
 
   }
 
-  void Viewer::init_plugins()
+  IGL_INLINE void Viewer::init_plugins()
   {
     // Init all plugins
     for (unsigned int i = 0; i<plugins.size(); ++i)
       plugins[i]->init(this);
   }
 
-  Viewer::~Viewer()
+  IGL_INLINE Viewer::~Viewer()
   {
   }
 
-  void Viewer::shutdown_plugins()
+  IGL_INLINE void Viewer::shutdown_plugins()
   {
     for (unsigned int i = 0; i<plugins.size(); ++i)
       plugins[i]->shutdown();
   }
 
-  bool Viewer::load_mesh_from_file(const char* mesh_file_name)
+  IGL_INLINE bool Viewer::load_mesh_from_file(const char* mesh_file_name)
   {
     std::string mesh_file_name_string = std::string(mesh_file_name);
 
@@ -513,10 +493,11 @@ namespace igl
 
     if (extension == "off" || extension =="OFF")
     {
-      if (!igl::readOFF(mesh_file_name_string, data.V, data.F))
-      {
+      Eigen::MatrixXd V;
+      Eigen::MatrixXi F;
+      if (!igl::readOFF(mesh_file_name_string, V, F))
         return false;
-      }
+      data.set_mesh(V,F);
     }
     else if (extension == "obj" || extension =="OBJ")
     {
@@ -525,11 +506,15 @@ namespace igl
 
       Eigen::MatrixXd UV_V;
       Eigen::MatrixXi UV_F;
+      Eigen::MatrixXd V;
+      Eigen::MatrixXi F;
 
-      if (!(igl::readOBJ(mesh_file_name_string, data.V, data.F, corner_normals, fNormIndices, UV_V, UV_F)))
-      {
+      if (!(igl::readOBJ(mesh_file_name_string, V, F, corner_normals, fNormIndices, UV_V, UV_F)))
         return false;
-      }
+
+      data.set_mesh(V,F);
+      data.set_uv(UV_V,UV_F);
+
     }
     else
     {
@@ -554,7 +539,7 @@ namespace igl
     return true;
   }
 
-  bool Viewer::save_mesh_to_file(const char* mesh_file_name)
+  IGL_INLINE bool Viewer::save_mesh_to_file(const char* mesh_file_name)
   {
     std::string mesh_file_name_string(mesh_file_name);
 
@@ -595,7 +580,7 @@ namespace igl
     return true;
   }
 
-  bool Viewer::key_down(unsigned char key, int modifiers)
+  IGL_INLINE bool Viewer::key_down(int key,int modifiers)
   {
     if (callback_key_down)
       if (callback_key_down(*this,key,modifiers))
@@ -605,27 +590,29 @@ namespace igl
       if (plugins[i]->key_down(key, modifiers))
         return true;
 
-    if (key == 'S')
+    char k = key;
+
+    if(key == GLFW_KEY_S && modifiers == GLFW_MOD_SHIFT)
       mouse_scroll(1);
 
-    if (key == 'A')
+    if(key == GLFW_KEY_A && modifiers == GLFW_MOD_SHIFT)
       mouse_scroll(-1);
 
     // Why aren't these handled via AntTweakBar?
-    if (key == 'z') // Don't use 'Z' because that clobbers snap_to_canonical_view_quat
+    if(key == GLFW_KEY_Z) // Don't use 'Z' because that clobbers snap_to_canonical_view_quat
       core.trackball_angle << 0.0f, 0.0f, 0.0f, 1.0f;
 
-    if (key == 'y')
+    if(key == GLFW_KEY_Y)
       core.trackball_angle << -sqrt(2.0f)/2.0f, 0.0f, 0.0f, sqrt(2.0f)/2.0f;
 
-    if (key == 'x')
+    if(key == GLFW_KEY_X)
       core.trackball_angle << -0.5f, -0.5f, -0.5f, 0.5f;
 
 
     return false;
   }
 
-  bool Viewer::key_up(unsigned char key, int modifiers)
+  IGL_INLINE bool Viewer::key_up(int key,int modifiers)
   {
     if (callback_key_up)
       if (callback_key_up(*this,key,modifiers))
@@ -638,7 +625,7 @@ namespace igl
     return false;
   }
 
-  bool Viewer::mouse_down(MouseButton button, int modifier)
+  IGL_INLINE bool Viewer::mouse_down(MouseButton button,int modifier)
   {
     if (callback_mouse_down)
       if (callback_mouse_down(*this,button,modifier))
@@ -686,7 +673,7 @@ namespace igl
     return true;
   }
 
-  bool Viewer::mouse_up(MouseButton button, int modifier)
+  IGL_INLINE bool Viewer::mouse_up(MouseButton button,int modifier)
   {
     down = false;
 
@@ -703,7 +690,7 @@ namespace igl
     return true;
   }
 
-  bool Viewer::mouse_move(int mouse_x, int mouse_y)
+  IGL_INLINE bool Viewer::mouse_move(int mouse_x,int mouse_y)
   {
     if(hack_never_moved)
     {
@@ -770,7 +757,7 @@ namespace igl
     return true;
   }
 
-  bool Viewer::mouse_scroll(float delta_y)
+  IGL_INLINE bool Viewer::mouse_scroll(float delta_y)
   {
     scroll_position += delta_y;
 
@@ -792,7 +779,7 @@ namespace igl
     return true;
   }
 
-  void Viewer::draw()
+  IGL_INLINE void Viewer::draw()
   {
     using namespace std;
     using namespace Eigen;
@@ -817,104 +804,98 @@ namespace igl
       if (plugins[i]->post_draw())
         break;
 
-        #ifndef NO_TBAR
-        TwDraw();
-        #endif
+    TwDraw();
   }
 
-  bool Viewer::save_scene()
+  IGL_INLINE bool Viewer::save_scene()
   {
-    #ifdef ENABLE_XML_SERIALIZATION
-    string fname = igl::file_dialog_save();
+    std::string fname = igl::file_dialog_save();
     if (fname.length() == 0)
       return false;
 
-    ::igl::XMLSerializer serializer("Viewer");
-    serializer.Add(data,"Data");
-    serializer.Add(options,"Options");
+#ifdef ENABLE_SERIALIZATION
 
-    if (plugin_manager)
-      for (unsigned int i = 0; i <plugin_manager->plugin_list.size(); ++i)
-        serializer.Add(*(plugin_manager->plugin_list[i]),plugin_manager->plugin_list[i]->plugin_name);
+    igl::serialize(core,"Core",fname.c_str(),true);
+    igl::serialize(data,"Data",fname.c_str());
 
-    serializer.Save(fname.c_str(),true);
+    for(unsigned int i = 0; i <plugins.size(); ++i)
+      igl::serialize(*plugins[i],plugins[i]->plugin_name,fname.c_str());
+
+#endif
 
-    #endif
     return true;
   }
 
-  bool Viewer::load_scene()
+  IGL_INLINE bool Viewer::load_scene()
   {
-    #ifdef ENABLE_XML_SERIALIZATION
-    string fname = igl::file_dialog_open();
+    std::string fname = igl::file_dialog_open();
     if (fname.length() == 0)
       return false;
 
-    ::igl::XMLSerializer serializer("Viewer");
-    serializer.Add(data,"Data");
-    serializer.Add(options,"Options");
+#ifdef ENABLE_SERIALIZATION
 
-    if (plugin_manager)
-      for (unsigned int i = 0; i <plugin_manager->plugin_list.size(); ++i)
-        serializer.Add(*(plugin_manager->plugin_list[i]),plugin_manager->plugin_list[i]->plugin_name);
+    igl::deserialize(core,"Core",fname.c_str());
+    igl::deserialize(data,"Data",fname.c_str());
 
-    serializer.Load(fname.c_str());
+    for(unsigned int i = 0; i <plugins.size(); ++i)
+      igl::deserialize(*plugins[i],plugins[i]->plugin_name,fname.c_str());
+
+#endif
 
-    #endif
     return true;
   }
 
-  void Viewer::resize(int w, int h)
+  IGL_INLINE void Viewer::resize(int w,int h)
   {
     core.viewport = Eigen::Vector4f(0,0,w,h);
   }
-  #ifndef NO_TBAR
-  void TW_CALL Viewer::snap_to_canonical_quaternion_cb(void *clientData)
+
+  IGL_INLINE void TW_CALL Viewer::snap_to_canonical_quaternion_cb(void *clientData)
   {
     Eigen::Vector4f snapq = static_cast<Viewer *>(clientData)->core.trackball_angle;
     igl::snap_to_canonical_view_quat<float>(snapq.data(),1,static_cast<Viewer *>(clientData)->core.trackball_angle.data());
   }
-  void TW_CALL Viewer::align_camera_center_cb(void *clientData)
+  IGL_INLINE void TW_CALL Viewer::align_camera_center_cb(void *clientData)
   {
     static_cast<Viewer *>(clientData)->core.align_camera_center(
       static_cast<Viewer *>(clientData)->data.V,
       static_cast<Viewer *>(clientData)->data.F);
   }
 
-  void TW_CALL Viewer::save_scene_cb(void *clientData)
+  IGL_INLINE void TW_CALL Viewer::save_scene_cb(void *clientData)
   {
     static_cast<Viewer *>(clientData)->save_scene();
   }
 
-  void TW_CALL Viewer::load_scene_cb(void *clientData)
+  IGL_INLINE void TW_CALL Viewer::load_scene_cb(void *clientData)
   {
     static_cast<Viewer *>(clientData)->load_scene();
   }
 
-  void TW_CALL Viewer::set_invert_normals_cb(const void *param, void *clientData)
+  IGL_INLINE void TW_CALL Viewer::set_invert_normals_cb(const void *param,void *clientData)
   {
     Viewer *viewer = static_cast<Viewer *>(clientData);
     viewer->data.dirty |= ViewerData::DIRTY_NORMAL;
     viewer->core.invert_normals = *((bool *) param);
   }
 
-  void TW_CALL Viewer::get_invert_normals_cb(void *param, void *clientData)
+  IGL_INLINE void TW_CALL Viewer::get_invert_normals_cb(void *param,void *clientData)
   {
     *((bool *) param) = static_cast<Viewer *>(clientData)->core.invert_normals;
   }
 
-  void TW_CALL Viewer::set_face_based_cb(const void *param, void *clientData)
+  IGL_INLINE void TW_CALL Viewer::set_face_based_cb(const void *param,void *clientData)
   {
     Viewer *viewer = static_cast<Viewer *>(clientData);
     viewer->data.set_face_based(*((bool *) param));
   }
 
-  void TW_CALL Viewer::get_face_based_cb(void *param, void *clientData)
+  IGL_INLINE void TW_CALL Viewer::get_face_based_cb(void *param,void *clientData)
   {
     *((bool *) param) = static_cast<Viewer *>(clientData)->data.face_based;
   }
 
-  void TW_CALL Viewer::open_dialog_mesh(void *clientData)
+  IGL_INLINE void TW_CALL Viewer::open_dialog_mesh(void *clientData)
   {
     std::string fname = igl::file_dialog_open();
 
@@ -923,8 +904,8 @@ namespace igl
 
     static_cast<Viewer *>(clientData)->load_mesh_from_file(fname.c_str());
   }
-#endif
-  int Viewer::launch(std::string filename)
+
+  IGL_INLINE int Viewer::launch(std::string filename)
   {
     GLFWwindow* window;
 
@@ -932,7 +913,7 @@ namespace igl
     if (!glfwInit())
       return EXIT_FAILURE;
 
-    glfwWindowHint(GLFW_SAMPLES, 16);
+    glfwWindowHint(GLFW_SAMPLES, 4);
     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
     #ifdef __APPLE__
@@ -972,17 +953,21 @@ namespace igl
     glfwSetInputMode(window,GLFW_CURSOR,GLFW_CURSOR_NORMAL);
 
     // Initialize AntTweakBar
-    #ifndef NO_TBAR
     TwInit(TW_OPENGL_CORE, NULL);
     TwCopyStdStringToClientFunc(static_cast<TwCopyStdStringToClient>(::copy_str));
-#endif
+
 
     // Initialize IGL viewer
     init();
     __viewer = this;
 
     // Register callbacks
-    glfwSetKeyCallback(window, glfw_key_callback); glfwSetCursorPosCallback(window,glfw_mouse_move); glfwSetWindowSizeCallback(window,glfw_window_size); glfwSetMouseButtonCallback(window,glfw_mouse_press); glfwSetScrollCallback(window,glfw_mouse_scroll); glfwSetCharCallback(window, glfw_char_callback);
+    glfwSetKeyCallback(window, glfw_key_callback);
+    glfwSetCursorPosCallback(window,glfw_mouse_move);
+    glfwSetWindowSizeCallback(window,glfw_window_size);
+    glfwSetMouseButtonCallback(window,glfw_mouse_press);
+    glfwSetScrollCallback(window,glfw_mouse_scroll);
+    glfwSetCharCallback(window, glfw_char_callback);
 
     // Handle retina displays (windows and mac)
     int width, height;

+ 18 - 23
include/igl/viewer/Viewer.h

@@ -26,18 +26,13 @@
 #define IGL_MOD_ALT             0x0004
 #define IGL_MOD_SUPER           0x0008
 
-#ifdef ENABLE_XML_SERIALIZATION
-  #include <igl/xml/XMLSerializer.h>
-  #include <igl/xml/XMLSerialization.h>
-#endif
-
 #include <Eigen/Core>
 #include <Eigen/Geometry>
 #include <igl/viewer/OpenGL_shader.h>
-#include <igl/viewer/ViewerData.h>
 #include <igl/viewer/OpenGL_state.h>
-#include <igl/viewer/ViewerPlugin.h>
 #include <igl/viewer/ViewerCore.h>
+#include <igl/viewer/ViewerData.h>
+#include <igl/viewer/ViewerPlugin.h>
 
 namespace igl
 {
@@ -46,8 +41,8 @@ namespace igl
   {
   public:
 
-    int launch(std::string filename = "");
-    void init();
+    IGL_INLINE int launch(std::string filename = "");
+    IGL_INLINE void init();
 
     // Stores all the viewing options
     igl::ViewerCore core;
@@ -60,8 +55,8 @@ namespace igl
 
     // List of registered plugins
     std::vector<ViewerPlugin*> plugins;
-    void init_plugins();
-    void shutdown_plugins();
+    IGL_INLINE void init_plugins();
+    IGL_INLINE void shutdown_plugins();
 
     // Temporary data stored when the mouse button is pressed
     Eigen::Vector4f down_rotation;
@@ -91,28 +86,28 @@ namespace igl
     ~Viewer();
 
     // Mesh IO
-    bool load_mesh_from_file(const char* mesh_file_name);
-    bool save_mesh_to_file(const char* mesh_file_name);
+    IGL_INLINE bool load_mesh_from_file(const char* mesh_file_name);
+    IGL_INLINE bool save_mesh_to_file(const char* mesh_file_name);
 
     // Callbacks
-    bool key_down(unsigned char key, int modifier);
-    bool key_up(unsigned char key, int modifier);
+    IGL_INLINE bool key_down(int key,int modifier);
+    IGL_INLINE bool key_up(int key,int modifier);
 
-    bool mouse_down(MouseButton button, int modifier);
-    bool mouse_up(MouseButton button, int modifier);
+    IGL_INLINE bool mouse_down(MouseButton button,int modifier);
+    IGL_INLINE bool mouse_up(MouseButton button,int modifier);
 
-    bool mouse_move(int mouse_x, int mouse_y);
-    bool mouse_scroll(float delta_y);
+    IGL_INLINE bool mouse_move(int mouse_x,int mouse_y);
+    IGL_INLINE bool mouse_scroll(float delta_y);
 
     // Scene IO
-    bool load_scene();
-    bool save_scene();
+    IGL_INLINE bool load_scene();
+    IGL_INLINE bool save_scene();
 
     // Draw everything
-    void draw();
+    IGL_INLINE void draw();
 
     // OpenGL context resize
-    void resize(int w, int h);
+    IGL_INLINE void resize(int w,int h);
 
 
     // C-style callbacks

+ 71 - 47
include/igl/viewer/ViewerCore.cpp

@@ -13,7 +13,7 @@
 #include <iostream>
 
 
-Eigen::Matrix4f lookAt (
+IGL_INLINE Eigen::Matrix4f lookAt (
                         const Eigen::Vector3f& eye,
                         const Eigen::Vector3f& center,
                         const Eigen::Vector3f& up)
@@ -38,7 +38,7 @@ Eigen::Matrix4f lookAt (
   return Result;
 }
 
-Eigen::Matrix4f ortho (
+IGL_INLINE Eigen::Matrix4f ortho(
                        const float left,
                        const float right,
                        const float bottom,
@@ -57,7 +57,7 @@ Eigen::Matrix4f ortho (
   return Result;
 }
 
-Eigen::Matrix4f frustum (
+IGL_INLINE Eigen::Matrix4f frustum(
                          const float left,
                          const float right,
                          const float bottom,
@@ -76,7 +76,7 @@ Eigen::Matrix4f frustum (
   return Result;
 }
 
-Eigen::Matrix4f scale (const Eigen::Matrix4f& m,
+IGL_INLINE Eigen::Matrix4f scale(const Eigen::Matrix4f& m,
                        const Eigen::Vector3f& v)
 {
   Eigen::Matrix4f Result;
@@ -87,7 +87,7 @@ Eigen::Matrix4f scale (const Eigen::Matrix4f& m,
   return Result;
 }
 
-Eigen::Matrix4f translate(
+IGL_INLINE Eigen::Matrix4f translate(
                           const Eigen::Matrix4f& m,
                           const Eigen::Vector3f& v)
 {
@@ -96,53 +96,80 @@ Eigen::Matrix4f translate(
   return Result;
 }
 
+#ifdef ENABLE_SERIALIZATION
+#include <igl/serialize.h>
+namespace igl {
+  namespace serialization {
 
+    IGL_INLINE void serialization(bool s,ViewerCore& obj,std::vector<char>& buffer)
+    {
+      SERIALIZE_MEMBER(shininess);
+
+      SERIALIZE_MEMBER(background_color);
+      SERIALIZE_MEMBER(line_color);
+
+      SERIALIZE_MEMBER(light_position);
+      SERIALIZE_MEMBER(lighting_factor);
+
+      SERIALIZE_MEMBER(trackball_angle);
+
+      SERIALIZE_MEMBER(model_zoom);
+      SERIALIZE_MEMBER(model_translation);
+
+      SERIALIZE_MEMBER(model_zoom_uv);
+      SERIALIZE_MEMBER(model_translation_uv);
+
+      SERIALIZE_MEMBER(object_scale);
+
+      SERIALIZE_MEMBER(camera_zoom);
+      SERIALIZE_MEMBER(orthographic);
+      SERIALIZE_MEMBER(camera_view_angle);
+      SERIALIZE_MEMBER(camera_dnear);
+      SERIALIZE_MEMBER(camera_dfar);
+      SERIALIZE_MEMBER(camera_eye);
+      SERIALIZE_MEMBER(camera_center);
+      SERIALIZE_MEMBER(camera_up);
+
+      SERIALIZE_MEMBER(show_faces);
+      SERIALIZE_MEMBER(show_lines);
+      SERIALIZE_MEMBER(invert_normals);
+      SERIALIZE_MEMBER(show_overlay);
+      SERIALIZE_MEMBER(show_overlay_depth);
+      SERIALIZE_MEMBER(show_vertid);
+      SERIALIZE_MEMBER(show_faceid);
+      SERIALIZE_MEMBER(show_texture);
+
+      SERIALIZE_MEMBER(point_size);
+      SERIALIZE_MEMBER(line_width);
+      SERIALIZE_MEMBER(is_animating);
+      SERIALIZE_MEMBER(animation_max_fps);
+
+      SERIALIZE_MEMBER(viewport);
+      SERIALIZE_MEMBER(view);
+      SERIALIZE_MEMBER(model);
+      SERIALIZE_MEMBER(proj);
+    }
 
-void igl::ViewerCore::InitSerialization()
-{
-  #ifdef ENABLE_XML_SERIALIZATION
-  xmlSerializer->Add(shininess, "shininess");
-  xmlSerializer->Add(background_color, "background_color");
-  xmlSerializer->Add(line_color, "line_color");
-  xmlSerializer->Add(light_position, "light_position");
-  xmlSerializer->Add(lighting_factor, "lighting_factor");
-  xmlSerializer->Add(trackball_angle, "trackball_angle");
-  xmlSerializer->Add(model_zoom, "model_zoom");
-  xmlSerializer->Add(model_translation, "model_translation");
-  xmlSerializer->Add(model_zoom_uv, "model_zoom_uv");
-  xmlSerializer->Add(model_translation_uv, "model_translation_uv");
-  xmlSerializer->Add(camera_zoom, "camera_zoom");
-  xmlSerializer->Add(orthographic, "orthographic");
-  xmlSerializer->Add(camera_eye, "camera_eye");
-  xmlSerializer->Add(camera_up, "camera_up");
-  xmlSerializer->Add(camera_center, "camera_center");
-  xmlSerializer->Add(camera_view_angle, "camera_view_angle");
-  xmlSerializer->Add(camera_dnear, "camera_dnear");
-  xmlSerializer->Add(camera_dfar, "camera_dfar");
-  xmlSerializer->Add(show_overlay, "show_overlay");
-  xmlSerializer->Add(show_overlay_depth, "show_overlay_depth");
-  xmlSerializer->Add(show_texture, "show_texture");
-  xmlSerializer->Add(show_faces, "show_faces");
-  xmlSerializer->Add(show_lines, "show_lines");
-  xmlSerializer->Add(show_vertid, "show_vertid");
-  xmlSerializer->Add(show_faceid, "show_faceid");
-  xmlSerializer->Add(point_size, "point_size");
-  xmlSerializer->Add(line_width, "line_width");
-  xmlSerializer->Add(invert_normals, "invert_normals");
-  xmlSerializer->Add(face_based, "face_based");
-  xmlSerializer->Add(face_based, "object_scale");
-  xmlSerializer->Add(viewport, "viewport");
-  xmlSerializer->Add(view, "view");
-  xmlSerializer->Add(model, "model");
-  xmlSerializer->Add(proj, "proj");
-
-  #endif
+    IGL_INLINE void serialize(const ViewerCore& obj,std::vector<char>& buffer)
+    {
+      serialization(true,const_cast<ViewerCore&>(obj),buffer);
+    }
+
+    IGL_INLINE void deserialize(ViewerCore& obj,const std::vector<char>& buffer)
+    {
+      serialization(false,obj,const_cast<std::vector<char>&>(buffer));
+    }
+  }
 }
+#endif
 
 IGL_INLINE void igl::ViewerCore::align_camera_center(
   const Eigen::MatrixXd& V,
   const Eigen::MatrixXi& F)
 {
+  if(V.rows() == 0)
+    return;
+
   get_scale_and_shift_to_fit_mesh(V,F,model_zoom,model_translation);
   // Rather than crash on empty mesh...
   if(V.size() > 0)
@@ -362,9 +389,6 @@ IGL_INLINE void igl::ViewerCore::draw(ViewerData& data, OpenGL_state& opengl)
 }
 
 IGL_INLINE igl::ViewerCore::ViewerCore()
-#ifdef ENABLE_XML_SERIALIZATION
-: XMLSerialization("Core")
-#endif
 {
   // Default shininess
   shininess = 35.0f;

+ 0 - 3
include/igl/viewer/ViewerCore.h

@@ -21,9 +21,6 @@ namespace igl
 // TODO: write documentation
 
 class ViewerCore
-#ifdef ENABLE_XML_SERIALIZATION
-: public ::igl::XMLSerialization
-#endif
 {
 public:
   IGL_INLINE ViewerCore();

+ 52 - 36
include/igl/viewer/ViewerData.cpp

@@ -12,46 +12,62 @@
 #include <igl/per_vertex_normals.h>
 #include <iostream>
 
-IGL_INLINE igl::ViewerData::ViewerData()
-#ifdef ENABLE_XML_SERIALIZATION
-: XMLSerialization("Data"), dirty(DIRTY_ALL)
+#ifdef ENABLE_SERIALIZATION
+#include <igl/serialize.h>
+namespace igl {
+  namespace serialization {
+
+    IGL_INLINE void serialization(bool s,ViewerData& obj,std::vector<char>& buffer)
+    {
+      SERIALIZE_MEMBER(V);
+      SERIALIZE_MEMBER(F);
+
+      SERIALIZE_MEMBER(F_normals);
+      SERIALIZE_MEMBER(F_material_ambient);
+      SERIALIZE_MEMBER(F_material_diffuse);
+      SERIALIZE_MEMBER(F_material_specular);
+
+      SERIALIZE_MEMBER(V_normals);
+      SERIALIZE_MEMBER(V_material_ambient);
+      SERIALIZE_MEMBER(V_material_diffuse);
+      SERIALIZE_MEMBER(V_material_specular);
+
+      SERIALIZE_MEMBER(V_uv);
+      SERIALIZE_MEMBER(F_uv);
+
+      SERIALIZE_MEMBER(texture_R);
+      SERIALIZE_MEMBER(texture_G);
+      SERIALIZE_MEMBER(texture_B);
+
+      SERIALIZE_MEMBER(lines);
+      SERIALIZE_MEMBER(points);
+
+      SERIALIZE_MEMBER(labels_positions);
+      SERIALIZE_MEMBER(labels_strings);
+
+      SERIALIZE_MEMBER(face_based);
+    }
+
+    IGL_INLINE void serialize(const ViewerData& obj,std::vector<char>& buffer)
+    {
+      serialization(true,const_cast<ViewerData&>(obj),buffer);
+    }
+
+    IGL_INLINE void deserialize(ViewerData& obj,const std::vector<char>& buffer)
+    {
+      serialization(false,obj,const_cast<std::vector<char>&>(buffer));
+      obj.dirty = ViewerData::DIRTY_ALL;
+    }
+  }
+}
 #endif
+
+IGL_INLINE igl::ViewerData::ViewerData()
+: dirty(DIRTY_ALL)
 {
   clear();
 };
 
-IGL_INLINE void igl::ViewerData::InitSerialization()
-{
-  #ifdef ENABLE_XML_SERIALIZATION
-  xmlSerializer->Add(V,"V");
-  xmlSerializer->Add(F,"F");
-  xmlSerializer->Add(F_normals,"F_normals");
-
-  xmlSerializer->Add(F_material_ambient,"F_material_ambient");
-  xmlSerializer->Add(F_material_diffuse,"F_material_diffuse");
-  xmlSerializer->Add(F_material_specular,"F_material_specular");
-
-  xmlSerializer->Add(V_normals,"V_normals");
-  xmlSerializer->Add(V_material_ambient,"V_material_ambient");
-  xmlSerializer->Add(V_material_diffuse,"V_material_diffuse");
-  xmlSerializer->Add(V_material_specular,"V_material_specular");
-
-  xmlSerializer->Add(V_uv,"V_uv");
-  xmlSerializer->Add(F_uv,"F_uv");
-  xmlSerializer->Add(texture_R,"texture_R");
-  xmlSerializer->Add(texture_G,"texture_G");
-  xmlSerializer->Add(texture_B,"texture_B");
-  xmlSerializer->Add(lines,"lines");
-  xmlSerializer->Add(points,"points");
-
-  xmlSerializer->Add(labels_positions,"labels_positions");
-  xmlSerializer->Add(labels_strings,"labels_strings");
-
-  xmlSerializer->Add(face_based,"face_based");
-
-  #endif
-}
-
 IGL_INLINE void igl::ViewerData::set_face_based(bool newvalue)
 {
   if (face_based != newvalue)
@@ -195,7 +211,7 @@ IGL_INLINE void igl::ViewerData::set_uv(const Eigen::MatrixXd& UV)
 IGL_INLINE void igl::ViewerData::set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F)
 {
   set_face_based(true);
-  V_uv = UV_V;
+  V_uv = UV_V.block(0,0,UV_V.rows(),2);
   F_uv = UV_F;
   dirty |= DIRTY_UV;
 }

+ 0 - 8
include/igl/viewer/ViewerData.h

@@ -15,13 +15,9 @@
 namespace igl
 {
 
-// Store the data visualized by ViewerCore
 // TODO: write documentation
 
 class ViewerData
-#ifdef ENABLE_XML_SERIALIZATION
-: public ::igl::XMLSerialization
-#endif
 {
 public:
   ViewerData();
@@ -96,9 +92,6 @@ public:
   // Generates a default grid texture
   IGL_INLINE void grid_texture();
 
-  // Serialization code
-  IGL_INLINE void InitSerialization();
-
   Eigen::MatrixXd V; // Vertices of the current mesh (#V x 3)
   Eigen::MatrixXi F; // Faces of the mesh (#F x 3)
 
@@ -151,7 +144,6 @@ public:
   /*********************************/
 };
 
-
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 36 - 14
include/igl/viewer/ViewerPlugin.h

@@ -6,16 +6,17 @@
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 
+// TODO:
+// * create plugins/skeleton.h
+// * pass time in draw function
+// * remove Preview3D from comments
+// * clean comments
+
 #ifndef IGL_VIEWER_PLUGIN_H
 #define IGL_VIEWER_PLUGIN_H
 #include <string>
 #include <igl/igl_inline.h>
 
-#ifdef ENABLE_XML_SERIALIZATION
-  #include <igl/xml/XMLSerializer.h>
-  #include <igl/xml/XMLSerialization.h>
-#endif
-
 namespace igl
 {
 
@@ -33,15 +34,9 @@ namespace igl
 class Viewer;
 
 class ViewerPlugin
-#ifdef ENABLE_XML_SERIALIZATION
-: public ::igl::XMLSerialization
-#endif
 {
 public:
   IGL_INLINE ViewerPlugin()
-  #ifdef ENABLE_XML_SERIALIZATION
-  : XMLSerialization("dummy")
-  #endif
   {plugin_name = "dummy";}
 
   virtual ~ViewerPlugin(){}
@@ -69,7 +64,19 @@ public:
     return false;
   }
 
-  // Runs immediately after a new mesh had been loaded.
+  // This function is called when the scene is serialized
+  IGL_INLINE virtual bool serialize(std::vector<char>& buffer) const
+  {
+    return false;
+  }
+
+  // This function is called when the scene is deserialized
+  IGL_INLINE virtual bool deserialize(const std::vector<char>& buffer)
+  {
+    return false;
+  }
+
+  // Runs immediately after a new mesh has been loaded.
   IGL_INLINE virtual bool post_load()
   {
     return false;
@@ -119,14 +126,14 @@ public:
 
   // This function is called when a keyboard key is pressed
   // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
-  IGL_INLINE virtual bool key_down(unsigned char key, int modifiers)
+  IGL_INLINE virtual bool key_down(int key, int modifiers)
   {
     return false;
   }
 
   // This function is called when a keyboard key is release
   // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
-  IGL_INLINE virtual bool key_up(unsigned char key, int modifiers)
+  IGL_INLINE virtual bool key_up(int key, int modifiers)
   {
     return false;
   }
@@ -137,6 +144,21 @@ protected:
   Viewer *viewer;
 };
 
+#ifdef ENABLE_SERIALIZATION
+namespace serialization
+{
+  IGL_INLINE void serialize(const ViewerPlugin& obj,std::vector<char>& buffer)
+  {
+    obj.serialize(buffer);
+  }
+
+  IGL_INLINE void deserialize(ViewerPlugin& obj,const std::vector<char>& buffer)
+  {
+    obj.deserialize(buffer);
+  }
+}
+#endif
+
 }
 
 #endif

+ 13 - 9
include/igl/xml/ReAntTweakBarXMLSerialization.h

@@ -8,7 +8,7 @@
 #ifndef IGL_REANTTWEAKBAR_XML_SERIALIZATION_H
 #define IGL_REANTTWEAKBAR_XML_SERIALIZATION_H
 #include "../igl_inline.h"
-#include "XMLSerializer.h"
+#include "serialize_xml.h"
 
 #undef IGL_HEADER_ONLY
 #include <igl/ReAntTweakBar.h>
@@ -44,7 +44,8 @@ namespace igl
       for(std::vector< ::igl::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
       {
         std::string val = bar->get_value_as_string(it->var,it->type);
-        ::igl::XMLSerializer::SaveObject(val,it->name,name,file_name,false);
+        //::igl::XMLSerializer::SaveObject(val,it->name,name,file_name,false);
+        ::igl::serialize_xml(val,it->name,file_name,false,false);
       }
       
       char var[REANTTWEAKBAR_MAX_CB_VAR_SIZE];
@@ -62,13 +63,14 @@ namespace igl
         getCallback(var,clientData);
         
         std::string val = bar->get_value_as_string(var,type);
-        ::igl::XMLSerializer::SaveObject(val,it->name,name,file_name,false);
+        //::igl::XMLSerializer::SaveObject(val,it->name,name,file_name,false);
+        ::igl::serialize_xml(val,it->name,file_name,false,false);
       }
       
       return true;
     }
     
-    IGL_INLINE bool save_ReAntTweakBar(::igl::ReTwBar* bar, tinyxml2::XMLDocument* doc)
+    /*IGL_INLINE bool save_ReAntTweakBar(::igl::ReTwBar* bar, tinyxml2::XMLDocument* doc)
     {
       std::vector<char**> buffer;
       
@@ -121,7 +123,7 @@ namespace igl
       delete s;
       
       return true;
-    }
+    }*/
     
     IGL_INLINE bool load_ReAntTweakBar(::igl::ReTwBar* bar, const char *file_name)
     {
@@ -136,7 +138,8 @@ namespace igl
       for(std::vector< ::igl::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
       {
         char* val;
-        ::igl::XMLSerializer::LoadObject(val,it->name,name,file_name);
+        //::igl::XMLSerializer::LoadObject(val,it->name,name,file_name);
+        ::igl::deserialize_xml(val,it->name,file_name);
         sscanf(val,"%s %[^\n]",type_str,value_str);
         
         if(!bar->type_from_string(type_str,type))
@@ -153,7 +156,8 @@ namespace igl
       for(std::vector< ::igl::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
       {
         char* val;
-        ::igl::XMLSerializer::LoadObject(val,it->name,name,file_name);
+        //::igl::XMLSerializer::LoadObject(val,it->name,name,file_name);
+        ::igl::deserialize_xml(val,it->name,file_name);
         sscanf(val,"%s %[^\n]",type_str,value_str);
         
         if(!bar->type_from_string(type_str,type))
@@ -169,7 +173,7 @@ namespace igl
       return true;
     }
     
-    IGL_INLINE bool load_ReAntTweakBar(::igl::ReTwBar* bar, tinyxml2::XMLDocument* doc)
+    /*IGL_INLINE bool load_ReAntTweakBar(::igl::ReTwBar* bar, tinyxml2::XMLDocument* doc)
     {
       std::map<std::string,char*> variables;
       std::map<std::string,char*> cbVariables;
@@ -251,7 +255,7 @@ namespace igl
       delete s;
       
       return true;
-    }
+    }*/
     
 //  }
 }

+ 0 - 51
include/igl/xml/XMLSerializable.h

@@ -1,51 +0,0 @@
-// This file is part of libigl, a simple c++ geometry processing library.
-// 
-// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
-// obtain one at http://mozilla.org/MPL/2.0/.
-/* ---------------------------------------------------------------------------
- // XMLSerializable.h
- // Author: Christian Schüller <schuellchr@gmail.com>
- ------------------------------------------------------------------------------
- Inherit from this abstract class to have full control over the serialization
- of your user defined class.
- ----------------------------------------------------------------------------*/
-#ifndef IGL_XML_SERIALIZABLE_H
-#define IGL_XML_SERIALIZABLE_H
-
-#include <iostream>
-#include <tinyxml2.h>
-
-namespace igl
-{
-
-  class XMLSerializable
-  {
-  public:
-    /**
-    * Default name of serializable object
-    */
-    std::string Name;
-      
-    /**
-      * This function gets called if the objects were not found during deserialization.
-      * Initialize your objects as you like.
-      */
-    virtual void Init() = 0;
-    /**
-      * Serialize your stuff within this function.
-      * It contains the current serialization xml file. You can use SaveToXMLDoc or SaveGroupToXMLElement to add your objects.
-      */
-    virtual bool Serialize(tinyxml2::XMLDocument* doc, tinyxml2::XMLElement* element) = 0;
-      
-    /**
-      * Deserialize your stuff within this function.
-      * It contains the current serialization xml file. You can use LoadFromXMLDoc or LoadGroupFromXMLElement to read out your objects.
-      */
-    virtual bool Deserialize(tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element) = 0;
-  };
-}
-
-#endif

+ 0 - 1
include/igl/xml/XMLSerializer.h.REMOVED.git-id

@@ -1 +0,0 @@
-ab26d135c79d225b587e9dd8a7cb86a677edcb82

+ 259 - 0
include/igl/xml/old_version/ReAntTweakBarXMLSerialization.h

@@ -0,0 +1,259 @@
+// 
+// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_REANTTWEAKBAR_XML_SERIALIZATION_H
+#define IGL_REANTTWEAKBAR_XML_SERIALIZATION_H
+#include "../igl_inline.h"
+#include "XMLSerializer.h"
+
+#undef IGL_HEADER_ONLY
+#include <igl/ReAntTweakBar.h>
+
+// Forward declarations
+namespace igl
+{
+  class ReTwBar;
+};
+namespace tinyxml2
+{
+  class XMLDocument;
+};
+
+namespace igl
+{
+  
+//  namespace
+//  {
+  
+//    IGL_INLINE bool save_ReAntTweakBar(::igl::ReTwBar* bar, const char* file_name);
+//    IGL_INLINE bool save_ReAntTweakBar(::igl::ReTwBar* bar, tinyxml2::XMLDocument* doc);
+//    IGL_INLINE bool load_ReAntTweakBar(::igl::ReTwBar* bar, const char *file_name);
+//    IGL_INLINE bool load_ReAntTweakBar(::igl::ReTwBar* bar, tinyxml2::XMLDocument* doc);
+    
+    
+    IGL_INLINE bool save_ReAntTweakBar(::igl::ReTwBar* bar, const char* file_name)
+    {
+      const char * name_chars = TwGetBarName(bar->bar);
+      std::string name = std::string(name_chars) + "_AntTweakBar";
+      
+      const std::vector< ::igl::ReTwRWItem>& rw_items = bar->get_rw_items();
+      for(std::vector< ::igl::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
+      {
+        std::string val = bar->get_value_as_string(it->var,it->type);
+        ::igl::XMLSerializer::SaveObject(val,it->name,name,file_name,false);
+      }
+      
+      char var[REANTTWEAKBAR_MAX_CB_VAR_SIZE];
+      // Print all CB variables
+      const std::vector< ::igl::ReTwCBItem>& cb_items = bar->get_cb_items();
+      for(std::vector< ::igl::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
+      {
+        TwType type = it->type;
+        //TwSetVarCallback setCallback = it->setCallback;
+        TwGetVarCallback getCallback = it->getCallback;
+        void * clientData = it->clientData;
+        // I'm not sure how to do what I want to do. getCallback needs to be sure
+        // that it can write to var. So var needs to point to a valid and big
+        // enough chunk of memory
+        getCallback(var,clientData);
+        
+        std::string val = bar->get_value_as_string(var,type);
+        ::igl::XMLSerializer::SaveObject(val,it->name,name,file_name,false);
+      }
+      
+      return true;
+    }
+    
+    IGL_INLINE bool save_ReAntTweakBar(::igl::ReTwBar* bar, tinyxml2::XMLDocument* doc)
+    {
+      std::vector<char**> buffer;
+      
+      const char * name_chars = TwGetBarName(bar->bar);
+      std::string name = std::string(name_chars) + "_AntTweakBar";
+      ::igl::XMLSerializer* s = new ::igl::XMLSerializer(name);
+      
+      const std::vector< ::igl::ReTwRWItem>& rw_items = bar->get_rw_items();
+      for(std::vector< ::igl::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
+      {
+        std::string val = bar->get_value_as_string(it->var,it->type);
+        char** cval = new char*; // create char* on heap
+        *cval = new char[val.size()+1];
+        buffer.push_back(cval);
+        strcpy(*cval,val.c_str());
+        s->Add(*cval,it->name);
+      }
+      
+      char var[REANTTWEAKBAR_MAX_CB_VAR_SIZE];
+      // Print all CB variables
+      const std::vector< ::igl::ReTwCBItem>& cb_items = bar->get_cb_items();
+      for(std::vector< ::igl::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
+      {
+        TwType type = it->type;
+        //TwSetVarCallback setCallback = it->setCallback;
+        TwGetVarCallback getCallback = it->getCallback;
+        void * clientData = it->clientData;
+        // I'm not sure how to do what I want to do. getCallback needs to be sure
+        // that it can write to var. So var needs to point to a valid and big
+        // enough chunk of memory
+        getCallback(var,clientData);
+        
+        std::string val = bar->get_value_as_string(var,type);
+        char** cval = new char*; // create char* on heap
+        *cval = new char[val.size()+1];
+        buffer.push_back(cval);
+        strcpy(*cval,val.c_str());
+        s->Add(*cval,it->name);
+      }
+      
+      s->SaveToXMLDoc(name,doc);
+      
+      // delete pointer buffers
+      for(unsigned int i=0;i<buffer.size();i++)
+      {
+        delete[] *buffer[i];
+        delete buffer[i];
+      }
+      
+      delete s;
+      
+      return true;
+    }
+    
+    IGL_INLINE bool load_ReAntTweakBar(::igl::ReTwBar* bar, const char *file_name)
+    {
+      char type_str[REANTTWEAKBAR_MAX_WORD];
+      char value_str[REANTTWEAKBAR_MAX_WORD];
+      TwType type;
+      
+      const char * name_chars = TwGetBarName(bar->bar);
+      std::string name = std::string(name_chars) + "_AntTweakBar";
+      
+      const std::vector< ::igl::ReTwRWItem>& rw_items = bar->get_rw_items();
+      for(std::vector< ::igl::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
+      {
+        char* val;
+        ::igl::XMLSerializer::LoadObject(val,it->name,name,file_name);
+        sscanf(val,"%s %[^\n]",type_str,value_str);
+        
+        if(!bar->type_from_string(type_str,type))
+        {
+          printf("ERROR: %s type not found... Skipping...\n",type_str);
+          continue;
+        }
+        
+        bar->set_value_from_string(it->name.c_str(),type,value_str);
+        delete[] val;
+      }
+      
+      const std::vector< ::igl::ReTwCBItem>& cb_items = bar->get_cb_items();
+      for(std::vector< ::igl::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
+      {
+        char* val;
+        ::igl::XMLSerializer::LoadObject(val,it->name,name,file_name);
+        sscanf(val,"%s %[^\n]",type_str,value_str);
+        
+        if(!bar->type_from_string(type_str,type))
+        {
+          printf("ERROR: %s type not found... Skipping...\n",type_str);
+          continue;
+        }
+        
+        bar->set_value_from_string(it->name.c_str(),type,value_str);
+        delete[] val;
+      }
+      
+      return true;
+    }
+    
+    IGL_INLINE bool load_ReAntTweakBar(::igl::ReTwBar* bar, tinyxml2::XMLDocument* doc)
+    {
+      std::map<std::string,char*> variables;
+      std::map<std::string,char*> cbVariables;
+      
+      const char * name_chars = TwGetBarName(bar->bar);
+      std::string name = std::string(name_chars) + "_AntTweakBar";
+      ::igl::XMLSerializer* s = new ::igl::XMLSerializer(name);
+      
+      std::map<std::string,char*>::iterator iter;
+      const std::vector< ::igl::ReTwRWItem>& rw_items = bar->get_rw_items();
+      for(std::vector< ::igl::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
+      {
+        variables[it->name] = NULL;
+        iter = variables.find(it->name);
+        s->Add(iter->second,iter->first);
+      }
+      
+      // Add all CB variables
+      const std::vector< ::igl::ReTwCBItem>& cb_items = bar->get_cb_items();
+      for(std::vector< ::igl::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
+      {
+        cbVariables[it->name] = NULL;
+        iter = cbVariables.find(it->name);
+        s->Add(iter->second,iter->first);
+      }
+      
+      s->LoadFromXMLDoc(doc);
+      
+      // Set loaded values
+      char type_str[REANTTWEAKBAR_MAX_WORD];
+      char value_str[REANTTWEAKBAR_MAX_WORD];
+      TwType type;
+      
+      for(iter = variables.begin(); iter != variables.end(); iter++)
+      {
+        if(iter->second == NULL)
+        {
+          printf("ERROR: '%s' entry not found... Skipping...\n",iter->first.c_str());
+          continue;
+        }
+        
+        sscanf(iter->second,"%s %[^\n]",type_str,value_str);
+        
+        if(!bar->type_from_string(type_str,type))
+        {
+          printf("ERROR: Type '%s' of '%s' not found... Skipping...\n",type_str,iter->first.c_str());
+          continue;
+        }
+        
+        bar->set_value_from_string(iter->first.c_str(),type,value_str);
+      }
+      
+      for(iter = cbVariables.begin(); iter != cbVariables.end(); iter++)
+      {
+        if(iter->second == NULL)
+        {
+          printf("ERROR: '%s' entry not found... Skipping...\n",iter->first.c_str());
+          continue;
+        }
+
+        sscanf(iter->second,"%s %[^\n]",type_str,value_str);
+        
+        if(!bar->type_from_string(type_str,type))
+        {
+          printf("ERROR: Type '%s' of '%s' not found... Skipping...\n",type_str,iter->first.c_str());
+          continue;
+        }
+        
+        bar->set_value_from_string(iter->first.c_str(),type,value_str);
+      }
+      
+      // delete buffers
+      for(iter = variables.begin(); iter != variables.end(); iter++)
+        delete[] iter->second;
+      
+      for(iter = cbVariables.begin(); iter != cbVariables.end(); iter++)
+        delete[] iter->second;
+      
+      delete s;
+      
+      return true;
+    }
+    
+//  }
+}
+
+#endif

+ 49 - 0
include/igl/xml/old_version/XMLSerializable.h

@@ -0,0 +1,49 @@
+// 
+// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+/* ------------------------------------------------------------------------------
+ Inherit from this abstract class to have full control over the serialization
+ of your user defined class.
+ ----------------------------------------------------------------------------*/
+#ifndef IGL_XML_SERIALIZABLE_H
+#define IGL_XML_SERIALIZABLE_H
+
+#include <iostream>
+#include <tinyxml2.h>
+
+namespace igl
+{
+  namespace
+  {
+    class XMLSerializable
+    {
+    public:
+      /**
+      * Default name of serializable object
+      */
+      std::string Name;
+
+      /**
+        * This function gets called if the objects were not found during deserialization.
+        * Initialize your objects as you like.
+        */
+      virtual void Init() = 0;
+      /**
+        * Serialize your stuff within this function.
+        * doc is the current serialization xml file. You can use SaveToXMLDoc to add your objects.
+        */
+      virtual bool Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) = 0;
+
+      /**
+        * Deserialize your stuff within this function.
+        * doc is the current serialization xml file. You can use LoadFromXMLDoc to read out your objects.
+        */
+      virtual bool Deserialize(tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element) = 0;
+    };
+  }
+}
+
+#endif

+ 4 - 8
include/igl/xml/XMLSerialization.h → include/igl/xml/old_version/XMLSerialization.h

@@ -1,13 +1,9 @@
-// This file is part of libigl, a simple c++ geometry processing library.
 // 
-// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
 // 
 // This Source Code Form is subject to the terms of the Mozilla Public License 
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can 
 // obtain one at http://mozilla.org/MPL/2.0/.
-/* ---------------------------------------------------------------------------
- // XMLSerialization.h
- // Author: Christian Schüller <schuellchr@gmail.com>
  ------------------------------------------------------------------------------
  Inherit from this class to have the easiest way to serialize your user defined class.
  
@@ -53,14 +49,14 @@ namespace igl
       XMLSerialization& operator=(const XMLSerialization& obj);
 
       /**
-      * Function which must be overriden in the subclass if you dont use
+      * Function which must be overridden in the subclass if you don't use
       * heap allocations (new) to create new instances.
       * It will get called if the assignment operator or copy constructor
       * is involved to update the references to the new copied data structures
       *
-      * Add in this fucntion all the variables you wanna serialize like:
+      * Add in this function all the variables you want to serialize like:
       * xmlSerializer->Add(var1);
-      * xmlSerializer->Add(varw);
+      * xmlSerializer->Add(var2);
       * ...
       */
       virtual void InitSerialization();

+ 1 - 5
include/igl/xml/XMLSerializationTest.h → include/igl/xml/old_version/XMLSerializationTest.h

@@ -1,13 +1,9 @@
-// This file is part of libigl, a simple c++ geometry processing library.
 // 
-// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
 // 
 // This Source Code Form is subject to the terms of the Mozilla Public License 
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can 
 // obtain one at http://mozilla.org/MPL/2.0/.
-/* ---------------------------------------------------------------------------
-// XMLSerializationTest.h
-// Author: Christian Schüller <schuellchr@gmail.com>
 ------------------------------------------------------------------------------
  Used to demonstrates howto use the XMLSerialization class.
 ----------------------------------------------------------------------------*/

+ 1 - 0
include/igl/xml/old_version/XMLSerializer.h.REMOVED.git-id

@@ -0,0 +1 @@
+172f806cdef073e1613fe0def62c0521976222bd

+ 485 - 0
include/igl/xml/serialization_test.cpp

@@ -0,0 +1,485 @@
+//
+// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//#ifndef IGL_SERIALIZATION_TEST_H
+//#define IGL_SERIALIZATION_TEST_H
+
+//#include <igl/Timer.h>
+#include <igl/xml/serialize_xml.h>
+
+namespace igl
+{
+
+  struct Test1111
+  {
+  };
+
+  struct Test1 : public XMLSerializable
+  {
+    std::string ts;
+    std::vector<Test1*> tvt;
+    Test1* tt;
+
+    Test1()
+    {
+      tt = NULL;
+    }
+
+    void InitSerialization()
+    {
+      Add(ts,"ts",false);
+      Add(tvt,"tvt");
+      Add(tt,"tt");
+    }
+  };
+
+  struct Test2: public igl::XMLSerializableBase
+  {
+    char tc;
+    int* ti;
+    std::vector<short> tvb;
+    float tf;
+
+    Test2()
+    {
+      tc = '1';
+      ti = NULL;
+      tf = 1.0004;
+      tvb.push_back(2);
+      tvb.push_back(3);
+    }
+
+    void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const
+    {
+      igl::serialize_xml(tc,"tc",doc,element);
+      igl::serialize_xml(ti,"ti",doc,element);
+      igl::serialize_xml(tvb,"tvb",doc,element);
+    }
+    void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element)
+    {
+      igl::deserialize_xml(tc,"tc",doc,element);
+      igl::deserialize_xml(ti,"ti",doc,element);
+      igl::deserialize_xml(tvb,"tvb",doc,element);
+    }
+    void Serialize(std::vector<char>& buffer) const
+    {
+      igl::serialize(tc,"tc",buffer);
+      igl::serialize(ti,"ti",buffer);
+      igl::serialize(tvb,"tvb",buffer);
+      igl::serialize(tf,"tf",buffer);
+    }
+    void Deserialize(const std::vector<char>& buffer)
+    {
+      igl::deserialize(tc,"tc",buffer);
+      igl::deserialize(ti,"ti",buffer);
+      igl::deserialize(tvb,"tvb",buffer);
+      igl::deserialize(tf,"tf",buffer);
+    }
+  };
+
+  void serialization_test()
+  {
+    std::string file("test");
+
+    bool tbIn = true,tbOut;
+    char tcIn = 't',tcOut;
+    unsigned char tucIn = 'u',tucOut;
+    short tsIn = 6,tsOut;
+    int tiIn = -10,tiOut;
+    unsigned int tuiIn = 10,tuiOut;
+    float tfIn = 1.0005,tfOut;
+    double tdIn = 1.000000005,tdOut;
+
+    int* tinpIn = NULL,*tinpOut = NULL;
+    float* tfpIn = new float,*tfpOut = NULL;
+    *tfpIn = 1.11101;
+
+    std::string tstrIn("test12345"),tstrOut;
+
+    Test2 tObjIn,tObjOut;
+    int ti = 2;
+    tObjIn.ti = &ti;
+
+
+    Test1 test1,test2,test3;
+    test1.ts = "100";
+    test2.ts = "200";
+    test3.ts = "300";
+
+    Test1 testA, testC;
+    testA.tt = &test1;
+    testA.ts = "test123";
+    testA.tvt.push_back(&test2);
+    testA.tvt.push_back(&test3);
+
+    Test1 testB = testA;
+    testB.ts = "400";
+    testB.tvt.pop_back();
+
+    std::pair<int,bool> tPairIn(10,true);
+    std::pair<int,bool> tPairOut;
+
+    std::vector<int> tVector1In ={1,2,3,4,5};
+    std::vector<int> tVector1Out;
+
+    std::pair<int,bool> p1(10,1);
+    std::pair<int,bool> p2(1,0);
+    std::pair<int,bool> p3(10000,1);
+    std::vector<std::pair<int,bool> > tVector2In ={p1,p2,p3};
+    std::vector<std::pair<int,bool> > tVector2Out;
+
+    std::set<std::pair<int,bool> > tSetIn ={p1,p2,p3};
+    std::set<std::pair<int,bool> > tSetOut;
+
+    std::map<int,bool> tMapIn ={p1,p2,p3};
+    std::map<int,bool> tMapOut;
+
+    Eigen::Matrix<float,3,3> tDenseMatrixIn;
+    tDenseMatrixIn << Eigen::Matrix<float,3,3>::Random();
+    tDenseMatrixIn.coeffRef(0,0) = 1.00001;
+    Eigen::Matrix<float,3,3> tDenseMatrixOut;
+
+    Eigen::Matrix<float,3,3,Eigen::RowMajor> tDenseRowMatrixIn;
+    tDenseRowMatrixIn << Eigen::Matrix<float,3,3,Eigen::RowMajor>::Random();
+    Eigen::Matrix<float,3,3,Eigen::RowMajor> tDenseRowMatrixOut;
+
+    Eigen::SparseMatrix<double> tSparseMatrixIn;
+    tSparseMatrixIn.resize(3,3);
+    tSparseMatrixIn.insert(0,0) = 1.3;
+    tSparseMatrixIn.insert(1,1) = 10.2;
+    tSparseMatrixIn.insert(2,2) = 100.1;
+    tSparseMatrixIn.finalize();
+    Eigen::SparseMatrix<double> tSparseMatrixOut;
+
+    // binary serialization
+
+    igl::serialize(tbIn,file);
+    igl::deserialize(tbOut,file);
+    assert(tbIn == tbOut);
+
+    igl::serialize(tcIn,file);
+    igl::deserialize(tcOut,file);
+    assert(tcIn == tcOut);
+
+    igl::serialize(tucIn,file);
+    igl::deserialize(tucOut,file);
+    assert(tucIn == tucOut);
+
+    igl::serialize(tsIn,file);
+    igl::deserialize(tsOut,file);
+    assert(tsIn == tsOut);
+
+    igl::serialize(tiIn,file);
+    igl::deserialize(tiOut,file);
+    assert(tiIn == tiOut);
+
+    igl::serialize(tuiIn,file);
+    igl::deserialize(tuiOut,file);
+    assert(tuiIn == tuiOut);
+
+    igl::serialize(tfIn,file);
+    igl::deserialize(tfOut,file);
+    assert(tfIn == tfOut);
+
+    igl::serialize(tdIn,file);
+    igl::deserialize(tdOut,file);
+    assert(tdIn == tdOut);
+
+    igl::serialize(tinpIn,file);
+    igl::deserialize(tinpOut,file);
+    assert(tinpIn == tinpOut);
+
+    igl::serialize(tfpIn,file);
+    igl::deserialize(tfpOut,file);
+    assert(*tfpIn == *tfpOut);
+    tfpOut = NULL;
+
+    igl::serialize(tstrIn,file);
+    igl::deserialize(tstrOut,file);
+    assert(tstrIn == tstrOut);
+
+    // updating
+    igl::serialize(tbIn,"tb",file,true);
+    igl::serialize(tcIn,"tc",file);
+    igl::serialize(tiIn,"ti",file);
+    tiIn++;
+    igl::serialize(tiIn,"ti",file);
+    tiIn++;
+    igl::serialize(tiIn,"ti",file);
+    igl::deserialize(tbOut,"tb",file);
+    igl::deserialize(tcOut,"tc",file);
+    igl::deserialize(tiOut,"ti",file);
+    assert(tbIn == tbOut);
+    assert(tcIn == tcOut);
+    assert(tiIn == tiOut);
+
+    igl::serialize(tsIn,"tsIn",file,true);
+    igl::serialize(tVector1In,"tVector1In",file);
+    igl::serialize(tVector2In,"tsIn",file);
+    igl::deserialize(tVector2Out,"tsIn",file);
+    for(unsigned int i=0;i<tVector2In.size();i++)
+    {
+      assert(tVector2In[i].first == tVector2Out[i].first);
+      assert(tVector2In[i].second == tVector2Out[i].second);
+    }
+    tVector2Out.clear();
+
+    igl::serialize(tObjIn,file);
+    igl::deserialize(tObjOut,file);
+    assert(tObjIn.tc == tObjOut.tc);
+    assert(*tObjIn.ti == *tObjOut.ti);
+    for(unsigned int i=0;i<tObjIn.tvb.size();i++)
+      assert(tObjIn.tvb[i] == tObjOut.tvb[i]);
+    tObjOut.ti = NULL;
+
+    igl::serialize(tPairIn,file);
+    igl::deserialize(tPairOut,file);
+    assert(tPairIn.first == tPairOut.first);
+    assert(tPairIn.second == tPairOut.second);
+
+    igl::serialize(tVector1In,file);
+    igl::deserialize(tVector1Out,file);
+    for(unsigned int i=0;i<tVector1In.size();i++)
+      assert(tVector1In[i] == tVector1Out[i]);
+
+    igl::serialize(tVector2In,file);
+    igl::deserialize(tVector2Out,file);
+    for(unsigned int i=0;i<tVector2In.size();i++)
+    {
+      assert(tVector2In[i].first == tVector2Out[i].first);
+      assert(tVector2In[i].second == tVector2Out[i].second);
+    }
+
+    igl::serialize(tSetIn,file);
+    igl::deserialize(tSetOut,file);
+    assert(tSetIn.size() == tSetOut.size());
+
+    igl::serialize(tMapIn,file);
+    igl::deserialize(tMapOut,file);
+    assert(tMapIn.size() == tMapOut.size());
+
+    igl::serialize(tDenseMatrixIn,file);
+    igl::deserialize(tDenseMatrixOut,file);
+    assert((tDenseMatrixIn - tDenseMatrixOut).sum() == 0);
+
+    igl::serialize(tDenseRowMatrixIn,file);
+    igl::deserialize(tDenseRowMatrixOut,file);
+    assert((tDenseRowMatrixIn - tDenseRowMatrixOut).sum() == 0);
+
+    igl::serialize(tSparseMatrixIn,file);
+    igl::deserialize(tSparseMatrixOut,file);
+    assert((tSparseMatrixIn - tSparseMatrixOut).sum() == 0);
+
+    igl::serialize(testB,file);
+    igl::deserialize(testC,file);
+    assert(testB.ts == testC.ts);
+    assert(testB.tvt.size() == testC.tvt.size());
+    for(unsigned int i=0;i<testB.tvt.size();i++)
+    {
+      assert(testB.tvt[i]->ts == testC.tvt[i]->ts);
+      assert(testB.tvt[i]->tvt.size() == testC.tvt[i]->tvt.size());
+      assert(testB.tvt[i]->tt == testC.tvt[i]->tt);
+    }
+    assert(testB.tt->ts == testC.tt->ts);
+    assert(testB.tt->tvt.size() == testC.tt->tvt.size());
+    assert(testB.tt->tt == testC.tt->tt);
+    testC = Test1();
+
+    // big data test
+    /*std::vector<std::vector<float> > bigDataIn,bigDataOut;
+    for(unsigned int i=0;i<10000;i++)
+    {
+    std::vector<float> v;
+    for(unsigned int j=0;j<10000;j++)
+    {
+    v.push_back(j);
+    }
+    bigDataIn.push_back(v);
+    }
+
+    igl::Timer timer;
+    timer.start();
+    igl::serialize(bigDataIn,file);
+    timer.stop();
+    std::cout << "ser: " << timer.getElapsedTimeInMilliSec() << std::endl;
+
+    timer.start();
+    igl::deserialize(bigDataOut,file);
+    timer.stop();
+    std::cout << "des: " << timer.getElapsedTimeInMilliSec() << std::endl;
+    char c;
+    std::cin >> c; */
+
+    // xml serialization
+
+    igl::serialize_xml(tbIn,file);
+    igl::deserialize_xml(tbOut,file);
+    assert(tbIn == tbOut);
+
+    igl::serialize_xml(tcIn,file);
+    igl::deserialize_xml(tcOut,file);
+    assert(tcIn == tcOut);
+
+    igl::serialize_xml(tucIn,file);
+    igl::deserialize_xml(tucOut,file);
+    assert(tucIn == tucOut);
+
+    igl::serialize_xml(tsIn,file);
+    igl::deserialize_xml(tsOut,file);
+    assert(tsIn == tsOut);
+
+    igl::serialize_xml(tiIn,file);
+    igl::deserialize_xml(tiOut,file);
+    assert(tiIn == tiOut);
+
+    igl::serialize_xml(tuiIn,file);
+    igl::deserialize_xml(tuiOut,file);
+    assert(tuiIn == tuiOut);
+
+    igl::serialize_xml(tfIn,file);
+    igl::deserialize_xml(tfOut,file);
+    assert(tfIn == tfOut);
+
+    igl::serialize_xml(tdIn,file);
+    igl::deserialize_xml(tdOut,file);
+    assert(tdIn == tdOut);
+
+    igl::serialize_xml(tinpIn,file);
+    igl::deserialize_xml(tinpOut,file);
+    assert(tinpIn == tinpOut);
+
+    igl::serialize_xml(tfpIn,file);
+    igl::deserialize_xml(tfpOut,file);
+    assert(*tfpIn == *tfpOut);
+
+    igl::serialize_xml(tstrIn,file);
+    igl::deserialize_xml(tstrOut,file);
+    assert(tstrIn == tstrOut);
+
+    // updating
+    igl::serialize_xml(tbIn,"tb",file,false,true);
+    igl::serialize_xml(tcIn,"tc",file);
+    igl::serialize_xml(tiIn,"ti",file);
+    tiIn++;
+    igl::serialize_xml(tiIn,"ti",file);
+    tiIn++;
+    igl::serialize_xml(tiIn,"ti",file);
+    igl::deserialize_xml(tbOut,"tb",file);
+    igl::deserialize_xml(tcOut,"tc",file);
+    igl::deserialize_xml(tiOut,"ti",file);
+    assert(tbIn == tbOut);
+    assert(tcIn == tcOut);
+    assert(tiIn == tiOut);
+
+    igl::serialize_xml(tsIn,"tsIn",file,false,true);
+    igl::serialize_xml(tVector1In,"tVector1In",file);
+    igl::serialize_xml(tVector2In,"tsIn",file);
+    igl::deserialize_xml(tVector2Out,"tsIn",file);
+    for(unsigned int i=0;i<tVector2In.size();i++)
+    {
+      assert(tVector2In[i].first == tVector2Out[i].first);
+      assert(tVector2In[i].second == tVector2Out[i].second);
+    }
+    tVector2Out.clear();
+
+    // binarization
+    igl::serialize_xml(tVector2In,"tVector2In",file,true);
+    igl::deserialize_xml(tVector2Out,"tVector2In",file);
+    for(unsigned int i=0;i<tVector2In.size();i++)
+    {
+      assert(tVector2In[i].first == tVector2Out[i].first);
+      assert(tVector2In[i].second == tVector2Out[i].second);
+    }
+
+    igl::serialize_xml(tObjIn,file);
+    igl::deserialize_xml(tObjOut,file);
+    assert(tObjIn.tc == tObjOut.tc);
+    assert(*tObjIn.ti == *tObjOut.ti);
+    for(unsigned int i=0;i<tObjIn.tvb.size();i++)
+      assert(tObjIn.tvb[i] == tObjOut.tvb[i]);
+
+    igl::serialize_xml(tPairIn,file);
+    igl::deserialize_xml(tPairOut,file);
+    assert(tPairIn.first == tPairOut.first);
+    assert(tPairIn.second == tPairOut.second);
+
+    igl::serialize_xml(tVector1In,file);
+    igl::deserialize_xml(tVector1Out,file);
+    for(unsigned int i=0;i<tVector1In.size();i++)
+      assert(tVector1In[i] == tVector1Out[i]);
+
+    igl::serialize_xml(tVector2In,file);
+    igl::deserialize_xml(tVector2Out,file);
+    for(unsigned int i=0;i<tVector2In.size();i++)
+    {
+      assert(tVector2In[i].first == tVector2Out[i].first);
+      assert(tVector2In[i].second == tVector2Out[i].second);
+    }
+
+    igl::serialize_xml(tSetIn,file);
+    igl::deserialize_xml(tSetOut,file);
+    assert(tSetIn.size() == tSetOut.size());
+
+    igl::serialize_xml(tMapIn,file);
+    igl::deserialize_xml(tMapOut,file);
+    assert(tMapIn.size() == tMapOut.size());
+
+    igl::serialize_xml(tDenseMatrixIn,file);
+    igl::deserialize_xml(tDenseMatrixOut,file);
+    assert((tDenseMatrixIn - tDenseMatrixOut).sum() == 0);
+
+    igl::serialize_xml(tDenseRowMatrixIn,file);
+    igl::deserialize_xml(tDenseRowMatrixOut,file);
+    assert((tDenseRowMatrixIn - tDenseRowMatrixOut).sum() == 0);
+
+    igl::serialize_xml(tSparseMatrixIn,file);
+    igl::deserialize_xml(tSparseMatrixOut,file);
+    assert((tSparseMatrixIn - tSparseMatrixOut).sum() == 0);
+
+    igl::serialize_xml(testB,file);
+    igl::deserialize_xml(testC,file);
+    assert(testB.ts == testC.ts);
+    assert(testB.tvt.size() == testC.tvt.size());
+    for(unsigned int i=0;i<testB.tvt.size();i++)
+    {
+      assert(testB.tvt[i]->ts == testC.tvt[i]->ts);
+      assert(testB.tvt[i]->tvt.size() == testC.tvt[i]->tvt.size());
+      assert(testB.tvt[i]->tt == testC.tvt[i]->tt);
+    }
+    assert(testB.tt->ts == testC.tt->ts);
+    assert(testB.tt->tvt.size() == testC.tt->tvt.size());
+    assert(testB.tt->tt == testC.tt->tt);
+
+    // big data test
+    /*std::vector<std::vector<float> > bigDataIn,bigDataOut;
+    for(unsigned int i=0;i<10000;i++)
+    {
+    std::vector<float> v;
+    for(unsigned int j=0;j<10000;j++)
+    {
+    v.push_back(j);
+    }
+    bigDataIn.push_back(v);
+    }
+
+    igl::Timer timer;
+    timer.start();
+    igl::serialize_xml(bigDataIn,"bigDataIn",file,igl::SERIALIZE_BINARY);
+    timer.stop();
+    std::cout << "ser: " << timer.getElapsedTimeInMilliSec() << std::endl;
+
+    timer.start();
+    igl::deserialize_xml(bigDataOut,"bigDataIn",file);
+    timer.stop();
+    std::cout << "des: " << timer.getElapsedTimeInMilliSec() << std::endl;
+    char c;
+    std::cin >> c;*/
+
+    std::cout << "All tests run successfully!\n";
+  }
+}
+
+//#endif

+ 970 - 0
include/igl/xml/serialize_xml.cpp

@@ -0,0 +1,970 @@
+//
+// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "serialize_xml.h"
+
+namespace igl
+{
+  template <typename T>
+  IGL_INLINE void serialize_xml(const T& obj,const std::string& filename)
+  {
+    serialize_xml(obj,"object",filename,false,true);
+  }
+
+  template <typename T>
+  IGL_INLINE void serialize_xml(const T& obj,const std::string& objectName,const std::string& filename,bool binary,bool overwrite)
+  {
+    tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
+
+    if(overwrite == false)
+    {
+      // Check if file exists
+      tinyxml2::XMLError error = doc->LoadFile(filename.c_str());
+      if(error != tinyxml2::XML_NO_ERROR)
+      {
+        doc->Clear();
+      }
+    }
+
+    tinyxml2::XMLElement* element = doc->FirstChildElement("serialization");
+    if(element == NULL)
+    {
+      element = doc->NewElement("serialization");
+      doc->InsertEndChild(element);
+    }
+
+    serialize_xml(obj,objectName,doc,element,binary);
+
+    // Save
+    tinyxml2::XMLError error = doc->SaveFile(filename.c_str());
+    if(error != tinyxml2::XML_NO_ERROR)
+    {
+      doc->PrintError();
+    }
+
+    delete doc;
+  }
+
+  template <typename T>
+  IGL_INLINE void serialize_xml(const T& obj,const std::string& objectName,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,bool binary)
+  {
+    static_assert(serialization_xml::is_serializable<T>::value,"'igl::serialize_xml': type is not serializable");
+
+    std::string name(objectName);
+    serialization_xml::encodeXMLElementName(name);
+
+    tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+    
+    if(child != NULL)
+      element->DeleteChild(child);
+
+    child = doc->NewElement(name.c_str());
+    element->InsertEndChild(child);
+
+    if(binary)
+    {
+      std::vector<char> buffer;
+      serialize(obj,name,buffer);
+      std::string data = serialization_xml::base64_encode(reinterpret_cast<const unsigned char*>(buffer.data()),buffer.size());
+      
+      child->SetAttribute("binary",true);
+
+      serialization_xml::serialize(data,doc,element,name);
+    }
+    else
+    {
+      serialization_xml::serialize(obj,doc,element,name);
+    }
+  }
+
+  template <typename T>
+  IGL_INLINE void deserialize_xml(T& obj,const std::string& filename)
+  {
+    deserialize_xml(obj,"object",filename);
+  }
+
+  template <typename T>
+  IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const std::string& filename)
+  {
+    tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
+
+    tinyxml2::XMLError error = doc->LoadFile(filename.c_str());
+    if(error != tinyxml2::XML_NO_ERROR)
+    {
+      std::cerr << "File not found!" << std::endl;
+      doc->PrintError();
+      doc = NULL;
+    }
+    else
+    {
+      tinyxml2::XMLElement* element = doc->FirstChildElement("serialization");
+      if(element == NULL)
+      {
+        std::cerr << "Name of object not found! Initialized with default value." << std::endl;
+        obj = T();
+      }
+      else
+      {
+        deserialize_xml(obj,objectName,doc,element);
+      }
+
+      delete doc;
+    }
+  }
+
+  template <typename T>
+  IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element)
+  {
+    static_assert(serialization::is_serializable<T>::value,"'igl::deserialize_xml': type is not deserializable");
+
+    std::string name(objectName);
+    serialization_xml::encodeXMLElementName(name);
+
+    const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+    if(child != NULL)
+    {
+      bool isBinary = false;
+      const tinyxml2::XMLAttribute* attr = child->FindAttribute("binary");
+      if(attr != NULL)
+      {
+        std::string code;
+        serialization_xml::deserialize(code,doc,element,name);
+        std::string decoded = serialization_xml::base64_decode(code);
+
+        std::vector<char> buffer;
+        std::copy(decoded.c_str(),decoded.c_str()+decoded.length(),std::back_inserter(buffer));
+
+        deserialize(obj,name,buffer);
+      }
+      else
+      {
+        serialization_xml::deserialize(obj,doc,element,name);
+      }
+    }
+  }
+
+  IGL_INLINE bool XMLSerializable::PreSerialization() const
+  { 
+    return true;
+  }
+  
+  IGL_INLINE void XMLSerializable::PostSerialization() const
+  {
+  }
+  
+  IGL_INLINE bool XMLSerializable::PreDeserialization()
+  { 
+    return true;
+  }
+
+  IGL_INLINE void XMLSerializable::PostDeserialization() 
+  {
+  }
+
+  IGL_INLINE void XMLSerializable::Serialize(std::vector<char>& buffer) const
+  {
+    if(this->PreSerialization())
+    {
+      if(initialized == false)
+      {
+        objects.clear();
+        (const_cast<XMLSerializable*>(this))->InitSerialization();
+        initialized = true;
+      }
+
+      for(unsigned int i=0;i<objects.size();i++)
+        objects[i]->Serialize(buffer);
+
+      this->PostSerialization();
+    }
+  }
+
+  IGL_INLINE void XMLSerializable::Deserialize(const std::vector<char>& buffer)
+  {
+    if(this->PreDeserialization())
+    {
+      if(initialized == false)
+      {
+        objects.clear();
+        (const_cast<XMLSerializable*>(this))->InitSerialization();
+        initialized = true;
+      }
+
+      for(unsigned int i=0;i<objects.size();i++)
+        objects[i]->Deserialize(buffer);
+
+      this->PostDeserialization();
+    }
+  }
+
+  IGL_INLINE void XMLSerializable::Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const
+  {
+    if(this->PreSerialization())
+    {
+      if(initialized == false)
+      {
+        objects.clear();
+        (const_cast<XMLSerializable*>(this))->InitSerialization();
+        initialized = true;
+      }
+
+      for(unsigned int i=0;i<objects.size();i++)
+        objects[i]->Serialize(doc,element);
+
+      this->PostSerialization();
+    }
+  }
+
+  IGL_INLINE void XMLSerializable::Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element)
+  {
+    if(this->PreDeserialization())
+    {
+      if(initialized == false)
+      {
+        objects.clear();
+        (const_cast<XMLSerializable*>(this))->InitSerialization();
+        initialized = true;
+      }
+
+      for(unsigned int i=0;i<objects.size();i++)
+        objects[i]->Deserialize(doc,element);
+
+      this->PostDeserialization();
+    }
+  }
+
+  IGL_INLINE XMLSerializable::XMLSerializable()
+  {
+    initialized = false;
+  }
+
+  IGL_INLINE XMLSerializable::XMLSerializable(const XMLSerializable& obj)
+  {
+    initialized = false;
+    objects.clear();
+  }
+
+  IGL_INLINE XMLSerializable::~XMLSerializable()
+  {
+    initialized = false;
+    objects.clear();
+  }
+
+
+  IGL_INLINE XMLSerializable& XMLSerializable::operator=(const XMLSerializable& obj)
+  {
+    if(this != &obj)
+    {
+      if(initialized)
+      {
+        initialized = false;
+        objects.clear();
+      }
+    }
+    return *this;
+  }
+
+  template <typename T>
+  IGL_INLINE void XMLSerializable::Add(T& obj,std::string name,bool binary)
+  {
+    XMLSerializationObject<T>* object = new XMLSerializationObject<T>();
+    object->Binary = binary;
+    object->Name = name;
+    object->Object = &obj;
+
+    objects.push_back(object);
+  }
+
+  namespace serialization_xml
+  {
+    // fundamental types
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+    {
+      tinyxml2::XMLElement* child = getElement(doc,element,name.c_str());
+      child->SetAttribute("val",obj);
+    }
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+    {
+      const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+      if(child != NULL)
+      {
+        getAttribute(child->Attribute("val"),obj);
+      }
+      else
+      {
+        obj = T();
+      }
+    }
+
+    // std::string
+
+    IGL_INLINE void serialize(const std::string& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+    {
+      tinyxml2::XMLElement* child = getElement(doc,element,name.c_str());
+      child->SetAttribute("val",obj.c_str());
+    }
+
+    IGL_INLINE void deserialize(std::string& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+    {
+      const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+      if(child != NULL)
+      {
+        getAttribute(child->Attribute("val"),obj);
+      }
+      else
+      {
+        obj = std::string("");
+      }
+    }
+
+    // Serializable
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_base_of<XMLSerializableBase,T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+    {
+      // Serialize object implementing Serializable interface
+      const XMLSerializableBase& object = dynamic_cast<const XMLSerializableBase&>(obj);
+
+      tinyxml2::XMLElement* child = getElement(doc,element,name.c_str());
+      object.Serialize(doc,child);
+    }
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_base_of<XMLSerializableBase,T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+    {
+      const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+
+      if(child != NULL)
+      {
+        obj.Deserialize(doc,child);
+      }
+      else
+      {
+        obj = T();
+      }
+    }
+
+    // STL containers
+
+    template <typename T1,typename T2>
+    IGL_INLINE void serialize(const std::pair<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+    {
+      tinyxml2::XMLElement* pair = getElement(doc,element,name.c_str());
+      serialize(obj.first,doc,pair,"first");
+      serialize(obj.second,doc,pair,"second");
+    }
+
+    template <typename T1,typename T2>
+    IGL_INLINE void deserialize(std::pair<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+    {
+      const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+      if(child != NULL)
+      {
+        deserialize(obj.first,doc,child,"first");
+        deserialize(obj.second,doc,child,"second");
+      }
+      else
+      {
+        obj.first = T1();
+        obj.second = T2();
+      }
+    }
+
+    template <typename T1,typename T2>
+    IGL_INLINE void serialize(const std::vector<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+    {
+      tinyxml2::XMLElement* vector = getElement(doc,element,name.c_str());
+      vector->SetAttribute("size",(unsigned int)obj.size());
+
+      std::stringstream num;
+      for(unsigned int i=0;i<obj.size();i++)
+      {
+        num.str("");
+        num << "value" << i;
+        serialize(obj[i],doc,vector,num.str());
+      }
+    }
+
+    template <typename T1,typename T2>
+    IGL_INLINE void deserialize(std::vector<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+    {
+      obj.clear();
+
+      const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+      if(child != NULL)
+      {
+        unsigned int size = child->UnsignedAttribute("size");
+        obj.resize(size);
+
+        std::stringstream num;
+        for(unsigned int i=0;i<size;i++)
+        {
+          num.str("");
+          num << "value" << i;
+
+          deserialize(obj[i],doc,child,num.str());
+        }
+      }
+      else
+      {
+        obj.clear();
+      }
+    }
+
+    template <typename T>
+    IGL_INLINE void serialize(const std::set<T>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+    {
+      tinyxml2::XMLElement* set = getElement(doc,element,name.c_str());
+      set->SetAttribute("size",(unsigned int)obj.size());
+
+      std::stringstream num;
+      typename std::set<T>::iterator iter = obj.begin();
+      for(int i=0;iter!=obj.end();iter++,i++)
+      {
+        num.str("");
+        num << "value" << i;
+        serialize((T)*iter,doc,set,num.str());
+      }
+    }
+
+    template <typename T>
+    IGL_INLINE void deserialize(std::set<T>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+    {
+      obj.clear();
+
+      const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+      if(child != NULL)
+      {
+        unsigned int size = child->UnsignedAttribute("size");
+
+        std::stringstream num;
+        typename std::set<T>::iterator iter = obj.begin();
+        for(int i=0;i<size;i++)
+        {
+          num.str("");
+          num << "value" << i;
+
+          T val;
+          deserialize(val,doc,child,num.str());
+          obj.insert(val);
+        }
+      }
+      else
+      {
+        obj.clear();
+      }
+    }
+
+    template <typename T1,typename T2>
+    IGL_INLINE void serialize(const std::map<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+    {
+      tinyxml2::XMLElement* map = getElement(doc,element,name.c_str());
+      map->SetAttribute("size",(unsigned int)obj.size());
+
+      std::stringstream num;
+      typename std::map<T1,T2>::const_iterator iter = obj.cbegin();
+      for(int i=0;iter!=obj.end();iter++,i++)
+      {
+        num.str("");
+        num << "value" << i;
+        serialize((std::pair<T1,T2>)*iter,doc,map,num.str());
+      }
+    }
+
+    template <typename T1,typename T2>
+    IGL_INLINE void deserialize(std::map<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+    {
+      obj.clear();
+
+      const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+      if(child != NULL)
+      {
+        unsigned int size = child->UnsignedAttribute("size");
+
+        std::stringstream num;
+        typename std::map<T1,T2>::iterator iter = obj.begin();
+        for(int i=0;i<size;i++)
+        {
+          num.str("");
+          num << "value" << i;
+
+          std::pair<T1,T2> pair;
+          deserialize(pair,doc,child,num.str());
+          obj.insert(pair);
+        }
+      }
+      else
+      {
+        obj.clear();
+      }
+    }
+
+    // Eigen types
+    template<typename T,int R,int C,int P,int MR,int MC>
+    IGL_INLINE void serialize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+    {
+      tinyxml2::XMLElement* matrix = getElement(doc,element,name.c_str());
+
+      const unsigned int rows = obj.rows();
+      const unsigned int cols = obj.cols();
+
+      matrix->SetAttribute("rows",rows);
+      matrix->SetAttribute("cols",cols);
+
+      char buffer[200];
+      std::stringstream ms;
+      ms << "\n";
+      for(unsigned int r=0;r<rows;r++)
+      {
+        for(unsigned int c=0;c<cols;c++)
+        {
+          tinyxml2::XMLUtil::ToStr(obj(r,c),buffer,200);
+          ms << buffer << ",";
+        }
+        ms << "\n";
+      }
+
+      std::string mString = ms.str();
+      if(mString.size() > 1)
+        mString[mString.size()-2] = '\0';
+
+      matrix->SetAttribute("matrix",mString.c_str());
+    }
+
+    template<typename T,int R,int C,int P,int MR,int MC>
+    IGL_INLINE void deserialize(Eigen::Matrix<T,R,C,P,MR,MC>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+    {
+      const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+      bool initialized = false;
+      if(child != NULL)
+      {
+        const unsigned int rows = child->UnsignedAttribute("rows");
+        const unsigned int cols = child->UnsignedAttribute("cols");
+
+        if(rows > 0 && cols > 0)
+        {
+          obj.resize(rows,cols);
+
+          const tinyxml2::XMLAttribute* attribute = child->FindAttribute("matrix");
+          if(attribute != NULL)
+          {
+            std::string matTemp;
+            getAttribute(attribute->Value(),matTemp);
+
+            std::string line,srows,scols;
+            std::stringstream mats;
+            mats << matTemp;
+
+            int r=0;
+            std::string val;
+            // for each line
+            getline(mats,line);
+            while(getline(mats,line))
+            {
+              // get current line
+              std::stringstream liness(line);
+
+              for(unsigned int c=0;c<cols-1;c++)
+              {
+                // split line
+                getline(liness,val,',');
+
+                // push pack the data if any
+                if(!val.empty())
+                  getAttribute(val.c_str(),obj.coeffRef(r,c));
+              }
+
+              getline(liness,val);
+              getAttribute(val.c_str(),obj.coeffRef(r,cols-1));
+
+              r++;
+            }
+            initialized = true;
+          }
+        }
+      }
+
+      if(!initialized)
+      {
+        obj = Eigen::Matrix<T,R,C,P,MR,MC>();
+      }
+    }
+
+    template<typename T,int P,typename I>
+    IGL_INLINE void serialize(const Eigen::SparseMatrix<T,P,I>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+    {
+      tinyxml2::XMLElement* matrix = getElement(doc,element,name.c_str());
+
+      const unsigned int rows = obj.rows();
+      const unsigned int cols = obj.cols();
+
+      matrix->SetAttribute("rows",rows);
+      matrix->SetAttribute("cols",cols);
+
+      char buffer[200];
+      std::stringstream ms;
+      ms << "\n";
+      for(int k=0;k<obj.outerSize();++k)
+      {
+        for(typename Eigen::SparseMatrix<T,P,I>::InnerIterator it(obj,k);it;++it)
+        {
+          tinyxml2::XMLUtil::ToStr(it.value(),buffer,200);
+          ms << it.row() << "," << it.col() << "," << buffer << "\n";
+        }
+      }
+
+      std::string mString = ms.str();
+      if(mString.size() > 0)
+        mString[mString.size()-1] = '\0';
+
+      matrix->SetAttribute("matrix",mString.c_str());
+    }
+
+    template<typename T,int P,typename I>
+    IGL_INLINE void deserialize(Eigen::SparseMatrix<T,P,I>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+    {
+      const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+      bool initialized = false;
+      if(child != NULL)
+      {
+        const unsigned int rows = child->UnsignedAttribute("rows");
+        const unsigned int cols = child->UnsignedAttribute("cols");
+
+        if(rows > 0 && cols > 0)
+        {
+          obj.resize(rows,cols);
+          obj.setZero();
+
+          const tinyxml2::XMLAttribute* attribute = child->FindAttribute("matrix");
+          if(attribute != NULL)
+          {
+            std::string matTemp;
+            getAttribute(attribute->Value(),matTemp);
+
+            std::string line,srows,scols;
+            std::stringstream mats;
+            mats << matTemp;
+
+            std::vector<Eigen::Triplet<T,I> > triplets;
+            int r=0;
+            std::string val;
+
+            // for each line
+            getline(mats,line);
+            while(getline(mats,line))
+            {
+              // get current line
+              std::stringstream liness(line);
+
+              // row
+              getline(liness,val,',');
+              int row = atoi(val.c_str());
+              // col
+              getline(liness,val,',');
+              int col = atoi(val.c_str());
+              // val
+              getline(liness,val);
+              T value;
+              getAttribute(val.c_str(),value);
+
+              triplets.push_back(Eigen::Triplet<T,I>(row,col,value));
+
+              r++;
+            }
+
+            obj.setFromTriplets(triplets.begin(),triplets.end());
+            initialized = true;
+          }
+        }
+      }
+
+      if(!initialized)
+      {
+        obj = Eigen::SparseMatrix<T,P,I>();
+      }
+    }
+
+    // pointers
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+    {
+      tinyxml2::XMLElement* pointer = getElement(doc,element,name.c_str());
+
+      bool isNullPtr = (obj == NULL);
+
+      pointer->SetAttribute("isNullPtr",isNullPtr);
+
+      if(isNullPtr == false)
+        serialization_xml::serialize(*obj,doc,element,name);
+    }
+
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+    {
+      const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+      if(child != NULL)
+      {
+        bool isNullPtr = child->BoolAttribute("isNullPtr");
+
+        if(isNullPtr)
+        {
+          if(obj != NULL)
+          {
+            std::cout << "deserialization: possible memory leak for '" << typeid(obj).name() << "'" << std::endl;
+            obj = NULL;
+          }
+        }
+        else
+        {
+          if(obj != NULL)
+            std::cout << "deserialization: possible memory leak for '" << typeid(obj).name() << "'" << std::endl;
+
+          obj = new typename std::remove_pointer<T>::type();
+
+          serialization_xml::deserialize(*obj,doc,element,name);
+        }
+      }
+    }
+
+    // helper functions
+
+    IGL_INLINE tinyxml2::XMLElement* getElement(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+    {
+      tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+      if(child == NULL)
+      {
+        child = doc->NewElement(name.c_str());
+        element->InsertEndChild(child);
+      }
+      return child;
+    }
+
+    IGL_INLINE void getAttribute(const char* src,bool& dest)
+    {
+      tinyxml2::XMLUtil::ToBool(src,&dest);
+    }
+
+    IGL_INLINE void getAttribute(const char* src,char& dest)
+    {
+      dest = (char)atoi(src);
+    }
+
+    IGL_INLINE void getAttribute(const char* src,std::string& dest)
+    {
+      dest = src;
+    }
+
+    IGL_INLINE void getAttribute(const char* src,float& dest)
+    {
+      tinyxml2::XMLUtil::ToFloat(src,&dest);
+    }
+
+    IGL_INLINE void getAttribute(const char* src,double& dest)
+    {
+      tinyxml2::XMLUtil::ToDouble(src,&dest);
+    }
+
+    template<typename T>
+    IGL_INLINE typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value>::type getAttribute(const char* src,T& dest)
+    {
+      unsigned int val;
+      tinyxml2::XMLUtil::ToUnsigned(src,&val);
+      dest = (T)val;
+    }
+
+    template<typename T>
+    IGL_INLINE typename std::enable_if<std::is_integral<T>::value && !std::is_unsigned<T>::value>::type getAttribute(const char* src,T& dest)
+    {
+      int val;
+      tinyxml2::XMLUtil::ToInt(src,&val);
+      dest = (T)val;
+    }
+
+    // tinyXML2 related stuff
+    static const int numForbiddenChars = 8;
+    static const char forbiddenChars[] ={' ','/','~','#','&','>','<','='};
+
+    IGL_INLINE void replaceSubString(std::string& str,const std::string& search,const std::string& replace)
+    {
+      size_t pos = 0;
+      while((pos = str.find(search,pos)) != std::string::npos)
+      {
+        str.replace(pos,search.length(),replace);
+        pos += replace.length();
+      }
+    }
+
+    IGL_INLINE void encodeXMLElementName(std::string& name)
+    {
+      // must not start with a digit
+      if(isdigit(*name.begin()))
+      {
+        name = ":::" + name;
+      }
+
+      std::stringstream stream;
+      for(int i=0;i<numForbiddenChars;i++)
+      {
+        std::string search;
+        search = forbiddenChars[i];
+        std::stringstream replaces;
+        replaces << ":" << (int)forbiddenChars[i];
+        std::string replace = replaces.str();
+
+        replaceSubString(name,search,replace);
+      }
+    }
+
+    IGL_INLINE void decodeXMLElementName(std::string& name)
+    {
+      if(name.find("::",0) == 0)
+        name.replace(0,3,"");
+
+      for(auto chr : forbiddenChars)
+      {
+        std::stringstream searchs;
+        searchs << ":" << (int)chr;
+        std::string search = searchs.str();
+        std::string replace;
+        replace = chr;
+
+        replaceSubString(name,search,replace);
+      }
+    }
+
+   /* Copyright(C) 2004-2008 Ren� Nyffenegger
+
+      This source code is provided 'as-is',without any express or implied
+      warranty.In no event will the author be held liable for any damages
+      arising from the use of this software.
+
+      Permission is granted to anyone to use this software for any purpose,
+      including commercial applications,and to alter it and redistribute it
+      freely,subject to the following restrictions:
+
+      1. The origin of this source code must not be misrepresented; you must not
+      claim that you wrote the original source code.If you use this source code
+      in a product,an acknowledgment in the product documentation would be
+      appreciated but is not required.
+
+      2. Altered source versions must be plainly marked as such,and must not be
+      misrepresented as being the original source code.
+
+      3. This notice may not be removed or altered from any source distribution.
+
+      Ren� Nyffenegger rene.nyffenegger@adp-gmbh.ch
+      */
+
+    static const std::string base64_chars =
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+      "abcdefghijklmnopqrstuvwxyz"
+      "0123456789+/";
+
+    static inline bool is_base64(unsigned char c) {
+      return (isalnum(c) || (c == '+') || (c == '/'));
+    }
+
+    std::string base64_encode(unsigned char const* bytes_to_encode,unsigned int in_len)
+    {
+      std::string ret;
+      int i = 0;
+      int j = 0;
+      unsigned char char_array_3[3];
+      unsigned char char_array_4[4];
+
+      while(in_len--) {
+        char_array_3[i++] = *(bytes_to_encode++);
+        if(i == 3) {
+          char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+          char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+          char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+          char_array_4[3] = char_array_3[2] & 0x3f;
+
+          for(i = 0; (i <4) ; i++)
+            ret += base64_chars[char_array_4[i]];
+
+          i = 0;
+        }
+      }
+
+      if(i)
+      {
+        for(j = i; j < 3; j++)
+          char_array_3[j] = '\0';
+
+        char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+        char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+        char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+        char_array_4[3] = char_array_3[2] & 0x3f;
+
+        for(j = 0; (j < i + 1); j++)
+          ret += base64_chars[char_array_4[j]];
+
+        while((i++ < 3))
+          ret += '=';
+      }
+
+      return ret;
+    }
+
+    std::string base64_decode(std::string const& encoded_string)
+    {
+      int in_len = encoded_string.size();
+      int i = 0;
+      int j = 0;
+      int in_ = 0;
+      unsigned char char_array_4[4],char_array_3[3];
+      std::string ret;
+
+      // construct fast lookup table
+      // added by Christian Sch�ller (schuellc@inf.ethz.ch)
+      int charLookup[200];
+      for(int i=0;i<(int)(base64_chars.length());i++)
+        charLookup[(int)base64_chars[i]] = i;
+
+      while(in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
+        char_array_4[i++] = encoded_string[in_]; in_++;
+        if(i ==4) {
+          for(i = 0; i <4; i++)
+            char_array_4[i] = charLookup[char_array_4[i]]; // new fast lookup
+          //char_array_4[i] = base64_chars.find(char_array_4[i]); // original version
+
+          char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+          char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+          char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+          for(i = 0; (i < 3); i++)
+            ret += char_array_3[i];
+
+          i = 0;
+        }
+      }
+
+      if(i) {
+        for(j = i; j <4; j++)
+          char_array_4[j] = 0;
+
+        for(j = 0; j <4; j++)
+          char_array_4[j] = base64_chars.find(char_array_4[j]);
+
+        char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+        char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+        char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+        for(j = 0; (j < i - 1);
+          j++) ret += char_array_3[j];
+      }
+
+      return ret;
+    }
+  }
+}

+ 259 - 0
include/igl/xml/serialize_xml.h

@@ -0,0 +1,259 @@
+//
+// Copyright (C) 2014 Christian Sch�ller <schuellchr@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+// -----------------------------------------------------------------------------
+// Functions to save and load a serialization of fundamental c++ data types to
+// and from a xml file. STL containers, Eigen matrix types and nested data
+// structures are also supported. To serialize a user defined class implement
+// the interface XMLSerializable or XMLSerializableBase.
+//
+// See also: serialize.h
+// -----------------------------------------------------------------------------
+
+#ifndef IGL_SERIALIZABLE_XML_H
+#define IGL_SERIALIZABLE_XML_H
+
+#include "../igl_inline.h"
+
+#include <type_traits>
+#include <iostream>
+#include <vector>
+#include <set>
+#include <map>
+#include <memory>
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+#include <igl/serialize.h>
+
+#include "tinyxml2.h"
+
+//#define SERIALIZE_XML(x) igl::serialize_xml(x,#x,doc,element);
+//#define DESERIALIZE_XML(x) igl::deserialize_xml(x,#x,,doc,element);
+
+namespace igl
+{
+  // serializes the given object either to a xml file or to the provided doc data
+  //
+  // Templates:
+  //   T  type of the object to serialize
+  // Inputs:
+  //   obj        object to serialize
+  //   objectName unique object name,used for the identification
+  //   filename   name of the file containing the serialization
+  //   binary     set to true to serialize the object in binary format (faster for big data)
+  //   overwrite  set to true to overwrite an existing xml file
+  //   element    tinyxml2 virtual representation of the current xml node
+  // Outputs:
+  //   doc        contains current tinyxml2 virtual representation of the xml data
+  //
+  template <typename T>
+  IGL_INLINE void serialize_xml(const T& obj,const std::string& filename);
+  template <typename T>
+  IGL_INLINE void serialize_xml(const T& obj,const std::string& objectName,const std::string& filename, bool binary = false,bool overwrite = false);
+  template <typename T>
+  IGL_INLINE void serialize_xml(const T& obj,const std::string& objectName,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,bool binary = false);
+
+  // deserializes the given data from a xml file or doc data back to the provided object
+  //
+  // Templates:
+  //   T  type of the object to serialize
+  // Inputs:
+  //
+  //   objectName unique object name,used for the identification
+  //   filename   name of the file containing the serialization
+  //   binary     set to true to serialize the object in binary format (faster for big data)
+  //   overwrite  set to true to overwrite an existing xml file
+  //   doc        contains current tinyxml2 virtual representation of the xml data
+  //   element    tinyxml2 virtual representation of the current xml node
+  // Outputs:
+  //   obj        object to load back serialization to
+  //
+  template <typename T>
+  IGL_INLINE void deserialize_xml(T& obj,const std::string& filename);
+  template <typename T>
+  IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const std::string& filename);
+  template <typename T>
+  IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element);
+
+  // interface for user defined types
+  struct XMLSerializableBase : public SerializableBase
+  {
+    virtual void Serialize(std::vector<char>& buffer) const = 0;
+    virtual void Deserialize(const std::vector<char>& buffer) = 0;
+    virtual void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const = 0;
+    virtual void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element) = 0;
+  };
+
+  // Convenient interface for user defined types
+  class XMLSerializable: public XMLSerializableBase
+  {
+  private:
+
+    template <typename T>
+    struct XMLSerializationObject: public XMLSerializableBase
+    {
+      bool Binary;
+      std::string Name;
+      T* Object;
+
+      void Serialize(std::vector<char>& buffer) const {
+        igl::serialize(*Object,Name,buffer);
+      }
+
+      void Deserialize(const std::vector<char>& buffer) {
+        igl::deserialize(*Object,Name,buffer);
+      }
+
+      void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const {
+        igl::serialize_xml(*Object,Name,doc,element,Binary);
+      }
+
+      void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element) {
+        igl::deserialize_xml(*Object,Name,doc,element);
+      }
+    };
+
+    mutable bool initialized;
+    mutable std::vector<XMLSerializableBase*> objects;
+
+  public:
+
+    // Override this function to add your member variables which should be serialized
+    IGL_INLINE virtual void InitSerialization() = 0;
+
+    // Following functions can be overridden to handle the specific events.
+    // Return false to prevent the de-/serialization of an object.
+    IGL_INLINE virtual bool PreSerialization() const;
+    IGL_INLINE virtual void PostSerialization() const;
+    IGL_INLINE virtual bool PreDeserialization();
+    IGL_INLINE virtual void PostDeserialization();
+
+    // Default implementation of XMLSerializableBase interface
+    IGL_INLINE void Serialize(std::vector<char>& buffer) const;
+    IGL_INLINE void Deserialize(const std::vector<char>& buffer);
+    IGL_INLINE void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const;
+    IGL_INLINE void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element);
+
+    // Default constructor, destructor, assignment and copy constructor
+    IGL_INLINE XMLSerializable();
+    IGL_INLINE XMLSerializable(const XMLSerializable& obj);
+    IGL_INLINE ~XMLSerializable();
+    IGL_INLINE XMLSerializable& operator=(const XMLSerializable& obj);
+
+    // Use this function to add your variables which should be serialized
+    template <typename T>
+    IGL_INLINE void Add(T& obj,std::string name,bool binary = false);
+  };
+
+  // internal functions
+  namespace serialization_xml
+  {
+    // fundamental types
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    // std::string
+    IGL_INLINE void serialize(const std::string& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    IGL_INLINE void deserialize(std::string& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    // XMLSerializableBase
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_base_of<XMLSerializableBase,T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_base_of<XMLSerializableBase,T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    // STL containers
+    template <typename T1, typename T2>
+    IGL_INLINE void serialize(const std::pair<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template <typename T1,typename T2>
+    IGL_INLINE void deserialize(std::pair<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    template <typename T1,typename T2>
+    IGL_INLINE void serialize(const std::vector<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template <typename T1,typename T2>
+    IGL_INLINE void deserialize(std::vector<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    template <typename T>
+    IGL_INLINE void serialize(const std::set<T>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template <typename T>
+    IGL_INLINE void deserialize(std::set<T>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    template <typename T1,typename T2>
+    IGL_INLINE void serialize(const std::map<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template <typename T1,typename T2>
+    IGL_INLINE void deserialize(std::map<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    // Eigen types
+    template<typename T,int R,int C,int P,int MR,int MC>
+    IGL_INLINE void serialize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template<typename T,int R,int C,int P,int MR,int MC>
+    IGL_INLINE void deserialize(Eigen::Matrix<T,R,C,P,MR,MC>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    template<typename T,int P,typename I>
+    IGL_INLINE void serialize(const Eigen::SparseMatrix<T,P,I>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template<typename T,int P,typename I>
+    IGL_INLINE void deserialize(Eigen::SparseMatrix<T,P,I>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    // raw pointers
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template <typename T>
+    IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    // helper functions
+    tinyxml2::XMLElement* getElement(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    IGL_INLINE void getAttribute(const char* src,bool& dest);
+    IGL_INLINE void getAttribute(const char* scr,char& dest);
+    IGL_INLINE void getAttribute(const char* src,std::string& dest);
+    IGL_INLINE void getAttribute(const char* src,float& dest);
+    IGL_INLINE void getAttribute(const char* src,double& dest);
+    template<typename T>
+    IGL_INLINE typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value>::type getAttribute(const char* src,T& dest);
+    template<typename T>
+    IGL_INLINE typename std::enable_if<std::is_integral<T>::value && !std::is_unsigned<T>::value>::type getAttribute(const char* src,T& dest);
+    IGL_INLINE void replaceSubString(std::string& str,const std::string& search,const std::string& replace);
+    IGL_INLINE void encodeXMLElementName(std::string& name);
+    IGL_INLINE void decodeXMLElementName(std::string& name);
+    IGL_INLINE std::string base64_encode(unsigned char const* bytes_to_encode,unsigned int in_len);
+    IGL_INLINE std::string base64_decode(std::string const& encoded_string);
+
+    // compile time type serializable check
+    template <typename T>
+    struct is_stl_container { static const bool value = false; };
+    template <typename T1,typename T2>
+    struct is_stl_container<std::pair<T1,T2> > { static const bool value = true; };
+    template <typename T1,typename T2>
+    struct is_stl_container<std::vector<T1,T2> > { static const bool value = true; };
+    template <typename T>
+    struct is_stl_container<std::set<T> > { static const bool value = true; };
+    template <typename T1,typename T2>
+    struct is_stl_container<std::map<T1,T2> > { static const bool value = true; };
+
+    template <typename T>
+    struct is_eigen_type { static const bool value = false; };
+    template <typename T,int R,int C,int P,int MR,int MC>
+    struct is_eigen_type<Eigen::Matrix<T,R,C,P,MR,MC> > { static const bool value = true; };
+    template <typename T,int P,typename I>
+    struct is_eigen_type<Eigen::SparseMatrix<T,P,I> > { static const bool value = true; };
+
+    template <typename T>
+    struct is_serializable {
+      using T0 = typename  std::remove_pointer<T>::type;
+      static const bool value = std::is_fundamental<T0>::value || std::is_same<std::string,T0>::value || std::is_base_of<XMLSerializableBase,T0>::value
+        || is_stl_container<T0>::value || is_eigen_type<T0>::value;
+    };
+  }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+  #include "serialize_xml.cpp"
+#endif
+
+#endif

+ 3 - 3
index.html

@@ -16,13 +16,13 @@
 
 <figure>
 <img src="libigl-teaser.png" alt="" />
-<figcaption></figcaption></figure>
+</figure>
 
 <p><a href="https://github.com/libigl/libigl/">https://github.com/libigl/libigl/</a></p>
 
 <p>libigl is a simple C++ geometry processing library. We have a wide
 functionality including construction of sparse discrete differential geometry
-operators and finite-elements matrices such as the contangent Laplacian and
+operators and finite-elements matrices such as the cotangent Laplacian and
 diagonalized mass matrix, simple facet and edge-based topology data structures,
 mesh-viewing utilities for OpenGL and GLSL, and many core functions for matrix
 manipulation which make <a href="http://eigen.tuxfamily.org">Eigen</a> feel a lot more
@@ -163,7 +163,7 @@ Takayama, Leo Sacht, Wenzel Jacob, Nico Pietroni, Amir Vaxman</p>
 
 <figure>
 <img src="tutorial/images/libigl-logo.jpg" alt="" />
-<figcaption></figcaption></figure>
+</figure>
 
 </body>
 </html>

+ 9 - 0
scripts/update_gh-pages.sh

@@ -2,6 +2,7 @@
 # Usage: cd $LIBIGL; scripts/update_gh-pages.sh
 set -o xtrace
 git pull && git checkout gh-pages && git rebase master && git pull
+
 HEADER="title: libigl
 author: Alec Jacobson and Daniele Panozzo and others
 css: tutorial/style.css
@@ -11,9 +12,11 @@ html header:   <script type='text/javascript' src='http://cdn.mathjax.org/mathja
 <script>hljs.initHighlightingOnLoad();</script>
 
 "
+
 echo "$HEADER" \
   | cat - README.md | multimarkdown -o index.html && \
   git commit -m "update index.html to match README.md" README.md index.html
+
 HEADER="title: libigl
 author: Alec Jacobson and Daniele Panozzo and others
 css: ../tutorial/style.css
@@ -23,8 +26,14 @@ html header:   <script type='text/javascript' src='http://cdn.mathjax.org/mathja
 <script>hljs.initHighlightingOnLoad();</script>
 
 "
+
+echo "$HEADER" \
+  | cat - google-soc/google-soc.md | multimarkdown -o google-soc/index.html && \
+  git commit -m "update google-soc/index.html to match google-soc/google-soc.md" google-soc/google-soc.md google-soc/index.html 
+
 echo "$HEADER" \
   | cat - build/README.md | multimarkdown -o build/index.html && \
   git commit -m "update index.html to match README.md" build/README.md \
   build/index.html
+
 git push origin gh-pages && git checkout master && git merge gh-pages && git push

+ 1 - 0
tutorial/402_PolyharmonicDeformation/main.cpp

@@ -52,6 +52,7 @@ bool key_down(igl::Viewer &viewer, unsigned char key, int mods)
       resolve = true;
       break;
   }
+  return true;
 }
 
 int main(int argc, char *argv[])

+ 1 - 0
tutorial/403_BoundedBiharmonicWeights/main.cpp

@@ -111,6 +111,7 @@ bool key_down(igl::Viewer &viewer, unsigned char key, int mods)
       set_color(viewer);
       break;
   }
+  return true;
 }
 
 int main(int argc, char *argv[])

+ 1 - 1
tutorial/501_HarmonicParam/main.cpp

@@ -43,7 +43,7 @@ int main(int argc, char *argv[])
 
   // Harmonic parametrization for the internal vertices
   igl::harmonic(V,F,bnd,bnd_uv,1,V_uv);
-
+  
   // Scale UV to make the texture more clear
   V_uv *= 5;
 

+ 61 - 27
tutorial/601_Serialization/main.cpp

@@ -1,17 +1,15 @@
 #include <igl/readOFF.h>
 #include <iostream>
 
-#include <igl/xml/XMLSerializer.h>
-#include <igl/xml/XMLSerialization.h>
+#include <igl/serialize.h>
+#include <igl/xml/serialize_xml.h>
 
 Eigen::MatrixXd V;
 Eigen::MatrixXi F;
 
-class State : public ::igl::XMLSerialization
+// derive from igl::Serializable to serialize your own type
+struct State : public igl::Serializable
 {
-public:
-  State() : XMLSerialization("dummy") {}
-
   Eigen::MatrixXd V;
   Eigen::MatrixXi F;
   std::vector<int> ids;
@@ -20,39 +18,75 @@ public:
   // register the fields you want to serialize
   void InitSerialization()
   {
-    xmlSerializer->Add(V  , "V");
-    xmlSerializer->Add(F  , "F");
-    xmlSerializer->Add(ids, "ids");
+    this->Add(V  , "V");
+    this->Add(F  , "F");
+    this->Add(ids, "ids");
   }
-
 };
 
+// alternatively you can do it like the following to have
+// a non-intrusive serialization:
+//
+// struct State
+// {
+//   Eigen::MatrixXd V;
+//   Eigen::MatrixXi F;
+//   std::vector<int> ids;
+// };
+// 
+// SERIALIZE_TYPE(State,
+//  SERIALIZE_MEMBER(V)
+//   SERIALIZE_MEMBER(F)
+//   SERIALIZE_MEMBER_NAME(ids,"ids")
+// )
+
 int main(int argc, char *argv[])
 {
-  State state;
+  std::string binaryFile = "binData";
+  std::string xmlFile = "data.xml";
+
+  bool b = true;
+  unsigned int num = 10;
+  std::vector<float> vec = {0.1f,0.002f,5.3f};
+
+  // use overwrite = true for the first serialization to create or overwrite an existing file
+  igl::serialize(b,"B",binaryFile,true);
+  // append following serialization to existing file
+  igl::serialize(num,"Number",binaryFile);
+  igl::serialize(vec,"VectorName",binaryFile);
+
+  // deserialize back to variables
+  igl::deserialize(b,"B",binaryFile);
+  igl::deserialize(num,"Number",binaryFile);
+  igl::deserialize(vec,"VectorName",binaryFile);
+
+  State stateIn, stateOut;
 
   // Load a mesh in OFF format
-  igl::readOFF("../shared/2triangles.off", state.V, state.F);
+  igl::readOFF("../shared/2triangles.off",stateIn.V,stateIn.F);
 
   // Save some integers in a vector
-  state.ids.push_back(6);
-  state.ids.push_back(7);
+  stateIn.ids.push_back(6);
+  stateIn.ids.push_back(7);
 
-  // Serialize to XML the state of the application
-  ::igl::XMLSerializer serializer_save("601_Serialization");
-  serializer_save.Add(state,"State");
-  serializer_save.Save("temp.xml",true);
+  // Serialize the state of the application
+  igl::serialize(stateIn,"State",binaryFile,true);
 
-  // Load the state from the same XML file
-  State loaded_state;
-  ::igl::XMLSerializer serializer_load("601_Serialization");
-  serializer_load.Add(loaded_state,"State");
-  serializer_load.Load("temp.xml");
+  // Load the state from the same file
+  igl::deserialize(stateOut,"State",binaryFile);
 
   // Plot the state
-  std::cout << "Vertices: " << std::endl << loaded_state.V << std::endl;
-  std::cout << "Faces:    " << std::endl << loaded_state.F << std::endl;
+  std::cout << "Vertices: " << std::endl << stateOut.V << std::endl;
+  std::cout << "Faces:    " << std::endl << stateOut.F << std::endl;
   std::cout << "ids:      " << std::endl
-            << loaded_state.ids[0] << " " << loaded_state.ids[1] << std::endl;
-
+            << stateOut.ids[0] << " " << stateOut.ids[1] << std::endl;
+			
+  // XML serialization
+  
+  // binary = false, overwrite = true
+  igl::serialize_xml(vec,"VectorXML",xmlFile,false,true);
+  // binary = true, overwrite = false
+  igl::serialize_xml(vec,"VectorBin",xmlFile,true,false);
+  igl::deserialize_xml(vec,"VectorXML",xmlFile);
+  igl::deserialize_xml(vec,"VectorBin",xmlFile);
 }

+ 4 - 4
tutorial/701_Statistics/main.cpp

@@ -5,7 +5,7 @@
 
 #include <igl/is_irregular_vertex.h>
 #include <igl/doublearea.h>
-#include <igl/internal_angles.h>
+#include <igl/angles.h>
 
 int main(int argc, char *argv[])
 {
@@ -30,7 +30,7 @@ int main(int argc, char *argv[])
   VectorXd area;
   igl::doublearea(V,F,area);
   area = area.array() / 2;
-  
+
   double area_avg   = area.mean();
   double area_min   = area.minCoeff() / area_avg;
   double area_max   = area.maxCoeff() / area_avg;
@@ -42,12 +42,12 @@ int main(int argc, char *argv[])
   MatrixXd angles;
   igl::angles(V,F,angles);
   angles = 360.0 * (angles/(2*M_PI)); // Convert to degrees
-  
+
   double angle_avg   = angles.mean();
   double angle_min   = angles.minCoeff();
   double angle_max   = angles.maxCoeff();
   double angle_sigma = sqrt( (angles.array()-angle_avg).square().mean() );
-  
+
   printf("Angles in degrees (Min/Max) Sigma: \n%.2f/%.2f (%.2f)\n",angle_min,angle_max,angle_sigma);
 
 }

+ 7 - 2
tutorial/CMakeLists.shared

@@ -65,8 +65,13 @@ link_directories(
 
 # Disable deprecated opengl code from libigl
 add_definitions(-DIGL_OPENGL_4)
-add_definitions(-DNDEBUG)
-add_definitions(-O3)
+
+IF(CMAKE_BUILD_TYPE MATCHES RELEASE)
+    add_definitions(-DNDEBUG)
+ENDIF(CMAKE_BUILD_TYPE MATCHES RELEASE)
+
+#add_definitions(-DENABLE_XML_SERIALIZATION)
+
 
 
 if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")

+ 1 - 0
tutorial/cmake/FindEIGEN.cmake

@@ -66,6 +66,7 @@ else ()
       ${CMAKE_INSTALL_PREFIX}/include
       ${KDE4_INCLUDE_DIR}
 	  ${PROJECT_SOURCE_DIR}/../../../Eigen
+	  $ENV{DevLibraries}/Eigen
       PATH_SUFFIXES eigen3 eigen
     )
 

+ 12 - 10
tutorial/cmake/FindEMBREE.cmake

@@ -7,22 +7,24 @@
 # EMBREE_LIBRARIES       - Link these to use EMBREE
 #
 
-FIND_PATH(EMBREE_INCLUDE_DIR embree/include/embree.h
+FIND_PATH(EMBREE_INCLUDE_DIR embree2/rtcore.h
 	  PATHS
-		${PROJECT_SOURCE_DIR}/../../external/embree
-		${PROJECT_SOURCE_DIR}/../external/embree
+		${PROJECT_SOURCE_DIR}/../../external/embree/include
+		${PROJECT_SOURCE_DIR}/../external/embree/include
+		${PROJECT_SOURCE_DIR}/../libigl/external/embree/include
 		NO_DEFAULT_PATH
     )
 
-# message(FATAL_ERROR ${PROJECT_SOURCE_DIR}/../../external/embree)
+#message(FATAL_ERROR ${PROJECT_SOURCE_DIR}/../libigl/external/embree)
+#message(FATAL_ERROR ${EMBREE_INCLUDE_DIR})
 
-SET(SEARCH_PATHS "${EMBREE_INCLUDE_DIR}" "${EMBREE_INCLUDE_DIR}/build" "${EMBREE_INCLUDE_DIR}/lib")
+SET(SEARCH_PATHS "${EMBREE_INCLUDE_DIR}/../" "${EMBREE_INCLUDE_DIR}/../build" "${EMBREE_INCLUDE_DIR}/../lib")
 
-FIND_LIBRARY(EMBREE_CORE_LIBRARY  NAMES embree PATHS ${SEARCH_PATHS} PATH_SUFFIXES a lib)
-FIND_LIBRARY(EMBREE_CORE_LIBRARY2 NAMES device PATHS ${SEARCH_PATHS} PATH_SUFFIXES a lib)
+FIND_LIBRARY(EMBREE_CORE_LIBRARY  NAMES embree_sse42 PATHS ${SEARCH_PATHS} PATH_SUFFIXES a lib)
+FIND_LIBRARY(EMBREE_CORE_LIBRARY2 NAMES transport PATHS ${SEARCH_PATHS} PATH_SUFFIXES a lib)
 FIND_LIBRARY(EMBREE_CORE_LIBRARY3 NAMES image PATHS ${SEARCH_PATHS} PATH_SUFFIXES a lib)
 FIND_LIBRARY(EMBREE_CORE_LIBRARY4 NAMES lexers PATHS ${SEARCH_PATHS} PATH_SUFFIXES a lib)
-#FIND_LIBRARY(EMBREE_CORE_LIBRARY5 NAMES loaders PATHS ${SEARCH_PATHS} PATH_SUFFIXES a lib)
+FIND_LIBRARY(EMBREE_CORE_LIBRARY5 NAMES embree PATHS ${SEARCH_PATHS} PATH_SUFFIXES dylib a lib)
 FIND_LIBRARY(EMBREE_CORE_LIBRARY6 NAMES sys PATHS ${SEARCH_PATHS} PATH_SUFFIXES a lib)
 
 if(EMBREE_CORE_LIBRARY AND EMBREE_INCLUDE_DIR)
@@ -37,10 +39,10 @@ IF (EMBREE_FOUND)
    "${EMBREE_CORE_LIBRARY2}"
    "${EMBREE_CORE_LIBRARY3}"
    "${EMBREE_CORE_LIBRARY4}"
-   #"${EMBREE_CORE_LIBRARY5}"
+   "${EMBREE_CORE_LIBRARY5}"
    "${EMBREE_CORE_LIBRARY6}"
    )
    SET(EMBREE_INCLUDE_DIRS ${EMBREE_INCLUDE_DIR} ${EMBREE_INCLUDE_DIR}/embree)
 ELSE (EMBREE_FOUND)
-    message(STATUS "could NOT find EMBREE")
+    message(FATAL_ERROR "could NOT find EMBREE")
 ENDIF (EMBREE_FOUND)

+ 1 - 1
tutorial/tutorial.html.REMOVED.git-id

@@ -1 +1 @@
-2e5cd62765c38c507481d1880609faab4f97a9a9
+e7693c2b991564ae8692d7ec89a150095b200c32

+ 1 - 1
tutorial/tutorial.md.REMOVED.git-id

@@ -1 +1 @@
-fa82ad61f8b29ace7195ce6be520e1735648430e
+f044dd289d758fe26b21e0ae0fa9e27dafd3dc99