Browse Source

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

Former-commit-id: a3c17ec2eb057e3a8f779d448cc0cf9bd0e684ac
Olga Diamanti 11 years ago
parent
commit
e11e60ce79
100 changed files with 6231 additions and 3362 deletions
  1. 1 1
      .gitignore
  2. 1 1
      include/igl/colon.cpp
  3. 5 7
      include/igl/column_to_quats.h
  4. 49 0
      include/igl/deform_skeleton.cpp
  5. 39 0
      include/igl/deform_skeleton.h
  6. 34 0
      include/igl/find.cpp
  7. 10 0
      include/igl/find.h
  8. 27 13
      include/igl/harmonic.cpp
  9. 11 5
      include/igl/harmonic.h
  10. 2 1
      include/igl/viewer/TODOs.txt
  11. 0 2467
      include/igl/viewer/Viewer.cpp
  12. 1 0
      include/igl/viewer/Viewer.cpp.REMOVED.git-id
  13. 19 0
      include/igl/viewer/Viewer.h
  14. 2 2
      tutorial/101_FileIO/CMakeLists.txt
  15. 2 2
      tutorial/102_DrawMesh/CMakeLists.txt
  16. 2 2
      tutorial/103_Events/CMakeLists.txt
  17. 0 1
      tutorial/103_Events/main.cpp
  18. 2 2
      tutorial/104_Colors/CMakeLists.txt
  19. 5 12
      tutorial/104_Colors/main.cpp
  20. 2 2
      tutorial/105_Overlays/CMakeLists.txt
  21. 2 2
      tutorial/106_Picking/CMakeLists.txt
  22. 3 1
      tutorial/106_Picking/main.cpp
  23. 2 2
      tutorial/201_Normals/CMakeLists.txt
  24. 2 2
      tutorial/202_GaussianCurvature/CMakeLists.txt
  25. 2 2
      tutorial/203_CurvatureDirections/CMakeLists.txt
  26. 2 2
      tutorial/204_Gradient/CMakeLists.txt
  27. 2 2
      tutorial/205_Laplacian/CMakeLists.txt
  28. 2 2
      tutorial/301_Slice/CMakeLists.txt
  29. 2 2
      tutorial/302_Sort/CMakeLists.txt
  30. 2 2
      tutorial/303_LaplaceEquation/CMakeLists.txt
  31. 2 2
      tutorial/304_LinearEqualityConstraints/CMakeLists.txt
  32. 2 2
      tutorial/305_QuadraticProgramming/CMakeLists.txt
  33. 11 0
      tutorial/401_BiharmonicDeformation/CMakeLists.txt
  34. 121 0
      tutorial/401_BiharmonicDeformation/main.cpp
  35. 11 0
      tutorial/402_PolyharmonicDeformation/CMakeLists.txt
  36. 105 0
      tutorial/402_PolyharmonicDeformation/main.cpp
  37. 13 0
      tutorial/403_BoundedBiharmonicWeights/CMakeLists.txt
  38. 169 0
      tutorial/403_BoundedBiharmonicWeights/main.cpp
  39. 2 2
      tutorial/501_HarmonicParam/CMakeLists.txt
  40. 2 2
      tutorial/502_LSCMParam/CMakeLists.txt
  41. 2 2
      tutorial/503_ARAPParam/CMakeLists.txt
  42. 3 3
      tutorial/504_NRosyDesign/CMakeLists.txt
  43. 2 2
      tutorial/505_MIQ/CMakeLists.txt
  44. 34 1
      tutorial/505_MIQ/main.cpp
  45. 2 2
      tutorial/506_FrameField/CMakeLists.txt
  46. 5 5
      tutorial/506_FrameField/main.cpp
  47. 2 2
      tutorial/601_Serialization/CMakeLists.txt
  48. 1 1
      tutorial/601_Serialization/main.cpp
  49. 2 2
      tutorial/602_Matlab/CMakeLists.txt
  50. 1 1
      tutorial/602_Matlab/main.cpp
  51. 1 1
      tutorial/602_Matlab/run.sh
  52. 2 2
      tutorial/604_Triangle/CMakeLists.txt
  53. 2 2
      tutorial/605_Tetgen/CMakeLists.txt
  54. 2 2
      tutorial/606_AmbientOcclusion/CMakeLists.txt
  55. 26 0
      tutorial/CMakeLists.txt
  56. 9 9
      tutorial/cmake/FindEMBREE.cmake
  57. 1 1
      tutorial/cmake/FindLIBCOMISO.cmake
  58. 19 3
      tutorial/cmake/FindLIBIGL.cmake
  59. 4 0
      tutorial/cmake/FindTRIANGLE.cmake
  60. 0 0
      tutorial/compile_dependencies_linux.sh
  61. 0 0
      tutorial/compile_dependencies_macosx.sh
  62. 1 0
      tutorial/images/102_DrawMesh.png.REMOVED.git-id
  63. 1 0
      tutorial/images/104_Colors.png.REMOVED.git-id
  64. 1 0
      tutorial/images/105_Overlays.png.REMOVED.git-id
  65. 1 0
      tutorial/images/106_Picking.png.REMOVED.git-id
  66. 1 0
      tutorial/images/501_HarmonicParam.png.REMOVED.git-id
  67. 1 0
      tutorial/images/502_LSCMParam.png.REMOVED.git-id
  68. 1 0
      tutorial/images/503_ARAPParam.png.REMOVED.git-id
  69. 1 0
      tutorial/images/504_nrosy_field.png.REMOVED.git-id
  70. 1 0
      tutorial/images/504_vector_field.png.REMOVED.git-id
  71. 1 0
      tutorial/images/505_MIQ_1.png.REMOVED.git-id
  72. 1 0
      tutorial/images/505_MIQ_2.png.REMOVED.git-id
  73. 1 0
      tutorial/images/505_MIQ_3.png.REMOVED.git-id
  74. 1 0
      tutorial/images/505_MIQ_4.png.REMOVED.git-id
  75. 1 0
      tutorial/images/505_MIQ_5.png.REMOVED.git-id
  76. 1 0
      tutorial/images/505_MIQ_6.png.REMOVED.git-id
  77. 1 0
      tutorial/images/505_MIQ_7.png.REMOVED.git-id
  78. 1 0
      tutorial/images/505_MIQ_8.png.REMOVED.git-id
  79. 1 0
      tutorial/images/506_FrameField_1.png.REMOVED.git-id
  80. 1 0
      tutorial/images/506_FrameField_2.png.REMOVED.git-id
  81. 1 0
      tutorial/images/506_FrameField_3.png.REMOVED.git-id
  82. 1 0
      tutorial/images/506_FrameField_4.png.REMOVED.git-id
  83. BIN
      tutorial/images/602_Matlab_1.png
  84. 1 0
      tutorial/images/602_Matlab_2.png.REMOVED.git-id
  85. 1 0
      tutorial/images/604_Triangle.png.REMOVED.git-id
  86. 1 0
      tutorial/images/605_Tetgen.png.REMOVED.git-id
  87. 1 0
      tutorial/images/606_AmbientOcclusion.png.REMOVED.git-id
  88. 1 0
      tutorial/images/VF.pdf.REMOVED.git-id
  89. 1 0
      tutorial/images/VF.png.REMOVED.git-id
  90. 1 0
      tutorial/images/bump-k-harmonic.jpg.REMOVED.git-id
  91. 1 0
      tutorial/images/hand-bbw.jpg.REMOVED.git-id
  92. 1 0
      tutorial/images/max-biharmonic.jpg.REMOVED.git-id
  93. 0 776
      tutorial/readme.md
  94. 8 0
      tutorial/shared/2triangles.off
  95. 1 0
      tutorial/shared/bump-domain.obj.REMOVED.git-id
  96. 5273 0
      tutorial/shared/decimated-max-selection.dmat
  97. 1 0
      tutorial/shared/decimated-max.obj.REMOVED.git-id
  98. 81 0
      tutorial/shared/hand-pose.dmat
  99. 1 0
      tutorial/shared/hand.mesh.REMOVED.git-id
  100. 43 0
      tutorial/shared/hand.tgf

+ 1 - 1
.gitignore

@@ -1,6 +1,6 @@
 # use glob syntax.
-scripts/change_name.sh
 syntax: glob
+scripts/change_name.sh
 *.o
 *.a
 *.dylib

+ 1 - 1
include/igl/colon.cpp

@@ -43,7 +43,7 @@ IGL_INLINE void igl::colon(
     }
   }
   // resize output
-  int n = floor(double((hi-low)/step))+1;
+  int n = std::floor(double((hi-low)/step))+1;
   I.resize(n);
   int i = 0;
   T v = (T)low;

+ 5 - 7
include/igl/column_to_quats.h

@@ -1,9 +1,9 @@
 // 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 
+//
+// 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_COLUMN_TO_QUATS_H
 #define IGL_COLUMN_TO_QUATS_H
@@ -28,9 +28,7 @@ namespace igl
 }
 
 #ifndef IGL_STATIC_LIBRARY
-#  include "columns_to_quats.cpp"
+#  include "column_to_quats.cpp"
 #endif
 
 #endif
-
-

+ 49 - 0
include/igl/deform_skeleton.cpp

@@ -0,0 +1,49 @@
+#include "deform_skeleton.h"
+void igl::deform_skeleton(
+  const Eigen::MatrixXd & C,
+  const Eigen::MatrixXi & BE,
+  const std::vector<
+    Eigen::Affine3d,Eigen::aligned_allocator<Eigen::Affine3d> > & vA,
+  Eigen::MatrixXd & CT,
+  Eigen::MatrixXi & BET)
+{
+  using namespace Eigen;
+  assert(BE.rows() == (int)vA.size());
+  CT.resize(2*BE.rows(),C.cols());
+  BET.resize(BE.rows(),2);
+  for(int e = 0;e<BE.rows();e++)
+  {
+    BET(e,0) = 2*e;
+    BET(e,1) = 2*e+1;
+    Affine3d a = vA[e];
+    Vector3d c0 = C.row(BE(e,0));
+    Vector3d c1 = C.row(BE(e,1));
+    CT.row(2*e) =   a * c0;
+    CT.row(2*e+1) = a * c1;
+  }
+
+}
+
+IGL_INLINE void igl::deform_skeleton(
+  const Eigen::MatrixXd & C,
+  const Eigen::MatrixXi & BE,
+  const Eigen::MatrixXd & T,
+  Eigen::MatrixXd & CT,
+  Eigen::MatrixXi & BET)
+{
+  using namespace Eigen;
+  //assert(BE.rows() == (int)vA.size());
+  CT.resize(2*BE.rows(),C.cols());
+  BET.resize(BE.rows(),2);
+  for(int e = 0;e<BE.rows();e++)
+  {
+    BET(e,0) = 2*e;
+    BET(e,1) = 2*e+1;
+    Affine3d a;
+    a.matrix() = T.block(e*4,0,4,3).transpose();
+    Vector3d c0 = C.row(BE(e,0));
+    Vector3d c1 = C.row(BE(e,1));
+    CT.row(2*e) =   a * c0;
+    CT.row(2*e+1) = a * c1;
+  }
+}

+ 39 - 0
include/igl/deform_skeleton.h

@@ -0,0 +1,39 @@
+#ifndef IGL_DEFORM_SKELETON_H
+#define IGL_DEFORM_SKELETON_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+#include <vector>
+namespace igl
+{
+  // Deform a skeleton.
+  //
+  // Inputs:
+  //   C  #C by 3 list of joint positions
+  //   BE  #BE by 2 list of bone edge indices
+  //   vA  #BE list of bone transformations
+  // Outputs
+  //   CT  #BE*2 by 3 list of deformed joint positions
+  //   BET  #BE by 2 list of bone edge indices (maintains order)
+  //
+  IGL_INLINE void deform_skeleton(
+    const Eigen::MatrixXd & C,
+    const Eigen::MatrixXi & BE,
+    const std::vector<
+      Eigen::Affine3d,Eigen::aligned_allocator<Eigen::Affine3d> > & vA,
+    Eigen::MatrixXd & CT,
+    Eigen::MatrixXi & BET);
+  // Inputs:
+  //   T  #BE*4 by 3 list of stacked transformation matrix
+  IGL_INLINE void deform_skeleton(
+    const Eigen::MatrixXd & C,
+    const Eigen::MatrixXi & BE,
+    const Eigen::MatrixXd & T,
+    Eigen::MatrixXd & CT,
+    Eigen::MatrixXi & BET);
+}
+  
+#ifndef IGL_STATIC_LIBRARY
+#  include "deform_skeleton.cpp"
+#endif
+#endif

+ 34 - 0
include/igl/find.cpp

@@ -8,6 +8,7 @@
 #include "find.h"
 
 #include "verbose.h"
+#include <iostream>
   
 template <
   typename T, 
@@ -39,6 +40,39 @@ IGL_INLINE void igl::find(
     }
   }
 }
+
+template <
+  typename DerivedX,
+  typename DerivedI, 
+  typename DerivedJ,
+  typename DerivedV>
+IGL_INLINE void igl::find(
+  const Eigen::PlainObjectBase<DerivedX>& X,
+  Eigen::PlainObjectBase<DerivedI> & I,
+  Eigen::PlainObjectBase<DerivedJ> & J,
+  Eigen::PlainObjectBase<DerivedV> & V)
+{
+  const int nnz = X.template cast<bool>().template cast<int>().sum();
+  I.resize(nnz,1);
+  J.resize(nnz,1);
+  V.resize(nnz,1);
+  {
+    int k = 0;
+    for(int j = 0;j<X.cols();j++)
+    {
+      for(int i = 0;i<X.rows();i++)
+      {
+        if(X(i,j))
+        {
+          I(k) = i;
+          J(k) = j;
+          V(k) = X(i,j);
+          k++;
+        }
+      }
+    }
+  }
+}
   
 template <typename T>
 IGL_INLINE void igl::find(

+ 10 - 0
include/igl/find.h

@@ -35,6 +35,16 @@ namespace igl
     Eigen::MatrixBase<DerivedI> & I,
     Eigen::MatrixBase<DerivedJ> & J,
     Eigen::MatrixBase<DerivedV> & V);
+  template <
+    typename DerivedX,
+    typename DerivedI, 
+    typename DerivedJ,
+    typename DerivedV>
+  IGL_INLINE void find(
+    const Eigen::PlainObjectBase<DerivedX>& X,
+    Eigen::PlainObjectBase<DerivedI> & I,
+    Eigen::PlainObjectBase<DerivedJ> & J,
+    Eigen::PlainObjectBase<DerivedV> & V);
   // Find the non-zero entries and there respective indices in a sparse vector.
   // Similar to matlab's [I,J,V] = find(X), but instead of [I,J] being
   // subscripts into X, since X is a vector we just return I, a list of indices

+ 27 - 13
include/igl/harmonic.cpp

@@ -12,17 +12,25 @@
 #include "min_quad_with_fixed.h"
 #include <Eigen/Sparse>
 
+template <
+  typename DerivedV,
+  typename DerivedF,
+  typename Derivedb,
+  typename Derivedbc,
+  typename DerivedW>
 IGL_INLINE bool igl::harmonic(
-  const Eigen::MatrixXd & V,
-  const Eigen::MatrixXi & F,
-  const Eigen::VectorXi & b,
-  const Eigen::MatrixXd & bc,
+  const Eigen::PlainObjectBase<DerivedV> & V,
+  const Eigen::PlainObjectBase<DerivedF> & F,
+  const Eigen::PlainObjectBase<Derivedb> & b,
+  const Eigen::PlainObjectBase<Derivedbc> & bc,
   const int k,
-  Eigen::MatrixXd & W)
+  Eigen::PlainObjectBase<DerivedW> & W)
 {
   using namespace igl;
   using namespace Eigen;
-  SparseMatrix<double> L,M,Mi;
+  typedef typename DerivedV::Scalar Scalar;
+  typedef Matrix<Scalar,Dynamic,1> VectorXS;
+  SparseMatrix<Scalar> L,M,Mi;
   cotmatrix(V,F,L);
   switch(F.cols())
   {
@@ -35,20 +43,20 @@ IGL_INLINE bool igl::harmonic(
       break;
   }
   invert_diag(M,Mi);
-  SparseMatrix<double> Q = -L;
+  SparseMatrix<Scalar> Q = -L;
   for(int p = 1;p<k;p++)
   {
     Q = (Q*Mi*-L).eval();
   }
-  const VectorXd B = VectorXd::Zero(V.rows(),1);
-  min_quad_with_fixed_data<double> data;
-  min_quad_with_fixed_precompute(Q,b,SparseMatrix<double>(),true,data);
+  const VectorXS B = VectorXS::Zero(V.rows(),1);
+  min_quad_with_fixed_data<Scalar> data;
+  min_quad_with_fixed_precompute(Q,b,SparseMatrix<Scalar>(),true,data);
   W.resize(V.rows(),bc.cols());
   for(int w = 0;w<bc.cols();w++)
   {
-    const VectorXd bcw = bc.col(w);
-    VectorXd Ww;
-    if(!min_quad_with_fixed_solve(data,B,bcw,VectorXd(),Ww))
+    const VectorXS bcw = bc.col(w);
+    VectorXS Ww;
+    if(!min_quad_with_fixed_solve(data,B,bcw,VectorXS(),Ww))
     {
       return false;
     }
@@ -56,3 +64,9 @@ IGL_INLINE bool igl::harmonic(
   }
   return true;
 }
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instanciation
+template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&); 
+template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif

+ 11 - 5
include/igl/harmonic.h

@@ -23,13 +23,19 @@ namespace igl
   // Outputs:
   //   W  #V by #W list of weights
   //
+  template <
+    typename DerivedV,
+    typename DerivedF,
+    typename Derivedb,
+    typename Derivedbc,
+    typename DerivedW>
   IGL_INLINE bool harmonic(
-    const Eigen::MatrixXd & V,
-    const Eigen::MatrixXi & F,
-    const Eigen::VectorXi & b,
-    const Eigen::MatrixXd & bc,
+    const Eigen::PlainObjectBase<DerivedV> & V,
+    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::PlainObjectBase<Derivedb> & b,
+    const Eigen::PlainObjectBase<Derivedbc> & bc,
     const int k,
-    Eigen::MatrixXd & W);
+    Eigen::PlainObjectBase<DerivedW> & W);
 };
 #ifndef IGL_STATIC_LIBRARY
 #include "harmonic.cpp"

+ 2 - 1
include/igl/viewer/TODOs.txt

@@ -1,5 +1,5 @@
+- data.lines, data.points should not concatenate colors with coordinates
 - snap to canonical recenters origin but trackball does not
-+ snap to canonical view key shortcut is not working
 - rewrite in libigl style
 - separate various class into their own .h/.cpp pairs
 - remove use of double underscores (http://stackoverflow.com/a/224420/148668)
@@ -14,6 +14,7 @@
 - zoom with pan rather than scaling
 - refresh draw while resizing
 - use constructor initializer list rather than complicated constructor
++ snap to canonical view key shortcut is not working
 + resize TwBar with window
 + trackball should be able to drag over TwBar
 + don't zoom on horizontal scale

+ 0 - 2467
include/igl/viewer/Viewer.cpp

@@ -1,2467 +0,0 @@
-#include "Viewer.h"
-
-#ifdef _WIN32
-#  include <windows.h>
-#  undef max
-#  undef min
-#endif
-
-#ifndef __APPLE__
-#  include <GL/glew.h>
-#endif
-
-#ifdef __APPLE__
-#   include <OpenGL/gl3.h>
-#   define __gl_h_ /* Prevent inclusion of the old gl.h */
-#else
-#   ifdef _WIN32
-#       include <windows.h>
-#   endif
-#   include <GL/gl.h>
-#endif
-
-#include <Eigen/LU>
-
-#define GLFW_INCLUDE_GLU
-#include <GLFW/glfw3.h>
-
-#include <cmath>
-#include <cstdio>
-#include <sstream>
-#include <iomanip>
-#include <iostream>
-#include <fstream>
-
-#include <algorithm>
-
-//OK NV
-Eigen::Vector3f project(const Eigen::Vector3f&  obj,
-                        const Eigen::Matrix4f& model,
-                        const Eigen::Matrix4f& proj,
-                        const Eigen::Vector4f&  viewport)
-{
-  Eigen::Vector4f tmp;
-  tmp << obj,1;
-
-  tmp = model * tmp;
-
-  tmp = proj * tmp;
-
-  tmp = tmp.array() / tmp(3);
-  tmp = tmp.array() * 0.5f + 0.5f;
-  tmp(0) = tmp(0) * viewport(2) + viewport(0);
-  tmp(1) = tmp(1) * viewport(3) + viewport(1);
-
-  return tmp.head(3);
-}
-
-Eigen::Matrix4f lookAt (
-                        const Eigen::Vector3f& eye,
-                        const Eigen::Vector3f& center,
-                        const Eigen::Vector3f& up)
-{
-  Eigen::Vector3f f = (center - eye).normalized();
-  Eigen::Vector3f s = f.cross(up).normalized();
-  Eigen::Vector3f u = s.cross(f);
-
-  Eigen::Matrix4f Result = Eigen::Matrix4f::Identity();
-  Result(0,0) = s(0);
-  Result(0,1) = s(1);
-  Result(0,2) = s(2);
-  Result(1,0) = u(0);
-  Result(1,1) = u(1);
-  Result(1,2) = u(2);
-  Result(2,0) =-f(0);
-  Result(2,1) =-f(1);
-  Result(2,2) =-f(2);
-  Result(0,3) =-s.transpose() * eye;
-  Result(1,3) =-u.transpose() * eye;
-  Result(2,3) = f.transpose() * eye;
-  return Result;
-}
-
-Eigen::Matrix4f ortho (
-                       const float left,
-                       const float right,
-                       const float bottom,
-                       const float top,
-                       const float zNear,
-                       const float zFar
-                       )
-{
-  Eigen::Matrix4f Result = Eigen::Matrix4f::Identity();
-  Result(0,0) = 2.0f / (right - left);
-  Result(1,1) = 2.0f / (top - bottom);
-  Result(2,2) = - 2.0f / (zFar - zNear);
-  Result(0,3) = - (right + left) / (right - left);
-  Result(1,3) = - (top + bottom) / (top - bottom);
-  Result(2,3) = - (zFar + zNear) / (zFar - zNear);
-  return Result;
-}
-
-Eigen::Matrix4f frustum (
-                         const float left,
-                         const float right,
-                         const float bottom,
-                         const float top,
-                         const float nearVal,
-                         const float farVal)
-{
-  Eigen::Matrix4f Result = Eigen::Matrix4f::Zero();
-  Result(0,0) = (2.0f * nearVal) / (right - left);
-  Result(1,1) = (2.0f * nearVal) / (top - bottom);
-  Result(0,2) = (right + left) / (right - left);
-  Result(1,2) = (top + bottom) / (top - bottom);
-  Result(2,2) = -(farVal + nearVal) / (farVal - nearVal);
-  Result(3,2) = -1.0f;
-  Result(2,3) = -(2.0f * farVal * nearVal) / (farVal - nearVal);
-  return Result;
-}
-
-Eigen::Matrix4f scale (const Eigen::Matrix4f& m,
-                       const Eigen::Vector3f& v)
-{
-  Eigen::Matrix4f Result;
-  Result.col(0) = m.col(0).array() * v(0);
-  Result.col(1) = m.col(1).array() * v(1);
-  Result.col(2) = m.col(2).array() * v(2);
-  Result.col(3) = m.col(3);
-  return Result;
-}
-
-Eigen::Matrix4f translate(
-                          const Eigen::Matrix4f& m,
-                          const Eigen::Vector3f& v)
-{
-  Eigen::Matrix4f Result = m;
-  Result.col(3) = m.col(0).array() * v(0) + m.col(1).array() * v(1) + m.col(2).array() * v(2) + m.col(3).array();
-  return Result;
-}
-
-
-#include <limits>
-#include <cassert>
-
-#ifdef ENABLE_XML_SERIALIZATION
-  #include "igl/xml/XMLSerializer.h"
-#endif
-
-#include <igl/readOBJ.h>
-#include <igl/readOFF.h>
-#include <igl/per_face_normals.h>
-#include <igl/per_vertex_normals.h>
-#include <igl/per_corner_normals.h>
-#include <igl/adjacency_list.h>
-#include <igl/writeOBJ.h>
-#include <igl/writeOFF.h>
-#include <igl/massmatrix.h>
-#include <igl/file_dialog_open.h>
-#include <igl/file_dialog_save.h>
-#include <igl/quat_to_mat.h>
-#include <igl/quat_mult.h>
-#include <igl/axis_angle_to_quat.h>
-#include <igl/trackball.h>
-#include <igl/snap_to_canonical_view_quat.h>
-#include <igl/unproject.h>
-#include <TwOpenGLCore.h>
-
-// Plugin manager (exported to other compilation units)
-igl::Plugin_manager igl_viewer_plugin_manager;
-
-// Internal global variables used for glfw event handling
-static igl::Viewer * __viewer;
-static double highdpi = 1;
-static double scroll_x = 0;
-static double scroll_y = 0;
-
-/* This class extends the font rendering code in AntTweakBar
-   so that it can be used to render text at arbitrary 3D positions */
-class TextRenderer : public CTwGraphOpenGLCore {
-public:
-  TextRenderer() : m_shaderHandleBackup(0) { }
-
-  virtual int Init()
-  {
-    int retval = CTwGraphOpenGLCore::Init();
-    if (retval == 1)
-    {
-      std::string vertexShader =
-          "#version 150\n"
-          "uniform vec2 offset;"
-          "uniform vec2 wndSize;"
-          "uniform vec4 color;"
-          "uniform float depth;"
-          "in vec2 vertex;"
-          "in vec2 uv;"
-          "out vec4 fcolor;"
-          "out vec2 fuv;"
-          "void main() {"
-          "  gl_Position = vec4(2.0*(vertex.x+offset.x-0.5)/wndSize.x - 1.0,"
-          "                     1.0 - 2.0*(vertex.y+offset.y-0.5)/wndSize.y,"
-          "                     depth, 1);"
-          " fuv = uv;"
-          " fcolor = color;"
-          "}";
-
-      std::string fragmentShader =
-        "#version 150\n"
-        "uniform sampler2D tex;"
-        "in vec2 fuv;"
-        "in vec4 fcolor;"
-        "out vec4 outColor;"
-        "void main() { outColor.rgb = fcolor.bgr; outColor.a = fcolor.a * texture(tex, fuv).r; }";
-
-      if (!m_shader.init(vertexShader, fragmentShader, "outColor"))
-        return 0;
-
-      /* Adjust location bindings */
-      glBindAttribLocation(m_shader.program_shader, 0, "vertex");
-      glBindAttribLocation(m_shader.program_shader, 1, "uv");
-      glBindAttribLocation(m_shader.program_shader, 2, "color");
-      glLinkProgram(m_shader.program_shader);
-
-      m_shaderHandleBackup = m_TriTexUniProgram;
-      m_TriTexUniProgram = m_shader.program_shader;
-      m_TriTexUniLocationOffset = m_shader.uniform("offset");
-      m_TriTexUniLocationWndSize = m_shader.uniform("wndSize");
-      m_TriTexUniLocationColor = m_shader.uniform("color");
-      m_TriTexUniLocationTexture = m_shader.uniform("tex");
-      m_TriTexUniLocationDepth = m_shader.uniform("depth");
-    }
-    return retval;
-  }
-
-  virtual int Shut()
-  {
-    for (auto kv : m_textObjects)
-      DeleteTextObj(kv.second);
-    m_shader.free();
-    m_TriTexUniProgram = m_shaderHandleBackup;
-    return CTwGraphOpenGLCore::Shut();
-  }
-
-  void BeginDraw(const Eigen::Matrix4f &view, const Eigen::Matrix4f &proj,
-    const Eigen::Vector4f &_viewport, float _object_scale)
-  {
-    viewport = _viewport;
-    proj_matrix = proj;
-    view_matrix = view;
-    CTwGraphOpenGLCore::BeginDraw(viewport[2], viewport[3]);
-    glEnable(GL_DEPTH_TEST);
-    glDepthMask(GL_FALSE);
-    object_scale = _object_scale;
-  }
-
-  void EndDraw()
-  {
-    /* Limit the number of cached text objects */
-    for (auto it = m_textObjects.cbegin(); it != m_textObjects.cend(); )
-    {
-      if (m_textObjects.size() < 1000000)
-        break;
-      DeleteTextObj(it->second);
-      m_textObjects.erase(it++);
-    }
-
-    glDepthMask(GL_TRUE);
-    CTwGraphOpenGLCore::EndDraw();
-  }
-
-  void DrawText(Eigen::Vector3d pos, Eigen::Vector3d normal, const std::string &text)
-  {
-    pos += normal * 0.005f * object_scale;
-    Eigen::Vector3f coord = project(Eigen::Vector3f(pos(0), pos(1), pos(2)),
-        view_matrix, proj_matrix, viewport);
-    auto it = m_textObjects.find(text);
-    void *text_obj = nullptr;
-    if (it == m_textObjects.end())
-    {
-      text_obj = NewTextObj();
-      BuildText(text_obj, &text, NULL, NULL, 1, g_DefaultNormalFont, 0, 0);
-      m_textObjects[text] = text_obj;
-    } else {
-      text_obj = it->second;
-    }
-    m_shader.bind();
-    glUniform1f(m_TriTexUniLocationDepth, 2*(coord(2)-0.5f));
-    CTwGraphOpenGLCore::DrawText(text_obj, coord[0], viewport[3] - coord[1], COLOR32_BLUE, 0);
-  }
-protected:
-  igl::Viewer::OpenGL_shader m_shader;
-  std::map<std::string, void *> m_textObjects;
-  GLuint m_shaderHandleBackup;
-  GLuint m_TriTexUniLocationDepth;
-  Eigen::Matrix4f view_matrix, proj_matrix;
-  Eigen::Vector4f viewport;
-  float object_scale;
-};
-
-static TextRenderer __font_renderer;
-
-static void glfw_mouse_press(GLFWwindow* window, int button, int action, int modifier)
-{
-  bool tw_used = TwEventMouseButtonGLFW(button, action);
-  igl::Viewer::MouseButton mb;
-
-  if (button == GLFW_MOUSE_BUTTON_1)
-    mb = igl::Viewer::IGL_LEFT;
-  else if (button == GLFW_MOUSE_BUTTON_2)
-    mb = igl::Viewer::IGL_RIGHT;
-  else //if (button == GLFW_MOUSE_BUTTON_3)
-    mb = igl::Viewer::IGL_MIDDLE;
-
-  if (action == GLFW_PRESS)
-  {
-    if(!tw_used)
-    {
-      __viewer->mouse_down(mb,modifier);
-    }
-  } else
-  {
-    // Always call mouse_up on up
-    __viewer->mouse_up(mb,modifier);
-  }
-
-}
-
-static void glfw_error_callback(int error, const char* description)
-{
-  fputs(description, stderr);
-}
-
-int global_KMod = 0;
-
-int TwEventKeyGLFW3(int glfwKey, int glfwAction)
-{
-  int handled = 0;
-
-  // Register of modifiers state
-  if (glfwAction==GLFW_PRESS)
-  {
-    switch (glfwKey)
-    {
-      case GLFW_KEY_LEFT_SHIFT:
-      case GLFW_KEY_RIGHT_SHIFT:
-        global_KMod |= TW_KMOD_SHIFT;
-        break;
-      case GLFW_KEY_LEFT_CONTROL:
-      case GLFW_KEY_RIGHT_CONTROL:
-        global_KMod |= TW_KMOD_CTRL;
-        break;
-      case GLFW_KEY_LEFT_ALT:
-      case GLFW_KEY_RIGHT_ALT:
-        global_KMod |= TW_KMOD_ALT;
-        break;
-    }
-  }
-  else
-  {
-    switch (glfwKey)
-    {
-      case GLFW_KEY_LEFT_SHIFT:
-      case GLFW_KEY_RIGHT_SHIFT:
-        global_KMod &= ~TW_KMOD_SHIFT;
-        break;
-      case GLFW_KEY_LEFT_CONTROL:
-      case GLFW_KEY_RIGHT_CONTROL:
-        global_KMod &= ~TW_KMOD_CTRL;
-        break;
-      case GLFW_KEY_LEFT_ALT:
-      case GLFW_KEY_RIGHT_ALT:
-        global_KMod &= ~TW_KMOD_ALT;
-        break;
-    }
-  }
-
-  // Process key pressed
-  if (glfwAction==GLFW_PRESS)
-  {
-    int mod = global_KMod;
-    int testkp = ((mod&TW_KMOD_CTRL) || (mod&TW_KMOD_ALT)) ? 1 : 0;
-
-    if ((mod&TW_KMOD_CTRL) && glfwKey>0 && glfwKey<GLFW_KEY_ESCAPE   )   // CTRL cases
-      handled = TwKeyPressed(glfwKey, mod);
-    else if (glfwKey>=GLFW_KEY_ESCAPE  )
-    {
-      int k = 0;
-
-      if (glfwKey>=GLFW_KEY_F1 && glfwKey<=GLFW_KEY_F15)
-        k = TW_KEY_F1 + (glfwKey-GLFW_KEY_F1);
-      else if (testkp && glfwKey>=GLFW_KEY_KP_0 && glfwKey<=GLFW_KEY_KP_9)
-        k = '0' + (glfwKey-GLFW_KEY_KP_0);
-      else
-      {
-        switch (glfwKey)
-        {
-          case GLFW_KEY_ESCAPE  :
-            k = TW_KEY_ESCAPE;
-            break;
-          case GLFW_KEY_UP:
-            k = TW_KEY_UP;
-            break;
-          case GLFW_KEY_DOWN:
-            k = TW_KEY_DOWN;
-            break;
-          case GLFW_KEY_LEFT:
-            k = TW_KEY_LEFT;
-            break;
-          case GLFW_KEY_RIGHT:
-            k = TW_KEY_RIGHT;
-            break;
-          case GLFW_KEY_TAB:
-            k = TW_KEY_TAB;
-            break;
-          case GLFW_KEY_ENTER:
-            k = TW_KEY_RETURN;
-            break;
-          case GLFW_KEY_BACKSPACE:
-            k = TW_KEY_BACKSPACE;
-            break;
-          case GLFW_KEY_INSERT:
-            k = TW_KEY_INSERT;
-            break;
-          case GLFW_KEY_DELETE:
-            k = TW_KEY_DELETE;
-            break;
-          case GLFW_KEY_PAGE_UP:
-            k = TW_KEY_PAGE_UP;
-            break;
-          case GLFW_KEY_PAGE_DOWN:
-            k = TW_KEY_PAGE_DOWN;
-            break;
-          case GLFW_KEY_HOME:
-            k = TW_KEY_HOME;
-            break;
-          case GLFW_KEY_END:
-            k = TW_KEY_END;
-            break;
-          case GLFW_KEY_KP_ENTER:
-            k = TW_KEY_RETURN;
-            break;
-          case GLFW_KEY_KP_DIVIDE:
-            if (testkp)
-              k = '/';
-            break;
-          case GLFW_KEY_KP_MULTIPLY:
-            if (testkp)
-              k = '*';
-            break;
-          case GLFW_KEY_KP_SUBTRACT:
-            if (testkp)
-              k = '-';
-            break;
-          case GLFW_KEY_KP_ADD:
-            if (testkp)
-              k = '+';
-            break;
-          case GLFW_KEY_KP_DECIMAL:
-            if (testkp)
-              k = '.';
-            break;
-          case GLFW_KEY_KP_EQUAL:
-            if (testkp)
-              k = '=';
-            break;
-        }
-      }
-
-      if (k>0)
-        handled = TwKeyPressed(k, mod);
-    }
-  }
-
-  return handled;
-}
-
-static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int modifier)
-{
-  if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
-    glfwSetWindowShouldClose(window, GL_TRUE);
-
-  if (!TwEventKeyGLFW3(key,action))
-  {
-    if (action == GLFW_PRESS)
-      __viewer->key_down(key, modifier);
-    else
-      __viewer->key_up(key, modifier);
-  }
-}
-
-static void glfw_window_size(GLFWwindow* window, int width, int height)
-{
-  int w = width*highdpi;
-  int h = height*highdpi;
-
-  __viewer->resize(w, h);
-
-  TwWindowSize(w, h);
-  const auto & bar = __viewer->bar;
-  // Keep AntTweakBar on right side of screen and height == opengl height
-  // get the current position of a bar
-  int size[2];
-  TwGetParam(bar, NULL, "size", TW_PARAM_INT32, 2, size);
-  int pos[2];
-  // Place bar on left side of opengl rect (padded by 10 pixels)
-  pos[0] = 10;//max(10,(int)width - size[0] - 10);
-  // place bar at top (padded by 10 pixels)
-  pos[1] = 10;
-  // Set height to new height of window (padded by 10 pixels on bottom)
-  size[1] = height-pos[1]-10;
-  TwSetParam(bar, NULL, "position", TW_PARAM_INT32, 2, pos);
-  TwSetParam(bar, NULL, "size", TW_PARAM_INT32, 2,size);
-}
-
-static void glfw_mouse_move(GLFWwindow* window, double x, double y)
-{
-  if(!TwEventMousePosGLFW(x*highdpi,y*highdpi) || __viewer->down)
-  {
-    // Call if TwBar hasn't used or if down
-    __viewer->mouse_move(x*highdpi, y*highdpi);
-  }
-}
-
-static void glfw_mouse_scroll(GLFWwindow* window, double x, double y)
-{
-  using namespace std;
-  scroll_x += x;
-  scroll_y += y;
-
-  if (!TwEventMouseWheelGLFW(scroll_y))
-    __viewer->mouse_scroll(y);
-}
-
-static void glfw_char_callback(GLFWwindow* window, unsigned int c)
-{
-  if ((c & 0xff00)==0)
-    TwKeyPressed(c, global_KMod);
-}
-
-namespace igl
-{
-  void Viewer::init(Plugin_manager* pm)
-  {
-    plugin_manager = pm;
-
-    // Create a tweak bar
-    bar = TwNewBar("libIGL-Viewer");
-    TwDefine(" libIGL-Viewer help='This is a simple 3D mesh viewer.' "); // Message added to the help bar->
-    TwDefine(" libIGL-Viewer size='200 685'"); // change default tweak bar size
-    TwDefine(" libIGL-Viewer color='76 76 127' "); // change default tweak bar color
-    TwDefine(" libIGL-Viewer refresh=0.5"); // change refresh rate
-
-    // ---------------------- LOADING ----------------------
-
-    #ifdef ENABLE_XML_SERIALIZATION
-    TwAddButton(bar,"Load Scene", load_scene_cb,    this, "group='Workspace'");
-    TwAddButton(bar,"Save Scene", save_scene_cb,    this, "group='Workspace'");
-    #endif
-
-    #ifdef ENABLE_IO
-    TwAddButton(bar,"Load Mesh",  open_dialog_mesh, this, "group='Mesh' key=o");
-    #endif
-
-    // ---------------------- SCENE ----------------------
-
-    TwAddButton(bar,"Center object", align_camera_center_cb, this,
-                " group='Viewing Options'"
-                " label='Center object' key=A help='Set the center of the camera to the mesh center.'");
-    TwAddVarRW(bar, "Zoom", TW_TYPE_FLOAT, &(options.camera_zoom),
-               " min=0.05 max=50 step=0.1 keyIncr=+ keyDecr=- help='Scale the object (1=original size).' group='Scene'");
-    TwAddButton(bar,"SnapView", snap_to_canonical_quaternion_cb, this,
-                " group='Scene'"
-                " label='Snap to canonical view' key=Z "
-                " help='Snaps view to nearest canonical view.'");
-    TwAddVarRW(bar,"LightDir", TW_TYPE_DIR3F, options.light_position.data(),
-               " group='Scene'"
-               " label='Light direction' open help='Change the light direction.' ");
-
-    // ---------------------- DRAW OPTIONS ----------------------
-    TwAddVarRW(bar, "Toggle Orthographic/Perspective", TW_TYPE_BOOLCPP, &(options.orthographic),
-               " group='Viewing Options'"
-               " label='Orthographic view' "
-               " help='Toggles orthographic / perspective view. Default: perspective.'");
-
-    TwAddVarCB(bar,"Face-based Normals/Colors", TW_TYPE_BOOLCPP, set_face_based_cb, get_face_based_cb, this,
-               " group='Draw options'"
-               " label='Face-based' key=T help='Toggle per face shading/colors.' ");
-
-    TwAddVarRW(bar,"Show texture", TW_TYPE_BOOLCPP, &(options.show_texture),
-               " group='Draw options'");
-
-    TwAddVarCB(bar,"Invert Normals", TW_TYPE_BOOLCPP, set_invert_normals_cb, get_invert_normals_cb, this,
-               " group='Draw options'"
-               " label='Invert normals' key=i help='Invert normal directions for inside out meshes.' ");
-
-    TwAddVarRW(bar,"ShowOverlay", TW_TYPE_BOOLCPP, &(options.show_overlay),
-               " group='Draw options'"
-               " label='Show overlay' key=o help='Show the overlay layers.' ");
-    TwAddVarRW(bar,"ShowOverlayDepth", TW_TYPE_BOOLCPP, &(options.show_overlay_depth),
-               " group='Draw options'"
-               " label='Show overlay depth test' help='Enable the depth test for overlay layer.' ");
-    TwAddVarRW(bar,"Background color", TW_TYPE_COLOR3F,
-               options.background_color.data(),
-               " help='Select a background color' colormode=hls group='Draw options'");
-    TwAddVarRW(bar, "LineColor", TW_TYPE_COLOR3F,
-               options.line_color.data(),
-               " label='Line color' help='Select a outline color' group='Draw options'");
-    TwAddVarRW(bar,"Shininess",TW_TYPE_FLOAT,&options.shininess," group='Draw options'"
-               " min=1 max=128");
-
-    // ---------------------- Overlays ----------------------
-
-    TwAddVarRW(bar,"Wireframe", TW_TYPE_BOOLCPP, &(options.show_lines),
-               " group='Overlays'"
-               " label='Wireframe' key=l help='Toggle wire frame of mesh'");
-    TwAddVarRW(bar,"Fill", TW_TYPE_BOOLCPP, &(options.show_faces),
-               " group='Overlays'"
-               " label='Fill' key=t help='Display filled polygons of mesh'");
-    TwAddVarRW(bar,"ShowVertexId", TW_TYPE_BOOLCPP, &(options.show_vertid),
-               " group='Overlays'"
-               " label='Show Vertex Labels' key=';' help='Toggle vertex indices'");
-    TwAddVarRW(bar,"ShowFaceId", TW_TYPE_BOOLCPP, &(options.show_faceid),
-               " group='Overlays'"
-               " label='Show Faces Labels' key='CTRL+;' help='Toggle face"
-               " indices'");
-
-    __font_renderer.Init();
-
-    init_plugins();
-  }
-
-  Viewer::Viewer()
-  {
-    plugin_manager = 0;
-
-    // Default shininess
-    options.shininess = 35.0f;
-
-    // Default colors
-    options.background_color << 0.3f, 0.3f, 0.5f;
-    options.line_color << 0.0f, 0.0f, 0.0f;
-
-    // Default lights settings
-    options.light_position << 0.0f, -0.30f, -5.0f;
-    options.lighting_factor = 1.0f; //on
-
-    // Default trackball
-    options.trackball_angle << 0.0f, 0.0f, 0.0f, 1.0f;
-
-    // Defalut model viewing parameters
-    options.model_zoom = 1.0f;
-    options.model_translation << 0,0,0;
-
-    // Camera parameters
-    options.camera_zoom = 1.0f;
-    options.orthographic = false;
-    options.camera_view_angle = 45.0;
-    options.camera_dnear = 1.0;
-    options.camera_dfar = 100.0;
-    options.camera_eye << 0, 0, 5;
-    options.camera_center << 0, 0, 0;
-    options.camera_up << 0, 1, 0;
-
-    // Default visualization options
-    options.show_faces = true;
-    options.show_lines = true;
-    options.invert_normals = false;
-    options.show_overlay = true;
-    options.show_overlay_depth = true;
-    options.show_vertid = false;
-    options.show_faceid = false;
-    options.show_texture = false;
-
-    // Default point size / line width
-    options.point_size = 15;
-    options.line_width = 0.5f;
-
-    // Temporary variables initialization
-    down = false;
-    scroll_position = 0.0f;
-
-    // Per face
-    set_face_based(false);
-
-    // C-style callbacks
-    callback_pre_draw     = 0;
-    callback_post_draw    = 0;
-    callback_mouse_down   = 0;
-    callback_mouse_up     = 0;
-    callback_mouse_move   = 0;
-    callback_mouse_scroll = 0;
-    callback_key_down     = 0;
-    callback_key_up       = 0;
-
-    callback_pre_draw_data = 0;
-    callback_post_draw     = 0;
-    callback_mouse_down    = 0;
-    callback_mouse_up      = 0;
-    callback_mouse_move    = 0;
-    callback_mouse_scroll  = 0;
-    callback_key_down      = 0;
-    callback_key_up        = 0;
-  }
-
-  void Viewer::init_plugins()
-  {
-    // Init all plugins
-    if (plugin_manager)
-      for (unsigned int i = 0; i<plugin_manager->plugin_list.size(); ++i)
-        plugin_manager->plugin_list[i]->init(this);
-  }
-
-  Viewer::~Viewer()
-  {
-  }
-
-  void Viewer::shutdown_plugins()
-  {
-    if (plugin_manager)
-      for (unsigned int i = 0; i<plugin_manager->plugin_list.size(); ++i)
-        plugin_manager->plugin_list[i]->shutdown();
-  }
-
-  bool Viewer::load_mesh_from_file(const char* mesh_file_name)
-  {
-    std::string mesh_file_name_string = std::string(mesh_file_name);
-
-    // first try to load it with a plugin
-    if (plugin_manager)
-      for (unsigned int i = 0; i<plugin_manager->plugin_list.size(); ++i)
-        if (plugin_manager->plugin_list[i]->load(mesh_file_name_string))
-          return true;
-
-    clear_mesh();
-
-    size_t last_dot = mesh_file_name_string.rfind('.');
-    if (last_dot == std::string::npos)
-    {
-      printf("Error: No file extension found in %s\n",mesh_file_name);
-      return false;
-    }
-
-    std::string extension = mesh_file_name_string.substr(last_dot+1);
-
-    if (extension == "off" || extension =="OFF")
-    {
-      if (!igl::readOFF(mesh_file_name_string, data.V, data.F))
-        return false;
-    }
-    else if (extension == "obj" || extension =="OBJ")
-    {
-      Eigen::MatrixXd corner_normals;
-      Eigen::MatrixXi fNormIndices;
-
-      Eigen::MatrixXd UV_V;
-      Eigen::MatrixXi UV_F;
-
-      if (!(igl::readOBJ(mesh_file_name_string, data.V, data.F, corner_normals, fNormIndices, UV_V, UV_F)))
-        return false;
-    }
-    else
-    {
-      // unrecognized file type
-      printf("Error: %s is not a recognized file type.\n",extension.c_str());
-      return false;
-    }
-
-    compute_normals();
-    uniform_colors(Eigen::Vector3d(51.0/255.0,43.0/255.0,33.3/255.0),
-                   Eigen::Vector3d(255.0/255.0,228.0/255.0,58.0/255.0),
-                   Eigen::Vector3d(255.0/255.0,235.0/255.0,80.0/255.0));
-    if (data.V_uv.rows() == 0)
-      grid_texture();
-
-    align_camera_center();
-
-    if (plugin_manager)
-      for (unsigned int i = 0; i<plugin_manager->plugin_list.size(); ++i)
-        if (plugin_manager->plugin_list[i]->post_load())
-          return true;
-
-    return true;
-  }
-
-  void Viewer::compute_normals()
-  {
-    igl::per_face_normals(data.V, data.F, data.F_normals);
-    igl::per_vertex_normals(data.V, data.F, data.F_normals, data.V_normals);
-    data.dirty |= DIRTY_NORMAL;
-  }
-
-  void Viewer::uniform_colors(Eigen::Vector3d ambient, Eigen::Vector3d diffuse, Eigen::Vector3d specular)
-  {
-    data.V_material_ambient.resize(data.V.rows(),3);
-    data.V_material_diffuse.resize(data.V.rows(),3);
-    data.V_material_specular.resize(data.V.rows(),3);
-
-    for (unsigned i=0; i<data.V.rows();++i)
-    {
-      data.V_material_ambient.row(i) = ambient;
-      data.V_material_diffuse.row(i) = diffuse;
-      data.V_material_specular.row(i) = specular;
-    }
-
-    data.F_material_ambient.resize(data.F.rows(),3);
-    data.F_material_diffuse.resize(data.F.rows(),3);
-    data.F_material_specular.resize(data.F.rows(),3);
-
-    for (unsigned i=0; i<data.F.rows();++i)
-    {
-      data.F_material_ambient.row(i) = ambient;
-      data.F_material_diffuse.row(i) = diffuse;
-      data.F_material_specular.row(i) = specular;
-    }
-    data.dirty |= DIRTY_SPECULAR | DIRTY_DIFFUSE | DIRTY_AMBIENT;
-  }
-
-  void Viewer::grid_texture()
-  {
-    if (data.V_uv.rows() == 0)
-    {
-      data.V_uv = data.V.block(0, 0, data.V.rows(), 2);
-      data.V_uv.col(0) = data.V_uv.col(0).array() - data.V_uv.col(0).minCoeff();
-      data.V_uv.col(0) = data.V_uv.col(0).array() / data.V_uv.col(0).maxCoeff();
-      data.V_uv.col(1) = data.V_uv.col(1).array() - data.V_uv.col(1).minCoeff();
-      data.V_uv.col(1) = data.V_uv.col(1).array() / data.V_uv.col(1).maxCoeff();
-      data.V_uv = data.V_uv.array() * 10;
-      data.dirty |= DIRTY_TEXTURE;
-    }
-
-    unsigned size = 128;
-    unsigned size2 = size/2;
-    data.texture_R.resize(size, size);
-    for (unsigned i=0; i<size; ++i)
-    {
-      for (unsigned j=0; j<size; ++j)
-      {
-        data.texture_R(i,j) = 0;
-        if ((i<size2 && j<size2) || (i>=size2 && j>=size2))
-          data.texture_R(i,j) = 255;
-      }
-    }
-
-    data.texture_G = data.texture_R;
-    data.texture_B = data.texture_R;
-    data.dirty |= DIRTY_TEXTURE;
-  }
-
-  bool Viewer::save_mesh_to_file(const char* mesh_file_name)
-  {
-    std::string mesh_file_name_string(mesh_file_name);
-
-    // first try to load it with a plugin
-    if (plugin_manager)
-      for (unsigned int i = 0; i<plugin_manager->plugin_list.size(); ++i)
-        if (plugin_manager->plugin_list[i]->save(mesh_file_name_string))
-          return true;
-
-    size_t last_dot = mesh_file_name_string.rfind('.');
-    if (last_dot == std::string::npos)
-    {
-      // No file type determined
-      printf("Error: No file extension found in %s\n",mesh_file_name);
-      return false;
-    }
-    std::string extension = mesh_file_name_string.substr(last_dot+1);
-    if (extension == "off" || extension =="OFF")
-    {
-      return igl::writeOFF(mesh_file_name_string,data.V,data.F);
-    }
-    else if (extension == "obj" || extension =="OBJ")
-    {
-      Eigen::MatrixXd corner_normals;
-      Eigen::MatrixXi fNormIndices;
-
-      Eigen::MatrixXd UV_V;
-      Eigen::MatrixXi UV_F;
-
-      return igl::writeOBJ(mesh_file_name_string, data.V,
-          data.F, corner_normals, fNormIndices, UV_V, UV_F);
-    }
-    else
-    {
-      // unrecognized file type
-      printf("Error: %s is not a recognized file type.\n",extension.c_str());
-      return false;
-    }
-    return true;
-  }
-
-  void Viewer::clear_mesh()
-  {
-    data.V                       = Eigen::MatrixXd (0,3);
-    data.F                       = Eigen::MatrixXi (0,3);
-
-    data.F_material_ambient      = Eigen::MatrixXd (0,3);
-    data.F_material_diffuse      = Eigen::MatrixXd (0,3);
-    data.F_material_specular     = Eigen::MatrixXd (0,3);
-
-    data.V_material_ambient      = Eigen::MatrixXd (0,3);
-    data.V_material_diffuse      = Eigen::MatrixXd (0,3);
-    data.V_material_specular     = Eigen::MatrixXd (0,3);
-
-    data.F_normals               = Eigen::MatrixXd (0,3);
-    data.V_normals               = Eigen::MatrixXd (0,3);
-
-    data.V_uv                    = Eigen::MatrixXd (0,2);
-    data.F_uv                    = Eigen::MatrixXi (0,3);
-
-    data.lines                   = Eigen::MatrixXd (0,9);
-    data.points                  = Eigen::MatrixXd (0,6);
-    data.labels_positions        = Eigen::MatrixXd (0,3);
-    data.labels_strings.clear();
-  }
-
-  bool Viewer::key_down(unsigned char key, int modifiers)
-  {
-    if (callback_key_down)
-      if (callback_key_down(*this,key,modifiers))
-        return true;
-
-    if (plugin_manager)
-      for (unsigned int i = 0; i <plugin_manager->plugin_list.size(); ++i)
-        if (plugin_manager->plugin_list[i]->key_down(key, modifiers))
-          return true;
-
-    if (key == 'S')
-      mouse_scroll(1);
-
-    if (key == 'A')
-      mouse_scroll(-1);
-
-    // Why aren't these handled view AntTweakBar?
-    if (key == 'z') // Don't use 'Z' because that clobbers snap_to_canonical_view_quat
-      options.trackball_angle << 0.0f, 0.0f, 0.0f, 1.0f;
-
-    if (key == 'y')
-      options.trackball_angle << -sqrt(2.0f)/2.0f, 0.0f, 0.0f, sqrt(2.0f)/2.0f;
-
-    if (key == 'x')
-      options.trackball_angle << -0.5f, -0.5f, -0.5f, 0.5f;
-
-
-    return false;
-  }
-
-  bool Viewer::key_up(unsigned char key, int modifiers)
-  {
-    if (callback_key_up)
-      if (callback_key_up(*this,key,modifiers))
-        return true;
-
-    if (plugin_manager)
-      for (unsigned int i = 0; i <plugin_manager->plugin_list.size(); ++i)
-        if (plugin_manager->plugin_list[i]->key_up(key, modifiers))
-          return true;
-
-    return false;
-  }
-
-  bool Viewer::mouse_down(MouseButton button, int modifier)
-  {
-    if (callback_mouse_down)
-      if (callback_mouse_down(*this,button,modifier))
-        return true;
-
-    if (plugin_manager)
-      for (unsigned int i = 0; i < plugin_manager->plugin_list.size(); ++i)
-        if (plugin_manager->plugin_list[i]->mouse_down(button,modifier))
-          return true;
-
-    down = true;
-
-    down_mouse_x = current_mouse_x;
-    down_mouse_y = current_mouse_y;
-    down_translation = options.model_translation;
-
-
-    // Initialization code for the trackball
-    Eigen::RowVector3d center;
-    if (data.V.rows() == 0)
-      center << 0,0,0;
-    else
-      center = data.V.colwise().sum()/data.V.rows();
-
-    Eigen::Vector3f coord = project(Eigen::Vector3f(center(0),center(1),center(2)), view * model, proj, viewport);
-    down_mouse_z = coord[2];
-    down_rotation = options.trackball_angle;
-
-    mouse_mode = ROTATION;
-
-    switch (button)
-    {
-      case IGL_LEFT:
-        mouse_mode = ROTATION;
-        break;
-
-      case IGL_RIGHT:
-        mouse_mode = TRANSLATE;
-        break;
-
-      default:
-        mouse_mode = NOTHING;
-        break;
-    }
-
-    return true;
-  }
-
-  bool Viewer::mouse_up(MouseButton button, int modifier)
-  {
-    down = false;
-
-    if (callback_mouse_up)
-      if (callback_mouse_up(*this,button,modifier))
-        return true;
-
-    if (plugin_manager)
-      for (unsigned int i = 0; i <plugin_manager->plugin_list.size(); ++i)
-        if (plugin_manager->plugin_list[i]->mouse_up(button,modifier))
-          return true;
-
-    mouse_mode = NOTHING;
-
-    return true;
-  }
-
-  bool Viewer::mouse_move(int mouse_x, int mouse_y)
-  {
-    current_mouse_x = mouse_x;
-    current_mouse_y = mouse_y;
-
-    if (callback_mouse_move)
-      if (callback_mouse_move(*this,mouse_x,mouse_y))
-        return true;
-
-    if (plugin_manager)
-      for (unsigned int i = 0; i < plugin_manager->plugin_list.size(); ++i)
-        if (plugin_manager->plugin_list[i]->mouse_move(mouse_x, mouse_y))
-          return true;
-
-    if (down)
-    {
-      switch (mouse_mode)
-      {
-        case ROTATION :
-        {
-          igl::trackball(width,
-                         height,
-                         2.0f,
-                         down_rotation.data(),
-                         down_mouse_x,
-                         down_mouse_y,
-                         mouse_x,
-                         mouse_y,
-                         options.trackball_angle.data());
-          //Eigen::Vector4f snapq = options.trackball_angle;
-
-          break;
-        }
-
-        case TRANSLATE:
-        {
-          //translation
-          Eigen::Vector3f pos1 = igl::unproject(Eigen::Vector3f(mouse_x, viewport[3] - mouse_y, down_mouse_z), view * model, proj, viewport);
-          Eigen::Vector3f pos0 = igl::unproject(Eigen::Vector3f(down_mouse_x, viewport[3] - down_mouse_y, down_mouse_z), view * model, proj, viewport);
-
-          Eigen::Vector3f diff = pos1 - pos0;
-          options.model_translation = down_translation + Eigen::Vector3f(diff[0],diff[1],diff[2]);
-
-          break;
-        }
-        case ZOOM:
-        {
-          //float delta = 0.001f * (mouse_x - down_mouse_x + mouse_y - down_mouse_y);
-          float delta = 0.001f * (mouse_x - down_mouse_x + mouse_y - down_mouse_y);
-          options.camera_zoom *= 1 + delta;
-          down_mouse_x = mouse_x;
-          down_mouse_y = mouse_y;
-          break;
-        }
-
-        default:
-          break;
-      }
-    }
-    return true;
-  }
-
-  bool Viewer::mouse_scroll(float delta_y)
-  {
-    scroll_position += delta_y;
-
-    if (callback_mouse_scroll)
-      if (callback_mouse_scroll(*this,delta_y))
-        return true;
-
-    if (plugin_manager)
-      for (unsigned int i = 0; i <plugin_manager->plugin_list.size(); ++i)
-        if (plugin_manager->plugin_list[i]->mouse_scroll(delta_y))
-          return true;
-
-    // Only zoom if there's actually a change
-    if(delta_y != 0)
-    {
-      float mult = (1.0+((delta_y>0)?1.:-1.)*0.05);
-      const float min_zoom = 0.1f;
-      options.camera_zoom = (options.camera_zoom * mult > min_zoom ? options.camera_zoom * mult : min_zoom);
-    }
-    return true;
-  }
-
-  static GLuint create_shader_helper(GLint type, const std::string &shader_string)
-  {
-    using namespace std;
-    if (shader_string.empty())
-      return (GLuint) 0;
-
-    GLuint id = glCreateShader(type);
-    const char *shader_string_const = shader_string.c_str();
-    glShaderSource(id, 1, &shader_string_const, NULL);
-    glCompileShader(id);
-
-    GLint status;
-    glGetShaderiv(id, GL_COMPILE_STATUS, &status);
-
-    if (status != GL_TRUE)
-    {
-      char buffer[512];
-      if (type == GL_VERTEX_SHADER)
-        cerr << "Vertex shader:" << endl;
-      else if (type == GL_FRAGMENT_SHADER)
-        cerr << "Fragment shader:" << endl;
-      else if (type == GL_GEOMETRY_SHADER)
-        cerr << "Geometry shader:" << endl;
-      cerr << shader_string << endl << endl;
-      glGetShaderInfoLog(id, 512, NULL, buffer);
-      cerr << "Error: " << endl << buffer << endl;
-      return (GLuint) 0;
-    }
-
-    return id;
-  }
-
-  bool Viewer::OpenGL_shader::init_from_files(
-    const std::string &vertex_shader_filename,
-    const std::string &fragment_shader_filename,
-    const std::string &fragment_data_name,
-    const std::string &geometry_shader_filename,
-    int geometry_shader_max_vertices)
-  {
-    auto file_to_string = [](const std::string &filename)
-    {
-      std::ifstream t(filename);
-      return std::string((std::istreambuf_iterator<char>(t)),
-                          std::istreambuf_iterator<char>());
-    };
-
-    return init(
-      file_to_string(vertex_shader_filename),
-      file_to_string(fragment_shader_filename),
-      fragment_data_name,
-      file_to_string(geometry_shader_filename),
-      geometry_shader_max_vertices
-   );
-  }
-
-  bool Viewer::OpenGL_shader::init(
-    const std::string &vertex_shader_string,
-    const std::string &fragment_shader_string,
-    const std::string &fragment_data_name,
-    const std::string &geometry_shader_string,
-    int geometry_shader_max_vertices)
-  {
-    using namespace std;
-    vertex_shader = create_shader_helper(GL_VERTEX_SHADER, vertex_shader_string);
-    geometry_shader = create_shader_helper(GL_GEOMETRY_SHADER, geometry_shader_string);
-    fragment_shader = create_shader_helper(GL_FRAGMENT_SHADER, fragment_shader_string);
-
-    if (!vertex_shader || !fragment_shader)
-      return false;
-
-    program_shader = glCreateProgram();
-
-    glAttachShader(program_shader, vertex_shader);
-    glAttachShader(program_shader, fragment_shader);
-
-    if (geometry_shader)
-    {
-      glAttachShader(program_shader, geometry_shader);
-
-      /* This covers only basic cases and may need to be modified */
-      glProgramParameteri(program_shader, GL_GEOMETRY_INPUT_TYPE, GL_TRIANGLES);
-      glProgramParameteri(program_shader, GL_GEOMETRY_OUTPUT_TYPE, GL_TRIANGLES);
-      glProgramParameteri(program_shader, GL_GEOMETRY_VERTICES_OUT, geometry_shader_max_vertices);
-    }
-
-    glBindFragDataLocation(program_shader, 0, fragment_data_name.c_str());
-    glLinkProgram(program_shader);
-
-    GLint status;
-    glGetProgramiv(program_shader, GL_LINK_STATUS, &status);
-
-    if (status != GL_TRUE)
-    {
-      char buffer[512];
-      glGetProgramInfoLog(program_shader, 512, NULL, buffer);
-      cerr << "Linker error: " << endl << buffer << endl;
-      program_shader = 0;
-      return false;
-    }
-
-    return true;
-  }
-
-  void Viewer::OpenGL_shader::bind()
-  {
-    glUseProgram(program_shader);
-  }
-
-  GLint Viewer::OpenGL_shader::attrib(const std::string &name) const
-  {
-    return glGetAttribLocation(program_shader, name.c_str());
-  }
-
-  GLint Viewer::OpenGL_shader::uniform(const std::string &name) const
-  {
-    return glGetUniformLocation(program_shader, name.c_str());
-  }
-
-  GLint Viewer::OpenGL_shader::bindVertexAttribArray(
-    const std::string &name, GLuint bufferID, const Eigen::MatrixXf &M, bool refresh) const
-  {
-    GLint id = attrib(name);
-    if (id < 0)
-      return id;
-    if (M.size() == 0)
-    {
-      glDisableVertexAttribArray(id);
-      return id;
-    }
-    glBindBuffer(GL_ARRAY_BUFFER, bufferID);
-    if (refresh)
-      glBufferData(GL_ARRAY_BUFFER, sizeof(float)*M.size(), M.data(), GL_DYNAMIC_DRAW);
-    glVertexAttribPointer(id, M.rows(), GL_FLOAT, GL_FALSE, 0, 0);
-    glEnableVertexAttribArray(id);
-    return id;
-  }
-
-  void Viewer::OpenGL_shader::free()
-  {
-    if (program_shader)
-    {
-      glDeleteProgram(program_shader);
-      program_shader = 0;
-    }
-    if (vertex_shader)
-    {
-      glDeleteShader(vertex_shader);
-      vertex_shader = 0;
-    }
-    if (fragment_shader)
-    {
-      glDeleteShader(fragment_shader);
-      fragment_shader = 0;
-    }
-    if (geometry_shader)
-    {
-      glDeleteShader(geometry_shader);
-      geometry_shader = 0;
-    }
-  }
-
-  void Viewer::OpenGL_state::init()
-  {
-    // Mesh: Vertex Array Object & Buffer objects
-    glGenVertexArrays(1, &vao_mesh);
-    glBindVertexArray(vao_mesh);
-    glGenBuffers(1, &vbo_V);
-    glGenBuffers(1, &vbo_V_normals);
-    glGenBuffers(1, &vbo_V_ambient);
-    glGenBuffers(1, &vbo_V_diffuse);
-    glGenBuffers(1, &vbo_V_specular);
-    glGenBuffers(1, &vbo_V_uv);
-    glGenBuffers(1, &vbo_F);
-    glGenTextures(1, &vbo_tex);
-
-    // Line overlay
-    glGenVertexArrays(1, &vao_overlay_lines);
-    glBindVertexArray(vao_overlay_lines);
-    glGenBuffers(1, &vbo_lines_F);
-    glGenBuffers(1, &vbo_lines_V);
-    glGenBuffers(1, &vbo_lines_V_colors);
-
-    // Point overlay
-    glGenVertexArrays(1, &vao_overlay_points);
-    glBindVertexArray(vao_overlay_points);
-    glGenBuffers(1, &vbo_points_F);
-    glGenBuffers(1, &vbo_points_V);
-    glGenBuffers(1, &vbo_points_V_colors);
-
-    dirty = DIRTY_ALL;
-  }
-
-  void Viewer::OpenGL_state::free()
-  {
-    glDeleteVertexArrays(1, &vao_mesh);
-    glDeleteVertexArrays(1, &vao_overlay_lines);
-    glDeleteVertexArrays(1, &vao_overlay_points);
-
-    glDeleteBuffers(1, &vbo_V);
-    glDeleteBuffers(1, &vbo_V_normals);
-    glDeleteBuffers(1, &vbo_V_ambient);
-    glDeleteBuffers(1, &vbo_V_diffuse);
-    glDeleteBuffers(1, &vbo_V_specular);
-    glDeleteBuffers(1, &vbo_V_uv);
-    glDeleteBuffers(1, &vbo_F);
-    glDeleteBuffers(1, &vbo_lines_F);
-    glDeleteBuffers(1, &vbo_lines_V);
-    glDeleteBuffers(1, &vbo_lines_V_colors);
-    glDeleteBuffers(1, &vbo_points_F);
-    glDeleteBuffers(1, &vbo_points_V);
-    glDeleteBuffers(1, &vbo_points_V_colors);
-
-    glDeleteTextures(1, &vbo_tex);
-  }
-
-  void Viewer::OpenGL_state::set_data(const Data &data, bool face_based, bool invert_normals)
-  {
-    bool per_corner_uv = (data.F_uv.rows() == data.F.rows());
-    bool per_corner_normals = (data.F_normals.rows() == 3 * data.F.rows());
-
-    dirty |= data.dirty;
-
-    if (!face_based)
-    {
-      if (!per_corner_uv)
-      {
-        // Vertex positions
-        if (dirty & DIRTY_POSITION)
-          V_vbo = (data.V.transpose()).cast<float>();
-
-        // Vertex normals
-        if (dirty & DIRTY_NORMAL)
-        {
-          V_normals_vbo = (data.V_normals.transpose()).cast<float>();
-          if (invert_normals)
-            V_normals_vbo = -V_normals_vbo;
-        }
-
-        // Per-vertex material settings
-        if (dirty & DIRTY_AMBIENT)
-          V_ambient_vbo = (data.V_material_ambient.transpose()).cast<float>();
-        if (dirty & DIRTY_DIFFUSE)
-          V_diffuse_vbo = (data.V_material_diffuse.transpose()).cast<float>();
-        if (dirty & DIRTY_SPECULAR)
-          V_specular_vbo = (data.V_material_specular.transpose()).cast<float>();
-
-        // Face indices
-        if (dirty & DIRTY_FACE)
-          F_vbo = (data.F.transpose()).cast<unsigned>();
-
-        // Texture coordinates
-        if (dirty & DIRTY_UV)
-          V_uv_vbo = (data.V_uv.transpose()).cast<float>();
-      }
-      else
-      {
-        // Per vertex properties with per corner UVs
-        if (dirty & DIRTY_POSITION)
-        {
-          V_vbo.resize(3,data.F.rows()*3);
-          for (unsigned i=0; i<data.F.rows();++i)
-            for (unsigned j=0;j<3;++j)
-              V_vbo.col(i*3+j) = data.V.row(data.F(i,j)).transpose().cast<float>();
-        }
-
-        if (dirty & DIRTY_AMBIENT)
-        {
-          V_ambient_vbo.resize(3,data.F.rows()*3);
-          for (unsigned i=0; i<data.F.rows();++i)
-            for (unsigned j=0;j<3;++j)
-              V_ambient_vbo.col (i*3+j) = data.V_material_ambient.row(data.F(i,j)).transpose().cast<float>();
-        }
-
-        if (dirty & DIRTY_DIFFUSE)
-        {
-          V_diffuse_vbo.resize(3,data.F.rows()*3);
-          for (unsigned i=0; i<data.F.rows();++i)
-            for (unsigned j=0;j<3;++j)
-              V_diffuse_vbo.col (i*3+j) = data.V_material_diffuse.row(data.F(i,j)).transpose().cast<float>();
-        }
-
-        if (dirty & DIRTY_SPECULAR)
-        {
-          V_specular_vbo.resize(3,data.F.rows()*3);
-          for (unsigned i=0; i<data.F.rows();++i)
-            for (unsigned j=0;j<3;++j)
-              V_specular_vbo.col(i*3+j) = data.V_material_specular.row(data.F(i,j)).transpose().cast<float>();
-        }
-
-        if (dirty & DIRTY_NORMAL)
-        {
-          V_normals_vbo.resize(3,data.F.rows()*3);
-          for (unsigned i=0; i<data.F.rows();++i)
-            for (unsigned j=0;j<3;++j)
-              V_normals_vbo.col (i*3+j) = data.V_normals.row(data.F(i,j)).transpose().cast<float>();
-
-          if (invert_normals)
-            V_normals_vbo = -V_normals_vbo;
-        }
-
-        if (dirty & DIRTY_FACE)
-        {
-          F_vbo.resize(3,data.F.rows());
-          for (unsigned i=0; i<data.F.rows();++i)
-            F_vbo.col(i) << i*3+0, i*3+1, i*3+2;
-        }
-
-        if (dirty & DIRTY_UV)
-        {
-          V_uv_vbo.resize(2,data.F.rows()*3);
-          for (unsigned i=0; i<data.F.rows();++i)
-            for (unsigned j=0;j<3;++j)
-              V_uv_vbo.col(i*3+j) = data.V_uv.row(data.F(i,j)).transpose().cast<float>();
-        }
-      }
-    }
-    else
-    {
-      if (dirty & DIRTY_POSITION)
-      {
-        V_vbo.resize(3,data.F.rows()*3);
-        for (unsigned i=0; i<data.F.rows();++i)
-          for (unsigned j=0;j<3;++j)
-            V_vbo.col(i*3+j) = data.V.row(data.F(i,j)).transpose().cast<float>();
-      }
-
-      if (dirty & DIRTY_AMBIENT)
-      {
-        V_ambient_vbo.resize(3,data.F.rows()*3);
-        for (unsigned i=0; i<data.F.rows();++i)
-          for (unsigned j=0;j<3;++j)
-            V_ambient_vbo.col (i*3+j) = data.F_material_ambient.row(i).transpose().cast<float>();
-      }
-
-      if (dirty & DIRTY_DIFFUSE)
-      {
-        V_diffuse_vbo.resize(3,data.F.rows()*3);
-        for (unsigned i=0; i<data.F.rows();++i)
-          for (unsigned j=0;j<3;++j)
-            V_diffuse_vbo.col (i*3+j) = data.F_material_diffuse.row(i).transpose().cast<float>();
-      }
-
-      if (dirty & DIRTY_SPECULAR)
-      {
-        V_specular_vbo.resize(3,data.F.rows()*3);
-        for (unsigned i=0; i<data.F.rows();++i)
-          for (unsigned j=0;j<3;++j)
-            V_specular_vbo.col(i*3+j) = data.F_material_specular.row(i).transpose().cast<float>();
-      }
-
-      if (dirty & DIRTY_NORMAL)
-      {
-        V_normals_vbo.resize(3,data.F.rows()*3);
-        for (unsigned i=0; i<data.F.rows();++i)
-          for (unsigned j=0;j<3;++j)
-            V_normals_vbo.col (i*3+j) =
-               per_corner_normals ?
-                 data.F_normals.row(i*3+j).transpose().cast<float>() :
-                 data.F_normals.row(i).transpose().cast<float>();
-
-        if (invert_normals)
-          V_normals_vbo = -V_normals_vbo;
-      }
-
-      if (dirty & DIRTY_FACE)
-      {
-        F_vbo.resize(3,data.F.rows());
-        for (unsigned i=0; i<data.F.rows();++i)
-          F_vbo.col(i) << i*3+0, i*3+1, i*3+2;
-      }
-
-      if (dirty & DIRTY_UV)
-      {
-          V_uv_vbo.resize(2,data.F.rows()*3);
-          for (unsigned i=0; i<data.F.rows();++i)
-            for (unsigned j=0;j<3;++j)
-              V_uv_vbo.col(i*3+j) = data.V_uv.row(per_corner_uv ? data.F_uv(i,j) : data.F(i,j)).transpose().cast<float>();
-      }
-    }
-
-    if (dirty & DIRTY_TEXTURE)
-    {
-      tex_u = data.texture_R.rows();
-      tex_v = data.texture_R.cols();
-      tex.resize(data.texture_R.size()*3);
-      for (unsigned i=0;i<data.texture_R.size();++i)
-      {
-        tex(i*3+0) = data.texture_R(i);
-        tex(i*3+1) = data.texture_G(i);
-        tex(i*3+2) = data.texture_B(i);
-      }
-    }
-
-    if (dirty & DIRTY_OVERLAY_LINES)
-    {
-      lines_V_vbo.resize(3, data.lines.rows()*2);
-      lines_V_colors_vbo.resize(3, data.lines.rows()*2);
-      lines_F_vbo.resize(1, data.lines.rows()*2);
-      for (unsigned i=0; i<data.lines.rows();++i)
-      {
-        lines_V_vbo.col(2*i+0) = data.lines.block<1, 3>(i, 0).transpose().cast<float>();
-        lines_V_vbo.col(2*i+1) = data.lines.block<1, 3>(i, 3).transpose().cast<float>();
-        lines_V_colors_vbo.col(2*i+0) = data.lines.block<1, 3>(i, 6).transpose().cast<float>();
-        lines_V_colors_vbo.col(2*i+1) = data.lines.block<1, 3>(i, 6).transpose().cast<float>();
-        lines_F_vbo(2*i+0) = 2*i+0;
-        lines_F_vbo(2*i+1) = 2*i+1;
-      }
-    }
-
-    if (dirty & DIRTY_OVERLAY_POINTS)
-    {
-      points_V_vbo.resize(3, data.points.rows());
-      points_V_colors_vbo.resize(3, data.points.rows());
-      points_F_vbo.resize(1, data.points.rows());
-      for (unsigned i=0; i<data.points.rows();++i)
-      {
-        points_V_vbo.col(i) = data.points.block<1, 3>(i, 0).transpose().cast<float>();
-        points_V_colors_vbo.col(i) = data.points.block<1, 3>(i, 3).transpose().cast<float>();
-        points_F_vbo(i) = i;
-      }
-    }
-  }
-
-  void Viewer::OpenGL_state::bind_mesh()
-  {
-    glBindVertexArray(vao_mesh);
-    shader_mesh.bind();
-    shader_mesh.bindVertexAttribArray("position", vbo_V, V_vbo, dirty & DIRTY_POSITION);
-    shader_mesh.bindVertexAttribArray("normal", vbo_V_normals, V_normals_vbo, dirty & DIRTY_NORMAL);
-    shader_mesh.bindVertexAttribArray("Ka", vbo_V_ambient, V_ambient_vbo, dirty & DIRTY_AMBIENT);
-    shader_mesh.bindVertexAttribArray("Kd", vbo_V_diffuse, V_diffuse_vbo, dirty & DIRTY_DIFFUSE);
-    shader_mesh.bindVertexAttribArray("Ks", vbo_V_specular, V_specular_vbo, dirty & DIRTY_SPECULAR);
-    shader_mesh.bindVertexAttribArray("texcoord", vbo_V_uv, V_uv_vbo, dirty & DIRTY_UV);
-
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_F);
-    if (dirty & DIRTY_FACE)
-      glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*F_vbo.size(), F_vbo.data(), GL_DYNAMIC_DRAW);
-
-    glActiveTexture(GL_TEXTURE0);
-    glBindTexture(GL_TEXTURE_2D, vbo_tex);
-    if (dirty & DIRTY_TEXTURE)
-    {
-      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_u, tex_v, 0, GL_RGB, GL_UNSIGNED_BYTE, tex.data());
-    }
-    glUniform1i(shader_mesh.uniform("tex"), 0);
-    dirty &= ~DIRTY_MESH;
-  }
-
-  void Viewer::OpenGL_state::bind_overlay_lines()
-  {
-    bool is_dirty = dirty & DIRTY_OVERLAY_LINES;
-
-    glBindVertexArray(vao_overlay_lines);
-    shader_overlay_lines.bind();
-    shader_overlay_lines.bindVertexAttribArray("position", vbo_lines_V, lines_V_vbo, is_dirty);
-    shader_overlay_lines.bindVertexAttribArray("color", vbo_lines_V_colors, lines_V_colors_vbo, is_dirty);
-
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_lines_F);
-    if (is_dirty)
-      glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*lines_F_vbo.size(), lines_F_vbo.data(), GL_DYNAMIC_DRAW);
-
-    dirty &= ~DIRTY_OVERLAY_LINES;
-  }
-
-  void Viewer::OpenGL_state::bind_overlay_points()
-  {
-    bool is_dirty = dirty & DIRTY_OVERLAY_POINTS;
-
-    glBindVertexArray(vao_overlay_points);
-    shader_overlay_points.bind();
-    shader_overlay_points.bindVertexAttribArray("position", vbo_points_V, points_V_vbo, is_dirty);
-    shader_overlay_points.bindVertexAttribArray("color", vbo_points_V_colors, points_V_colors_vbo, is_dirty);
-
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_points_F);
-    if (is_dirty)
-      glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*points_F_vbo.size(), points_F_vbo.data(), GL_DYNAMIC_DRAW);
-
-    dirty &= ~DIRTY_OVERLAY_POINTS;
-  }
-
-  void Viewer::OpenGL_state::draw_mesh(bool solid)
-  {
-    glPolygonMode(GL_FRONT_AND_BACK, solid ? GL_FILL : GL_LINE);
-
-    /* Avoid Z-buffer fighting between filled triangles & wireframe lines */
-    if (solid)
-    {
-      glEnable(GL_POLYGON_OFFSET_FILL);
-      glPolygonOffset(1.0, 1.0);
-    }
-    glDrawElements(GL_TRIANGLES, 3*F_vbo.cols(), GL_UNSIGNED_INT, 0);
-
-    glDisable(GL_POLYGON_OFFSET_FILL);
-    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-  }
-
-  void Viewer::OpenGL_state::draw_overlay_lines()
-  {
-    glDrawElements(GL_LINES, lines_F_vbo.cols(), GL_UNSIGNED_INT, 0);
-  }
-
-  void Viewer::OpenGL_state::draw_overlay_points()
-  {
-    glDrawElements(GL_POINTS, points_F_vbo.cols(), GL_UNSIGNED_INT, 0);
-  }
-
-  void Viewer::init_opengl()
-  {
-    std::string mesh_vertex_shader_string =
-    "#version 150\n"
-    "uniform mat4 model;"
-    "uniform mat4 view;"
-    "uniform mat4 proj;"
-    "in vec3 position;"
-    "in vec3 normal;"
-    "out vec3 position_eye;"
-    "out vec3 normal_eye;"
-    "in vec3 Ka;"
-    "in vec3 Kd;"
-    "in vec3 Ks;"
-    "in vec2 texcoord;"
-    "out vec2 texcoordi;"
-    "out vec3 Kai;"
-    "out vec3 Kdi;"
-    "out vec3 Ksi;"
-
-    "void main()"
-    "{"
-    "  position_eye = vec3 (view * model * vec4 (position, 1.0));"
-    "  normal_eye = vec3 (view * model * vec4 (normal, 0.0));"
-    "  normal_eye = normalize(normal_eye);"
-    "  gl_Position = proj * vec4 (position_eye, 1.0);" //proj * view * model * vec4(position, 1.0);"
-    "  Kai = Ka;"
-    "  Kdi = Kd;"
-    "  Ksi = Ks;"
-    "  texcoordi = texcoord;"
-    "}";
-
-    std::string mesh_fragment_shader_string =
-    "#version 150\n"
-    "uniform mat4 model;"
-    "uniform mat4 view;"
-    "uniform mat4 proj;"
-    "uniform vec4 fixed_color;"
-    "in vec3 position_eye;"
-    "in vec3 normal_eye;"
-    "uniform vec3 light_position_world;"
-    "vec3 Ls = vec3 (1, 1, 1);"
-    "vec3 Ld = vec3 (1, 1, 1);"
-    "vec3 La = vec3 (1, 1, 1);"
-    "in vec3 Ksi;"
-    "in vec3 Kdi;"
-    "in vec3 Kai;"
-    "in vec2 texcoordi;"
-    "uniform sampler2D tex;"
-    "uniform float specular_exponent;"
-    "uniform float lighting_factor;"
-    "uniform float texture_factor;"
-    "out vec4 outColor;"
-    "void main()"
-    "{"
-    "vec3 Ia = La * Kai;"    // ambient intensity
-
-    "vec3 light_position_eye = vec3 (view * vec4 (light_position_world, 1.0));"
-    "vec3 distance_to_light_eye = light_position_eye - position_eye;"
-    "vec3 direction_to_light_eye = normalize (distance_to_light_eye);"
-    "float dot_prod = dot (direction_to_light_eye, normal_eye);"
-    "dot_prod = max (dot_prod, 0.0);"
-    "vec3 Id = Ld * Kdi * dot_prod;"    // Diffuse intensity
-
-    "vec3 reflection_eye = reflect (-direction_to_light_eye, normal_eye);"
-    "vec3 surface_to_viewer_eye = normalize (-position_eye);"
-    "float dot_prod_specular = dot (reflection_eye, surface_to_viewer_eye);"
-    "dot_prod_specular = max (dot_prod_specular, 0.0);"
-    "float specular_factor = pow (dot_prod_specular, specular_exponent);"
-    "vec3 Is = Ls * Ksi * specular_factor;"    // specular intensity
-    "vec4 color = vec4(lighting_factor * (Is + Id) + Ia, 1.0) + vec4((1.0-lighting_factor) * Kdi,1.0);"
-    "outColor = mix(vec4(1,1,1,1), texture(tex, texcoordi), texture_factor) * color;"
-    "if (fixed_color != vec4(0.0)) outColor = fixed_color;"
-    "}";
-
-    std::string overlay_vertex_shader_string =
-    "#version 150\n"
-    "uniform mat4 model;"
-    "uniform mat4 view;"
-    "uniform mat4 proj;"
-    "in vec3 position;"
-    "in vec3 color;"
-    "out vec3 color_frag;"
-
-    "void main()"
-    "{"
-    "  gl_Position = proj * view * model * vec4 (position, 1.0);"
-    "  color_frag = color;"
-    "}";
-
-    std::string overlay_fragment_shader_string =
-    "#version 150\n"
-    "in vec3 color_frag;"
-    "out vec4 outColor;"
-    "void main()"
-    "{"
-    "  outColor = vec4(color_frag, 1.0);"
-    "}";
-
-    std::string overlay_point_fragment_shader_string =
-    "#version 150\n"
-    "in vec3 color_frag;"
-    "out vec4 outColor;"
-    "void main()"
-    "{"
-    "  if (length(gl_PointCoord - vec2(0.5)) > 0.5)"
-    "    discard;"
-    "  outColor = vec4(color_frag, 1.0);"
-    "}";
-
-    opengl.init();
-    opengl.shader_mesh.init(mesh_vertex_shader_string,
-        mesh_fragment_shader_string, "outColor");
-    opengl.shader_overlay_lines.init(overlay_vertex_shader_string,
-        overlay_fragment_shader_string, "outColor");
-    opengl.shader_overlay_points.init(overlay_vertex_shader_string,
-        overlay_point_fragment_shader_string, "outColor");
-  }
-
-  void Viewer::free_opengl()
-  {
-    opengl.shader_mesh.free();
-    opengl.shader_overlay_lines.free();
-    opengl.shader_overlay_points.free();
-    opengl.free();
-    __font_renderer.Shut();
-  }
-
-  void Viewer::draw()
-  {
-    using namespace std;
-    using namespace Eigen;
-    glClearColor(options.background_color[0],
-                 options.background_color[1],
-                 options.background_color[2],
-                 1.0f);
-    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-    glEnable(GL_DEPTH_TEST);
-
-    if (callback_pre_draw)
-      if (callback_pre_draw(*this))
-        return;
-
-    if (plugin_manager)
-      for (unsigned int i = 0; i <plugin_manager->plugin_list.size(); ++i)
-        if (plugin_manager->plugin_list[i]->pre_draw())
-          return;
-
-    /* Bind and potentially refresh mesh/line/point data */
-    if (data.dirty)
-    {
-      opengl.set_data(data, options.face_based, options.invert_normals);
-      data.dirty = DIRTY_NONE;
-    }
-    opengl.bind_mesh();
-
-    // Initialize uniform
-    glViewport(0, 0, width, height);
-
-    model = Eigen::Matrix4f::Identity();
-    view  = Eigen::Matrix4f::Identity();
-    proj  = Eigen::Matrix4f::Identity();
-
-    // Set view
-    view = lookAt(Eigen::Vector3f(options.camera_eye[0], options.camera_eye[1], options.camera_eye[2]),
-                  Eigen::Vector3f(options.camera_center[0], options.camera_center[1], options.camera_center[2]),
-                  Eigen::Vector3f(options.camera_up[0], options.camera_up[1], options.camera_up[2]));
-
-    // Set projection
-    if (options.orthographic)
-    {
-      float length = (options.camera_eye - options.camera_center).norm();
-      float h = tan(options.camera_view_angle/360.0 * M_PI) * (length);
-      proj = ortho(-h*width/height, h*width/height, -h, h, options.camera_dnear, options.camera_dfar);
-    }
-    else
-    {
-      float fH = tan(options.camera_view_angle / 360.0 * M_PI) * options.camera_dnear;
-      float fW = fH * (double)width/(double)height;
-      proj = frustum(-fW, fW, -fH, fH, options.camera_dnear, options.camera_dfar);
-    }
-    // end projection
-
-    // Set model transformation
-    float mat[16];
-    igl::quat_to_mat(options.trackball_angle.data(), mat);
-
-    for (unsigned i=0;i<4;++i)
-      for (unsigned j=0;j<4;++j)
-        model(i,j) = mat[i+4*j];
-
-    model = scale(model, Eigen::Vector3f(options.camera_zoom,options.camera_zoom,options.camera_zoom));
-    model = scale(model, Eigen::Vector3f(options.model_zoom,options.model_zoom,options.model_zoom));
-    model = translate(model, Eigen::Vector3f(options.model_translation[0],options.model_translation[1],options.model_translation[2]));
-
-    // Send transformations to the GPU
-    GLint modeli = opengl.shader_mesh.uniform("model");
-    GLint viewi  = opengl.shader_mesh.uniform("view");
-    GLint proji  = opengl.shader_mesh.uniform("proj");
-    glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
-    glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
-    glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
-
-    // Light parameters
-    GLint specular_exponenti    = opengl.shader_mesh.uniform("specular_exponent");
-    GLint light_position_worldi = opengl.shader_mesh.uniform("light_position_world");
-    GLint lighting_factori      = opengl.shader_mesh.uniform("lighting_factor");
-    GLint fixed_colori          = opengl.shader_mesh.uniform("fixed_color");
-    GLint texture_factori       = opengl.shader_mesh.uniform("texture_factor");
-
-    glUniform1f(specular_exponenti, options.shininess);
-    Vector3f rev_light = -1.*options.light_position;
-    glUniform3fv(light_position_worldi, 1, rev_light.data());
-    glUniform1f(lighting_factori, options.lighting_factor); // enables lighting
-    glUniform4f(fixed_colori, 0.0, 0.0, 0.0, 0.0);
-
-    if (data.V.rows()>0)
-    {
-      // Render fill
-      if (options.show_faces)
-      {
-        // Texture
-        glUniform1f(texture_factori, options.show_texture ? 1.0f : 0.0f);
-        opengl.draw_mesh(true);
-        glUniform1f(texture_factori, 0.0f);
-      }
-
-      // Render wireframe
-      if (options.show_lines)
-      {
-        glLineWidth(options.line_width);
-        glUniform4f(fixed_colori, options.line_color[0], options.line_color[1],
-          options.line_color[2], 1.0f);
-        opengl.draw_mesh(false);
-        glUniform4f(fixed_colori, 0.0f, 0.0f, 0.0f, 0.0f);
-      }
-
-      if (options.show_vertid)
-      {
-        __font_renderer.BeginDraw(view*model, proj, viewport, data.object_scale);
-        for (int i=0; i<data.V.rows(); ++i)
-          __font_renderer.DrawText(data.V.row(i), data.V_normals.row(i), to_string(i));
-        __font_renderer.EndDraw();
-      }
-
-      if (options.show_faceid)
-      {
-        __font_renderer.BeginDraw(view*model, proj, viewport, data.object_scale);
-
-        for (int i=0; i<data.F.rows(); ++i)
-        {
-          Eigen::RowVector3d p = Eigen::RowVector3d::Zero();
-          for (int j=0;j<data.F.cols();++j)
-            p += data.V.row(data.F(i,j));
-          p /= data.F.cols();
-
-          __font_renderer.DrawText(p, data.F_normals.row(i), to_string(i));
-        }
-        __font_renderer.EndDraw();
-      }
-    }
-
-    if (options.show_overlay)
-    {
-      if (options.show_overlay_depth)
-        glEnable(GL_DEPTH_TEST);
-      else
-        glDisable(GL_DEPTH_TEST);
-
-      if (data.lines.rows() > 0)
-      {
-        opengl.bind_overlay_lines();
-        modeli = opengl.shader_overlay_lines.uniform("model");
-        viewi  = opengl.shader_overlay_lines.uniform("view");
-        proji  = opengl.shader_overlay_lines.uniform("proj");
-
-        glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
-        glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
-        glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
-        glLineWidth(options.line_width);
-
-        opengl.draw_overlay_lines();
-      }
-
-      if (data.points.rows() > 0)
-      {
-        opengl.bind_overlay_points();
-        modeli = opengl.shader_overlay_points.uniform("model");
-        viewi  = opengl.shader_overlay_points.uniform("view");
-        proji  = opengl.shader_overlay_points.uniform("proj");
-
-        glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
-        glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
-        glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
-        glPointSize(options.point_size);
-
-        opengl.draw_overlay_points();
-      }
-
-      if (data.labels_positions.rows() > 0)
-      {
-        __font_renderer.BeginDraw(view*model, proj, viewport, data.object_scale);
-        for (int i=0; i<data.labels_positions.rows(); ++i)
-          __font_renderer.DrawText(data.labels_positions.row(i), Eigen::Vector3d(0.0,0.0,0.0),
-              data.labels_strings[i]);
-        __font_renderer.EndDraw();
-      }
-
-      glEnable(GL_DEPTH_TEST);
-    }
-
-    if (callback_post_draw)
-      if (callback_post_draw(*this))
-        return;
-
-    if (plugin_manager)
-      for (unsigned int i = 0; i <plugin_manager->plugin_list.size(); ++i)
-        if (plugin_manager->plugin_list[i]->post_draw())
-          break;
-
-    TwDraw();
-  }
-
-  bool Viewer::save_scene()
-  {
-    #ifdef ENABLE_XML_SERIALIZATION
-    string fname = igl::file_dialog_save();
-    if (fname.length() == 0)
-      return false;
-
-    ::igl::XMLSerializer serializer("Viewer");
-    serializer.Add(data,"Data");
-    serializer.Add(options,"Options");
-
-    if (plugin_manager)
-      for (unsigned int i = 0; i <plugin_manager->plugin_list.size(); ++i)
-        serializer.Add(*(plugin_manager->plugin_list[i]),plugin_manager->plugin_list[i]->plugin_name);
-
-    serializer.Save(fname.c_str(),true);
-
-    #endif
-    return true;
-  }
-
-  bool Viewer::load_scene()
-  {
-    #ifdef ENABLE_XML_SERIALIZATION
-    string fname = igl::file_dialog_open();
-    if (fname.length() == 0)
-      return false;
-
-    ::igl::XMLSerializer serializer("Viewer");
-    serializer.Add(data,"Data");
-    serializer.Add(options,"Options");
-
-    if (plugin_manager)
-      for (unsigned int i = 0; i <plugin_manager->plugin_list.size(); ++i)
-        serializer.Add(*(plugin_manager->plugin_list[i]),plugin_manager->plugin_list[i]->plugin_name);
-
-    serializer.Load(fname.c_str());
-
-    #endif
-    return true;
-  }
-
-  void Viewer::align_camera_center()
-  {
-    get_scale_and_shift_to_fit_mesh(data.V,data.F,options.model_zoom,options.model_translation);
-    data.object_scale = (data.V.colwise().maxCoeff() - data.V.colwise().minCoeff()).norm();
-  }
-
-  void Viewer::resize(int w, int h)
-  {
-    width = w;
-    height = h;
-    viewport = Eigen::Vector4f(0,0,width,height);
-  }
-
-  void Viewer::get_scale_and_shift_to_fit_mesh(
-    const Eigen::MatrixXd& V,
-    const Eigen::MatrixXi& F,
-    float& zoom,
-    Eigen::Vector3f& shift)
-  {
-    if (V.rows() == 0)
-      return;
-    //Compute mesh centroid
-    Eigen::SparseMatrix<double> M;
-    igl::massmatrix(V,F,igl::MASSMATRIX_TYPE_VORONOI,M);
-    const auto & MV = M*V;
-    Eigen::RowVector3d centroid  = MV.colwise().sum()/M.diagonal().sum();
-    Eigen::RowVector3d min_point = V.colwise().minCoeff();
-    Eigen::RowVector3d max_point = V.colwise().maxCoeff();
-
-    shift = -centroid.cast<float>();
-    double x_scale = fabs(max_point[0] - min_point[0]);
-    double y_scale = fabs(max_point[1] - min_point[1]);
-    double z_scale = fabs(max_point[2] - min_point[2]);
-    zoom = 2.0/ std::max(z_scale,std::max(x_scale,y_scale));
-  }
-
-  void TW_CALL Viewer::snap_to_canonical_quaternion_cb(void *clientData)
-  {
-    Eigen::Vector4f snapq = static_cast<Viewer *>(clientData)->options.trackball_angle;
-    igl::snap_to_canonical_view_quat<float>(snapq.data(),1,static_cast<Viewer *>(clientData)->options.trackball_angle.data());
-  }
-  void TW_CALL Viewer::align_camera_center_cb(void *clientData)
-  {
-    static_cast<Viewer *>(clientData)->align_camera_center();
-  }
-
-  void TW_CALL Viewer::save_scene_cb(void *clientData)
-  {
-    static_cast<Viewer *>(clientData)->save_scene();
-  }
-
-  void TW_CALL Viewer::load_scene_cb(void *clientData)
-  {
-    static_cast<Viewer *>(clientData)->load_scene();
-  }
-
-  void TW_CALL Viewer::set_invert_normals_cb(const void *param, void *clientData)
-  {
-    Viewer *viewer = static_cast<Viewer *>(clientData);
-    viewer->data.dirty |= Viewer::DIRTY_NORMAL;
-    viewer->options.invert_normals = *((bool *) param);
-  }
-
-  void TW_CALL Viewer::get_invert_normals_cb(void *param, void *clientData)
-  {
-    *((bool *) param) = static_cast<Viewer *>(clientData)->options.invert_normals;
-  }
-
-  void TW_CALL Viewer::set_face_based_cb(const void *param, void *clientData)
-  {
-    Viewer *viewer = static_cast<Viewer *>(clientData);
-    viewer->set_face_based(*((bool *) param));
-  }
-
-  void TW_CALL Viewer::get_face_based_cb(void *param, void *clientData)
-  {
-    *((bool *) param) = static_cast<Viewer *>(clientData)->options.face_based;
-  }
-
-  void TW_CALL Viewer::open_dialog_mesh(void *clientData)
-  {
-    std::string fname = igl::file_dialog_open();
-
-    if (fname.length() == 0)
-      return;
-
-    static_cast<Viewer *>(clientData)->load_mesh_from_file(fname.c_str());
-  }
-
-  // Serialization
-  void Viewer::Options::InitSerialization()
-  {
-    #ifdef ENABLE_XML_SERIALIZATION
-    xmlSerializer->Add(shininess, "shininess");
-    xmlSerializer->Add(background_color, "background_color");
-    xmlSerializer->Add(line_color, "line_color");
-    xmlSerializer->Add(light_position, "light_position");
-    xmlSerializer->Add(lighting_factor, "lighting_factor");
-    xmlSerializer->Add(trackball_angle, "trackball_angle");
-    xmlSerializer->Add(model_zoom, "model_zoom");
-    xmlSerializer->Add(model_translation, "model_translation");
-    xmlSerializer->Add(model_zoom_uv, "model_zoom_uv");
-    xmlSerializer->Add(model_translation_uv, "model_translation_uv");
-    xmlSerializer->Add(camera_zoom, "camera_zoom");
-    xmlSerializer->Add(orthographic, "orthographic");
-    xmlSerializer->Add(camera_eye, "camera_eye");
-    xmlSerializer->Add(camera_up, "camera_up");
-    xmlSerializer->Add(camera_center, "camera_center");
-    xmlSerializer->Add(camera_view_angle, "camera_view_angle");
-    xmlSerializer->Add(camera_dnear, "camera_dnear");
-    xmlSerializer->Add(camera_dfar, "camera_dfar");
-    xmlSerializer->Add(show_overlay, "show_overlay");
-    xmlSerializer->Add(show_overlay_depth, "show_overlay_depth");
-    xmlSerializer->Add(show_texture, "show_texture");
-    xmlSerializer->Add(show_faces, "show_faces");
-    xmlSerializer->Add(show_lines, "show_lines");
-    xmlSerializer->Add(show_vertid, "show_vertid");
-    xmlSerializer->Add(show_faceid, "show_faceid");
-    xmlSerializer->Add(point_size, "point_size");
-    xmlSerializer->Add(line_width, "line_width");
-    xmlSerializer->Add(invert_normals, "invert_normals");
-    xmlSerializer->Add(face_based, "face_based");
-    #endif
-  }
-
-  void Viewer::Data::InitSerialization()
-  {
-    #ifdef ENABLE_XML_SERIALIZATION
-    xmlSerializer->Add(V,"V");
-    xmlSerializer->Add(F,"F");
-    xmlSerializer->Add(F_normals,"F_normals");
-
-    xmlSerializer->Add(F_material_ambient,"F_material_ambient");
-    xmlSerializer->Add(F_material_diffuse,"F_material_diffuse");
-    xmlSerializer->Add(F_material_specular,"F_material_specular");
-
-    xmlSerializer->Add(V_normals,"V_normals");
-    xmlSerializer->Add(V_material_ambient,"V_material_ambient");
-    xmlSerializer->Add(V_material_diffuse,"V_material_diffuse");
-    xmlSerializer->Add(V_material_specular,"V_material_specular");
-
-    xmlSerializer->Add(V_uv,"V_uv");
-    xmlSerializer->Add(F_uv,"F_uv");
-    xmlSerializer->Add(texture_R,"texture_R");
-    xmlSerializer->Add(texture_G,"texture_G");
-    xmlSerializer->Add(texture_B,"texture_B");
-    xmlSerializer->Add(lines,"lines");
-    xmlSerializer->Add(points,"points");
-
-    xmlSerializer->Add(labels_positions,"labels_positions");
-    xmlSerializer->Add(labels_strings,"labels_strings");
-    #endif
-  }
-
-  void Viewer::set_face_based(bool newvalue)
-  {
-    if (options.face_based != newvalue)
-    {
-      options.face_based = newvalue;
-      data.dirty = DIRTY_ALL;
-    }
-  }
-
-  // Helpers that draws the most common meshes
-  void Viewer::set_mesh(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F)
-  {
-    using namespace std;
-
-    Eigen::MatrixXd V_temp;
-
-    // If V only has two columns, pad with a column of zeros
-    if (V.cols() == 2)
-    {
-      V_temp = Eigen::MatrixXd::Zero(V.rows(),3);
-      V_temp.block(0,0,V.rows(),2) = V;
-    }
-    else
-      V_temp = V;
-
-    if (data.V.rows() == 0 && data.F.rows() == 0)
-    {
-      clear_mesh();
-      data.V = V_temp;
-      data.F = F;
-
-      compute_normals();
-      uniform_colors(Eigen::Vector3d(51.0/255.0,43.0/255.0,33.3/255.0),
-                     Eigen::Vector3d(255.0/255.0,228.0/255.0,58.0/255.0),
-                     Eigen::Vector3d(255.0/255.0,235.0/255.0,80.0/255.0));
-
-      grid_texture();
-      align_camera_center();
-    }
-    else
-    {
-      if (data.V.rows() == V.rows() && data.F.rows() == F.rows())
-      {
-        data.V = V_temp;
-        data.F = F;
-        align_camera_center();
-      }
-      else
-        cerr << "ERROR (set_mesh): The new mesh has a different number of vertices/faces. Please clear the mesh before plotting.";
-    }
-    data.dirty |= DIRTY_FACE | DIRTY_POSITION;
-  }
-
-  void Viewer::set_vertices(const Eigen::MatrixXd& V)
-  {
-    data.V = V;
-    assert(data.F.size() == 0 || data.F.maxCoeff() < data.V.rows());
-    data.dirty |= DIRTY_POSITION;
-  }
-
-  void Viewer::set_normals(const Eigen::MatrixXd& N)
-  {
-    using namespace std;
-    if (N.rows() == data.V.rows())
-    {
-      set_face_based(false);
-      data.V_normals = N;
-    }
-    else if (N.rows() == data.F.rows() || N.rows() == data.F.rows()*3)
-    {
-      set_face_based(true);
-      data.F_normals = N;
-    }
-    else
-      cerr << "ERROR (set_normals): Please provide a normal per face, per corner or per vertex.";
-    data.dirty |= DIRTY_NORMAL;
-  }
-
-  void Viewer::set_colors(const Eigen::MatrixXd &C)
-  {
-    using namespace std;
-    using namespace Eigen;
-    // Ambient color should be darker color
-    const auto ambient = [](const MatrixXd & C)->MatrixXd
-    {
-      return 0.1*C;
-    };
-    // Specular color should be a less saturated and darker color: dampened
-    // highlights
-    const auto specular = [](const MatrixXd & C)->MatrixXd
-    {
-      const double grey = 0.3;
-      return grey+0.1*(C.array()-grey);
-    };
-    if (C.rows() == 1)
-    {
-      for (unsigned i=0;i<data.V_material_diffuse.rows();++i)
-      {
-        data.V_material_diffuse.row(i) = C.row(0);
-      }
-      data.V_material_ambient = ambient(data.V_material_diffuse);
-      data.V_material_specular = specular(data.V_material_diffuse);
-
-      for (unsigned i=0;i<data.F_material_diffuse.rows();++i)
-      {
-        data.F_material_diffuse.row(i) = C.row(0);
-      }
-      data.F_material_ambient = ambient(data.F_material_diffuse);
-      data.F_material_specular = specular(data.F_material_diffuse);
-    }
-    else if (C.rows() == data.V.rows())
-    {
-      set_face_based(false);
-      data.V_material_diffuse = C;
-      data.V_material_ambient = ambient(data.V_material_diffuse);
-      data.V_material_specular = specular(data.V_material_diffuse);
-    }
-    else if (C.rows() == data.F.rows())
-    {
-      set_face_based(true);
-      data.F_material_diffuse = C;
-      data.F_material_ambient = ambient(data.F_material_diffuse);
-      data.F_material_specular = specular(data.F_material_diffuse);
-    }
-    else
-      cerr << "ERROR (set_colors): Please provide a single color, or a color per face or per vertex.";
-    data.dirty |= DIRTY_DIFFUSE;
-
-  }
-
-  void Viewer::set_uv(const Eigen::MatrixXd& UV)
-  {
-    using namespace std;
-    if (UV.rows() == data.V.rows())
-    {
-      set_face_based(false);
-      data.V_uv = UV;
-    }
-    else
-      cerr << "ERROR (set_UV): Please provide uv per vertex.";
-    data.dirty |= DIRTY_UV;
-  }
-
-  void Viewer::set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F)
-  {
-    set_face_based(true);
-    data.V_uv = UV_V;
-    data.F_uv = UV_F;
-    data.dirty |= DIRTY_UV;
-  }
-
-
-  void Viewer::set_texture(
-    const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& R,
-    const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& G,
-    const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& B)
-  {
-    data.texture_R = R;
-    data.texture_G = G;
-    data.texture_B = B;
-    data.dirty |= DIRTY_TEXTURE;
-  }
-
-  void Viewer::add_points(const Eigen::MatrixXd& P,  const Eigen::MatrixXd& C)
-  {
-    Eigen::MatrixXd P_temp;
-
-    // If P only has two columns, pad with a column of zeros
-    if (P.cols() == 2)
-    {
-      P_temp = Eigen::MatrixXd::Zero(P.rows(),3);
-      P_temp.block(0,0,P.rows(),2) = P;
-    }
-    else
-      P_temp = P;
-
-    int lastid = data.points.rows();
-    data.points.conservativeResize(data.points.rows() + P_temp.rows(),6);
-    for (unsigned i=0; i<P_temp.rows(); ++i)
-      data.points.row(lastid+i) << P_temp.row(i), i<C.rows() ? C.row(i) : C.row(C.rows()-1);
-
-    data.dirty |= DIRTY_OVERLAY_POINTS;
-  }
-
-  void Viewer::add_edges(const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C)
-  {
-    Eigen::MatrixXd P1_temp,P2_temp;
-
-    // If P1 only has two columns, pad with a column of zeros
-    if (P1.cols() == 2)
-    {
-      P1_temp = Eigen::MatrixXd::Zero(P1.rows(),3);
-      P1_temp.block(0,0,P1.rows(),2) = P1;
-      P2_temp = Eigen::MatrixXd::Zero(P2.rows(),3);
-      P2_temp.block(0,0,P2.rows(),2) = P2;
-    }
-    else
-    {
-      P1_temp = P1;
-      P2_temp = P2;
-    }
-
-    int lastid = data.lines.rows();
-    data.lines.conservativeResize(data.lines.rows() + P1_temp.rows(),9);
-    for (unsigned i=0; i<P1_temp.rows(); ++i)
-      data.lines.row(lastid+i) << P1_temp.row(i), P2_temp.row(i), i<C.rows() ? C.row(i) : C.row(C.rows()-1);
-
-    data.dirty |= DIRTY_OVERLAY_LINES;
-  }
-
-  void Viewer::add_label(const Eigen::VectorXd& P,  const std::string& str)
-  {
-    Eigen::MatrixXd P_temp;
-
-    // If P only has two columns, pad with a column of zeros
-    if (P.cols() == 2)
-    {
-      P_temp = Eigen::MatrixXd::Zero(P.rows(),3);
-      P_temp.block(0,0,P.rows(),2) = P;
-    }
-    else
-      P_temp = P;
-
-    int lastid = data.labels_positions.rows();
-    data.labels_positions.conservativeResize(lastid+1, 3);
-    data.labels_positions.row(lastid) = P_temp;
-    data.labels_strings.push_back(str);
-  }
-
-  int Viewer::launch(std::string filename)
-  {
-    GLFWwindow* window;
-
-    glfwSetErrorCallback(glfw_error_callback);
-    if (!glfwInit())
-      return EXIT_FAILURE;
-
-    glfwWindowHint(GLFW_SAMPLES, 16);
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
-    #ifdef __APPLE__
-    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
-    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
-    #endif
-    window = glfwCreateWindow(1280, 800, "IGL Viewer", NULL, NULL);
-    if (!window)
-    {
-      glfwTerminate();
-      return EXIT_FAILURE;
-    }
-
-	glfwMakeContextCurrent(window);
-
-#ifndef __APPLE__
-	glewExperimental = true;
-	GLenum err = glewInit();
-	if (GLEW_OK != err)
-	{
-		/* Problem: glewInit failed, something is seriously wrong. */
-		fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
-	}
-	fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
-#endif
-
-    #ifdef DEBUG
-      int major, minor, rev;
-      major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
-      minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
-      rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);
-      printf("OpenGL version recieved: %d.%d.%d\n", major, minor, rev);
-      printf("Supported OpenGL is %s\n", (const char*)glGetString(GL_VERSION));
-      printf("Supported GLSL is %s\n", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
-    #endif
-
-    glfwSetInputMode(window,GLFW_CURSOR,GLFW_CURSOR_NORMAL);
-
-    // Initialize AntTweakBar
-    TwInit(TW_OPENGL_CORE, NULL);
-
-    // Initialize IGL viewer
-    init(&igl_viewer_plugin_manager);
-    __viewer = this;
-
-    // Register callbacks
-    glfwSetKeyCallback(window, glfw_key_callback);
-    glfwSetCursorPosCallback(window,glfw_mouse_move);
-    glfwSetWindowSizeCallback(window,glfw_window_size);
-    glfwSetMouseButtonCallback(window,glfw_mouse_press);
-    glfwSetScrollCallback(window,glfw_mouse_scroll);
-    glfwSetCharCallback(window, glfw_char_callback);
-
-    // Handle retina displays (windows and mac)
-    int width, height;
-    glfwGetFramebufferSize(window, &width, &height);
-
-    int width_window, height_window;
-    glfwGetWindowSize(window, &width_window, &height_window);
-
-    highdpi = width/width_window;
-
-    glfw_window_size(window,width_window,height_window);
-
-    init_opengl();
-
-    // Load the mesh passed as input
-    if (filename.size() > 0)
-      load_mesh_from_file(filename.c_str());
-
-    // Rendering loop
-    while (!glfwWindowShouldClose(window))
-    {
-      draw();
-
-      glfwSwapBuffers(window);
-      //glfwPollEvents();
-      glfwWaitEvents();
-    }
-
-    free_opengl();
-    shutdown_plugins();
-
-    glfwDestroyWindow(window);
-    glfwTerminate();
-    return EXIT_SUCCESS;
-  }
-} // end namespace

+ 1 - 0
include/igl/viewer/Viewer.cpp.REMOVED.git-id

@@ -0,0 +1 @@
+b02c6fbf6cb464fdaf3bfb95194978587d5cbd50

+ 19 - 0
include/igl/viewer/Viewer.h

@@ -94,6 +94,10 @@ namespace igl
 
       // Enable per-face colors and normals
       bool face_based;
+
+      // Animation
+      bool is_animating;
+      double animation_max_fps;
     };
 
     enum DirtyFlags
@@ -327,6 +331,7 @@ namespace igl
     float down_mouse_z;
     Eigen::Vector3f down_translation;
     bool down;
+    bool hack_never_moved;
 
     // Anttweak bar
     TwBar* bar;
@@ -366,6 +371,14 @@ namespace igl
                       const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& B);
 
     void add_points(const Eigen::MatrixXd& P,  const Eigen::MatrixXd& C);
+    // Sets edges given a list of edge vertices and edge indices. In constrast
+    // to `add_edges` this will (purposefully) clober existing edges.
+    //
+    // Inputs:
+    //   P  #P by 3 list of vertex positions
+    //   E  #E by 2 list of edge indices into P
+    //   C  #E|1 by 3 color(s)
+    void set_edges (const Eigen::MatrixXd& P, const Eigen::MatrixXi& E, const Eigen::MatrixXd& C);
     void add_edges (const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C);
     void add_label (const Eigen::VectorXd& P,  const std::string& str);
 
@@ -453,6 +466,8 @@ namespace igl
     static void TW_CALL get_face_based_cb(void *param, void *clientData);
     static void TW_CALL set_invert_normals_cb(const void *param, void *clientData);
     static void TW_CALL get_invert_normals_cb(void *param, void *clientData);
+  public:
+      EIGEN_MAKE_ALIGNED_OPERATOR_NEW
   };
 
 
@@ -573,6 +588,8 @@ namespace igl
   protected:
     // Pointer to the main Preview3D class
     Viewer *viewer;
+  public:
+      EIGEN_MAKE_ALIGNED_OPERATOR_NEW
   };
 
   // Keeps the lists of plugins
@@ -595,6 +612,8 @@ namespace igl
     }
 
     std::vector<Viewer_plugin*> plugin_list;
+  public:
+      EIGEN_MAKE_ALIGNED_OPERATOR_NEW
   };
 
 

+ 2 - 2
tutorial/101_FileIO/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/102_DrawMesh/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/103_Events/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 0 - 1
tutorial/103_Events/main.cpp

@@ -1,4 +1,3 @@
-#define IGL_HEADER_ONLY
 #include <igl/readOFF.h>
 #include <igl/viewer/Viewer.h>
 

+ 2 - 2
tutorial/104_Colors/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 5 - 12
tutorial/104_Colors/main.cpp

@@ -5,6 +5,7 @@
 
 Eigen::MatrixXd V;
 Eigen::MatrixXi F;
+Eigen::MatrixXd C;
 
 int main(int argc, char *argv[])
 {
@@ -15,19 +16,11 @@ int main(int argc, char *argv[])
   igl::Viewer viewer;
   viewer.set_mesh(V, F);
 
+  // Use the x coordinate as a scalar field over the surface
+  Eigen::VectorXd x = V.col(2);
 
-  // Normalize x coordinate between 0 and 1
-  Eigen::VectorXd value = V.col(0).array() - V.col(0).minCoeff();
-  value = value.array() / value.maxCoeff();
-
-  // Map to colors using jet colorramp
-  Eigen::MatrixXd C(V.rows(),3);
-  for (unsigned i=0; i<V.rows(); ++i)
-  {
-    double r,g,b;
-    igl::jet(value(i),r,g,b);
-    C.row(i) << r,g,b;
-  }
+  // Compute per-vertex colors
+  igl::jet(x,true,C);
 
   // Add per-vertex colors
   viewer.set_colors(C);

+ 2 - 2
tutorial/105_Overlays/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/106_Picking/CMakeLists.txt

@@ -11,5 +11,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES} ${EMBREE_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES} ${EMBREE_LIBRARIES})

+ 3 - 1
tutorial/106_Picking/main.cpp

@@ -25,7 +25,9 @@ bool mouse_down(igl::Viewer& viewer, int button, int modifier)
   int vid, fid;
 
   // Cast a ray in the view direction starting from the mouse position
-  bool hit = unproject_in_mesh(Vector2f(viewer.current_mouse_x,viewer.viewport(3) - viewer.current_mouse_y),
+  double x = viewer.current_mouse_x;
+  double y = viewer.viewport(3) - viewer.current_mouse_y;
+  bool hit = unproject_in_mesh(Vector2f(x,y),
                                 F,
                                 viewer.view * viewer.model,
                                 viewer.proj,

+ 2 - 2
tutorial/201_Normals/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/202_GaussianCurvature/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/203_CurvatureDirections/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/204_Gradient/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/205_Laplacian/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/301_Slice/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/302_Sort/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/303_LaplaceEquation/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/304_LinearEqualityConstraints/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/305_QuadraticProgramming/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 11 - 0
tutorial/401_BiharmonicDeformation/CMakeLists.txt

@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 2.6)
+project(401_BiharmonicDeformation)
+
+include("../CMakeLists.shared")
+
+set(SOURCES
+${PROJECT_SOURCE_DIR}/main.cpp
+)
+
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 121 - 0
tutorial/401_BiharmonicDeformation/main.cpp

@@ -0,0 +1,121 @@
+#include <igl/colon.h>
+#include <igl/harmonic.h>
+#include <igl/readOBJ.h>
+#include <igl/readDMAT.h>
+#include <igl/viewer/Viewer.h>
+#include <algorithm>
+#include <iostream>
+
+double bc_frac = 1.0;
+double bc_dir = -0.03;
+bool deformation_field = false;
+Eigen::MatrixXd V,U,V_bc,U_bc;
+Eigen::VectorXd Z;
+Eigen::MatrixXi F;
+Eigen::VectorXi b;
+
+bool pre_draw(igl::Viewer & viewer)
+{
+  using namespace Eigen;
+  // Determine boundary conditions
+  if(viewer.options.is_animating)
+  {
+    bc_frac += bc_dir;
+    bc_dir *= (bc_frac>=1.0 || bc_frac<=0.0?-1.0:1.0);
+  }
+
+  const MatrixXd U_bc_anim = V_bc+bc_frac*(U_bc-V_bc);
+  if(deformation_field)
+  {
+    MatrixXd D;
+    MatrixXd D_bc = U_bc_anim - V_bc;
+    igl::harmonic(V,F,b,D_bc,2,D);
+    U = V+D;
+  }else
+  {
+    igl::harmonic(V,F,b,U_bc_anim,2,U);
+  }
+  viewer.set_vertices(U);
+  viewer.compute_normals();
+  return false;
+}
+
+bool key_down(igl::Viewer &viewer, unsigned char key, int mods)
+{
+  switch(key)
+  {
+    case ' ':
+      viewer.options.is_animating = !viewer.options.is_animating;
+      break;
+    case 'D':
+    case 'd':
+      deformation_field = !deformation_field;
+      break;
+  }
+}
+
+int main(int argc, char *argv[])
+{
+  using namespace Eigen;
+  using namespace std;
+  igl::readOBJ("../shared/decimated-max.obj",V,F);
+  U=V;
+  // S(i) = j: j<0 (vertex i not in handle), j >= 0 (vertex i in handle j)
+  VectorXi S;
+  igl::readDMAT("../shared/decimated-max-selection.dmat",S);
+  igl::colon<int>(0,V.rows()-1,b);
+  b.conservativeResize(stable_partition( b.data(), b.data()+b.size(), 
+   [&S](int i)->bool{return S(i)>=0;})-b.data());
+
+  // Boundary conditions directly on deformed positions
+  U_bc.resize(b.size(),V.cols());
+  V_bc.resize(b.size(),V.cols());
+  for(int bi = 0;bi<b.size();bi++)
+  {
+    V_bc.row(bi) = V.row(b(bi));
+    switch(S(b(bi)))
+    {
+      case 0:
+        // Don't move handle 0
+        U_bc.row(bi) = V.row(b(bi));
+        break;
+      case 1:
+        // move handle 1 down
+        U_bc.row(bi) = V.row(b(bi)) + RowVector3d(0,-50,0);
+        break;
+      case 2:
+      default:
+        // move other handles forward
+        U_bc.row(bi) = V.row(b(bi)) + RowVector3d(0,0,-25);
+        break;
+    }
+  }
+
+  // Pseudo-color based on selection
+  MatrixXd C(F.rows(),3);
+  RowVector3d purple(80.0/255.0,64.0/255.0,255.0/255.0);
+  RowVector3d gold(255.0/255.0,228.0/255.0,58.0/255.0);
+  for(int f = 0;f<F.rows();f++)
+  {
+    if( S(F(f,0))>=0 && S(F(f,1))>=0 && S(F(f,2))>=0)
+    {
+      C.row(f) = purple;
+    }else
+    {
+      C.row(f) = gold;
+    }
+  }
+
+  // Plot the mesh with pseudocolors
+  igl::Viewer viewer;
+  viewer.set_mesh(U, F);
+  viewer.options.show_lines = false;
+  viewer.set_colors(C);
+  viewer.options.trackball_angle << 0,sqrt(2.0),0,sqrt(2.0);
+  viewer.options.trackball_angle.normalize();
+  viewer.callback_pre_draw = &pre_draw;
+  viewer.callback_key_down = &key_down;
+  //viewer.options.is_animating = true;
+  viewer.options.animation_max_fps = 30.;
+  viewer.launch();
+}

+ 11 - 0
tutorial/402_PolyharmonicDeformation/CMakeLists.txt

@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 2.6)
+project(402_PolyharmonicDeformation)
+
+include("../CMakeLists.shared")
+
+set(SOURCES
+${PROJECT_SOURCE_DIR}/main.cpp
+)
+
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

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

@@ -0,0 +1,105 @@
+#include <igl/colon.h>
+#include <igl/harmonic.h>
+#include <igl/readOBJ.h>
+#include <igl/viewer/Viewer.h>
+#include <algorithm>
+#include <iostream>
+
+double z_max = 1.0;
+double z_dir = -0.03;
+int k = 2;
+bool resolve = true;
+Eigen::MatrixXd V,U;
+Eigen::VectorXd Z;
+Eigen::MatrixXi F;
+Eigen::VectorXi b;
+Eigen::VectorXd bc;
+
+bool pre_draw(igl::Viewer & viewer)
+{
+  using namespace Eigen;
+  if(resolve)
+  {
+    igl::harmonic(V,F,b,bc,k,Z);
+    resolve = false;
+  }
+  U.col(2) = z_max*Z;
+  viewer.set_vertices(U);
+  viewer.compute_normals();
+  if(viewer.options.is_animating)
+  {
+    z_max += z_dir;
+    z_dir *= (z_max>=1.0 || z_max<=0.0?-1.0:1.0);
+  }
+  return false;
+}
+
+bool key_down(igl::Viewer &viewer, unsigned char key, int mods)
+{
+  switch(key)
+  {
+    case ' ':
+      viewer.options.is_animating = !viewer.options.is_animating;
+      break;
+    case '.':
+      k++;
+      k = (k>4?4:k);
+      resolve = true;
+      break;
+    case ',':
+      k--;
+      k = (k<1?1:k);
+      resolve = true;
+      break;
+  }
+}
+
+int main(int argc, char *argv[])
+{
+  using namespace Eigen;
+  using namespace std;
+  igl::readOBJ("../shared/bump-domain.obj",V,F);
+  U=V;
+  // Find boundary vertices outside annulus
+  typedef Matrix<bool,Dynamic,1> VectorXb;
+  VectorXb is_outer = (V.rowwise().norm().array()-1.0)>-1e-15;
+  VectorXb is_inner = (V.rowwise().norm().array()-0.15)<1e-15;
+  VectorXb in_b = is_outer.array() || is_inner.array();
+  igl::colon<int>(0,V.rows()-1,b);
+  b.conservativeResize(stable_partition( b.data(), b.data()+b.size(), 
+   [&in_b](int i)->bool{return in_b(i);})-b.data());
+  bc.resize(b.size(),1);
+  for(int bi = 0;bi<b.size();bi++)
+  {
+    bc(bi) = (is_outer(b(bi))?0.0:1.0);
+  }
+
+
+  // Pseudo-color based on selection
+  MatrixXd C(F.rows(),3);
+  RowVector3d purple(80.0/255.0,64.0/255.0,255.0/255.0);
+  RowVector3d gold(255.0/255.0,228.0/255.0,58.0/255.0);
+  for(int f = 0;f<F.rows();f++)
+  {
+    if( in_b(F(f,0)) && in_b(F(f,1)) && in_b(F(f,2)))
+    {
+      C.row(f) = purple;
+    }else
+    {
+      C.row(f) = gold;
+    }
+  }
+
+  // Plot the mesh with pseudocolors
+  igl::Viewer viewer;
+  viewer.set_mesh(U, F);
+  viewer.options.show_lines = false;
+  viewer.set_colors(C);
+  viewer.options.trackball_angle << -0.58,-0.03,-0.03,0.81;
+  viewer.options.trackball_angle.normalize();
+  viewer.callback_pre_draw = &pre_draw;
+  viewer.callback_key_down = &key_down;
+  viewer.options.is_animating = true;
+  viewer.options.animation_max_fps = 30.;
+  viewer.launch();
+}

+ 13 - 0
tutorial/403_BoundedBiharmonicWeights/CMakeLists.txt

@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 2.6)
+project(403_BoundedBiharmonicWeights)
+
+include("../CMakeLists.shared")
+
+add_definitions(-DIGL_NO_MOSEK)
+
+set(SOURCES
+${PROJECT_SOURCE_DIR}/main.cpp
+)
+
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

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

@@ -0,0 +1,169 @@
+// Don't use static library for this example because of Mosek complications
+//#define IGL_NO_MOSEK
+#ifdef IGL_NO_MOSEK
+#undef IGL_STATIC_LIBRARY
+#endif
+#include <igl/boundary_conditions.h>
+#include <igl/colon.h>
+#include <igl/column_to_quats.h>
+#include <igl/forward_kinematics.h>
+#include <igl/jet.h>
+#include <igl/lbs_matrix.h>
+#include <igl/deform_skeleton.h>
+#include <igl/normalize_row_sums.h>
+#include <igl/readDMAT.h>
+#include <igl/readMESH.h>
+#include <igl/readTGF.h>
+#include <igl/viewer/Viewer.h>
+#include <igl/bbw/bbw.h>
+
+#include <Eigen/Geometry>
+#include <Eigen/StdVector>
+#include <vector>
+#include <algorithm>
+#include <iostream>
+
+typedef 
+  std::vector<Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> >
+  RotationList;
+
+const Eigen::RowVector3d sea_green(70./255.,252./255.,167./255.);
+int selected = 0;
+Eigen::MatrixXd V,W,U,C,M;
+Eigen::MatrixXi T,F,BE;
+Eigen::VectorXi P;
+RotationList pose;
+double anim_t = 1.0;
+double anim_t_dir = -0.03;
+
+bool pre_draw(igl::Viewer & viewer)
+{
+  using namespace Eigen;
+  using namespace std;
+  if(viewer.options.is_animating)
+  {
+    // Interpolate pose and identity
+    RotationList anim_pose(pose.size());
+    for(int e = 0;e<pose.size();e++)
+    {
+      anim_pose[e] = pose[e].slerp(anim_t,Quaterniond::Identity());
+    }
+    // Propogate relative rotations via FK to retrieve absolute transformations
+    RotationList vQ;
+    vector<Vector3d> vT;
+    igl::forward_kinematics(C,BE,P,anim_pose,vQ,vT);
+    const int dim = C.cols();
+    MatrixXd T(BE.rows()*(dim+1),dim);
+    for(int e = 0;e<BE.rows();e++)
+    {
+      Affine3d a = Affine3d::Identity();
+      a.translate(vT[e]);
+      a.rotate(vQ[e]);
+      T.block(e*(dim+1),0,dim+1,dim) =
+        a.matrix().transpose().block(0,0,dim+1,dim);
+    }
+    // Compute deformation via LBS as matrix multiplication
+    U = M*T;
+
+    // Also deform skeleton edges
+    MatrixXd CT;
+    MatrixXi BET;
+    igl::deform_skeleton(C,BE,T,CT,BET);
+    
+    viewer.set_vertices(U);
+    viewer.set_edges(CT,BET,sea_green);
+    viewer.compute_normals();
+    anim_t += anim_t_dir;
+    anim_t_dir *= (anim_t>=1.0 || anim_t<=0.0?-1.0:1.0);
+  }
+  return false;
+}
+
+void set_color(igl::Viewer &viewer)
+{
+  Eigen::MatrixXd C;
+  igl::jet(W.col(selected).eval(),true,C);
+  viewer.set_colors(C);
+}
+
+bool key_down(igl::Viewer &viewer, unsigned char key, int mods)
+{
+  switch(key)
+  {
+    case ' ':
+      viewer.options.is_animating = !viewer.options.is_animating;
+      break;
+    case '.':
+      selected++;
+      selected = std::min(std::max(selected,0),(int)W.cols()-1);
+      set_color(viewer);
+      break;
+    case ',':
+      selected--;
+      selected = std::min(std::max(selected,0),(int)W.cols()-1);
+      set_color(viewer);
+      break;
+  }
+}
+
+int main(int argc, char *argv[])
+{
+  using namespace Eigen;
+  using namespace std;
+  igl::readMESH("../shared/hand.mesh",V,T,F);
+  U=V;
+  igl::readTGF("../shared/hand.tgf",C,BE);
+  // retrieve parents for forward kinematics
+  P.resize(BE.rows(),1);
+  for(int e = 0;e<BE.rows();e++)
+  {
+    P(e) = -1;
+    for(int f = 0;f<BE.rows();f++)
+    {
+      if(BE(e,0) == BE(f,1))
+      {
+        P(e) = f;
+      }
+    }
+  }
+
+  // Read pose as matrix of quaternions per row
+  MatrixXd Q;
+  igl::readDMAT("../shared/hand-pose.dmat",Q);
+  igl::column_to_quats(Q,pose);
+  assert(pose.size() == BE.rows());
+
+  // List of boundary indices (aka fixed value indices into VV)
+  VectorXi b;
+  // List of boundary conditions of each weight function
+  MatrixXd bc;
+  igl::boundary_conditions(V,T,C,VectorXi(),BE,MatrixXi(),b,bc);
+
+  // compute BBW weights matrix
+  igl::BBWData bbw_data;
+  // only a few iterations for sake of demo
+  bbw_data.active_set_params.max_iter = 8;
+  if(!igl::bbw(V,T,b,bc,bbw_data,W))
+  {
+    return false;
+  }
+  // Normalize weights to sum to one
+  igl::normalize_row_sums(W,W);
+  // precompute linear blend skinning matrix
+  igl::lbs_matrix(V,W,M);
+
+  // Plot the mesh with pseudocolors
+  igl::Viewer viewer;
+  viewer.set_mesh(U, F);
+  set_color(viewer);
+  viewer.set_edges(C,BE,sea_green);
+  viewer.options.show_lines = false;
+  viewer.options.show_overlay_depth = false;
+  viewer.options.line_width = 1;
+  viewer.options.trackball_angle.normalize();
+  viewer.callback_pre_draw = &pre_draw;
+  viewer.callback_key_down = &key_down;
+  viewer.options.is_animating = false;
+  viewer.options.animation_max_fps = 30.;
+  viewer.launch();
+}

+ 2 - 2
tutorial/501_HarmonicParam/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/502_LSCMParam/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/503_ARAPParam/CMakeLists.txt

@@ -7,5 +7,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 3 - 3
tutorial/504_NRosyDesign/CMakeLists.txt

@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 2.6)
-project(504_NRoSyDesign)
+project(504_NRosyDesign)
 
 include("../CMakeLists.shared")
 
@@ -11,5 +11,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES} ${LIBCOMISO_LIBRARY})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES} ${LIBCOMISO_LIBRARY})

+ 2 - 2
tutorial/505_MIQ/CMakeLists.txt

@@ -11,5 +11,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES} ${LIBCOMISO_LIBRARY})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES} ${LIBCOMISO_LIBRARY})

+ 34 - 1
tutorial/505_MIQ/main.cpp

@@ -38,6 +38,11 @@ Eigen::MatrixXi Seams;
 // Combed field
 Eigen::MatrixXd X1_combed, X2_combed;
 
+
+// Global parametrization (with seams)
+Eigen::MatrixXd UV_seams;
+Eigen::MatrixXi FUV_seams;
+
 // Global parametrization
 Eigen::MatrixXd UV;
 Eigen::MatrixXi FUV;
@@ -65,7 +70,7 @@ void line_texture(Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic> &texture_R,
 
 bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
 {
-  if (key <'1' || key >'7')
+  if (key <'1' || key >'8')
     return false;
 
   viewer.clear_mesh();
@@ -186,6 +191,14 @@ bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
     viewer.options.show_texture = true;
   }
 
+  if (key == '8')
+  {
+    // Global parametrization in 3D with seams
+    viewer.set_mesh(V, F);
+    viewer.set_uv(UV_seams,FUV_seams);
+    viewer.options.show_texture = true;
+  }
+
   viewer.set_colors(Eigen::RowVector3d(1,1,1));
 
   // Replace the standard texture with an integer shift invariant texture
@@ -268,6 +281,26 @@ int main(int argc, char *argv[])
            5,
            true);
 
+// Global parametrization (with seams, only for demonstration)
+igl::miq(V,
+         F,
+         X1_combed,
+         X2_combed,
+         BIS1_combed,
+         BIS2_combed,
+         MMatch,
+         isSingularity,
+         singularityIndex,
+         Seams,
+         UV_seams,
+         FUV_seams,
+         gradient_size,
+         stiffness,
+         direct_round,
+         iter,
+         5,
+         false);
+
   // Plot the mesh
   igl::Viewer viewer;
 

+ 2 - 2
tutorial/506_FrameField/CMakeLists.txt

@@ -11,5 +11,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES} ${LIBCOMISO_LIBRARY})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES} ${LIBCOMISO_LIBRARY})

+ 5 - 5
tutorial/506_FrameField/main.cpp

@@ -59,7 +59,7 @@ void line_texture(Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic> &texture_R,
   for (unsigned i=size2-lineWidth; i<=size2+lineWidth; ++i)
     for (unsigned j=0; j<size; ++j)
       texture_R(i,j) = 0;
-  
+
   texture_G = texture_R;
   texture_B = texture_R;
 }
@@ -189,7 +189,7 @@ int main(int argc, char *argv[])
   b   = temp.block(0,0,temp.rows(),1).cast<int>();
   bc1 = temp.block(0,1,temp.rows(),3);
   bc2 = temp.block(0,4,temp.rows(),3);
-  
+
   // Interpolate the frame field
   igl::frame_field(V, F, b, bc1, bc2, FF1, FF2);
 
@@ -201,12 +201,12 @@ int main(int argc, char *argv[])
 
   // Find the closest crossfield to the deformed frame field
   igl::frame_to_cross_field(V,F,FF1_deformed,FF2_deformed,X1_deformed);
-  
+
   // Find a smooth crossfield that interpolates the deformed constraints
   MatrixXd bc_x(b.size(),3);
   for (unsigned i=0; i<b.size();++i)
     bc_x.row(i) = X1_deformed.row(b(i));
-  
+
   VectorXd S;
   igl::nrosy(
              V,
@@ -236,7 +236,7 @@ int main(int argc, char *argv[])
            60.0,
            5.0,
            false,
-           0);
+           2);
 
   igl::Viewer viewer;
   // Plot the original mesh with a texture parametrization

+ 2 - 2
tutorial/601_Serialization/CMakeLists.txt

@@ -11,5 +11,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES} ${TINYXML2_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES} ${TINYXML2_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 1 - 1
tutorial/601_Serialization/main.cpp

@@ -32,7 +32,7 @@ int main(int argc, char *argv[])
   State state;
 
   // Load a mesh in OFF format
-  igl::readOFF("../shared/cube.off", state.V, state.F);
+  igl::readOFF("../shared/2triangles.off", state.V, state.F);
 
   // Save some integers in a vector
   state.ids.push_back(6);

+ 2 - 2
tutorial/602_Matlab/CMakeLists.txt

@@ -14,5 +14,5 @@ if(APPLE)
   set(CMAKE_EXE_LINKER_FLAGS "-rpath ${MATLAB_INCLUDE_DIR}/../../bin/maci64"})
 endif (APPLE) #APPLE
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES} ${MATLAB_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES} ${MATLAB_LIBRARIES})

+ 1 - 1
tutorial/602_Matlab/main.cpp

@@ -57,7 +57,7 @@ int main(int argc, char *argv[])
   // Send Laplacian matrix to matlab
   igl::mlsetmatrix(&engine,"L",L);
 
-  // Plot the laplacian matri using matlab spy
+  // Plot the laplacian matrix using matlab spy
   igl::mleval(&engine,"spy(L)");
 
   // Extract the first 10 eigenvectors

+ 1 - 1
tutorial/602_Matlab/run.sh

@@ -7,4 +7,4 @@
 
 export DYLD_LIBRARY_PATH=/Applications/MATLAB_R2012b.app/bin/maci64/
 
-./build/602_Matlab
+./build/602_Matlab_bin

+ 2 - 2
tutorial/604_Triangle/CMakeLists.txt

@@ -10,5 +10,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES} ${TRIANGLE_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES} ${TRIANGLE_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/605_Tetgen/CMakeLists.txt

@@ -10,5 +10,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES} ${TETGEN_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES} ${TETGEN_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES})

+ 2 - 2
tutorial/606_AmbientOcclusion/CMakeLists.txt

@@ -11,5 +11,5 @@ set(SOURCES
 ${PROJECT_SOURCE_DIR}/main.cpp
 )
 
-add_executable(${PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
-target_link_libraries(${PROJECT_NAME} ${SHARED_LIBRARIES} ${EMBREE_LIBRARIES})
+add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES} ${EMBREE_LIBRARIES})

+ 26 - 0
tutorial/CMakeLists.txt

@@ -1,13 +1,27 @@
 cmake_minimum_required(VERSION 2.6)
 project(libigl_tutorials)
 
+SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ../)
+SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
+
+## Check for CoMiSo, if not available skip the examples that depends on it
+find_package(LIBCOMISO QUIET)
+
+## Check for MATLAB, if not available skip the examples that depends on it
+find_package(LIBMATLAB QUIET)
+
+## Check for EMBREE, if not available skip the examples that depends on it
+find_package(LIBEMBREE QUIET)
+
 # Chapter 1
 add_subdirectory("101_FileIO")
 add_subdirectory("102_DrawMesh")
 add_subdirectory("103_Events")
 add_subdirectory("104_Colors")
 add_subdirectory("105_Overlays")
+if(EMBREE_FOUND)
 add_subdirectory("106_Picking")
+endif(EMBREE_FOUND)
 
 # Chapter 2
 add_subdirectory("201_Normals")
@@ -23,17 +37,29 @@ add_subdirectory("303_LaplaceEquation")
 add_subdirectory("304_LinearEqualityConstraints")
 add_subdirectory("305_QuadraticProgramming")
 
+# Chapter 4
+add_subdirectory("401_BiharmonicDeformation")
+add_subdirectory("402_PolyharmonicDeformation")
+add_subdirectory("403_BoundedBiharmonicWeights")
+
 # Chapter 5
 add_subdirectory("501_HarmonicParam")
 add_subdirectory("502_LSCMParam")
 add_subdirectory("503_ARAPParam")
+
+if(LIBCOMISO_FOUND)
 add_subdirectory("504_NRosyDesign")
 add_subdirectory("505_MIQ")
 add_subdirectory("506_FrameField")
+endif(LIBCOMISO_FOUND)
 
 # Chapter 6
 add_subdirectory("601_Serialization")
+if(MATLAB_FOUND)
 add_subdirectory("602_Matlab")
+endif(MATLAB_FOUND)
 add_subdirectory("604_Triangle")
 add_subdirectory("605_Tetgen")
+if(EMBREE_FOUND)
 add_subdirectory("606_AmbientOcclusion")
+endif(EMBREE_FOUND)

+ 9 - 9
tutorial/cmake/FindEMBREE.cmake

@@ -13,14 +13,14 @@ FIND_PATH(EMBREE_INCLUDE_DIR embree/include/embree.h
 		NO_DEFAULT_PATH
     )
 
-SET(SEARCH_PATHS "${EMBREE_INCLUDE_DIR}" "${EMBREE_INCLUDE_DIR}/build")
+SET(SEARCH_PATHS "${EMBREE_INCLUDE_DIR}" "${EMBREE_INCLUDE_DIR}/build" "${EMBREE_INCLUDE_DIR}/lib")
 
-FIND_LIBRARY(EMBREE_CORE_LIBRARY  NAMES libembree.a PATHS ${SEARCH_PATHS})
-FIND_LIBRARY(EMBREE_CORE_LIBRARY2 NAMES libdevice.a PATHS ${SEARCH_PATHS})
-FIND_LIBRARY(EMBREE_CORE_LIBRARY3 NAMES libimage.a PATHS ${SEARCH_PATHS})
-FIND_LIBRARY(EMBREE_CORE_LIBRARY4 NAMES liblexers.a PATHS ${SEARCH_PATHS})
-FIND_LIBRARY(EMBREE_CORE_LIBRARY5 NAMES libloaders.a PATHS ${SEARCH_PATHS})
-FIND_LIBRARY(EMBREE_CORE_LIBRARY6 NAMES libsys.a PATHS ${SEARCH_PATHS})
+FIND_LIBRARY(EMBREE_CORE_LIBRARY  NAMES embree PATHS ${SEARCH_PATHS} PATH_SUFFIXES a lib)
+FIND_LIBRARY(EMBREE_CORE_LIBRARY2 NAMES device PATHS ${SEARCH_PATHS} PATH_SUFFIXES a lib)
+FIND_LIBRARY(EMBREE_CORE_LIBRARY3 NAMES image PATHS ${SEARCH_PATHS} PATH_SUFFIXES a lib)
+FIND_LIBRARY(EMBREE_CORE_LIBRARY4 NAMES lexers PATHS ${SEARCH_PATHS} PATH_SUFFIXES a lib)
+#FIND_LIBRARY(EMBREE_CORE_LIBRARY5 NAMES loaders PATHS ${SEARCH_PATHS} PATH_SUFFIXES a lib)
+FIND_LIBRARY(EMBREE_CORE_LIBRARY6 NAMES sys PATHS ${SEARCH_PATHS} PATH_SUFFIXES a lib)
 
 if(EMBREE_CORE_LIBRARY AND EMBREE_INCLUDE_DIR)
 set(EMBREE_FOUND TRUE)
@@ -34,10 +34,10 @@ IF (EMBREE_FOUND)
    "${EMBREE_CORE_LIBRARY2}"
    "${EMBREE_CORE_LIBRARY3}"
    "${EMBREE_CORE_LIBRARY4}"
-   "${EMBREE_CORE_LIBRARY5}"
+   #"${EMBREE_CORE_LIBRARY5}"
    "${EMBREE_CORE_LIBRARY6}"
    )
    SET(EMBREE_INCLUDE_DIRS ${EMBREE_INCLUDE_DIR} ${EMBREE_INCLUDE_DIR}/embree)
 ELSE (EMBREE_FOUND)
-    message(FATAL_ERROR "could NOT find EMBREE")
+    message(STATUS "could NOT find EMBREE")
 ENDIF (EMBREE_FOUND)

+ 1 - 1
tutorial/cmake/FindLIBCOMISO.cmake

@@ -49,5 +49,5 @@ if(LIBCOMISO_INCLUDE_DIR AND LIBCOMISO_LIBRARY)
    message(STATUS "Found LIBCOMISO: ${LIBCOMISO_INCLUDE_DIR} ${LIBCOMISO_LIBRARY}")
    set(LIBCOMISO_FOUND TRUE)
 else(LIBCOMISO_INCLUDE_DIR)
-   message(FATAL_ERROR "could NOT find LIBCOMISO")
+   message(STATUS "could NOT find LIBCOMISO")
 endif(LIBCOMISO_INCLUDE_DIR AND LIBCOMISO_LIBRARY)

+ 19 - 3
tutorial/cmake/FindLIBIGL.cmake

@@ -20,15 +20,13 @@ FIND_PATH(LIBIGL_INCLUDE_DIR igl/readOBJ.h
 if(LIBIGL_INCLUDE_DIR)
    set(LIBIGL_FOUND TRUE)
    set(LIBIGL_INCLUDE_DIR ${LIBIGL_INCLUDE_DIR}  ${LIBIGL_INCLUDE_DIR}/../external/Singular_Value_Decomposition)
-   if(LIBIGL_USE_STATIC_LIBRARY)
-      add_definitions(-DIGL_STATIC_LIBRARY)
-   endif(LIBIGL_USE_STATIC_LIBRARY)
    #set(LIBIGL_SOURCES
    #   ${LIBIGL_INCLUDE_DIR}/igl/viewer/Viewer.cpp
    #)
 endif(LIBIGL_INCLUDE_DIR)
 
 if(LIBIGL_USE_STATIC_LIBRARY)
+  add_definitions(-DIGL_STATIC_LIBRARY)
   set(LIBIGL_LIB_DIRS 
    /usr/lib
    /usr/local/lib
@@ -44,6 +42,24 @@ if(LIBIGL_USE_STATIC_LIBRARY)
   endif(NOT LIBIGL_LIBRARY)
   set(LIBIGL_LIBRARIES ${LIBIGL_LIBRARIES}  ${LIBIGL_LIBRARY})
 
+  FIND_LIBRARY( LIBIGLBBW_LIBRARY NAMES iglbbw PATHS ${LIBIGL_LIB_DIRS})
+  if(NOT LIBIGLBBW_LIBRARY)
+    set(LIBIGL_FOUND FALSE)
+  endif(NOT LIBIGLBBW_LIBRARY)
+  set(LIBIGL_LIBRARIES ${LIBIGL_LIBRARIES}  ${LIBIGLBBW_LIBRARY})
+  FIND_LIBRARY( LIBIGLMOSEK_LIBRARY NAMES iglmosek PATHS ${LIBIGL_LIB_DIRS})
+  if(NOT LIBIGLMOSEK_LIBRARY)
+    set(LIBIGL_FOUND FALSE)
+  endif(NOT LIBIGLMOSEK_LIBRARY)
+  set(LIBIGL_LIBRARIES ${LIBIGL_LIBRARIES}  ${LIBIGLMOSEK_LIBRARY})
+  find_package(Mosek REQUIRED)
+  if(MOSEK_FOUND)
+    set(LIBIGL_INCLUDE_DIR ${LIBIGL_INCLUDE_DIR}  ${MOSEK_INCLUDE_DIR})
+    set(LIBIGL_LIBRARIES ${LIBIGL_LIBRARIES}  ${MOSEK_LIBRARIES})
+  else(MOSEK_FOUND)
+    set(LIBIGL_FOUND FALSE)
+  endif(MOSEK_FOUND)
+
   FIND_LIBRARY( LIBIGLEMBREE_LIBRARY NAMES iglembree PATHS ${LIBIGL_LIB_DIRS})
   if(NOT LIBIGLEMBREE_LIBRARY)
     set(LIBIGL_FOUND FALSE)

+ 4 - 0
tutorial/cmake/FindTRIANGLE.cmake

@@ -5,6 +5,10 @@
 #  TRIANGLE_INCLUDE_DIR - the TRIANGLE include directory
 #  TRIANGLE_SOURCES - the TRIANGLE source files
 
+IF (WIN32)
+   add_definitions(-DNO_TIMER)
+ENDIF (WIN32)
+
 FIND_PATH(TRIANGLE_INCLUDE_DIR triangle.h
    /usr/include
    /usr/local/include

+ 0 - 0
tutorial/compile_linux.sh → tutorial/compile_dependencies_linux.sh


+ 0 - 0
tutorial/compile_macosx.sh → tutorial/compile_dependencies_macosx.sh


+ 1 - 0
tutorial/images/102_DrawMesh.png.REMOVED.git-id

@@ -0,0 +1 @@
+3f7c5ae444c18f1c10501e0de58247c70fad7c9b

+ 1 - 0
tutorial/images/104_Colors.png.REMOVED.git-id

@@ -0,0 +1 @@
+f3849d85e8946a298f288132cd3b3a3eee9ff228

+ 1 - 0
tutorial/images/105_Overlays.png.REMOVED.git-id

@@ -0,0 +1 @@
+c81c264b82b4fd4cded7da143be3ae9cad47c634

+ 1 - 0
tutorial/images/106_Picking.png.REMOVED.git-id

@@ -0,0 +1 @@
+82a2caf85135d994691b249beef229bc7a192ea1

+ 1 - 0
tutorial/images/501_HarmonicParam.png.REMOVED.git-id

@@ -0,0 +1 @@
+c83e722e160a101036a28bff54be0367c6db3f3c

+ 1 - 0
tutorial/images/502_LSCMParam.png.REMOVED.git-id

@@ -0,0 +1 @@
+81f6613358be22cf2fbcd93954303b8508b9c8fc

+ 1 - 0
tutorial/images/503_ARAPParam.png.REMOVED.git-id

@@ -0,0 +1 @@
+c853fa15b768b5dcf88bea69aa24715ab18e1f98

+ 1 - 0
tutorial/images/504_nrosy_field.png.REMOVED.git-id

@@ -0,0 +1 @@
+1686bacfbb5df106f28812c957d09305bec2ba92

+ 1 - 0
tutorial/images/504_vector_field.png.REMOVED.git-id

@@ -0,0 +1 @@
+f50949f140bda0226adfecbc622a03987faac74e

+ 1 - 0
tutorial/images/505_MIQ_1.png.REMOVED.git-id

@@ -0,0 +1 @@
+433c482262ee9d30f58bd3400eb95790cfcd9f0a

+ 1 - 0
tutorial/images/505_MIQ_2.png.REMOVED.git-id

@@ -0,0 +1 @@
+2a722b5a91fbe49d34f0bba1476beefc11daaf78

+ 1 - 0
tutorial/images/505_MIQ_3.png.REMOVED.git-id

@@ -0,0 +1 @@
+78bb8ce227dbfce1dc4ad037db4994b7bb0fda22

+ 1 - 0
tutorial/images/505_MIQ_4.png.REMOVED.git-id

@@ -0,0 +1 @@
+0d63d20eab443d6ded5487915ba532b0d5e5b202

+ 1 - 0
tutorial/images/505_MIQ_5.png.REMOVED.git-id

@@ -0,0 +1 @@
+3a80d5a52fc68e4206c5854008869216bf9d2977

+ 1 - 0
tutorial/images/505_MIQ_6.png.REMOVED.git-id

@@ -0,0 +1 @@
+e63976e71eeee28470da60b732a24654e1ce7b84

+ 1 - 0
tutorial/images/505_MIQ_7.png.REMOVED.git-id

@@ -0,0 +1 @@
+124ada800a90dba1fc780c33a12a0c84a50777af

+ 1 - 0
tutorial/images/505_MIQ_8.png.REMOVED.git-id

@@ -0,0 +1 @@
+e0a6eb0701d8155e3af93ece4d86ce7d8c3a737d

+ 1 - 0
tutorial/images/506_FrameField_1.png.REMOVED.git-id

@@ -0,0 +1 @@
+33e082f2adb373fe71cec2d76ff66da33f102e12

+ 1 - 0
tutorial/images/506_FrameField_2.png.REMOVED.git-id

@@ -0,0 +1 @@
+b75e297a5acf0abbbb81a86e5df8f3ebfe65803f

+ 1 - 0
tutorial/images/506_FrameField_3.png.REMOVED.git-id

@@ -0,0 +1 @@
+a8c51e8c1520154d85d6344be61a449d5af9ac80

+ 1 - 0
tutorial/images/506_FrameField_4.png.REMOVED.git-id

@@ -0,0 +1 @@
+43ee5e148a9e99d3c68a62005144d5cfcab9766b

BIN
tutorial/images/602_Matlab_1.png


+ 1 - 0
tutorial/images/602_Matlab_2.png.REMOVED.git-id

@@ -0,0 +1 @@
+2beb0ca7990862a5838a719ad3c13680f169ede3

+ 1 - 0
tutorial/images/604_Triangle.png.REMOVED.git-id

@@ -0,0 +1 @@
+36007271400d1da84375594fce31ffa8a994beef

+ 1 - 0
tutorial/images/605_Tetgen.png.REMOVED.git-id

@@ -0,0 +1 @@
+9573b35d541d6f4fafd0f686be21f59162f54c1d

+ 1 - 0
tutorial/images/606_AmbientOcclusion.png.REMOVED.git-id

@@ -0,0 +1 @@
+24cf1f058d4c5a8b0a085f2189189b2f790734f8

+ 1 - 0
tutorial/images/VF.pdf.REMOVED.git-id

@@ -0,0 +1 @@
+e37343c2bb0fffbe8572d6c0ecd62713430b76d3

+ 1 - 0
tutorial/images/VF.png.REMOVED.git-id

@@ -0,0 +1 @@
+8df9bef00048d9fd942f74ee127b14ab2d86984d

+ 1 - 0
tutorial/images/bump-k-harmonic.jpg.REMOVED.git-id

@@ -0,0 +1 @@
+e2b983b8b9ee35f70aad5ae130419ae78d52d813

+ 1 - 0
tutorial/images/hand-bbw.jpg.REMOVED.git-id

@@ -0,0 +1 @@
+65841362faf22ff5e76c1375fc3ee6d62f2a78fe

+ 1 - 0
tutorial/images/max-biharmonic.jpg.REMOVED.git-id

@@ -0,0 +1 @@
+309580da7118bfd3ed60c3cdc3fc77bc0365cdde

+ 0 - 776
tutorial/readme.md

@@ -1,776 +0,0 @@
-title: libigl Tutorial
-author: Alec Jacobson, Daniele Pannozo and others
-date: 20 June 2014
-css: style.css
-html header:   <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
-<link rel="stylesheet" href="http://yandex.st/highlightjs/7.3/styles/default.min.css">
-<script src="http://yandex.st/highlightjs/7.3/highlight.min.js"></script>
-<script>hljs.initHighlightingOnLoad();</script>
-
-# Introduction
-Libigl is an open source C++ library for geometry processing research and
-development.  Dropping the heavy data structures of tradition geometry
-libraries, libigl is a simple header-only library of encapsulated functions.
-This combines the rapid prototyping familiar to Matlab or Python programmers
-with the performance and versatility of C++.  The tutorial is a self-contained,
-hands-on introduction to libigl.  Via live coding and interactive examples, we
-demonstrate how to accomplish various common geometry processing tasks such as
-computation of differential quantities and operators, real-time deformation,
-global parametrization, numerical optimization and mesh repair.  Each section
-of these lecture notes links to a cross-platform example application.
-
-# Table of Contents
-
-* Basic Usage
-    * **100_FileIO**: Example of reading/writing mesh files
-    * **101_Serialization**: Example of using the XML serialization framework
-    * **102_DrawMesh**: Example of plotting a mesh
-* [Chapter 2: Discrete Geometric Quantities and
-  Operators](#chapter2:discretegeometricquantitiesandoperators)
-    * [201 Normals](#normals)
-        * [Per-face](#per-face)
-        * [Per-vertex](#per-vertex)
-        * [Per-corner](#per-corner)
-    * [202 Gaussian Curvature](#gaussiancurvature)
-    * [203 Curvature Directions](#curvaturedirections)
-    * [204 Gradient](#gradient)
-    * [204 Laplacian](#laplacian)
-        * [Mass matrix](#massmatrix)
-        * [Alternative construction of
-          Laplacian](#alternativeconstructionoflaplacian)
-* [Chapter 3: Matrices and Linear Algebra](#chapter3:matricesandlinearalgebra)
-    * [301 Slice](#slice)
-    * [302 Sort](#sort)
-        * [Other Matlab-style functions](#othermatlab-stylefunctions) 
-    * [303 Laplace Equation](#laplaceequation)
-        * [Quadratic energy minimization](#quadraticenergyminimization)
-    * [304 Linear Equality Constraints](#linearequalityconstraints)
-    * [305 Quadratic Programming](#quadraticprogramming)
-* [Chapter 4: Shape Deformation](#chapter4:shapedeformation)
-    * [401 Biharmonic Deformation](#biharmonicdeformation)
-    * [402 Bounded Biharmonic Weights](#boundedbiharmonicweights)
-    * [403 Dual Quaternion Skinning](#dualquaternionskinning)
-    * [404 As-rigid-as-possible](#as-rigid-as-possible)
-    * [405 Fast automatic skinning
-      transformations](#fastautomaticskinningtransformations)
-
-
-# Compilation Instructions
-
-All examples depends on glfw, glew and anttweakbar. A copy
-of the sourcecode of each library is provided together with libigl
-and they can be precompiled using:
-
-**Alec: Is this just compiling the dependencies? Then perhaps rename `compile_dependencies_*`**
-
-    sh compile_macosx.sh (MACOSX)
-    sh compile_linux.sh (LINUX)
-    compile_windows.bat (Visual Studio 2012)
-
-Every example can be compiled by using the cmake file provided in its folder.
-On Linux and MacOSX, you can use the provided bash script:
-
-    sh ../compile_example.sh
-
-## (Optional: compilation with libigl as static library)
-
-By default, libigl is a _headers only_ library, thus it does not require
-compilation. However, one can precompile libigl as a statically linked library.
-See `../README.md` in the main directory for compilations instructions to
-produce `libigl.a` and other libraries. Once compiled, these examples can be
-compiled using the `CMAKE` flag `-DLIBIGL_USE_STATIC_LIBRARY=ON`:
-
-    ../compile_example.sh -DLIBIGL_USE_STATIC_LIBRARY=ON
-
-# Chapter 2: Discrete Geometric Quantities and Operators
-This chapter illustrates a few discrete quantities that libigl can compute on a
-mesh. This also provides an introduction to basic drawing and coloring routines
-in our example viewer. Finally, we construct popular discrete differential
-geometry operators.
-
-## Normals
-Surface normals are a basic quantity necessary for rendering a surface. There
-are a variety of ways to compute and store normals on a triangle mesh.
-
-### Per-face
-Normals are well defined on each triangle of a mesh as the vector orthogonal to
-triangle's plane. These piecewise constant normals produce piecewise-flat
-renderings: the surface appears non-smooth and reveals its underlying
-discretization.
-
-### Per-vertex
-Storing normals at vertices, Phong or Gouraud shading will interpolate shading
-inside mesh triangles to produce smooth(er) renderings. Most techniques for
-computing per-vertex normals take an average of incident face normals. The
-techniques vary with respect to their different weighting schemes. Uniform
-weighting is heavily biased by the discretization choice, where as area-based
-or angle-based weighting is more forgiving.
-
-The typical half-edge style computation of area-based weights might look
-something like this:
-
-```cpp
-N.setZero(V.rows(),3);
-for(int i : vertices)
-{
-  for(face : incident_faces(i))
-  {
-    N.row(i) += face.area * face.normal;
-  }
-}
-N.rowwise().normalize();
-```
-
-Without a half-edge data-structure it may seem at first glance that looping
-over incident faces---and thus constructing the per-vertex normals---would be
-inefficient. However, per-vertex normals may be _throwing_ each face normal to
-running sums on its corner vertices:
-
-```cpp
-N.setZero(V.rows(),3);
-for(int f = 0; f < F.rows();f++)
-{
-  for(int c = 0; c < 3;c++)
-  {
-    N.row(F(f,c)) += area(f) * face_normal.row(f);
-  }
-}
-N.rowwise().normalize();
-```
-
-### Per-corner
-
-Storing normals per-corner is an efficient an convenient way of supporting both
-smooth and sharp (e.g. creases and corners) rendering. This format is common to
-OpenGL and the .obj mesh file format. Often such normals are tuned by the mesh
-designer, but creases and corners can also be computed automatically. Libigl
-implements a simple scheme which computes corner normals as averages of
-normals of faces incident on the corresponding vertex which do not deviate by a
-specified dihedral angle (e.g. 20°).
-
-![The `Normals` example computes per-face (left), per-vertex (middle) and
-per-corner (right) normals](images/fandisk-normals.jpg)
-
-## Gaussian Curvature
-Gaussian curvature on a continuous surface is defined as the product of the
-principal curvatures:
-
- $k_G = k_1 k_2.$
-
-As an _intrinsic_ measure, it depends on the metric and
-not the surface's embedding.
-
-Intuitively, Gaussian curvature tells how locally spherical or _elliptic_ the
-surface is ( $k_G>0$ ), how locally saddle-shaped or _hyperbolic_ the surface
-is ( $k_G<0$ ), or how locally cylindrical or _parabolic_ ( $k_G=0$ ) the
-surface is.
-
-In the discrete setting, one definition for a ``discrete Gaussian curvature''
-on a triangle mesh is via a vertex's _angular deficit_:
-
- $k_G(v_i) = 2π - \sum\limits_{j\in N(i)}θ_{ij},$
-
-where $N(i)$ are the triangles incident on vertex $i$ and $θ_{ij}$ is the angle
-at vertex $i$ in triangle $j$ [][#meyer_2003].
-
-Just like the continuous analog, our discrete Gaussian curvature reveals
-elliptic, hyperbolic and parabolic vertices on the domain.
-
-![The `GaussianCurvature` example computes discrete Gaussian curvature and visualizes it in
-pseudocolor.](images/bumpy-gaussian-curvature.jpg)
-
-## Curvature Directions
-The two principal curvatures $(k_1,k_2)$ at a point on a surface measure how much the
-surface bends in different directions. The directions of maximum and minimum
-(signed) bending are call principal directions and are always
-orthogonal.
-
-Mean curvature is defined simply as the average of principal curvatures:
-
- $H = \frac{1}{2}(k_1 + k_2).$ 
-
-One way to extract mean curvature is by examining the Laplace-Beltrami operator
-applied to the surface positions. The result is a so-called mean-curvature
-normal:
-
-  $-\Delta \mathbf{x} = H \mathbf{n}.$ 
-
-It is easy to compute this on a discrete triangle mesh in libigl using the cotangent
-Laplace-Beltrami operator [][#meyer_2003].
-
-```cpp
-#include <igl/cotmatrix.h>
-#include <igl/massmatrix.h>
-#include <igl/invert_diag.h>
-...
-MatrixXd HN;
-SparseMatrix<double> L,M,Minv;
-igl::cotmatrix(V,F,L);
-igl::massmatrix(V,F,igl::MASSMATRIX_TYPE_VORONOI,M);
-igl::invert_diag(M,Minv);
-HN = -Minv*(L*V);
-H = (HN.rowwise().squaredNorm()).array().sqrt();
-```
-
-Combined with the angle defect definition of discrete Gaussian curvature, one
-can define principal curvatures and use least squares fitting to find
-directions [][#meyer_2003].
-
-Alternatively, a robust method for determining principal curvatures is via
-quadric fitting [][#pannozo_2010]. In the neighborhood
-around every vertex, a best-fit quadric is found and principal curvature values
-and directions are sampled from this quadric. With these in tow, one can
-compute mean curvature and Gaussian curvature as sums and products
-respectively.
-
-![The `CurvatureDirections` example computes principal curvatures via quadric
-fitting and visualizes mean curvature in pseudocolor and principal directions
-with a cross field.](images/fertility-principal-curvature.jpg)
-
-This is an example of syntax highlighted code:
-
-```cpp
-#include <foo.html>
-int main(int argc, char * argv[])
-{
-  return 0;
-}
-```
-
-## Gradient
-Scalar functions on a surface can be discretized as a piecewise linear function
-with values defined at each mesh vertex:
-
- $f(\mathbf{x}) \approx \sum\limits_{i=0}^n \phi_i(\mathbf{x})\, f_i,$
-
-where $\phi_i$ is a piecewise linear hat function defined by the mesh so that
-for each triangle $\phi_i$ is _the_ linear function which is one only at
-vertex $i$ and zero at the other corners.
-
-![Hat function $\phi_i$ is one at vertex $i$, zero at all other vertices, and
-linear on incident triangles.](images/hat-function.jpg)
-
-Thus gradients of such piecewise linear functions are simply sums of gradients
-of the hat functions:
-
- $\nabla f(\mathbf{x}) \approx 
- \nabla \sum\limits_{i=0}^n \nabla \phi_i(\mathbf{x})\, f_i = 
- \sum\limits_{i=0}^n \nabla \phi_i(\mathbf{x})\, f_i.$
-
-This reveals that the gradient is a linear function of the vector of $f_i$
-values. Because $\phi_i$ are linear in each triangle their gradient are
-_constant_ in each triangle. Thus our discrete gradient operator can be written
-as a matrix multiplication taking vertex values to triangle values:
-
- $\nabla f \approx \mathbf{G}\,\mathbf{f},$
-
-where $\mathbf{f}$ is $n\times 1$ and $\mathbf{G}$ is an $md\times n$ sparse
-matrix. This matrix $\mathbf{G}$ can be derived geometrically, e.g.
-[ch. 2][#jacobson_thesis_2013].
-Libigl's `gradMat`**Alec: check name** function computes $\mathbf{G}$ for
-triangle and tetrahedral meshes:
-
-![The `Gradient` example computes gradients of an input function on a mesh and
-visualizes the vector field.](images/cheburashka-gradient.jpg)
-
-## Laplacian
-
-The discrete Laplacian is an essential geometry processing tool. Many
-interpretations and flavors of the Laplace and Laplace-Beltrami operator exist. 
-
-In open Euclidean space, the _Laplace_ operator is the usual divergence of gradient
-(or equivalently the Laplacian of a function is the trace of its Hessian):
-
- $\Delta f = 
- \frac{\partial^2 f}{\partial x^2} +
- \frac{\partial^2 f}{\partial y^2} +
- \frac{\partial^2 f}{\partial z^2}.$
-
-The _Laplace-Beltrami_ operator generalizes this to surfaces.
-
-When considering piecewise-linear functions on a triangle mesh, a discrete Laplacian may
-be derived in a variety of ways. The most popular in geometry processing is the
-so-called ``cotangent Laplacian'' $\mathbf{L}$, arising simultaneously from FEM, DEC and
-applying divergence theorem to vertex one-rings. As a linear operator taking
-vertex values to vertex values, the Laplacian $\mathbf{L}$ is a $n\times n$
-matrix with elements:
-
-$L_{ij} = \begin{cases}j \in N(i) &\cot \alpha_{ij} + \cot \beta_{ij},\\
-j \notin N(i) & 0,\\
-i = j & -\sum\limits_{k\neq i} L_{ik},
-\end{cases}$
-
-where $N(i)$ are the vertices adjacent to (neighboring) vertex $i$, and
-$\alpha_{ij},\beta_{ij}$ are the angles opposite edge ${ij}$.
-This oft
-produced formula leads to a typical half-edge style implementation for
-constructing $\mathbf{L}$:
-
-```cpp
-for(int i : vertices)
-{
-  for(int j : one_ring(i))
-  {
-    for(int k : triangle_on_edge(i,j))
-    {
-      L(i,j) = cot(angle(i,j,k));
-      L(i,i) -= cot(angle(i,j,k));
-    }
-  }
-}
-```
-
-Without a half-edge data-structure it may seem at first glance that looping
-over one-rings, and thus constructing the Laplacian would be inefficient.
-However, the Laplacian may be built by summing together contributions for each
-triangle, much in spirit with its FEM discretization of the Dirichlet energy
-(sum of squared gradients):
-
-```cpp
-for(triangle t : triangles)
-{
-  for(edge i,j : t)
-  {
-    L(i,j) += cot(angle(i,j,k));
-    L(j,i) += cot(angle(i,j,k));
-    L(i,i) -= cot(angle(i,j,k));
-    L(j,j) -= cot(angle(i,j,k));
-  }
-}
-```
-
-Libigl implements discrete "cotangent" Laplacians for triangles meshes and
-tetrahedral meshes, building both with fast geometric rules rather than "by the
-book" FEM construction which involves many (small) matrix inversions, cf.
-**Alec: cite Ariel reconstruction paper**.
-
-The operator applied to mesh vertex positions amounts to smoothing by _flowing_
-the surface along the mean curvature normal direction. This is equivalent to
-minimizing surface area.
-
-![The `Laplacian` example computes conformalized mean curvature flow using the
-cotangent Laplacian [#kazhdan_2012][].](images/cow-curvature-flow.jpg)
-
-### Mass matrix
-The mass matrix $\mathbf{M}$ is another $n \times n$ matrix which takes vertex
-values to vertex values. From an FEM point of view, it is a discretization of
-the inner-product: it accounts for the area around each vertex. Consequently,
-$\mathbf{M}$ is often a diagonal matrix, such that $M_{ii}$ is the barycentric
-or voronoi area around vertex $i$ in the mesh [#meyer_2003][]. The inverse of
-this matrix is also very useful as it transforms integrated quantities into
-point-wise quantities, e.g.:
-
- $\nabla f \approx \mathbf{M}^{-1} \mathbf{L} \mathbf{f}.$
-
-In general, when encountering squared quantities integrated over the surface,
-the mass matrix will be used as the discretization of the inner product when
-sampling function values at vertices:
-
- $\int_S x\, y\ dA \approx \mathbf{x}^T\mathbf{M}\,\mathbf{y}.$
-
-An alternative mass matrix $\mathbf{T}$ is a $md \times md$ matrix which takes
-triangle vector values to triangle vector values. This matrix represents an
-inner-product accounting for the area associated with each triangle (i.e. the
-triangles true area).
-
-### Alternative construction of Laplacian
-
-An alternative construction of the discrete cotangent Laplacian is by
-"squaring" the discrete gradient operator. This may be derived by applying
-Green's identity (ignoring boundary conditions for the moment):
-
-  $\int_S \|\nabla f\|^2 dA = \int_S f \Delta f dA$
-
-Or in matrix form which is immediately translatable to code:
-
-  $\mathbf{f}^T \mathbf{G}^T \mathbf{T} \mathbf{G} \mathbf{f} = 
-  \mathbf{f}^T \mathbf{M} \mathbf{M}^{-1} \mathbf{L} \mathbf{f} = 
-  \mathbf{f}^T \mathbf{L} \mathbf{f}.$
-
-So we have that $\mathbf{L} = \mathbf{G}^T \mathbf{T} \mathbf{G}$. This also
-hints that we may consider $\mathbf{G}^T$ as a discrete _divergence_ operator,
-since the Laplacian is the divergence of gradient. Naturally, $\mathbf{G}^T$ is
-$n \times md$ sparse matrix which takes vector values stored at triangle faces
-to scalar divergence values at vertices.
-
-# Chapter 3: Matrices and Linear Algebra
-Libigl relies heavily on the Eigen library for dense and sparse linear algebra
-routines. Besides geometry processing routines, libigl has a few linear algebra
-routines which bootstrap Eigen and make Eigen feel even more like a high-level
-algebra library like Matlab.
-
-## Slice
-A very familiar and powerful routine in Matlab is array slicing. This allows
-reading from or writing to a possibly non-contiguous sub-matrix. Let's consider
-the matlab code:
-
-```matlab
-B = A(R,C);
-```
-
-If `A` is a $m \times n$ matrix and `R` is a $j$-long list of row-indices
-(between 1 and $m$) and `C` is a $k$-long list of column-indices, then as a
-result `B` will be a $j \times k$ matrix drawing elements from `A` according to
-`R` and `C`. In libigl, the same functionality is provided by the `slice`
-function:
-
-```cpp
-VectorXi R,C;
-MatrixXd A,B;
-...
-igl::slice(A,R,C,B);
-```
-
-`A` and `B` could also be sparse matrices.
-
-Similarly, consider the matlab code:
-
-```matlab
-A(R,C) = B;
-```
-
-Now, the selection is on the left-hand side so the $j \times k$ matrix  `B` is
-being _written into_ the submatrix of `A` determined by `R` and `C`. This
-functionality is provided in libigl using `slice_into`:
-
-```cpp
-igl::slice_into(B,R,C,A);
-```
-
-![The example `Slice` shows how to use `igl::slice` to change the colors for triangles
-on a mesh.](images/decimated-knight-slice-color.jpg)
-
-## Sort
-
-Matlab and other higher-level languages make it very easy to extract indices of
-sorting and comparison routines. For example in Matlab, one can write:
-
-```matlab
-[Y,I] = sort(X,1,'ascend');
-```
-
-so if `X` is a $m \times n$ matrix then `Y` will also be an $m \times n$ matrix
-with entries sorted along dimension `1` in `'ascend'`ing order. The second
-output `I` is a $m \times n$ matrix of indices such that `Y(i,j) =
-X(I(i,j),j);`. That is, `I` reveals how `X` is sorted into `Y`.
-
-This same functionality is supported in libigl:
-
-```cpp
-igl::sort(X,1,true,Y,I);
-```
-
-Similarly, sorting entire rows can be accomplished in matlab using:
-
-```matlab
-[Y,I] = sortrows(X,'ascend');
-```
-
-where now `I` is a $m$ vector of indices such that `Y = X(I,:)`.
-
-In libigl, this is supported with
-
-```cpp
-igl::sortrows(X,true,Y,I);
-```
-where again `I` reveals the index of sort so that it can be reproduced with
-`igl::slice(X,I,1,Y)`.
-
-Analogous functions are available in libigl for: `max`, `min`, and `unique`.
-
-![The example `Sort` shows how to use `igl::sortrows` to 
-pseudocolor triangles according to their barycenters' sorted
-order.](images/decimated-knight-sort-color.jpg)
-
-
-### Other Matlab-style functions
-Libigl implements a variety of other routines with the same api and
-functionality as common matlab functions.
-
-- `igl::any_of` Whether any elements are non-zero (true)
-- `igl::cat` Concatenate two matrices (especially useful for dealing with Eigen
-  sparse matrices)
-- `igl::ceil` Round entries up to nearest integer
-- `igl::cumsum` Cumulative sum of matrix elements
-- `igl::colon` Act like Matlab's `:`, similar to Eigen's `LinSpaced`
-- `igl::cross` Cross product per-row
-- `igl::dot` dot product per-row
-- `igl::find` Find subscripts of non-zero entries
-- `igl::floot` Round entries down to nearest integer
-- `igl::histc` Counting occurrences for building a histogram
-- `igl::hsv_to_rgb` Convert HSV colors to RGB (cf. Matlab's `hsv2rgb`)
-- `igl::intersect` Set intersection of matrix elements.
-- `igl::jet` Quantized colors along the rainbow.
-- `igl::kronecker_product` Compare to Matlab's `kronprod`
-- `igl::median` Compute the median per column
-- `igl::mode` Compute the mode per column
-- `igl::orth` Orthogonalization of a basis
-- `igl::setdiff` Set difference of matrix elements
-- `igl::speye` Identity as sparse matrix
-
-## Laplace Equation
-A common linear system in geometry processing is the Laplace equation:
-
- $∆z = 0$
-
-subject to some boundary conditions, for example Dirichlet boundary conditions
-(fixed value):
-
- $\left.z\right|_{\partial{S}} = z_{bc}$
-
-In the discrete setting, this begins with the linear system:
-
- $\mathbf{L} \mathbf{z} = \mathbf{0}$
-
-where $\mathbf{L}$ is the $n \times n$ discrete Laplacian and $\mathbf{z}$ is a
-vector of per-vertex values. Most of $\mathbf{z}$ correspond to interior
-vertices and are unknown, but some of $\mathbf{z}$ represent values at boundary
-vertices. Their values are known so we may move their corresponding terms to
-the right-hand side.
-
-Conceptually, this is very easy if we have sorted $\mathbf{z}$ so that interior
-vertices come first and then boundary vertices:
-
- $$\left(\begin{array}{cc}
- \mathbf{L}_{in,in} & \mathbf{L}_{in,b}\\
- \mathbf{L}_{b,in} & \mathbf{L}_{b,b}\end{array}\right) 
- \left(\begin{array}{c}
- \mathbf{z}_{in}\\
- \mathbf{L}_{b}\end{array}\right) = 
- \left(\begin{array}{c}
- \mathbf{0}_{in}\\
- \mathbf{*}_{b}\end{array}\right)$$ 
-
-The bottom block of equations is no longer meaningful so we'll only consider
-the top block:
-
- $$\left(\begin{array}{cc}
- \mathbf{L}_{in,in} & \mathbf{L}_{in,b}\end{array}\right) 
- \left(\begin{array}{c}
- \mathbf{z}_{in}\\
- \mathbf{z}_{b}\end{array}\right) = 
- \mathbf{0}_{in}$$
-
-Where now we can move known values to the right-hand side:
-
- $$\mathbf{L}_{in,in} 
- \mathbf{z}_{in} = -
- \mathbf{L}_{in,b}
- \mathbf{z}_{b}$$
-
-Finally we can solve this equation for the unknown values at interior vertices
-$\mathbf{z}_{in}$.
-
-However, probably our vertices are not sorted. One option would be to sort `V`,
-then proceed as above and then _unsort_ the solution `Z` to match `V`. However,
-this solution is not very general.
-
-With array slicing no explicit sort is needed. Instead we can _slice-out_
-submatrix blocks ($\mathbf{L}_{in,in}$, $\mathbf{L}_{in,b}$, etc.) and follow
-the linear algebra above directly. Then we can slice the solution _into_ the
-rows of `Z` corresponding to the interior vertices.
-
-![The `LaplaceEquation` example solves a Laplace equation with Dirichlet
-boundary conditions.](images/camelhead-laplace-equation.jpg)
-
-### Quadratic energy minimization
-
-The same Laplace equation may be equivalently derived by minimizing Dirichlet
-energy subject to the same boundary conditions:
-
- $\mathop{\text{minimize }}_z \frac{1}{2}\int\limits_S \|\nabla z\|^2 dA$
-
-On our discrete mesh, recall that this becomes
-
- $\mathop{\text{minimize }}_\mathbf{z}  \frac{1}{2}\mathbf{z}^T \mathbf{G}^T \mathbf{D}
- \mathbf{G} \mathbf{z} \rightarrow \mathop{\text{minimize }}_\mathbf{z} \mathbf{z}^T \mathbf{L} \mathbf{z}$
-
-The general problem of minimizing some energy over a mesh subject to fixed
-value boundary conditions is so wide spread that libigl has a dedicated api for
-solving such systems. 
-
-Let's consider a general quadratic minimization problem subject to different
-common constraints:
-
- $$\mathop{\text{minimize }}_\mathbf{z}  \frac{1}{2}\mathbf{z}^T \mathbf{Q} \mathbf{z} +
- \mathbf{z}^T \mathbf{B} + \text{constant},$$
-
- subject to
- 
- $$\mathbf{z}_b = \mathbf{z}_{bc} \text{ and } \mathbf{A}_{eq} \mathbf{z} =
- \mathbf{B}_{eq},$$
-
-where 
-
-  - $\mathbf{Q}$ is a (usually sparse) $n \times n$ positive semi-definite
-    matrix of quadratic coefficients (Hessian), 
-  - $\mathbf{B}$ is a $n \times 1$ vector of linear coefficients, 
-  - $\mathbf{z}_b$ is a $|b| \times 1$ portion of
-$\mathbf{z}$ corresponding to boundary or _fixed_ vertices,
-  - $\mathbf{z}_{bc}$ is a $|b| \times 1$ vector of known values corresponding to
-    $\mathbf{z}_b$,
-  - $\mathbf{A}_{eq}$ is a (usually sparse) $m \times n$ matrix of linear
-    equality constraint coefficients (one row per constraint), and
-  - $\mathbf{B}_{eq}$ is a $m \times 1$ vector of linear equality constraint
-    right-hand side values.
-
-This specification is overly general as we could write $\mathbf{z}_b =
-\mathbf{z}_{bc}$ as rows of $\mathbf{A}_{eq} \mathbf{z} =
-\mathbf{B}_{eq}$, but these fixed value constraints appear so often that they
-merit a dedicated place in the API.
-
-In libigl, solving such quadratic optimization problems is split into two
-routines: precomputation and solve. Precomputation only depends on the
-quadratic coefficients, known value indices and linear constraint coefficients:
-
-```cpp
-igl::min_quad_with_fixed_data mqwf;
-igl::min_quad_with_fixed_precompute(Q,b,Aeq,true,mqwf);
-```
-
-The output is a struct `mqwf` which contains the system matrix factorization
-and is used during solving with arbitrary linear terms, known values, and
-constraint right-hand sides:
-
-```cpp
-igl::min_quad_with_fixed_solve(mqwf,B,bc,Beq,Z);
-```
-
-The output `Z` is a $n \times 1$ vector of solutions with fixed values
-correctly placed to match the mesh vertices `V`.
-
-## Linear Equality Constraints
-We saw above that `min_quad_with_fixed_*` in libigl provides a compact way to
-solve general quadratic programs. Let's consider another example, this time
-with active linear equality constraints. Specifically let's solve the
-`bi-Laplace equation` or equivalently minimize the Laplace energy:
-
- $$\Delta^2 z = 0 \leftrightarrow \mathop{\text{minimize }}\limits_z \frac{1}{2}
- \int\limits_S (\Delta z)^2 dA$$
-
-subject to fixed value constraints and a linear equality constraint:
-
- $z_{a} = 1, z_{b} = -1$ and $z_{c} = z_{d}$.
-
-Notice that we can rewrite the last constraint in the familiar form from above:
-
- $z_{c} - z_{d} = 0.$
-
-Now we can assembly `Aeq` as a $1 \times n$ sparse matrix with a coefficient
-$1$
-in the column corresponding to vertex $c$ and a $-1$ at $d$. The right-hand side
-`Beq` is simply zero.
-
-Internally, `min_quad_with_fixed_*` solves using the Lagrange Multiplier
-method. This method adds additional variables for each linear constraint (in
-general a $m \times 1$ vector of variables $\lambda$) and then solves the
-saddle problem:
-
- $$\mathop{\text{find saddle }}_{\mathbf{z},\lambda}\, \frac{1}{2}\mathbf{z}^T \mathbf{Q} \mathbf{z} +
-  \mathbf{z}^T \mathbf{B} + \text{constant} + \lambda^T\left(\mathbf{A}_{eq}
- \mathbf{z} - \mathbf{B}_{eq}\right)$$
-
-This can be rewritten in a more familiar form by stacking $\mathbf{z}$ and
-$\lambda$ into one $(m+n) \times 1$ vector of unknowns:
-
- $$\mathop{\text{find saddle }}_{\mathbf{z},\lambda}\, 
- \frac{1}{2}
- \left(
-  \mathbf{z}^T 
-  \lambda^T
- \right)
- \left(
-  \begin{array}{cc}
-  \mathbf{Q}      & \mathbf{A}_{eq}^T\\
-  \mathbf{A}_{eq} & 0
-  \end{array}
- \right)
- \left(
-  \begin{array}{c}
-  \mathbf{z}\\
-  \lambda
-  \end{array}
- \right) + 
- \left(
-  \mathbf{z}^T 
-  \lambda^T
- \right)
- \left(
-  \begin{array}{c}
-  \mathbf{B}\\
-  -\mathbf{B}_{eq}
-  \end{array}
-  \right)
-  + \text{constant}$$
-
-Differentiating with respect to $\left( \mathbf{z}^T \lambda^T \right)$ reveals
-a linear system and we can solve for $\mathbf{z}$ and $\lambda$. The only
-difference from
-the straight quadratic
-_minimization_ system, is that 
-this saddle problem system will not be positive definite. Thus, we must use a
-different factorization technique (LDLT rather than LLT). Luckily, libigl's
-`min_quad_with_fixed_precompute` automatically chooses the correct solver in
-the presence of linear equality constraints.
-
-![The example `LinearEqualityConstraints` first solves with just fixed value
-constraints (left: 1 and -1 on the left hand and foot respectively), then
-solves with an additional linear equality constraint (right: points on right
-hand and foot constrained to be equal).](images/cheburashka-biharmonic-leq.jpg)
-
-## Quadratic Programming
-
-We can generalize the quadratic optimization in the previous section even more
-by allowing inequality constraints. Specifically box constraints (lower and
-upper bounds):
-
- $\mathbf{l} \le \mathbf{z} \le \mathbf{u},$
-
-where $\mathbf{l},\mathbf{u}$ are $n \times 1$ vectors of lower and upper
-bounds
-and general linear inequality constraints:
-
- $\mathbf{A}_{ieq} \mathbf{z} \le \mathbf{B}_{ieq},$
-
-where $\mathbf{A}_{ieq}$ is a $k \times n$ matrix of linear coefficients and
-$\mathbf{B}_{ieq}$ is a $k \times 1$ matrix of constraint right-hand sides.
-
-Again, we are overly general as the box constraints could be written as
-rows of the linear inequality constraints, but bounds appear frequently enough
-to merit a dedicated api.
-
-Libigl implements its own active set routine for solving _quadratric programs_
-(QPs). This algorithm works by iteratively "activating" violated inequality
-constraints by enforcing them as equalities and "deactivating" constraints
-which are no longer needed.
-
-After deciding which constraints are active each iteration simple reduces to a
-quadratic minimization subject to linear _equality_ constraints, and the method
-from the previous section is invoked. This is repeated until convergence.
-
-Currently the implementation is efficient for box constraints and sparse
-non-overlapping linear inequality constraints.
-
-Unlike alternative interior-point methods, the active set method benefits from
-a warm-start (initial guess for the solution vector $\mathbf{z}$).
-
-```cpp
-igl::active_set_params as;
-// Z is optional initial guess and output
-igl::active_set(Q,B,b,bc,Aeq,Beq,Aieq,Bieq,lx,ux,as,Z);
-```
-
-![The example `QuadraticProgramming` uses an active set solver to optimize
-discrete biharmonic kernels at multiple scales [#rustamov_2011][].](images/cheburashka-multiscale-biharmonic-kernels.jpg)
-
-[#meyer_2003]: Mark Meyer and Mathieu Desbrun and Peter Schröder and Alan H.  Barr,
-"Discrete Differential-Geometry Operators for Triangulated
-2-Manifolds," 2003.
-[#pannozo_2010]: Daniele Pannozo, Enrico Puppo, Luigi Rocca,
-"Efficient Multi-scale Curvature and Crease Estimation," 2010.
-[#jacobson_thesis_2013]: Alec Jacobson,
-_Algorithms and Interfaces for Real-Time Deformation of 2D and 3D Shapes_,
-2013.
-[#kazhdan_2012]: Michael Kazhdan, Jake Solomon, Mirela Ben-Chen,
-"Can Mean-Curvature Flow Be Made Non-Singular," 2012.
-[#rustamov_2011]: Raid M. Rustamov, "Multiscale Biharmonic Kernels", 2011.

+ 8 - 0
tutorial/shared/2triangles.off

@@ -0,0 +1,8 @@
+OFF
+4 2 5
+ 0.0   0.0   0.0
+ 1.0   0.0   0.0
+ 1.0   1.0   1.0
+ 2.0   1.0   0.0
+ 3  0 1 2
+ 3  1 3 2

+ 1 - 0
tutorial/shared/bump-domain.obj.REMOVED.git-id

@@ -0,0 +1 @@
+e696d4d47e13c890229c4a6c17bf41befd337ae8

+ 5273 - 0
tutorial/shared/decimated-max-selection.dmat

@@ -0,0 +1,5273 @@
+1 5272
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+0
+-1
+0
+0
+0
+0
+0
+0
+-1
+-1
+0
+-1
+0
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+0
+0
+0
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+0
+-1
+1
+1
+0
+-1
+-1
+-1
+1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+0
+0
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+1
+-1
+0
+1
+-1
+-1
+-1
+0
+0
+1
+1
+1
+1
+0
+0
+-1
+1
+0
+1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+-1
+-1
+-1
+1
+-1
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+2
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+2
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+-1
+2
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+2
+-1
+2
+2
+0
+0
+-1
+-1
+-1
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+-1
+-1
+0
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+1
+-1
+0
+1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+0
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+1
+1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+1
+1
+1
+-1
+2
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+0
+0
+0
+1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+1
+-1
+2
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+2
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+2
+2
+2
+2
+-1
+-1
+-1
+-1
+1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+2
+2
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+0
+0
+0
+-1
+-1
+0
+0
+-1
+-1
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+0
+0
+0
+-1
+-1
+-1
+0
+0
+0
+0
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+0
+0
+0
+-1
+-1
+0
+0
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+0
+0
+0
+0
+-1
+0
+-1
+0
+0
+0
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+0
+0
+-1
+0
+0
+0
+0
+-1
+0
+0
+0
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+-1
+0
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+-1
+-1
+0
+0
+0
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+-1
+-1
+0
+0
+-1
+-1
+0
+0
+0
+0
+0
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+-1
+-1
+0
+-1
+-1
+0
+0
+-1
+-1
+0
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+2
+0
+-1
+0
+2
+-1
+2
+2
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+0
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+-1
+0
+-1
+0
+-1
+-1
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+2
+-1
+2
+2
+2
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+0
+-1
+-1
+0
+0
+0
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+1
+1
+1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+1
+1
+1
+1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+2
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+2
+2
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+1
+1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+-1
+0
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+0
+-1
+0
+0
+0
+0
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+0
+0
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+0
+0
+-1
+0
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+0
+0
+-1
+0
+-1
+0
+0
+0
+-1
+0
+0
+0
+0
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+0
+0
+-1
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+0
+-1
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+0
+0
+-1
+0
+0
+0
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+0
+-1
+0
+0
+0
+0
+0
+0
+-1
+-1
+0
+0
+0
+0
+0
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+0
+-1
+0
+0
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+0
+0
+0
+0
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+0
+-1
+-1
+0
+0
+0
+0
+0
+0
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+0
+0
+0
+0
+-1
+0
+0
+0
+0
+0
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+0
+0
+0
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+0
+-1
+-1
+0
+-1
+0
+0
+0
+0
+-1
+-1
+0
+-1
+0
+0
+0
+0
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+0
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+0
+-1
+-1
+0
+0
+-1
+-1
+-1
+0
+0
+-1
+0
+0
+0
+-1
+-1
+0
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+0
+0
+0
+0
+-1
+0
+0
+-1
+-1
+0
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+-1
+-1
+0
+0
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+-1
+-1
+0
+-1
+-1
+0
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+0
+-1
+0
+-1
+-1
+-1
+0
+-1
+-1
+-1
+0
+-1
+-1
+-1
+0
+-1
+0
+0
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+0
+-1
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+-1
+-1
+-1
+-1
+2
+2
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+0
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+2
+-1
+-1
+-1
+-1
+2
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+0
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+0
+0
+0
+0
+0
+0
+0
+-1
+0
+0
+0
+0
+0
+-1
+0
+0
+-1
+0
+-1
+0
+0
+0
+0
+0
+-1
+0
+0
+0
+-1
+-1
+0
+0
+0
+0
+0
+-1
+0
+0
+-1
+-1
+-1
+0
+-1
+2
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+0
+-1
+0
+0
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+2
+2
+2
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+2
+2
+2
+2
+2
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+0
+-1
+0
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+1
+-1
+-1
+-1
+0
+0
+0
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+-1
+0
+0
+-1
+0
+-1
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+0
+2
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+2
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+2
+-1
+-1
+-1
+-1
+-1
+-1
+2
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+-1
+-1
+2
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+0
+-1
+0
+0
+0
+-1
+-1
+-1
+0
+0
+0
+0
+-1
+-1
+-1
+0
+0
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+-1
+-1
+0
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+2
+2
+2
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+2
+-1
+1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+0
+0
+0
+0
+-1
+0
+0
+-1
+0
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+-1
+-1
+0
+-1
+-1
+-1
+0
+-1
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+0
+0
+0
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+0
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+-1
+-1
+-1
+0
+-1
+-1
+-1
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+2
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+0
+0
+0
+0
+0
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+-1
+-1
+-1

+ 1 - 0
tutorial/shared/decimated-max.obj.REMOVED.git-id

@@ -0,0 +1 @@
+a872c870b4c1875b235ac2f85db80cd12cbb1161

+ 81 - 0
tutorial/shared/hand-pose.dmat

@@ -0,0 +1,81 @@
+1 80
+0.61618142029453848
+0.21865691494778211
+-0.074398815808914262
+0.75297704283434619
+0.016137740405538198
+0.0075736234381567954
+-0.01978957096844574
+0.9996452302909804
+-0.0031783575088926955
+-0.0021852197161076415
+0.025195604356894566
+0.99967509940951804
+0
+0
+0
+1
+0
+0
+0
+1
+-0.06502916547759717
+-0.018228928610557554
+-0.10960238233656835
+0.99167849204525316
+0.65862930444592327
+-0.28749500451272225
+0.047433167985789754
+0.69376087831482691
+0.71088878530987565
+0.13051734182532121
+-0.024300471136119696
+0.69066044153843431
+0.12918716086559792
+0.42797711290327217
+-0.23378675140515992
+0.86341764121767584
+0.5777562073061252
+-0.10739726497891923
+0.027027719666595052
+0.80866129792634012
+0
+0
+0
+1
+0.25064723245034182
+0.062362300611793375
+0.055537180373327777
+0.96447007725671363
+0.68233863926855265
+-0.043115978196253735
+0.066162231411292738
+0.72675824929614585
+0.53643420171330392
+-0.34234055129349178
+0.079151746448423155
+0.76731759735246274
+0.37119350486218949
+-0.20651629016779105
+0.015792865442698228
+0.90516130564935249
+0.46007394537647717
+-0.033329312116362406
+-0.011156066109515889
+0.88718468422788521
+0.36118819983774919
+0.046197896403048229
+0.048746682979448855
+0.93007128735619049
+-0.080434792811141881
+0.24444948358806326
+-0.37172646406082138
+0.89196083433960183
+0.34016846232137932
+0.054859354927957418
+0.046210032868129636
+0.93762492569317746
+0.45250460737446119
+0.27010308530876809
+0.1405545502553627
+0.83816962603883571

+ 1 - 0
tutorial/shared/hand.mesh.REMOVED.git-id

@@ -0,0 +1 @@
+cbe696a1280075895d31178317b30d722e0af9f3

+ 43 - 0
tutorial/shared/hand.tgf

@@ -0,0 +1,43 @@
+   1 0.11429762 -0.76590296 -0.11140733          0          1          0          1          1          1          0          0          0          1          1  1.0061325 0.88859267          0    1 
+   2 0.10546931 -0.57479244 -0.084241846 2.7982368e+199 3.7150555e-27 6.0174446e+175          1          1          1          0          0          0          1 0.99850723   1.182572 0.91575815          0    2 
+   3 -0.24048184 -0.34974589 0.083588056 2.0750757e-322 3.9525252e-322 2.5296161e-321          1          1          1          0          0          0          1 0.65901122  1.2530116  1.0835881          0    4 
+   4 -0.41528797 -0.19724228 0.15108035 6.953262e-310 6.953262e-310 6.953262e-310          1          1          1          0          0          0          1 0.86263359  1.1364105  1.1510803          0    6 
+   5 -0.53251027 -0.043704366   0.220108          0          1          0          1          1          1          0          0          0          1 0.91920809  1.1497897   1.220108          0    8 
+   6 -0.16766723 0.12476223 -0.049004442 1.0869444e-322 3.9525252e-322 2.5296161e-321          1          1          1          0          0          0          1 0.72621948  1.7247165 0.95099556          0   10 
+   7 -0.22466126 0.29596172 -0.045066203 6.9532642e-310 6.9532642e-310 6.9532642e-310          1          1          1          0          0          0          1 0.92992065  1.1895161  0.9549338          0   12 
+   8 -0.29358606 0.48060868 -0.018623317 5.4347221e-323 5.4347221e-323 3.9525252e-323          1          1          1          0          0          0          1 0.93107519  1.1835472 0.98137668          0   14 
+   9 -0.3288664 0.60375622 0.0023204123 5.4347221e-323 5.4347221e-323 3.9525252e-323          1          1          1          0          0          0          1 0.94905516  1.1441107  1.0023204          0   16 
+  10 -0.0045596564 0.17429162 -0.063580889 5.4347221e-323 5.4347221e-323 3.9525252e-323          1          1          1          0          0          0          1 0.87811436  1.7574269 0.93641911          0   18 
+  11 -0.035737249 0.36523184 -0.049670244          0          1          0          1          1          1          0          0          0          1 0.95065421  1.2251482 0.95032976          0   20 
+  12 -0.063819738 0.56050302 -0.026654403 5.4347221e-323 5.4347221e-323 3.9525252e-323          1          1          1          0          0          0          1 0.95901298  1.2354098  0.9733456          0   22 
+  13 -0.080813321 0.71934417 0.0051323801 6.9532642e-310 6.9532642e-310 6.9532642e-310          1          1          1          0          0          0          1 0.96724796  1.2232573  1.0051324          0   24 
+  14 0.15872682  0.1411217 -0.041958815          0          1          0          1          1          1          0          0          0          1   1.044204  1.7326665 0.95804118          0   26 
+  15 0.16999343 0.35280711 -0.0202035          0          1          0          1          1          1          0          0          0          1  1.0246357  1.2351488  0.9797965          0   28 
+  16  0.1877683 0.51268791 0.010202099 6.9533558e-309 6.9532426e-310          0          1          1          1          0          0          0          1   1.017182  1.1791852  1.0102021          0   30 
+  17 0.20129211 0.64288912 0.029292092 6.9398703e-310 6.9398703e-310 6.9398703e-310          1          1          1          0          0          0          1   1.002674  1.1159674  1.0292921          0   32 
+  18 0.34208039 0.052370865          0 6.9398715e-310 2.3912777e-321          0          1          1          1          0          0          0          1  1.2359671  1.6383093          1          0   34 
+  19 0.40904104 0.18734965 0.027992567          0          1          0          1          1          1          0          0          0          1   1.081477  1.1621961  1.0279926          0   36 
+  20 0.49154459 0.32275416 0.058527871 6.9398703e-310 6.9398703e-310 6.9398703e-310          1          1          1          0          0          0          1   1.074279  1.1322133  1.0585279          0   38 
+  21 0.54469073 0.41146288 0.082016739 6.9398703e-310 2.3912777e-321          0          1          1          1          0          0          0          1  1.0377236  1.0807633  1.0820167          0   40 
+#
+   6    7
+   2    6
+   2   18
+   2   10
+   2   14
+   2    3
+  18   19
+  10   11
+   4    5
+  16   17
+   1    2
+   8    9
+  14   15
+  20   21
+  19   20
+  15   16
+  11   12
+   3    4
+  12   13
+   7    8
+#

Some files were not shown because too many files changed in this diff