Explorar o código

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

Former-commit-id: 0d4a6668def28549fa8eff246f24cd3d23e15603
Daniele Panozzo %!s(int64=10) %!d(string=hai) anos
pai
achega
d4255d26d3

+ 1 - 0
RELEASE_HISTORY.txt

@@ -1,3 +1,4 @@
+1.1.3  Bug fixes in active set and boundary_conditions
 1.1.1  PLY file format support
 1.1.0  Mesh boolean operations using CGAL and cork, implementing [Attene 14]
 1.0.3  Bone heat method

+ 1 - 1
VERSION.txt

@@ -3,4 +3,4 @@
 # Anyone may increment Minor to indicate a small change.
 # Major indicates a large change or large number of changes (upload to website)
 # World indicates a substantial change or release
-1.1.2
+1.1.3

+ 39 - 22
include/igl/active_set.cpp

@@ -8,6 +8,7 @@
 #include "active_set.h"
 #include "min_quad_with_fixed.h"
 #include "slice.h"
+#include "slice_into.h"
 #include "cat.h"
 #include "matlab_format.h"
 
@@ -44,6 +45,9 @@ IGL_INLINE igl::SolverStatus igl::active_set(
   )
 {
 //#define ACTIVE_SET_CPP_DEBUG
+#ifdef ACTIVE_SET_CPP_DEBUG
+#  warning "ACTIVE_SET_CPP_DEBUG"
+#endif
   using namespace igl;
   using namespace Eigen;
   using namespace std;
@@ -259,39 +263,52 @@ IGL_INLINE igl::SolverStatus igl::active_set(
     }
 #endif
     
+    Eigen::PlainObjectBase<DerivedZ> sol;
+    if(known_i.size() == A.rows())
+    {
+      // Everything's fixed?
 #ifdef ACTIVE_SET_CPP_DEBUG
-    cout<<"  min_quad_with_fixed_precompute"<<endl;
+      cout<<"  everything's fixed."<<endl;
 #endif
-    if(!min_quad_with_fixed_precompute(A,known_i,Aeq_i,params.Auu_pd,data))
+      Z.resize(A.rows(),Y_i.cols());
+      slice_into(Y_i,known_i,1,Z);
+      sol.resize(0,Y_i.cols());
+      assert(Aeq_i.rows() == 0 && "All fixed but linearly constrained");
+    }else
     {
-      cerr<<"Error: min_quad_with_fixed precomputation failed."<<endl;
-      if(iter > 0 && Aeq_i.rows() > Aeq.rows())
+#ifdef ACTIVE_SET_CPP_DEBUG
+      cout<<"  min_quad_with_fixed_precompute"<<endl;
+#endif
+      if(!min_quad_with_fixed_precompute(A,known_i,Aeq_i,params.Auu_pd,data))
       {
-        cerr<<"  *Are you sure rows of [Aeq;Aieq] are linearly independent?*"<<
-          endl;
+        cerr<<"Error: min_quad_with_fixed precomputation failed."<<endl;
+        if(iter > 0 && Aeq_i.rows() > Aeq.rows())
+        {
+          cerr<<"  *Are you sure rows of [Aeq;Aieq] are linearly independent?*"<<
+            endl;
+        }
+        ret = SOLVER_STATUS_ERROR;
+        break;
       }
-      ret = SOLVER_STATUS_ERROR;
-      break;
-    }
 #ifdef ACTIVE_SET_CPP_DEBUG
-    cout<<"  min_quad_with_fixed_solve"<<endl;
+      cout<<"  min_quad_with_fixed_solve"<<endl;
 #endif
-    Eigen::PlainObjectBase<DerivedZ> sol;
-    if(!min_quad_with_fixed_solve(data,B,Y_i,Beq_i,Z,sol))
-    {
-      cerr<<"Error: min_quad_with_fixed solve failed."<<endl;
-      ret = SOLVER_STATUS_ERROR;
-      break;
-    }
-    //cout<<matlab_format((Aeq*Z-Beq).eval(),"cr")<<endl;
-    //cout<<matlab_format(Z,"Z")<<endl;
+      if(!min_quad_with_fixed_solve(data,B,Y_i,Beq_i,Z,sol))
+      {
+        cerr<<"Error: min_quad_with_fixed solve failed."<<endl;
+        ret = SOLVER_STATUS_ERROR;
+        break;
+      }
+      //cout<<matlab_format((Aeq*Z-Beq).eval(),"cr")<<endl;
+      //cout<<matlab_format(Z,"Z")<<endl;
 #ifdef ACTIVE_SET_CPP_DEBUG
-    cout<<"  post"<<endl;
+      cout<<"  post"<<endl;
 #endif
+      // Computing Lagrange multipliers needs to be adjusted slightly if A is not symmetric
+      assert(data.Auu_sym);
+    }
 
     // Compute Lagrange multiplier values for known_i
-    // This needs to be adjusted slightly if A is not symmetric
-    assert(data.Auu_sym);
     SparseMatrix<AT> Ak;
     // Slow
     slice(A,known_i,1,Ak);

+ 4 - 4
include/igl/bbw/bbw.cpp

@@ -104,11 +104,11 @@ IGL_INLINE bool igl::bbw(
     {
       case QP_SOLVER_IGL_ACTIVE_SET:
       {
-        //if(data.verbosity >= 1)
-        //{
+        if(data.verbosity >= 1)
+        {
           cout<<"BBW: max_iter: "<<data.active_set_params.max_iter<<endl;
-          cout<<"BBW: max_iter: "<<eff_params.max_iter<<endl;
-        //}
+          cout<<"BBW: eff_max_iter: "<<eff_params.max_iter<<endl;
+        }
         if(data.verbosity >= 1)
         {
           cout<<"BBW: Computing initial weights for "<<m<<" handle"<<

+ 4 - 4
include/igl/boolean/mesh_boolean.cpp

@@ -1,5 +1,5 @@
 #include "mesh_boolean.h"
-#include <igl/peal_outer_hull_layers.h>
+#include <igl/peel_outer_hull_layers.h>
 #include <igl/cgal/remesh_self_intersections.h>
 #include <igl/remove_unreferenced.h>
 #include <igl/unique_simplices.h>
@@ -169,13 +169,13 @@ IGL_INLINE void igl::mesh_boolean(
   }
 
 #ifdef IGL_MESH_BOOLEAN_DEBUG
-  cout<<"peal..."<<endl;
+  cout<<"peel..."<<endl;
 #endif
   Matrix<bool,Dynamic,1> from_A(CF.rows());
-  // Peal layers keeping track of odd and even flips
+  // peel layers keeping track of odd and even flips
   Matrix<bool,Dynamic,1> odd;
   Matrix<bool,Dynamic,1> flip;
-  peal_outer_hull_layers(CV,CF,odd,flip);
+  peel_outer_hull_layers(CV,CF,odd,flip);
 
 #ifdef IGL_MESH_BOOLEAN_DEBUG
   cout<<"categorize..."<<endl;

+ 2 - 4
include/igl/boundary_conditions.cpp

@@ -35,10 +35,9 @@ IGL_INLINE bool igl::boundary_conditions(
     return false;
   }
 
-
   vector<int> bci;
   vector<int> bcj;
-  vector<int> bcv;
+  vector<double> bcv;
 
   // loop over points
   for(int p = 0;p<P.size();p++)
@@ -95,7 +94,6 @@ IGL_INLINE bool igl::boundary_conditions(
     }
   }
 
-  // Cage edges are not considered yet
   // loop over cage edges
   for(int e = 0;e<CE.rows();e++)
   {
@@ -153,7 +151,7 @@ IGL_INLINE bool igl::boundary_conditions(
   for(i = 0;i<bc.rows();i++)
   {
     double sum = bc.row(i).sum();
-    assert(sum != 0);
+    assert(sum != 0 && "Some boundary vertex getting all zero BCs");
     bc.row(i).array() /= sum;
   }
 

+ 1 - 7
include/igl/boundary_loop.cpp

@@ -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());
 
           newBndEdge = false;
-          if (unvisited[vPrev] && TT(fid,(vLoc+2) % F.cols()) < 0)
-          {
-            next = vPrev;
-            newBndEdge = true;
-          }
-          else if (unvisited[vNext] && TT(fid,vLoc) < 0)
+          if (unvisited[vNext] && TT(fid,vLoc) < 0)
           {
             next = vNext;
             newBndEdge = true;

+ 1 - 1
include/igl/doublearea.cpp

@@ -124,7 +124,7 @@ IGL_INLINE void igl::doublearea(
   sort(ul,2,false,l,_);
   // semiperimeters
   Matrix<typename Derivedl::Scalar,Dynamic,1> s = l.rowwise().sum()*0.5;
-  assert(s.rows() == m);
+  assert((size_t)s.rows() == m);
   // resize output
   dblA.resize(l.rows(),1);
   // Minimum number of iterms per openmp thread

+ 4 - 3
include/igl/facet_components.cpp

@@ -13,7 +13,8 @@ IGL_INLINE void igl::facet_components(
   vector<vector<vector<Index > > > TT;
   vector<vector<vector<Index > > > TTi;
   triangle_triangle_adjacency(F,TT,TTi);
-  return facet_components(TT,C);
+  Eigen::VectorXi counts;
+  return facet_components(TT,C,counts);
 }
 
 template <
@@ -68,9 +69,9 @@ IGL_INLINE void igl::facet_components(
     }
     id++;
   }
-  assert(id == vcounts.size());
+  assert((size_t) id == vcounts.size());
   const size_t ncc = vcounts.size();
-  assert(C.maxCoeff()+1 == ncc);
+  assert((size_t)C.maxCoeff()+1 == ncc);
   counts.resize(ncc,1);
   for(size_t i = 0;i<ncc;i++)
   {

+ 1 - 0
include/igl/min_quad_with_fixed.cpp

@@ -96,6 +96,7 @@ IGL_INLINE bool igl::min_quad_with_fixed_precompute(
 
   SparseMatrix<T> Auu;
   slice(A,data.unknown,data.unknown,Auu);
+  assert(Auu.size() > 0 && "All DOFs seem to be fixed.");
 
   // Positive definiteness is *not* determined, rather it is given as a
   // parameter

+ 15 - 10
include/igl/peal_outer_hull_layers.cpp → include/igl/peel_outer_hull_layers.cpp

@@ -1,16 +1,19 @@
-#include "peal_outer_hull_layers.h"
+#include "peel_outer_hull_layers.h"
 #include "outer_hull.h"
 #include "writePLY.h"
 #include <vector>
 #include <iostream>
-//#define IGL_PEAL_OUTER_HULL_LAYERS_DEBUG
+//#define IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
+#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
+#include "STR.h"
+#endif
 
 template <
   typename DerivedV,
   typename DerivedF,
   typename Derivedodd,
   typename Derivedflip>
-IGL_INLINE void igl::peal_outer_hull_layers(
+IGL_INLINE size_t igl::peel_outer_hull_layers(
   const Eigen::PlainObjectBase<DerivedV > & V,
   const Eigen::PlainObjectBase<DerivedF > & F,
   Eigen::PlainObjectBase<Derivedodd > & odd,
@@ -23,11 +26,11 @@ IGL_INLINE void igl::peal_outer_hull_layers(
   typedef Matrix<Index,Dynamic,1> MatrixXI;
   typedef Matrix<typename Derivedflip::Scalar,Dynamic,Derivedflip::ColsAtCompileTime> MatrixXflip;
   const Index m = F.rows();
-#ifdef IGL_PEAL_OUTER_HULL_LAYERS_DEBUG
-  cout<<"peal outer hull layers..."<<endl;
+#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
+  cout<<"peel outer hull layers..."<<endl;
 #endif
 
-#ifdef IGL_PEAL_OUTER_HULL_LAYERS_DEBUG
+#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
   cout<<"resize output ..."<<endl;
 #endif
   // keep track of iteration parity and whether flipped in hull
@@ -47,12 +50,13 @@ IGL_INLINE void igl::peal_outer_hull_layers(
     MatrixXF Fo;
     MatrixXI Jo;
     MatrixXflip flipr;
-#ifdef IGL_PEAL_OUTER_HULL_LAYERS_DEBUG
+#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
   cout<<"calling outer hull..."<<endl;
-  writePLY("outer-hull-input.ply",V,Fr);
+  writePLY(STR("outer-hull-input-"<<iter<<".ply"),V,Fr);
 #endif
     outer_hull(V,Fr,Fo,Jo,flipr);
-#ifdef IGL_PEAL_OUTER_HULL_LAYERS_DEBUG
+#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
+  writePLY(STR("outer-hull-output-"<<iter<<".ply"),V,Fo);
   cout<<"reindex, flip..."<<endl;
 #endif
     assert(Fo.rows() == Jo.rows());
@@ -86,10 +90,11 @@ IGL_INLINE void igl::peal_outer_hull_layers(
     odd_iter = !odd_iter;
     iter++;
   }
+  return iter;
 }
 
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template specialization
-template void igl::peal_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<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> >&);
 #endif

+ 9 - 8
include/igl/peal_outer_hull_layers.h → include/igl/peel_outer_hull_layers.h

@@ -1,27 +1,28 @@
-#ifndef PEAL_OUTER_HULL_LAYERS_H
-#define PEAL_OUTER_HULL_LAYERS_H
+#ifndef PEEL_OUTER_HULL_LAYERS_H
+#define PEEL_OUTER_HULL_LAYERS_H
 #include "igl_inline.h"
 #include <Eigen/Core>
 namespace igl
 {
   // Computes necessary generic information for boolean operations by
-  // successively "pealing" off the "outer hull" of a mesh (V,F) resulting from
+  // successively "peeling" off the "outer hull" of a mesh (V,F) resulting from
   // "resolving" all (self-)intersections.
   //
   // Inputs:
   //   V  #V by 3 list of vertex positions
   //   F  #F by 3 list of triangle indices into V
   // Outputs:
-  //   odd  #F list of whether facet belongs to an odd iteration peal (otherwise
-  //     an even iteration peal)
+  //   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
-  //     "pealed" into its associated outer hull layer.
+  //     "peeled" into its associated outer hull layer.
+  // Returns number of peels
   template <
     typename DerivedV,
     typename DerivedF,
     typename Derivedodd,
     typename Derivedflip>
-  IGL_INLINE void peal_outer_hull_layers(
+  IGL_INLINE size_t peel_outer_hull_layers(
     const Eigen::PlainObjectBase<DerivedV > & V,
     const Eigen::PlainObjectBase<DerivedF > & F,
     Eigen::PlainObjectBase<Derivedodd > & odd,
@@ -29,6 +30,6 @@ namespace igl
 }
 
 #ifndef IGL_STATIC_LIBRARY
-#  include "peal_outer_hull_layers.cpp"
+#  include "peel_outer_hull_layers.cpp"
 #endif
 #endif

+ 248 - 162
include/igl/serialize.cpp

@@ -22,24 +22,6 @@ namespace igl
     
     std::vector<char> buffer;
 
-    // open existing file for updating objects
-    /*if(overwrite == false)
-    {
-      std::ifstream file(filename.c_str(),std::ios::binary);
-
-      if(file.is_open())
-      {
-        file.seekg(0,std::ios::end);
-        int size = file.tellg();
-        file.seekg(0,std::ios::beg);
-
-        buffer.resize(size);
-        file.read(&buffer[0],size);
-
-        file.close();
-      }
-    }*/
-
     std::ios_base::openmode mode = std::ios::out | std::ios::binary;
 
     if(overwrite)
@@ -70,88 +52,29 @@ namespace igl
   template <typename T>
   IGL_INLINE bool serialize(const T& obj,const std::string& objectName,std::vector<char>& buffer)
   {
-    static_assert(detail::is_serializable<T>::value,"'igl::serialize': type is not serializable");
-
     // serialize object data
-    size_t size = detail::getByteSize(obj);
+    size_t size = serialization::getByteSize(obj);
     std::vector<char> tmp(size);
-    std::vector<char>::iterator it = tmp.begin();
-    detail::serialize(obj,tmp,it);
+    auto it = tmp.begin();
+    serialization::serialize(obj,tmp,it);
 
     std::string objectType(typeid(obj).name());
     size_t newObjectSize = tmp.size();
-    size_t newHeaderSize = detail::getByteSize(objectName) + detail::getByteSize(objectType) + sizeof(size_t);
-//    size_t oldObjectSize = 0;
-//    size_t oldHeaderSize = 0;
-
-    // find object header to replace existing object
-    /*std::vector<char>::const_iterator citer = buffer.cbegin();
-    while(citer != buffer.cend())
-    {
-      std::vector<char>::const_iterator citerTemp = citer;
-
-      std::string name;
-      std::string type;
-      detail::deserialize(name,citer);
-      detail::deserialize(type,citer);
-      detail::deserialize(oldObjectSize,citer);
-
-      if(name == objectName)
-      {
-        if(type != typeid(obj).raw_name())
-          std::cout << "object " + objectName + " was overwriten with different data type!" << std::endl;
-
-        oldHeaderSize = citer - citerTemp;
-        citer = citerTemp;
-        break;
-      }
-      else
-        citer+=oldObjectSize;
-    }
-
-    std::vector<char>::iterator iter = buffer.begin() + (citer-buffer.cbegin());
-    if(iter != buffer.end())
-    {
-      std::vector<char>::iterator iterEndPart = iter+oldHeaderSize+oldObjectSize;
-      size_t startPartSize = iter - buffer.begin();
-      size_t endPartSize = buffer.end()-iterEndPart;
-
-      // copy end part of buffer
-      std::vector<char> endPartBuffer(endPartSize);
-      std::copy(iterEndPart,buffer.end(),endPartBuffer.begin());
-
-      size_t newSize = startPartSize + newHeaderSize + newObjectSize + endPartSize;
-      buffer.resize(newSize);
-      iter = buffer.begin() + startPartSize;
-
-      // serialize object header (name/type/size)
-      detail::serialize(objectName,buffer,iter);
-      detail::serialize(objectType,buffer,iter);
-      detail::serialize(newObjectSize,buffer,iter);
-
-      // copy serialized data to buffer
-      iter = std::copy(tmp.begin(),tmp.end(),iter);
+    size_t newHeaderSize = serialization::getByteSize(objectName) + serialization::getByteSize(objectType) + sizeof(size_t);
+    size_t curSize = buffer.size();
+    size_t newSize = curSize + newHeaderSize + newObjectSize;
 
-      // copy back end part of buffer
-      std::copy(endPartBuffer.begin(),endPartBuffer.end(),iter);
-    }
-    else*/
-    {
-      size_t curSize = buffer.size();
-      size_t newSize = curSize + newHeaderSize + newObjectSize;
-
-      buffer.resize(newSize);
+    buffer.resize(newSize);
 
-      std::vector<char>::iterator iter = buffer.begin()+curSize;
+    std::vector<char>::iterator iter = buffer.begin()+curSize;
 
-      // serialize object header (name/type/size)
-      detail::serialize(objectName,buffer,iter);
-      detail::serialize(objectType,buffer,iter);
-      detail::serialize(newObjectSize,buffer,iter);
+    // 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);
-    }
+    // copy serialized data to buffer
+    iter = std::copy(tmp.begin(),tmp.end(),iter);
 
     return true;
   }
@@ -194,21 +117,19 @@ namespace igl
   template <typename T>
   IGL_INLINE bool deserialize(T& obj,const std::string& objectName,const std::vector<char>& buffer)
   {   
-    static_assert(detail::is_serializable<T>::value,"'igl::deserialize': type is not deserializable");
-
     bool success = false;
 
     // find suitable object header
-    std::vector<char>::const_iterator objectIter = buffer.end();
-    std::vector<char>::const_iterator iter = buffer.begin();
+    auto objectIter = buffer.cend();
+    auto iter = buffer.cbegin();
     while(iter != buffer.end())
     {
       std::string name;
       std::string type;
       size_t size;
-      detail::deserialize(name,iter);
-      detail::deserialize(type,iter);
-      detail::deserialize(size,iter);
+      serialization::deserialize(name,iter);
+      serialization::deserialize(type,iter);
+      serialization::deserialize(size,iter);
 
       if(name == objectName && type == typeid(obj).name())
       {
@@ -221,7 +142,7 @@ namespace igl
 
     if(objectIter != buffer.end())
     {
-      detail::deserialize(obj,objectIter);
+      serialization::deserialize(obj,objectIter);
       success = true;
     }
     else
@@ -232,6 +153,25 @@ namespace igl
     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;
@@ -261,8 +201,10 @@ namespace igl
         initialized = true;
       }
 
-      for(unsigned int i=0;i<objects.size();i++)
-        objects[i]->Serialize(buffer);
+      for(const auto& v : objects)
+      {
+        v->Serialize(buffer);
+      }
 
       this->PostSerialization();
     }
@@ -279,9 +221,11 @@ namespace igl
         initialized = true;
       }
 
-      for(unsigned int i=0;i<objects.size();i++)
-        objects[i]->Deserialize(buffer);
-
+      for(auto& v : objects)
+      {
+        v->Deserialize(buffer);
+      }
+          
       this->PostDeserialization();
     }
   }
@@ -319,16 +263,54 @@ namespace igl
   template <typename T>
   IGL_INLINE void Serializable::Add(T& obj,std::string name,bool binary)
   {
-    SerializationObject<T>* object = new SerializationObject<T>();
+    auto object = new SerializationObject<T>();
     object->Binary = binary;
     object->Name = name;
-    object->Object = &obj;
+    object->Object = std::unique_ptr<T>(&obj);
 
     objects.push_back(object);
   }
 
-  namespace detail
+  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>
@@ -340,6 +322,7 @@ namespace igl
     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);
     }
@@ -361,19 +344,22 @@ namespace igl
 
     IGL_INLINE void serialize(const std::string& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
     {
-      detail::serialize(obj.length(),buffer,iter);
-      for(const auto& cur : obj) { detail::serialize(cur,buffer,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;
-      detail::deserialize(size,iter);
+      serialization::deserialize(size,iter);
 
       std::string str(size,'\0');
       for(size_t i=0; i<size; ++i)
       {
-        detail::deserialize(str.at(i),iter);
+        serialization::deserialize(str.at(i),iter);
       }
 
       obj = str;
@@ -396,7 +382,7 @@ namespace igl
 
       // size
       size_t size = buffer.size();
-      detail::serialize(tmp.size(),buffer,iter);
+      serialization::serialize(tmp.size(),buffer,iter);
       size_t cur = iter - buffer.begin();
 
       buffer.resize(size+tmp.size());
@@ -408,7 +394,7 @@ namespace igl
     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;
-      detail::deserialize(size,iter);
+      serialization::deserialize(size,iter);
 
       std::vector<char> tmp;
       tmp.resize(size);
@@ -431,15 +417,15 @@ namespace igl
     template <typename T1,typename T2>
     IGL_INLINE void serialize(const std::pair<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
     {
-      detail::serialize(obj.first,buffer,iter);
-      detail::serialize(obj.second,buffer,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)
     {
-      detail::deserialize(obj.first,iter);
-      detail::deserialize(obj.second,iter);
+      serialization::deserialize(obj.first,iter);
+      serialization::deserialize(obj.second,iter);
     }
 
     // std::vector
@@ -454,10 +440,10 @@ namespace igl
     IGL_INLINE void serialize(const std::vector<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
     {
       size_t size = obj.size();
-      detail::serialize(size,buffer,iter);
+      serialization::serialize(size,buffer,iter);
       for(const auto& cur : obj)
       {
-        detail::serialize(cur,buffer,iter);
+        serialization::serialize(cur,buffer,iter);
       }
     }
 
@@ -465,12 +451,12 @@ namespace igl
     IGL_INLINE void deserialize(std::vector<T1,T2>& obj,std::vector<char>::const_iterator& iter)
     {
       size_t size;
-      detail::deserialize(size,iter);
+      serialization::deserialize(size,iter);
 
       obj.resize(size);
-      for(size_t i=0; i<size; ++i)
+      for(auto& v : obj)
       {
-        detail::deserialize(obj[i],iter);
+        serialization::deserialize(v,iter);
       }
     }
 
@@ -485,21 +471,24 @@ namespace igl
     template <typename T>
     IGL_INLINE void serialize(const std::set<T>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
     {
-      detail::serialize(obj.size(),buffer,iter);
-      for(const auto& cur : obj) { detail::serialize(cur,buffer,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;
-      detail::deserialize(size,iter);
+      serialization::deserialize(size,iter);
 
       obj.clear();
       for(size_t i=0; i<size; ++i)
       {
         T val;
-        detail::deserialize(val,iter);
+        serialization::deserialize(val,iter);
         obj.insert(val);
       }
     }
@@ -515,21 +504,24 @@ namespace igl
     template <typename T1,typename T2>
     IGL_INLINE void serialize(const std::map<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
     {
-      detail::serialize(obj.size(),buffer,iter);
-      for(const auto& cur : obj) { detail::serialize(cur,buffer,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;
-      detail::deserialize(size,iter);
+      serialization::deserialize(size,iter);
 
       obj.clear();
       for(size_t i=0; i<size; ++i)
       {
         std::pair<T1,T2> pair;
-        detail::deserialize(pair,iter);
+        serialization::deserialize(pair,iter);
         obj.insert(pair);
       }
     }
@@ -545,10 +537,10 @@ namespace igl
     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)
     {
-      detail::serialize(obj.rows(),buffer,iter);
-      detail::serialize(obj.cols(),buffer,iter);
+      serialization::serialize(obj.rows(),buffer,iter);
+      serialization::serialize(obj.cols(),buffer,iter);
       size_t size = sizeof(T)*obj.rows()*obj.cols();
-      const uint8_t* ptr = reinterpret_cast<const uint8_t*>(obj.data());
+      auto ptr = reinterpret_cast<const uint8_t*>(obj.data());
       iter = std::copy(ptr,ptr+size,iter);
     }
 
@@ -556,11 +548,11 @@ namespace igl
     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;
-      detail::deserialize(rows,iter);
-      detail::deserialize(cols,iter);
+      serialization::deserialize(rows,iter);
+      serialization::deserialize(cols,iter);
       size_t size = sizeof(T)*rows*cols;
       obj.resize(rows,cols);
-      uint8_t* ptr = reinterpret_cast<uint8_t*>(obj.data());
+      auto ptr = reinterpret_cast<uint8_t*>(obj.data());
       std::copy(iter,iter+size,ptr);
       iter+=size;
     }
@@ -576,17 +568,17 @@ namespace igl
     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)
     {
-      detail::serialize(obj.rows(),buffer,iter);
-      detail::serialize(obj.cols(),buffer,iter);
-      detail::serialize(obj.nonZeros(),buffer,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)
         {
-          detail::serialize(it.row(),buffer,iter);
-          detail::serialize(it.col(),buffer,iter);
-          detail::serialize(it.value(),buffer,iter);
+          serialization::serialize(it.row(),buffer,iter);
+          serialization::serialize(it.col(),buffer,iter);
+          serialization::serialize(it.value(),buffer,iter);
         }
       }
     }
@@ -595,9 +587,9 @@ namespace igl
     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;
-      detail::deserialize(rows,iter);
-      detail::deserialize(cols,iter);
-      detail::deserialize(nonZeros,iter);
+      serialization::deserialize(rows,iter);
+      serialization::deserialize(cols,iter);
+      serialization::deserialize(nonZeros,iter);
 
       obj.resize(rows,cols);
       obj.setZero();
@@ -606,10 +598,10 @@ namespace igl
       for(int i=0;i<nonZeros;i++)
       {
         typename Eigen::SparseMatrix<T,P,I>::Index rowId,colId;
-        detail::deserialize(rowId,iter);
-        detail::deserialize(colId,iter);
+        serialization::deserialize(rowId,iter);
+        serialization::deserialize(colId,iter);
         T value;
-        detail::deserialize(value,iter);
+        serialization::deserialize(value,iter);
         triplets.push_back(Eigen::Triplet<T,I>(rowId,colId,value));
       }
       obj.setFromTriplets(triplets.begin(),triplets.end());
@@ -620,11 +612,9 @@ namespace igl
     template <typename T>
     IGL_INLINE typename std::enable_if<std::is_pointer<T>::value,size_t>::type getByteSize(const T& obj)
     {
-      bool isNullPtr = (obj == NULL);
-
       size_t size = sizeof(bool);
 
-      if(isNullPtr == false)
+      if(obj)
         size += getByteSize(*obj);
 
       return size;
@@ -633,38 +623,134 @@ namespace igl
     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)
     {
-      bool isNullPtr = (obj == NULL);
-
-      detail::serialize(isNullPtr,buffer,iter);
+      serialization::serialize(obj == nullptr,buffer,iter);
 
-      if(isNullPtr == false)
-        detail::serialize(*obj,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;
-      detail::deserialize(isNullPtr,iter);
+      serialization::deserialize(isNullPtr,iter);
 
       if(isNullPtr)
       {
-        if(obj != NULL)
+        if(obj)
         {
           std::cout << "deserialization: possible memory leak for '" << typeid(obj).name() << "'" << std::endl;
-          obj = NULL;
+          obj = nullptr;
         }
       }
       else
       {
-        if(obj != NULL)
+        if(obj)
           std::cout << "deserialization: possible memory leak for '" << typeid(obj).name() << "'" << std::endl;
 
-        obj = new typename std::remove_pointer<T>::type();
+        obj = new 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());
+    }
 
-        detail::deserialize(*obj,iter);
+    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)
+    {
+      static_assert(false,"type is not serializable: derive from igl::Serializable or overload the function igl::serialization::serialize(const T& obj,std::vector<char>& buffer)");
+    }
+
+    template <typename T>
+    IGL_INLINE void deserialize(T& obj,const std::vector<char>& buffer)
+    {
+      static_assert(false,"type is not serializable: derive from igl::Serializable or overload the function igl::serialization::deserialize(const T& obj,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)
+    {
+      // 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);
+      }
+    }
   }
 }

+ 133 - 34
include/igl/serialize.h

@@ -13,7 +13,8 @@
 // See also: xml/serialize_xml.h
 // -----------------------------------------------------------------------------
 // TODOs:
-// * loops of pointers and from multiple objects
+// * non-intrusive serialization example
+// * arbitrary pointer graph structures
 // * cross-platform compatibility (big-, little-endian)
 // -----------------------------------------------------------------------------
 
@@ -28,17 +29,33 @@
 #include <vector>
 #include <set>
 #include <map>
+#include <memory>
+#include <cstdint>
 
 #include <Eigen/Dense>
 #include <Eigen/Sparse>
 
 #include "igl_inline.h"
 
-//#define SERIALIZE(x) igl::serialize(x,#x,buffer);
-//#define DESERIALIZE(x) igl::deserialize(x,#x,buffer);
+// 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:
@@ -76,11 +93,39 @@ namespace igl
   template <typename T>
   IGL_INLINE bool deserialize(T& obj,const std::string& objectName,const std::vector<char>& buffer);
 
-  // User defined types have to derive from the class Serializable
-  // and add their member variables in InitSerialization like the
-  // following:
+  // 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 Test : public igl::Serializable {
+  // class UserType : public igl::Serializable {
   //
   //   int var;
   //
@@ -106,13 +151,13 @@ namespace igl
     {
       bool Binary;
       std::string Name;
-      T* Object;
+      std::unique_ptr<T> Object;
 
-      void Serialize(std::vector<char>& buffer) const {
+      void Serialize(std::vector<char>& buffer) const override {
         igl::serialize(*Object,Name,buffer);
       }
 
-      void Deserialize(const std::vector<char>& buffer) {
+      void Deserialize(const std::vector<char>& buffer) override {
         igl::deserialize(*Object,Name,buffer);
       }
     };
@@ -133,8 +178,8 @@ namespace igl
     IGL_INLINE virtual void PostDeserialization();
 
     // Default implementation of SerializableBase interface
-    IGL_INLINE void Serialize(std::vector<char>& buffer) const;
-    IGL_INLINE void Deserialize(const std::vector<char>& buffer);
+    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();
@@ -147,9 +192,63 @@ namespace igl
     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 detail
+  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);
@@ -169,7 +268,7 @@ namespace igl
     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);
+    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
@@ -219,7 +318,7 @@ namespace igl
     template<typename T,int P,typename I>
     IGL_INLINE void deserialize(Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>::const_iterator& iter);
 
-    // pointers
+    // 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>
@@ -227,31 +326,31 @@ namespace igl
     template <typename T>
     IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);
 
-    // compile time type serializable check
+    // 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>
-    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; };
+    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>
-    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; };
+    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>
-    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; };
+    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>
-    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<SerializableBase,T0>::value
-        || is_stl_container<T0>::value || is_eigen_type<T0>::value;
-    };
+    IGL_INLINE void updateMemoryMap(T& obj,size_t size,std::map<std::uintptr_t,IndexedPointerBase*>& memoryMap);
   }
 }
 

+ 53 - 57
include/igl/viewer/Viewer.cpp

@@ -65,11 +65,16 @@
 #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 {
 void TW_CALL copy_str(std::string& dst, const std::string& src)
@@ -109,9 +114,7 @@ static void glfw_error_callback(int error, const char* description)
   fputs(description, stderr);
 }
 
-int global_KMod = 0;
-
-int TwEventKeyGLFW3(int glfwKey, int glfwAction)
+IGL_INLINE int TwEventKeyGLFW3(int glfwKey, int glfwAction)
 {
   int handled = 0;
 
@@ -318,7 +321,7 @@ static void glfw_char_callback(GLFWwindow* window, unsigned int c)
 
 namespace igl
 {
-  void Viewer::init()
+  IGL_INLINE void Viewer::init()
   {
     // Create a tweak bar
     bar = TwNewBar("libIGL-Viewer");
@@ -329,8 +332,10 @@ namespace igl
 
     // ---------------------- LOADING ----------------------
 
+    #ifdef ENABLE_SERIALIZATION
     TwAddButton(bar,"Load Scene", load_scene_cb,    this, "group='Workspace'");
     TwAddButton(bar,"Save Scene", save_scene_cb,    this, "group='Workspace'");
+    #endif
 
     #ifdef ENABLE_IO
     TwAddButton(bar,"Load Mesh",  open_dialog_mesh, this, "group='Mesh' key=o");
@@ -411,7 +416,7 @@ namespace igl
     init_plugins();
   }
 
-  Viewer::Viewer()
+  IGL_INLINE Viewer::Viewer()
   {
 
     // Temporary variables initialization
@@ -445,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);
 
@@ -534,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);
 
@@ -575,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))
@@ -585,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))
@@ -618,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))
@@ -666,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;
 
@@ -683,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)
     {
@@ -750,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;
 
@@ -772,7 +779,7 @@ namespace igl
     return true;
   }
 
-  void Viewer::draw()
+  IGL_INLINE void Viewer::draw()
   {
     using namespace std;
     using namespace Eigen;
@@ -800,48 +807,32 @@ namespace igl
     TwDraw();
   }
 
-  bool Viewer::save_scene()
+  IGL_INLINE bool Viewer::save_scene()
   {
     std::string fname = igl::file_dialog_save();
     if (fname.length() == 0)
       return false;
 
-#ifdef ENABLE_XML_SERIALIZATION
-    
-    igl::serialize_xml(core,"Core",fname.c_str(),false,false);
-    igl::serialize_xml(data,"Data",fname.c_str(),false,true);
+#ifdef ENABLE_SERIALIZATION
 
-    for(unsigned int i = 0; i <plugins.size(); ++i)
-      igl::serialize_xml(*plugins[i],plugins[i]->plugin_name,fname.c_str(),false,true);
-#else
-
-    igl::serialize(core,"Core",fname.c_str(),false);
-    igl::serialize(data,"Data",fname.c_str(),true);
+    igl::serialize(core,"Core",fname.c_str(),true);
+    igl::serialize(data,"Data",fname.c_str());
 
     for(unsigned int i = 0; i <plugins.size(); ++i)
-      igl::serialize(*plugins[i],plugins[i]->plugin_name,fname.c_str(),true);
+      igl::serialize(*plugins[i],plugins[i]->plugin_name,fname.c_str());
 
 #endif
 
     return true;
   }
 
-  bool Viewer::load_scene()
+  IGL_INLINE bool Viewer::load_scene()
   {
     std::string fname = igl::file_dialog_open();
     if (fname.length() == 0)
       return false;
 
-#ifdef ENABLE_XML_SERIALIZATION
-    
-    igl::deserialize_xml(core,"Core",fname.c_str());
-    igl::deserialize_xml(data,"Data",fname.c_str());
-
-    for(unsigned int i = 0; i <plugins.size(); ++i)
-      igl::deserialize_xml(*plugins[i],plugins[i]->plugin_name,fname.c_str());
-
-
-#else
+#ifdef ENABLE_SERIALIZATION
 
     igl::deserialize(core,"Core",fname.c_str());
     igl::deserialize(data,"Data",fname.c_str());
@@ -854,57 +845,57 @@ namespace igl
     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);
   }
 
-  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();
 
@@ -914,7 +905,7 @@ namespace igl
     static_cast<Viewer *>(clientData)->load_mesh_from_file(fname.c_str());
   }
 
-  int Viewer::launch(std::string filename)  
+  IGL_INLINE int Viewer::launch(std::string filename)
   {
     GLFWwindow* window;
 
@@ -971,7 +962,12 @@ namespace igl
     __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;

+ 16 - 16
include/igl/viewer/Viewer.h

@@ -38,8 +38,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;
@@ -52,8 +52,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;
@@ -81,28 +81,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

+ 69 - 52
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,55 +96,72 @@ Eigen::Matrix4f translate(
   return Result;
 }
 
+#ifdef ENABLE_SERIALIZATION
+#include <igl/serialize.h>
+namespace igl {
+  namespace serialization {
 
-void igl::ViewerCore::InitSerialization()
-{
-  Add(shininess, "shininess");
-  
-  Add(background_color, "background_color");
-  Add(line_color, "line_color");
-  
-  Add(light_position, "light_position");
-  Add(lighting_factor, "lighting_factor");
-  
-  Add(trackball_angle, "trackball_angle");
-  
-  Add(model_zoom, "model_zoom");
-  Add(model_translation, "model_translation");
-  
-  Add(model_zoom_uv, "model_zoom_uv");
-  Add(model_translation_uv, "model_translation_uv");
-  
-  Add(object_scale, "object_scale");
-  
-  Add(camera_zoom, "camera_zoom");
-  Add(orthographic, "orthographic");
-  Add(camera_view_angle, "camera_view_angle");
-  Add(camera_dnear, "camera_dnear");
-  Add(camera_dfar, "camera_dfar");
-  Add(camera_eye, "camera_eye");
-  Add(camera_center, "camera_center");
-  Add(camera_up, "camera_up");
-  
-  Add(show_faces, "show_faces");
-  Add(show_lines, "show_lines");
-  Add(invert_normals, "invert_normals");
-  Add(show_overlay, "show_overlay");
-  Add(show_overlay_depth, "show_overlay_depth");
-  Add(show_vertid, "show_vertid");
-  Add(show_faceid, "show_faceid");
-  Add(show_texture, "show_texture");
-  
-  Add(point_size, "point_size");
-  Add(line_width, "line_width");
-  Add(is_animating, "is_animating");
-  Add(animation_max_fps, "animation_max_fps");
-  
-  Add(viewport, "viewport");
-  Add(view, "view");
-  Add(model, "model");
-  Add(proj, "proj");
+    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);
+    }
+
+    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,

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

@@ -14,12 +14,6 @@
 #include <igl/viewer/ViewerData.h>
 #include <igl/viewer/OpenGL_state.h>
 
-#ifdef ENABLE_XML_SERIALIZATION
-  #include <igl/xml/serialize_xml.h>
-#else
-  #include <igl/serialize.h>
-#endif
-
 namespace igl
 {
 
@@ -27,11 +21,6 @@ namespace igl
 // TODO: write documentation
 
 class ViewerCore
-#ifdef ENABLE_XML_SERIALIZATION
-  : public igl::XMLSerializable
-#else
-  : public igl::Serializable
-#endif
 {
 public:
   IGL_INLINE ViewerCore();

+ 50 - 38
include/igl/viewer/ViewerData.cpp

@@ -12,50 +12,62 @@
 #include <igl/per_vertex_normals.h>
 #include <iostream>
 
+#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()
-{  
-  Add(V,"V");
-  Add(F,"F");
-  
-  Add(F_normals,"F_normals");
-
-  Add(F_material_ambient,"F_material_ambient");
-  Add(F_material_diffuse,"F_material_diffuse");
-  Add(F_material_specular,"F_material_specular");
-
-  Add(V_normals,"V_normals");
-  
-  Add(V_material_ambient,"V_material_ambient");
-  Add(V_material_diffuse,"V_material_diffuse");
-  Add(V_material_specular,"V_material_specular");
-
-  Add(V_uv,"V_uv");
-  Add(F_uv,"F_uv");
-  
-  Add(texture_R,"texture_R");
-  Add(texture_G,"texture_G");
-  Add(texture_B,"texture_B");
-
-  Add(lines,"lines");
-  Add(points,"points");
-
-  Add(labels_positions,"labels_positions");
-  Add(labels_strings,"labels_strings");
-
-  Add(face_based,"face_based");
-}
-
-IGL_INLINE void igl::ViewerData::PostDeserialization()
-{
-  dirty = DIRTY_ALL;
-}
-
 IGL_INLINE void igl::ViewerData::set_face_based(bool newvalue)
 {
   if (face_based != newvalue)

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

@@ -12,23 +12,12 @@
 #include <igl/igl_inline.h>
 #include <Eigen/Core>
 
-#ifdef ENABLE_XML_SERIALIZATION
-  #include <igl/xml/serialize_xml.h>
-#else
-  #include <igl/serialize.h>
-#endif
-
 namespace igl
 {
 
 // TODO: write documentation
 
 class ViewerData
-#ifdef ENABLE_XML_SERIALIZATION
-  : public igl::XMLSerializable
-#else
-  : public igl::Serializable
-#endif
 {
 public:
   ViewerData();
@@ -103,10 +92,6 @@ public:
   // Generates a default grid texture
   IGL_INLINE void grid_texture();
 
-  // Serialization code
-  IGL_INLINE void InitSerialization();
-  IGL_INLINE void PostDeserialization();
-
   Eigen::MatrixXd V; // Vertices of the current mesh (#V x 3)
   Eigen::MatrixXi F; // Faces of the mesh (#F x 3)
 
@@ -159,7 +144,6 @@ public:
   /*********************************/
 };
 
-
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 30 - 18
include/igl/viewer/ViewerPlugin.h

@@ -10,18 +10,13 @@
 // * 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/serialize_xml.h>
-#else
-  #include <igl/serialize.h>
-#endif
-
 namespace igl
 {
 
@@ -39,11 +34,6 @@ namespace igl
 class Viewer;
 
 class ViewerPlugin
-#ifdef ENABLE_XML_SERIALIZATION
-  : public igl::XMLSerializable
-#else
-  : public igl::Serializable
-#endif
 {
 public:
   IGL_INLINE ViewerPlugin()
@@ -51,11 +41,6 @@ public:
 
   virtual ~ViewerPlugin(){}
 
-  // This is a interface function for the serialization
-  IGL_INLINE virtual void InitSerialization()
-  {
-  }
-
   // This function is called when the viewer is initialized (no mesh will be loaded at this stage)
   IGL_INLINE virtual void init(igl::Viewer *_viewer)
   {
@@ -79,6 +64,18 @@ public:
     return false;
   }
 
+  // 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()
   {
@@ -129,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;
   }
@@ -147,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 - 13
include/igl/xml/serialize_xml.cpp

@@ -52,10 +52,10 @@ namespace igl
   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(detail_xml::is_serializable<T>::value,"'igl::serialize_xml': type is not serializable");
+    static_assert(serialization_xml::is_serializable<T>::value,"'igl::serialize_xml': type is not serializable");
 
     std::string name(objectName);
-    detail_xml::encodeXMLElementName(name);
+    serialization_xml::encodeXMLElementName(name);
 
     tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
     
@@ -69,15 +69,15 @@ namespace igl
     {
       std::vector<char> buffer;
       serialize(obj,name,buffer);
-      std::string data = detail_xml::base64_encode(reinterpret_cast<const unsigned char*>(buffer.data()),buffer.size());
+      std::string data = serialization_xml::base64_encode(reinterpret_cast<const unsigned char*>(buffer.data()),buffer.size());
       
       child->SetAttribute("binary",true);
 
-      detail_xml::serialize(data,doc,element,name);
+      serialization_xml::serialize(data,doc,element,name);
     }
     else
     {
-      detail_xml::serialize(obj,doc,element,name);
+      serialization_xml::serialize(obj,doc,element,name);
     }
   }
 
@@ -119,10 +119,10 @@ namespace igl
   template <typename T>
   IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element)
   {
-    static_assert(detail::is_serializable<T>::value,"'igl::deserialize_xml': type is not deserializable");
+    static_assert(serialization::is_serializable<T>::value,"'igl::deserialize_xml': type is not deserializable");
 
     std::string name(objectName);
-    detail_xml::encodeXMLElementName(name);
+    serialization_xml::encodeXMLElementName(name);
 
     const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
     if(child != NULL)
@@ -132,8 +132,8 @@ namespace igl
       if(attr != NULL)
       {
         std::string code;
-        detail_xml::deserialize(code,doc,element,name);
-        std::string decoded = detail_xml::base64_decode(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));
@@ -142,7 +142,7 @@ namespace igl
       }
       else
       {
-        detail_xml::deserialize(obj,doc,element,name);
+        serialization_xml::deserialize(obj,doc,element,name);
       }
     }
   }
@@ -279,7 +279,7 @@ namespace igl
     objects.push_back(object);
   }
 
-  namespace detail_xml
+  namespace serialization_xml
   {
     // fundamental types
 
@@ -704,7 +704,7 @@ namespace igl
       pointer->SetAttribute("isNullPtr",isNullPtr);
 
       if(isNullPtr == false)
-        detail_xml::serialize(*obj,doc,element,name);
+        serialization_xml::serialize(*obj,doc,element,name);
     }
 
     template <typename T>
@@ -730,7 +730,7 @@ namespace igl
 
           obj = new typename std::remove_pointer<T>::type();
 
-          detail_xml::deserialize(*obj,doc,element,name);
+          serialization_xml::deserialize(*obj,doc,element,name);
         }
       }
     }

+ 3 - 2
include/igl/xml/serialize_xml.h

@@ -23,6 +23,7 @@
 #include <vector>
 #include <set>
 #include <map>
+#include <memory>
 
 #include <Eigen/Dense>
 #include <Eigen/Sparse>
@@ -150,7 +151,7 @@ namespace igl
   };
 
   // internal functions
-  namespace detail_xml
+  namespace serialization_xml
   {
     // fundamental types
     template <typename T>
@@ -200,7 +201,7 @@ namespace igl
     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);
 
-    // pointers
+    // 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>

+ 21 - 4
tutorial/601_Serialization/main.cpp

@@ -7,6 +7,7 @@
 Eigen::MatrixXd V;
 Eigen::MatrixXi F;
 
+// derive from igl::Serializable to serialize your own type
 struct State : public igl::Serializable
 {
   Eigen::MatrixXd V;
@@ -23,6 +24,22 @@ struct State : public igl::Serializable
   }
 };
 
+// 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[])
 {
   std::string binaryFile = "binData";
@@ -32,9 +49,9 @@ int main(int argc, char *argv[])
   unsigned int num = 10;
   std::vector<float> vec = {0.1f,0.002f,5.3f};
 
-  // use overwrite = true for first serialization to create a new file
+  // use overwrite = true for the first serialization to create or overwrite an existing file
   igl::serialize(b,"B",binaryFile,true);
-  // appends serialization to existing file
+  // append following serialization to existing file
   igl::serialize(num,"Number",binaryFile);
   igl::serialize(vec,"VectorName",binaryFile);
 
@@ -46,7 +63,7 @@ int main(int argc, char *argv[])
   State stateIn, stateOut;
 
   // Load a mesh in OFF format
-  igl::readOFF("../../shared/2triangles.off",stateIn.V,stateIn.F);
+  igl::readOFF("../shared/2triangles.off",stateIn.V,stateIn.F);
 
   // Save some integers in a vector
   stateIn.ids.push_back(6);
@@ -55,7 +72,7 @@ int main(int argc, char *argv[])
   // Serialize the state of the application
   igl::serialize(stateIn,"State",binaryFile,true);
 
-  // Load the state from the same XML file
+  // Load the state from the same file
   igl::deserialize(stateOut,"State",binaryFile);
 
   // Plot the state

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

@@ -1 +1 @@
-65f03843aee5fa051933483e51bc0a045058efeb
+f044dd289d758fe26b21e0ae0fa9e27dafd3dc99