Selaa lähdekoodia

Added new serialize function
Modified xml serialization
Updated Embree ray intersection checks
Updateded LIM
Various bug fixes


Former-commit-id: 52e7231ceeabb90a9626c85194c88b42b138c931

schuellc 10 vuotta sitten
vanhempi
commit
4cfcce85bf

+ 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());

+ 272 - 102
include/igl/embree/EmbreeIntersector.h

@@ -5,19 +5,21 @@
 // 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 +31,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 +44,7 @@ namespace igl
     inline EmbreeIntersector & operator=(const EmbreeIntersector &);
   public:
     virtual inline ~EmbreeIntersector();
-      
+    
     // Initialize with a given mesh.
     //
     // Inputs:
@@ -53,11 +53,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 +79,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 = -1,
+      int mask = 0xFFFFFFFF) const;
+
+    // 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 = embree::inf) const;
+      float tfar = -1,
+      int mask = 0xFFFFFFFF,
+      int geoId = -1,
+      bool closestHit = true) const;
 
-    // Given a ray find the all hits in order
+    // 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 = -1,
+      int mask = 0xFFFFFFFF) const;
 
     // Given a ray find the first hit
     // 
@@ -103,14 +147,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 +187,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 +205,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 +265,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);
+  
+  // 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)
+  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 +362,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,25 +428,26 @@ 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.primID = -1;
     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;
+        std::cerr<<"  t_push: "<<t_push<<endl;
 #endif
         //o = o+t_push*d;
         min_t += t_push;
@@ -309,13 +456,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 +472,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 +506,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 +526,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

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

@@ -14,6 +14,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
   };

+ 455 - 0
include/igl/serialize.cpp

@@ -0,0 +1,455 @@
+// 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/.
+// ---------------------------------------------------------------------------
+// serialize.h
+// author: Christian Schüller <schuellchr@gmail.com>
+// -----------------------------------------------------------------------------
+#include "serialize.h"
+
+namespace igl
+{
+  template <typename T>
+  void serialize(const T& obj,const std::string& filename)
+  {
+    std::ofstream fout(filename.c_str(),std::ios::out | std::ios::binary);
+    
+    if(fout.is_open())
+    {
+      std::vector<char> buffer;
+      serialize(obj,"obj",buffer);
+
+      fout.write(&buffer[0],buffer.size());
+
+      fout.close();
+    }
+    else
+    {
+      std::cerr << "Saving binary serialization failed!" << std::endl; 
+    }
+  }
+
+  template <typename T>
+  void 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);
+    std::vector<char> tmp(size);
+    detail::serialize(obj,tmp,tmp.begin());
+   
+    std::string objectType(typeid(obj).name());
+
+    size_t curSize = buffer.size();
+    size_t objSize = tmp.size();
+    size_t newSize = curSize + detail::getByteSize(objectName) + detail::getByteSize(objectType) + sizeof(size_t)+objSize;
+
+    buffer.resize(newSize);
+
+    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(objSize,buffer,iter);
+
+    // copy serilized data to buffer
+    iter = std::copy(tmp.begin(),tmp.end(),iter);
+  }
+
+  template <typename T>
+  void deserialize(T& obj,const std::string& filename)
+  {
+    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);
+      
+      std::vector<char> buffer(size);
+      file.read(&buffer[0],size);
+      
+      deserialize(obj,"obj",buffer);
+      file.close();
+    }
+    else
+    {
+      std::cerr << "Loading binary serialization failed!" << std::endl;
+    }
+  }
+
+  template <typename T>
+  void 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");
+    
+    // find suitable object header
+    std::vector<char>::const_iterator iter = buffer.begin();
+    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);
+      
+      if(name == objectName && type == typeid(obj).name())
+        break;
+      else
+        iter+=size;
+    }
+
+    if(iter != buffer.end())
+      detail::deserialize(obj,iter);
+    else
+      obj = T();
+  }
+
+  namespace detail
+  {
+    // fundamental types
+
+    template <typename T>
+    typename std::enable_if_t<std::is_fundamental<T>::value,size_t> getByteSize(const T& obj)
+    {
+      return sizeof(T);
+    }
+
+    template <typename T>
+    std::enable_if_t<std::is_fundamental<T>::value> serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+      const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&obj);
+      iter = std::copy(ptr,ptr+sizeof(T),iter);
+    }
+
+    template <typename T>
+    std::enable_if_t<std::is_fundamental<T>::value> 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
+
+    size_t getByteSize(const std::string& obj)
+    {
+      return getByteSize(obj.length())+obj.length()*sizeof(uint8_t);
+    }
+
+    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); }
+    }
+
+    void deserialize(std::string& obj,std::vector<char>::const_iterator& iter)
+    {
+      size_t size;
+      detail::deserialize(size,iter);
+
+      std::string str(size,'\0');
+      for(size_t i=0; i<size; ++i)
+      {
+        detail::deserialize(str.at(i),iter);
+      }
+
+      obj = str;
+    }
+
+    // Serializable
+
+    template <typename T>
+    typename std::enable_if_t<std::is_base_of<Serializable,T>::value,size_t> getByteSize(const T& obj)
+    {
+      return sizeof(std::vector<char>::size_type);
+    }
+
+    template <typename T>
+    std::enable_if_t<std::is_base_of<Serializable,T>::value> 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();
+      detail::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>
+    std::enable_if_t<std::is_base_of<Serializable,T>::value> deserialize(T& obj,std::vector<char>::const_iterator& iter)
+    {
+      std::vector<char>::size_type size;
+      detail::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>
+    size_t getByteSize(const std::pair<T1,T2>& obj)
+    {
+      return getByteSize(obj.first)+getByteSize(obj.second);
+    }
+
+    template <typename T1,typename T2>
+    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);
+    }
+
+    template <typename T1,typename T2>
+    void deserialize(std::pair<T1,T2>& obj,std::vector<char>::const_iterator& iter)
+    {
+      detail::deserialize(obj.first,iter);
+      detail::deserialize(obj.second,iter);
+    }
+
+    // std::vector
+
+    template <typename T1,typename T2>
+    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>
+    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);
+      for(const auto& cur : obj)
+      {
+        detail::serialize(cur,buffer,iter);
+      }
+    }
+
+    template <typename T1,typename T2>
+    void deserialize(std::vector<T1,T2>& obj,std::vector<char>::const_iterator& iter)
+    {
+      size_t size;
+      detail::deserialize(size,iter);
+
+      obj.resize(size);
+      for(size_t i=0; i<size; ++i)
+      {
+        detail::deserialize(obj[i],iter);
+      }
+    }
+
+    //std::set
+
+    template <typename T>
+    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>
+    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); }
+    }
+
+    template <typename T>
+    void deserialize(std::set<T>& obj,std::vector<char>::const_iterator& iter)
+    {
+      size_t size;
+      detail::deserialize(size,iter);
+
+      obj.clear();
+      for(size_t i=0; i<size; ++i)
+      {
+        T val;
+        detail::deserialize(val,iter);
+        obj.insert(val);
+      }
+    }
+
+    // std::map
+
+    template <typename T1,typename T2>
+    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>
+    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); }
+    }
+
+    template <typename T1,typename T2>
+    void deserialize(std::map<T1,T2>& obj,std::vector<char>::const_iterator& iter)
+    {
+      size_t size;
+      detail::deserialize(size,iter);
+
+      obj.clear();
+      for(size_t i=0; i<size; ++i)
+      {
+        std::pair<T1,T2> pair;
+        detail::deserialize(pair,iter);
+        obj.insert(pair);
+      }
+    }
+
+    // Eigen types
+    template<typename T,int R,int C,int P,int MR,int MC>
+    size_t getByteSize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj)
+    {
+      // space for numbers of rows,cols and data
+      return 2*sizeof(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>
+    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);
+      size_t size = sizeof(T)*obj.rows()*obj.cols();
+      const uint8_t* 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>
+    void deserialize(Eigen::Matrix<T,R,C,P,MR,MC>& obj,std::vector<char>::const_iterator& iter)
+    {
+      Eigen::Matrix<T,R,C,P,MR,MC>::Index rows,cols;
+      detail::deserialize(rows,iter);
+      detail::deserialize(cols,iter);
+      size_t size = sizeof(T)*rows*cols;
+      obj.resize(rows,cols);
+      uint8_t* ptr = reinterpret_cast<uint8_t*>(obj.data());
+      std::copy(iter,iter+size,ptr);
+      iter+=size;
+    }
+
+    template<typename T,int P,typename I>
+    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>
+    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);
+
+      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);
+        }
+      }
+    }
+
+    template<typename T,int P,typename I>
+    void deserialize(Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>::const_iterator& iter)
+    {
+      Eigen::SparseMatrix<T,P,I>::Index rows,cols,nonZeros;
+      detail::deserialize(rows,iter);
+      detail::deserialize(cols,iter);
+      detail::deserialize(nonZeros,iter);
+
+      obj.resize(rows,cols);
+      obj.setZero();
+
+      std::vector<Eigen::Triplet<T,I> > triplets;
+      for(int i=0;i<nonZeros;i++)
+      {
+        Eigen::SparseMatrix<T,P,I>::Index rowId,colId;
+        detail::deserialize(rowId,iter);
+        detail::deserialize(colId,iter);
+        T value;
+        detail::deserialize(value,iter);
+        triplets.push_back(Eigen::Triplet<T,I>(rowId,colId,value));
+      }
+      obj.setFromTriplets(triplets.begin(),triplets.end());
+    }
+
+    // pointers
+
+    template <typename T>
+    std::enable_if_t<std::is_pointer<T>::value,size_t> getByteSize(const T& obj)
+    {
+      bool isNullPtr = (obj == NULL);
+
+      size_t size = sizeof(bool);
+
+      if(isNullPtr == false)
+        size += getByteSize(*obj);
+
+      return size;
+    }
+
+    template <typename T>
+    std::enable_if_t<std::is_pointer<T>::value> serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+    {
+      bool isNullPtr = (obj == NULL);
+
+      detail::serialize(isNullPtr,buffer,iter);
+
+      if(isNullPtr == false) 
+        detail::serialize(*obj,buffer,iter);
+    }
+
+    template <typename T>
+    std::enable_if_t<std::is_pointer<T>::value> deserialize(T& obj,std::vector<char>::const_iterator& iter)
+    {
+      bool isNullPtr;
+      detail::deserialize(isNullPtr,iter);
+
+      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 std::remove_pointer<T>::type();
+
+        detail::deserialize(*obj,iter);
+      }
+    }
+  }
+}

+ 204 - 0
include/igl/serialize.h

@@ -0,0 +1,204 @@
+// 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/.
+// ---------------------------------------------------------------------------
+// serialize.h
+// author: Christian Schüller <schuellchr@gmail.com>
+// -----------------------------------------------------------------------------
+// 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.
+//
+// See also: xml/serialize_xml.h
+// -----------------------------------------------------------------------------
+// TODOs:
+// * loops of pointers and from multiple objects
+// * cross-platform compatibility (big-, little-endian)
+// -----------------------------------------------------------------------------
+
+#ifndef IGL_SERIALIZE_H
+#define IGL_SERIALIZE_H
+
+#include <type_traits>
+#include <iostream>
+#include <numeric>
+#include <vector>
+#include <set>
+#include <map>
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+//#define SERIALIZE(x) igl::serialize(x,#x,buffer);
+//#define DESERIALIZE(x) igl::deserialize(x,#x,buffer);
+
+namespace igl
+{
+
+  // 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
+  //   filename   name of the file containing the serialization
+  // Outputs: 
+  //   buffer     binary serialization
+  //
+  template <typename T>
+  void serialize(const T& obj,const std::string& filename);
+  template <typename T>
+  void 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>
+  void deserialize(T& obj,const std::string& filename);
+  template <typename T>
+  void deserialize(T& obj,const std::string& objectName,const std::vector<char>& buffer);
+
+  // interface for user defined types
+  struct Serializable
+  {
+    virtual void Serialize(std::vector<char>& buffer) const = 0;
+    virtual void Deserialize(const std::vector<char>& buffer) = 0;
+  };
+  // example:
+  //
+  // class Test : public igl::Serializable {
+  //   
+  //   int var;
+  // 
+  //   void Serialize(std::vector<char>& buffer) {
+  //     serialize(var,"var1",buffer);
+  //   }
+  //   void Deserialize(const std::vector<char>& buffer) {
+  //     deserialize(var,"var1",buffer);
+  //   }
+  // }
+
+  // internal functions
+  namespace detail
+  {
+    // fundamental types
+    template <typename T>
+    std::enable_if_t<std::is_fundamental<T>::value,size_t> getByteSize(const T& obj);
+    template <typename T>
+    std::enable_if_t<std::is_fundamental<T>::value> serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T>
+    std::enable_if_t<std::is_fundamental<T>::value> deserialize(T& obj,std::vector<char>::const_iterator& iter);
+
+    // std::string
+    size_t getByteSize(const std::string& obj);
+    void serialize(const std::string& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    void deserialize(std::string& obj,std::vector<char>::iterator& iter);
+
+    // Serializable
+    template <typename T>
+    std::enable_if_t<std::is_base_of<Serializable,T>::value,size_t> getByteSize(const T& obj);
+    template <typename T>
+    std::enable_if_t<std::is_base_of<Serializable,T>::value> serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T>
+    std::enable_if_t<std::is_base_of<Serializable,T>::value> deserialize(T& obj,std::vector<char>::const_iterator& iter);
+
+    // stl containers
+    // std::pair
+    template <typename T1,typename T2>
+    size_t getByteSize(const std::pair<T1,T2>& obj);
+    template <typename T1,typename T2>
+    void serialize(const std::pair<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T1,typename T2>
+    void deserialize(std::pair<T1,T2>& obj,std::vector<char>::const_iterator& iter);
+
+    // std::vector
+    template <typename T1,typename T2>
+    size_t getByteSize(const std::vector<T1,T2>& obj);
+    template <typename T1,typename T2>
+    void serialize(const std::vector<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T1,typename T2>
+    void deserialize(std::vector<T1,T2>& obj,std::vector<char>::const_iterator& iter);
+
+    // std::set
+    template <typename T>
+    size_t getByteSize(const std::set<T>& obj);
+    template <typename T>
+    void serialize(const std::set<T>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T>
+    void deserialize(std::set<T>& obj,std::vector<char>::const_iterator& iter);
+
+    // std::map
+    template <typename T1,typename T2>
+    size_t getByteSize(const std::map<T1,T2>& obj);
+    template <typename T1,typename T2>
+    void serialize(const std::map<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T1,typename T2>
+    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>
+    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>
+    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>
+    void deserialize(Eigen::Matrix<T,R,C,P,MR,MC>& obj,std::vector<char>::const_iterator& iter);
+
+    template<typename T,int P,typename I>
+    size_t getByteSize(const Eigen::SparseMatrix<T,P,I>& obj);
+    template<typename T,int P,typename I>
+    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>
+    void deserialize(Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>::const_iterator& iter);
+
+    // pointers
+    template <typename T>
+    std::enable_if_t<std::is_pointer<T>::value,size_t> getByteSize(const T& obj);
+    template <typename T>
+    std::enable_if_t<std::is_pointer<T>::value> serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+    template <typename T>
+    std::enable_if_t<std::is_pointer<T>::value> deserialize(T& obj,std::vector<char>::const_iterator& iter);
+
+    // 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<Serializable,T0>::value
+        || is_stl_container<T0>::value || is_eigen_type<T0>::value;
+    };
+  }
+}
+
+#include "serialize.cpp"
+
+#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));

+ 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;
-    }
+    }*/
     
 //  }
 }

+ 133 - 127
include/igl/xml/XMLSerialization.h

@@ -1,182 +1,188 @@
-// 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/.
-/* ---------------------------------------------------------------------------
- // XMLSerialization.h
- // Author: Christian Schüller <schuellchr@gmail.com>
- ------------------------------------------------------------------------------
- Inherit from this class to have the easiest way to serialize your user defined class.
- 
- 1) Pass the default name of your class to the base constructor.
- 2) Override InitSerialization() and add your variables to serialize like:
- xmlSerializer->Add(var1,"name1");
- xmlSerializer->Add(var2,"name2");
-
- Workaround for Visual Studio run time debugger inspection problem:
- Copy and implement all the functions, splitting them into a source and header file.
- Restrictions on Native C++ Expressions (Anonymous Namespaces):
- http://msdn.microsoft.com/en-us/library/0888kc6a%28VS.80%29.aspx
- ----------------------------------------------------------------------------*/
 #ifndef IGL_XML_SERIALIZATION_H
 #define IGL_XML_SERIALIZATION_H
 
-#include <igl/xml/XMLSerializer.h>
+#include <igl/xml/serialize_xml.h>
 
 namespace igl
 {
-  namespace
+  class XMLSerialization: public XMLSerializable
   {
-    class XMLSerializer;
-
-    class XMLSerialization : public igl::XMLSerializable
+  private:
+    
+    template <typename T>
+    struct XMLSerializationObject: public XMLSerializable
     {
-    public:
-      XMLSerializer* xmlSerializer;
-
-      /**
-       * Default implementation of XMLSerializable interface
-       */
-      virtual void Init();
-      virtual bool Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element);
-      virtual bool Deserialize(tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element);
-
-      /**
-      * Default constructor, destructor, assignment and copy constructor
-      */
-      XMLSerialization(const std::string& name);
-      ~XMLSerialization();
-      XMLSerialization(const XMLSerialization& obj);
-      XMLSerialization& operator=(const XMLSerialization& obj);
-
-      /**
-      * Function which must be overriden in the subclass if you dont 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:
-      * xmlSerializer->Add(var1);
-      * xmlSerializer->Add(varw);
-      * ...
-      */
-      virtual void InitSerialization();
-
-      /**
-       * Following functions can be overwritten to handle the specific events.
-       * Return false to prevent serialization of object.
-       */
-      virtual bool BeforeSerialization();
-      virtual void AfterSerialization();
-      virtual bool BeforeDeserialization();
-      virtual void AfterDeserialization();
-
-    private:
-      void initXMLSerializer();
-    };
+      bool Binary;
+      std::string Name;
+      T* Object;
 
-    // Implementation
+      void Serialize(std::vector<char>& buffer) const {
+        igl::serialize(*Object,Name,buffer);
+      }
 
-    void XMLSerialization::Init()
-    {
-    }
+      void Deserialize(const std::vector<char>& buffer) {
+        igl::deserialize(*Object,Name,buffer);
+      }
 
-    bool XMLSerialization::Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element)
-    {
-      bool serialized = false;
+      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<XMLSerializable*> objects;
+  
+  public:
+
+    /**
+    * Override this function to add your member variables which should be
+    * serialized:
+    *
+    * this->Add(var1);
+    * this->Add(var2);
+    * ...
+    */
+    virtual void InitSerialization() = 0;
+
+    /**
+    * Following functions can be overridden to handle the specific events.
+    * Return false to prevent the de-/serialization of an object.
+    */
+    virtual bool BeforeSerialization() const { return true; }
+    virtual void AfterSerialization() const {}
+    virtual bool BeforeDeserialization() { return true; }
+    virtual void AfterDeserialization() {}
+
+    /**
+    * Default implementation of XMLSerializable interface
+    */
+    void Serialize(std::vector<char>& buffer) const
+    {
       if(this->BeforeSerialization())
       {
-        if(xmlSerializer==NULL)
+        if(initialized == false)
         {
-          xmlSerializer = new XMLSerializer(Name);
-          this->InitSerialization();
+          objects.clear();
+          (const_cast<XMLSerialization*>(this))->InitSerialization();
+          initialized = true;
         }
-        serialized = xmlSerializer->SaveGroupToXMLElement(doc,element,Name);
+
+        for(int i=0;i<objects.size();i++)
+          objects[i]->Serialize(buffer);
+
         this->AfterSerialization();
       }
-
-      return serialized;
     }
 
-    bool XMLSerialization::Deserialize(tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element)
+    void Deserialize(const std::vector<char>& buffer)
     {
-      bool serialized = false;
-
       if(this->BeforeDeserialization())
       {
-        if(xmlSerializer==NULL)
+        if(initialized == false)
         {
-          xmlSerializer = new XMLSerializer(Name);
-          this->InitSerialization();
+          objects.clear();
+          (const_cast<XMLSerialization*>(this))->InitSerialization();
+          initialized = true;
         }
-        serialized = xmlSerializer->LoadGroupFromXMLElement(Name,doc,element);
+
+        for(int i=0;i<objects.size();i++)
+          objects[i]->Deserialize(buffer);
+
         this->AfterDeserialization();
       }
-
-      return serialized;
     }
 
-    void XMLSerialization::InitSerialization()
+    void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const
     {
-      std::cout<<"You have to override InitSerialization()"<<"\n";
-      //assert(false);
+      if(this->BeforeSerialization())
+      {
+        if(initialized == false)
+        {
+          objects.clear();
+          (const_cast<XMLSerialization*>(this))->InitSerialization();
+          initialized = true;
+        }
+
+        for(int i=0;i<objects.size();i++)
+          objects[i]->Serialize(doc,element);
+
+        this->AfterSerialization();
+      }
     }
 
-    XMLSerialization::XMLSerialization(const std::string& name)
+    void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element)
     {
-      Name = name;
-      xmlSerializer = NULL;
+      if(this->BeforeDeserialization())
+      {
+        if(initialized == false)
+        {
+          objects.clear();
+          (const_cast<XMLSerialization*>(this))->InitSerialization();
+          initialized = true;
+        }
+
+        for(int i=0;i<objects.size();i++)
+          objects[i]->Deserialize(doc,element);
+
+        this->AfterDeserialization();
+      }
     }
 
-    XMLSerialization::~XMLSerialization()
+    /**
+    * Default constructor, destructor, assignment and copy constructor
+    */
+
+    XMLSerialization()
+    {
+      initialized = false;
+    }
+    
+    XMLSerialization(const XMLSerialization& obj)
     {
-      if(xmlSerializer!=NULL)
-        delete xmlSerializer;
-      xmlSerializer = NULL;
+      initialized = false;
+      objects.clear();
     }
 
-    XMLSerialization::XMLSerialization(const XMLSerialization& obj)
+    ~XMLSerialization()
     {
-      Name = obj.Name;
-      xmlSerializer = NULL;
+      initialized = false;
+      objects.clear();
     }
 
-    XMLSerialization& XMLSerialization::operator=(const XMLSerialization& obj)
+
+    XMLSerialization& operator=(const XMLSerialization& obj)
     {
-      if(this!=&obj)
+      if(this != &obj)
       {
-        Name = obj.Name;
-        if(xmlSerializer!=NULL)
+        if(initialized)
         {
-          delete xmlSerializer;
-          xmlSerializer = NULL;
+          initialized = false;
+          objects.clear();
         }
       }
       return *this;
     }
 
-    bool XMLSerialization::BeforeSerialization()
+    /**
+    * Use this function to add your variables which should be serialized.
+    */
+  
+    template <typename T>
+    void Add(T& obj,std::string name, bool binary = false)
     {
-      return true;
-    }
+      XMLSerializationObject<T>* object = new XMLSerializationObject<T>();
+      object->Binary = binary;
+      object->Name = name;
+      object->Object = &obj;
 
-    void XMLSerialization::AfterSerialization()
-    {
+      objects.push_back(object);
     }
+  };
 
-    bool XMLSerialization::BeforeDeserialization()
-    {
-      return true;
-    }
-
-    void XMLSerialization::AfterDeserialization()
-    {
-    }
-  }
 }
 
-#endif
+#endif

+ 259 - 0
include/igl/xml/old version/ReAntTweakBarXMLSerialization.h

@@ -0,0 +1,259 @@
+// 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/.
+#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

+ 26 - 24
include/igl/xml/XMLSerializable.h → include/igl/xml/old version/XMLSerializable.h

@@ -20,32 +20,34 @@
 
 namespace igl
 {
-
-  class XMLSerializable
+  namespace
   {
-  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.
+    class XMLSerializable
+    {
+    public:
+      /**
+      * Default name of serializable object
       */
-    virtual bool Deserialize(tinyxml2::XMLDocument* doc, const tinyxml2::XMLElement* element) = 0;
-  };
+      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 void 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 void Deserialize(tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element) = 0;
+    };
+  }
 }
 
 #endif

+ 182 - 0
include/igl/xml/old version/XMLSerialization.h

@@ -0,0 +1,182 @@
+// 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/.
+/* ---------------------------------------------------------------------------
+ // XMLSerialization.h
+ // Author: Christian Schüller <schuellchr@gmail.com>
+ ------------------------------------------------------------------------------
+ Inherit from this class to have the easiest way to serialize your user defined class.
+ 
+ 1) Pass the default name of your class to the base constructor.
+ 2) Override InitSerialization() and add your variables to serialize like:
+ xmlSerializer->Add(var1,"name1");
+ xmlSerializer->Add(var2,"name2");
+
+ Workaround for Visual Studio run time debugger inspection problem:
+ Copy and implement all the functions, splitting them into a source and header file.
+ Restrictions on Native C++ Expressions (Anonymous Namespaces):
+ http://msdn.microsoft.com/en-us/library/0888kc6a%28VS.80%29.aspx
+ ----------------------------------------------------------------------------*/
+#ifndef IGL_XML_SERIALIZATION_H
+#define IGL_XML_SERIALIZATION_H
+
+#include <igl/xml/XMLSerializer.h>
+
+namespace igl
+{
+  namespace
+  {
+    class XMLSerializer;
+
+    class XMLSerialization : public igl::XMLSerializable
+    {
+    public:
+      XMLSerializer* xmlSerializer;
+
+      /**
+       * Default implementation of XMLSerializable interface
+       */
+      virtual void Init();
+      virtual bool Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element);
+      virtual bool Deserialize(tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element);
+
+      /**
+      * Default constructor, destructor, assignment and copy constructor
+      */
+      XMLSerialization(const std::string& name);
+      ~XMLSerialization();
+      XMLSerialization(const XMLSerialization& obj);
+      XMLSerialization& operator=(const XMLSerialization& obj);
+
+      /**
+      * 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 function all the variables you want to serialize like:
+      * xmlSerializer->Add(var1);
+      * xmlSerializer->Add(var2);
+      * ...
+      */
+      virtual void InitSerialization();
+
+      /**
+       * Following functions can be overwritten to handle the specific events.
+       * Return false to prevent serialization of object.
+       */
+      virtual bool BeforeSerialization();
+      virtual void AfterSerialization();
+      virtual bool BeforeDeserialization();
+      virtual void AfterDeserialization();
+
+    private:
+      void initXMLSerializer();
+    };
+
+    // Implementation
+
+    void XMLSerialization::Init()
+    {
+    }
+
+    bool XMLSerialization::Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element)
+    {
+      bool serialized = false;
+
+      if(this->BeforeSerialization())
+      {
+        if(xmlSerializer==NULL)
+        {
+          xmlSerializer = new XMLSerializer(Name);
+          this->InitSerialization();
+        }
+        serialized = xmlSerializer->SaveGroupToXMLElement(doc,element,Name);
+        this->AfterSerialization();
+      }
+
+      return serialized;
+    }
+
+    bool XMLSerialization::Deserialize(tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element)
+    {
+      bool serialized = false;
+
+      if(this->BeforeDeserialization())
+      {
+        if(xmlSerializer==NULL)
+        {
+          xmlSerializer = new XMLSerializer(Name);
+          this->InitSerialization();
+        }
+        serialized = xmlSerializer->LoadGroupFromXMLElement(Name,doc,element);
+        this->AfterDeserialization();
+      }
+
+      return serialized;
+    }
+
+    void XMLSerialization::InitSerialization()
+    {
+      std::cout<<"You have to override InitSerialization()"<<"\n";
+      //assert(false);
+    }
+
+    XMLSerialization::XMLSerialization(const std::string& name)
+    {
+      Name = name;
+      xmlSerializer = NULL;
+    }
+
+    XMLSerialization::~XMLSerialization()
+    {
+      if(xmlSerializer!=NULL)
+        delete xmlSerializer;
+      xmlSerializer = NULL;
+    }
+
+    XMLSerialization::XMLSerialization(const XMLSerialization& obj)
+    {
+      Name = obj.Name;
+      xmlSerializer = NULL;
+    }
+
+    XMLSerialization& XMLSerialization::operator=(const XMLSerialization& obj)
+    {
+      if(this!=&obj)
+      {
+        Name = obj.Name;
+        if(xmlSerializer!=NULL)
+        {
+          delete xmlSerializer;
+          xmlSerializer = NULL;
+        }
+      }
+      return *this;
+    }
+
+    bool XMLSerialization::BeforeSerialization()
+    {
+      return true;
+    }
+
+    void XMLSerialization::AfterSerialization()
+    {
+    }
+
+    bool XMLSerialization::BeforeDeserialization()
+    {
+      return true;
+    }
+
+    void XMLSerialization::AfterDeserialization()
+    {
+    }
+  }
+}
+
+#endif

+ 0 - 0
include/igl/xml/XMLSerializationTest.h → include/igl/xml/old version/XMLSerializationTest.h


+ 0 - 0
include/igl/xml/XMLSerializer.h.REMOVED.git-id → include/igl/xml/old version/XMLSerializer.h.REMOVED.git-id


+ 435 - 0
include/igl/xml/serialization_test.h

@@ -0,0 +1,435 @@
+#ifndef IGL_SERIALIZATION_TEST_H
+#define IGL_SERIALIZATION_TEST_H
+
+#include <igl/Timer.h>
+#include <igl/xml/serialize_xml.h>
+
+namespace igl
+{
+  struct Test1: public igl::XMLSerialization
+  {
+    std::string ts;
+    std::vector<Test1*> tvt;
+    Test1* tt;
+
+    Test1()
+    {
+      tt = NULL;
+    }
+
+    void InitSerialization()
+    {
+      Add(ts,"ts");
+      Add(tvt,"tvt",true);
+      Add(tt,"tt",true);
+    }
+  };
+
+  struct Test2: public igl::XMLSerializable
+  {
+    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();
+    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);
+
+    igl::serialize(tObjIn,file);
+    igl::deserialize(tObjOut,file);
+    assert(tObjIn.tc == tObjOut.tc);
+    assert(*tObjIn.ti == *tObjOut.ti);
+    for(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(int i=0;i<tVector1In.size();i++)
+      assert(tVector1In[i] == tVector1Out[i]);
+
+    igl::serialize(tVector2In,file);
+    igl::deserialize(tVector2Out,file);
+    for(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(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(int i=0;i<10000;i++)
+    {
+    std::vector<float> v;
+    for(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(tsIn,"tsIn",file);
+    igl::serialize_xml(tVector2In,"tVector2In",file,false,true);
+    igl::deserialize_xml(tVector2Out,"tVector2In",file);
+    igl::deserialize_xml(tsOut,"tsIn",file);
+    assert(tsIn == tsOut);
+    for(int i=0;i<tVector2In.size();i++)
+    {
+      assert(tVector2In[i].first == tVector2Out[i].first);
+      assert(tVector2In[i].second == tVector2Out[i].second);
+    }
+    tsOut = 0;
+    tVector2Out.clear();
+
+    // binarization
+    igl::serialize_xml(tVector2In,"tVector2In",file,true);
+    igl::deserialize_xml(tVector2Out,"tVector2In",file);
+    for(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(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(int i=0;i<tVector1In.size();i++)
+      assert(tVector1In[i] == tVector1Out[i]);
+
+    igl::serialize_xml(tVector2In,file);
+    igl::deserialize_xml(tVector2Out,file);
+    for(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(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(int i=0;i<10000;i++)
+    {
+    std::vector<float> v;
+    for(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

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

@@ -0,0 +1,836 @@
+// 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/.
+// ---------------------------------------------------------------------------
+// serialize.h
+// author: Christian Schüller <schuellchr@gmail.com>
+// -----------------------------------------------------------------------------
+
+#include "serialize_xml.h"
+
+namespace igl
+{
+  template <typename T>
+  void serialize_xml(const T& obj,const std::string& filename)
+  {
+    serialize_xml(obj,"object",filename,0);
+  }
+
+  template <typename T>
+  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)
+    {
+      // 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>
+  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");
+
+    std::string name(objectName);
+    detail_xml::encodeXMLElementName(name);
+
+    if(binary)
+    {
+      std::vector<char> buffer;
+      serialize(obj,name,buffer);
+      std::string data = detail_xml::base64_encode(reinterpret_cast<const unsigned char*>(buffer.data()),buffer.size());
+
+      tinyxml2::XMLElement* child = detail_xml::getElement(doc,element,name);
+      child->SetAttribute("binary",true);
+
+      detail_xml::serialize(data,doc,element,name);
+    }
+    else
+    {
+      detail_xml::serialize(obj,doc,element,name);
+    }
+  }
+
+  template <typename T>
+  void deserialize_xml(T& obj,const std::string& filename)
+  {
+    deserialize_xml(obj,"object",filename);
+  }
+
+  template <typename T>
+  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>
+  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");
+
+    std::string name(objectName);
+    detail_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;
+        detail_xml::deserialize(code,doc,element,name);
+        std::string decoded = detail_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
+      {
+        detail_xml::deserialize(obj,doc,element,name);
+      }
+    }
+  }
+
+  namespace detail_xml
+  {
+    // fundamental types
+
+    template <typename T>
+    std::enable_if_t<std::is_fundamental<T>::value> 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>
+    std::enable_if_t<std::is_fundamental<T>::value> 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
+
+    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());
+    }
+
+    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>
+    std::enable_if_t<std::is_base_of<XMLSerializable,T>::value> serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+    {
+      // Serialize object implementing Serializable interface
+      const XMLSerializable& object = dynamic_cast<const XMLSerializable&>(obj);
+
+      tinyxml2::XMLElement* child = getElement(doc,element,name.c_str());
+      object.Serialize(doc,child);
+    }
+
+    template <typename T>
+    std::enable_if_t<std::is_base_of<XMLSerializable,T>::value> 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>
+    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>
+    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>
+    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>
+    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>
+    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>
+    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>
+    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>
+    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>
+    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>
+    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>
+    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>
+    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>
+    std::enable_if_t<std::is_pointer<T>::value> 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)
+        detail_xml::serialize(*obj,doc,element,name);
+    }
+
+    template <typename T>
+    std::enable_if_t<std::is_pointer<T>::value> 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 std::remove_pointer<T>::type();
+
+          detail_xml::deserialize(*obj,doc,element,name);
+        }
+      }
+    }
+
+    // helper functions
+
+    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;
+    }
+
+    void getAttribute(const char* src,bool& dest)
+    {
+      tinyxml2::XMLUtil::ToBool(src,&dest);
+    }
+
+    void getAttribute(const char* src,char& dest)
+    {
+      dest = (char)atoi(src);
+    }
+
+    void getAttribute(const char* src,std::string& dest)
+    {
+      dest = src;
+    }
+
+    void getAttribute(const char* src,float& dest)
+    {
+      tinyxml2::XMLUtil::ToFloat(src,&dest);
+    }
+
+    void getAttribute(const char* src,double& dest)
+    {
+      tinyxml2::XMLUtil::ToDouble(src,&dest);
+    }
+
+    template<typename T>
+    std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value> getAttribute(const char* src,T& dest)
+    {
+      unsigned int val;
+      tinyxml2::XMLUtil::ToUnsigned(src,&val);
+      dest = (T)val;
+    }
+
+    template<typename T>
+    std::enable_if_t<std::is_integral<T>::value && !std::is_unsigned<T>::value> 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[] ={' ','/','~','#','&','>','<','='};
+
+    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();
+      }
+    }
+
+    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);
+      }
+    }
+
+    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<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;
+    }
+  }
+}

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

@@ -0,0 +1,216 @@
+// 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/.
+// ---------------------------------------------------------------------------
+// serialize.h
+// author: Christian Schüller <schuellchr@gmail.com>
+// -----------------------------------------------------------------------------
+// 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.
+//
+// See also: serialize.h
+// -----------------------------------------------------------------------------
+
+#ifndef IGL_SERIALIZABLE_XML_H
+#define IGL_SERIALIZABLE_XML_H
+
+#include <type_traits>
+#include <iostream>
+#include <vector>
+#include <set>
+#include <map>
+
+#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 update the serialization in 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>
+  void serialize_xml(const T& obj,const std::string& filename);
+  template <typename T>
+  void serialize_xml(const T& obj,const std::string& objectName,const std::string& filename, bool binary = false,bool overwrite = false);
+  template <typename T>
+  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 update the serialization in 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>
+  void deserialize_xml(T& obj,const std::string& filename);
+  template <typename T>
+  void deserialize_xml(T& obj,const std::string& objectName,const std::string& filename);
+  template <typename T>
+  void deserialize_xml(T& obj,const std::string& objectName,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element);
+
+  // interface for user defined types
+  struct XMLSerializable : public Serializable
+  {
+    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;
+  };
+  // example:
+  //
+  // class Test : public igl::Serializable {
+  //   
+  //   int var;
+  // 
+  //   void Serialize(std::vector<char>& buffer) {
+  //     serialize(var,"var1",buffer);
+  //   }
+  //   void Deserialize(const std::vector<char>& buffer) {
+  //     deserialize(var,"var1",buffer);
+  //   }
+  //   void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const {
+  //     serialize_xml(var,"var1",doc,element);
+  //   }
+  //   void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element) {
+  //     deserialize_xml(var,"var1",doc,element);
+  //   }
+  // }
+
+  // internal functions
+  namespace detail_xml
+  {
+    // fundamental types
+    template <typename T>
+    std::enable_if_t<std::is_fundamental<T>::value> serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template <typename T>
+    std::enable_if_t<std::is_fundamental<T>::value> deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    // std::string
+    void serialize(const std::string& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    void deserialize(std::string& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    // Serializable
+    template <typename T>
+    std::enable_if_t<std::is_base_of<XMLSerializable,T>::value> serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template <typename T>
+    std::enable_if_t<std::is_base_of<XMLSerializable,T>::value> deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    // STL containers
+    template <typename T1, typename T2>
+    void serialize(const std::pair<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template <typename T1,typename T2>
+    void deserialize(std::pair<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    template <typename T1,typename T2>
+    void serialize(const std::vector<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template <typename T1,typename T2>
+    void deserialize(std::vector<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    template <typename T>
+    void serialize(const std::set<T>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template <typename T>
+    void deserialize(std::set<T>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    template <typename T1,typename T2>
+    void serialize(const std::map<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template <typename T1,typename T2>
+    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>
+    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>
+    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>
+    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>
+    void deserialize(Eigen::SparseMatrix<T,P,I>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+    // pointers
+    template <typename T>
+    std::enable_if_t<std::is_pointer<T>::value> serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+    template <typename T>
+    std::enable_if_t<std::is_pointer<T>::value> 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);
+    void getAttribute(const char* src,bool& dest);
+    void getAttribute(const char* scr,char& dest);
+    void getAttribute(const char* src,std::string& dest);
+    void getAttribute(const char* src,float& dest);
+    void getAttribute(const char* src,double& dest);
+    template<typename T>
+    std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value> getAttribute(const char* src,T& dest);
+    template<typename T>
+    std::enable_if_t<std::is_integral<T>::value && !std::is_unsigned<T>::value> getAttribute(const char* src,T& dest);
+    void replaceSubString(std::string& str,const std::string& search,const std::string& replace);
+    void encodeXMLElementName(std::string& name);
+    void decodeXMLElementName(std::string& name);
+    std::string base64_encode(unsigned char const* bytes_to_encode,unsigned int in_len);
+    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<Serializable,T0>::value
+        || is_stl_container<T0>::value || is_eigen_type<T0>::value;
+    };
+  }
+}
+
+#include "serialize_xml.cpp";
+
+#endif