Jelajahi Sumber

Merge remote-tracking branch 'origin/master' into cgal

Former-commit-id: 5aa1360ab8b43dab7ff8f6f757a4f23c2009d425
Jérémie Dumas 7 tahun lalu
induk
melakukan
a5635bf05f
100 mengubah file dengan 2405 tambahan dan 1116 penghapusan
  1. 12 5
      .gitmodules
  2. 3 3
      .travis.yml
  3. 1 1
      README.md
  4. 1 1
      RELEASE_HISTORY.md
  5. 2 2
      file-formats/dmat.html
  6. 2 2
      file-formats/index.html
  7. 1 1
      file-formats/tgf.html
  8. 1 1
      file-formats/xml.html
  9. 60 57
      include/igl/AABB.cpp
  10. 130 0
      include/igl/AtA_cached.cpp
  11. 70 0
      include/igl/AtA_cached.h
  12. 40 0
      include/igl/Attribute.h
  13. 1 1
      include/igl/Camera.h
  14. 1 1
      include/igl/REDRUM.h
  15. 1 1
      include/igl/SortableRow.h
  16. 3 3
      include/igl/WindingNumberTree.h
  17. 4 3
      include/igl/adjacency_matrix.cpp
  18. 3 3
      include/igl/arap_dof.cpp
  19. 1 1
      include/igl/arap_dof.h
  20. 1 1
      include/igl/bbw.h
  21. 4 4
      include/igl/bijective_composite_harmonic_mapping.h
  22. 1 1
      include/igl/boundary_conditions.cpp
  23. 1 1
      include/igl/cat.h
  24. 3 1
      include/igl/colormap.cpp
  25. 32 2
      include/igl/combine.cpp
  26. 19 2
      include/igl/combine.h
  27. 1 1
      include/igl/connect_boundary_to_infinity.h
  28. 1 1
      include/igl/copyleft/cgal/SelfIntersectMesh.h
  29. 41 4
      include/igl/copyleft/cgal/assign_scalar.cpp
  30. 22 4
      include/igl/copyleft/cgal/assign_scalar.h
  31. 1 1
      include/igl/copyleft/cgal/cell_adjacency.h
  32. 1 1
      include/igl/copyleft/cgal/closest_facet.cpp
  33. 0 7
      include/igl/copyleft/cgal/intersect_other.h
  34. 6 27
      include/igl/copyleft/cgal/mesh_boolean.cpp
  35. 2 1
      include/igl/copyleft/cgal/minkowski_sum.cpp
  36. 2 2
      include/igl/copyleft/cgal/order_facets_around_edge.h
  37. 1 1
      include/igl/copyleft/cgal/outer_facet.h
  38. 1 1
      include/igl/copyleft/cgal/point_mesh_squared_distance.cpp
  39. 1 1
      include/igl/copyleft/cgal/points_inside_component.cpp
  40. 4 3
      include/igl/copyleft/cgal/propagate_winding_numbers.cpp
  41. 16 12
      include/igl/copyleft/cgal/remesh_intersections.cpp
  42. 1 1
      include/igl/copyleft/cgal/remesh_intersections.h
  43. 1 1
      include/igl/copyleft/cgal/trim_with_solid.cpp
  44. 42 8
      include/igl/copyleft/cgal/wire_mesh.cpp
  45. 35 16
      include/igl/copyleft/cgal/wire_mesh.h
  46. 1 1
      include/igl/copyleft/comiso/miq.h
  47. 1 1
      include/igl/copyleft/comiso/nrosy.h
  48. 1 0
      include/igl/copyleft/marching_cubes.cpp
  49. 1 0
      include/igl/copyleft/offset_surface.cpp
  50. 1 1
      include/igl/copyleft/offset_surface.h
  51. 1 1
      include/igl/copyleft/opengl2/render_to_tga.h
  52. 1 1
      include/igl/copyleft/tetgen/cdt.h
  53. 2 2
      include/igl/copyleft/tetgen/read_into_tetgenio.h
  54. 1 1
      include/igl/cotmatrix.h
  55. 2 2
      include/igl/cotmatrix_entries.cpp
  56. 1 1
      include/igl/crouzeix_raviart_cotmatrix.cpp
  57. 1 1
      include/igl/crouzeix_raviart_massmatrix.cpp
  58. 3 3
      include/igl/cut_mesh.cpp
  59. 1 1
      include/igl/directed_edge_parents.h
  60. 1 0
      include/igl/edges.cpp
  61. 4 4
      include/igl/embree/EmbreeIntersector.h
  62. 1 1
      include/igl/exterior_edges.cpp
  63. 1 1
      include/igl/exterior_edges.h
  64. 2 2
      include/igl/facet_components.h
  65. 1 1
      include/igl/hausdorff.h
  66. 6 6
      include/igl/hessian.cpp
  67. 8 8
      include/igl/hessian_energy.cpp
  68. 1 1
      include/igl/histc.h
  69. 2 2
      include/igl/integrable_polyvector_fields.h
  70. 4 4
      include/igl/is_boundary_edge.cpp
  71. 1 1
      include/igl/is_planar.h
  72. 3 2
      include/igl/is_stl.cpp
  73. 4 1
      include/igl/ismember.cpp
  74. 2 0
      include/igl/jet.cpp
  75. 1 1
      include/igl/lim/lim.h
  76. 3 2
      include/igl/list_to_matrix.cpp
  77. 2 2
      include/igl/matlab/validate_arg.h
  78. 3 3
      include/igl/matlab_format.h
  79. 1 1
      include/igl/min_quad_with_fixed.cpp
  80. 1 1
      include/igl/mosek/bbw.h
  81. 2 2
      include/igl/mosek/mosek_linprog.cpp
  82. 5 2
      include/igl/mosek/mosek_quadprog.cpp
  83. 311 0
      include/igl/opengl/MeshGL.cpp
  84. 44 28
      include/igl/opengl/MeshGL.h
  85. 58 116
      include/igl/opengl/ViewerCore.cpp
  86. 62 100
      include/igl/opengl/ViewerCore.h
  87. 689 0
      include/igl/opengl/ViewerData.cpp
  88. 127 77
      include/igl/opengl/ViewerData.h
  89. 24 0
      include/igl/opengl/bind_vertex_attrib_array.cpp
  90. 32 0
      include/igl/opengl/bind_vertex_attrib_array.h
  91. 6 25
      include/igl/opengl/gl.h
  92. 6 6
      include/igl/opengl/glfw/TextRenderer.cpp
  93. 6 3
      include/igl/opengl/glfw/TextRenderer.h
  94. 0 0
      include/igl/opengl/glfw/TextRenderer_fonts.cpp.REMOVED.git-id
  95. 2 2
      include/igl/opengl/glfw/TextRenderer_fonts.h
  96. 301 419
      include/igl/opengl/glfw/Viewer.cpp
  97. 70 67
      include/igl/opengl/glfw/Viewer.h
  98. 6 5
      include/igl/opengl/glfw/ViewerPlugin.h
  99. 5 10
      include/igl/opengl/glfw/background_window.cpp
  100. 2 3
      include/igl/opengl/glfw/background_window.h

+ 12 - 5
.gitmodules

@@ -1,8 +1,3 @@
-[submodule "external/nanogui"]
-	path = external/nanogui
-	url=https://github.com/libigl/nanogui.git
-	fetchRecursiveSubmodules = true
-	ignore = dirty
 [submodule "external/embree"]
 [submodule "external/embree"]
 	path = external/embree
 	path = external/embree
 	url = https://github.com/embree/embree.git
 	url = https://github.com/embree/embree.git
@@ -24,3 +19,15 @@
 [submodule "external/cork"]
 [submodule "external/cork"]
 	path = external/cork
 	path = external/cork
 	url = https://github.com/libigl/cork.git
 	url = https://github.com/libigl/cork.git
+[submodule "external/imgui"]
+	path = external/imgui/imgui
+	url = https://github.com/ocornut/imgui.git
+[submodule "external/glfw"]
+	path = external/glfw
+	url = https://github.com/glfw/glfw.git
+[submodule "external/eigen"]
+	path = external/eigen
+	url = https://github.com/eigenteam/eigen-git-mirror.git
+[submodule "external/pybind11"]
+	path = external/pybind11
+	url = https://github.com/pybind/pybind11

+ 3 - 3
.travis.yml

@@ -7,8 +7,8 @@ matrix:
       compiler: gcc-4.8.1
       compiler: gcc-4.8.1
       script:
       script:
         - git submodule update --init --recursive
         - git submodule update --init --recursive
-        - mkdir external/nanogui/ext/glfw/include/GL
-        - wget --no-check-certificate -P external/nanogui/ext/glfw/include/GL http://www.opengl.org/registry/api/GL/glcorearb.h
+        - mkdir external/glfw/include/GL
+        - wget --no-check-certificate -P external/glfw/include/GL http://www.opengl.org/registry/api/GL/glcorearb.h
         - cd python
         - cd python
         - mkdir build
         - mkdir build
         - cd build
         - cd build
@@ -63,5 +63,5 @@ matrix:
         - cd tutorial
         - cd tutorial
         - mkdir build
         - mkdir build
         - cd build
         - cd build
-        - cmake -DLIBIGL_USE_STATIC_LIBRARY=ON -DLIBIGL_WITH_NANOGUI=ON ../
+        - cmake -DLIBIGL_USE_STATIC_LIBRARY=ON ../
         - make -j 2
         - make -j 2

+ 1 - 1
README.md

@@ -193,7 +193,7 @@ BibTeX entry:
   title = {{libigl}: A simple {C++} geometry processing library},
   title = {{libigl}: A simple {C++} geometry processing library},
   author = {Alec Jacobson and Daniele Panozzo and others},
   author = {Alec Jacobson and Daniele Panozzo and others},
   note = {http://libigl.github.io/libigl/},
   note = {http://libigl.github.io/libigl/},
-  year = {2016},
+  year = {2017},
 }
 }
 ```
 ```
 
 

+ 1 - 1
RELEASE_HISTORY.md

@@ -37,7 +37,7 @@ Version | Short description
 0.3.1   | Linearly dependent constraints in min_quad_with_fixed, SparseQR buggy
 0.3.1   | Linearly dependent constraints in min_quad_with_fixed, SparseQR buggy
 0.3.0   | Better active set method support
 0.3.0   | Better active set method support
 0.2.3   | More explicits, active set method, opengl/anttweakbar guards
 0.2.3   | More explicits, active set method, opengl/anttweakbar guards
-0.2.2   | More explicit instanciations, faster sorts and uniques
+0.2.2   | More explicit instantiations, faster sorts and uniques
 0.2.1   | Bug fixes in barycenter and doublearea found by Martin Bisson
 0.2.1   | Bug fixes in barycenter and doublearea found by Martin Bisson
 0.2.0   | XML serializer more stable and fixed bug in remove_duplicate_vertices
 0.2.0   | XML serializer more stable and fixed bug in remove_duplicate_vertices
 0.1.8   | Embree and xml (windows only) extras
 0.1.8   | Embree and xml (windows only) extras

+ 2 - 2
file-formats/dmat.html

@@ -12,7 +12,7 @@
     <p>
     <p>
 A .dmat file contains a dense matrix in column major order. It can contain
 A .dmat file contains a dense matrix in column major order. It can contain
 ASCII or binary data. Note that it is uncompressed so binary only reduces the
 ASCII or binary data. Note that it is uncompressed so binary only reduces the
-file size by 50%. But writing and reading binary is usualy faster. In MATLAB,
+file size by 50%. But writing and reading binary is usually faster. In MATLAB,
 binary is almost 100x faster.
 binary is almost 100x faster.
     </p>
     </p>
     <h2>ASCII</h2>
     <h2>ASCII</h2>
@@ -33,7 +33,7 @@ Then there should be another header containing the size of the binary part:
     </p>
     </p>
     <pre><code>[#cols] [#rows]</code></pre>
     <pre><code>[#cols] [#rows]</code></pre>
     <p>
     <p>
-Then coefficents are written in column-major order in Little-endian 8-byte
+Then coefficients are written in column-major order in Little-endian 8-byte
 double precision IEEE floating point format.
 double precision IEEE floating point format.
     </p>
     </p>
     <p><strong>Note:</strong> Line endings must be <code>'\n'</code> aka char(10) aka line feeds.</p>
     <p><strong>Note:</strong> Line endings must be <code>'\n'</code> aka char(10) aka line feeds.</p>

+ 2 - 2
file-formats/index.html

@@ -20,7 +20,7 @@
     <li><a href=http://tetgen.berlios.de/fformats.face.html
     <li><a href=http://tetgen.berlios.de/fformats.face.html
     class=missing>.face</a> TetGen's file format for simplicial facets.</li>
     class=missing>.face</a> TetGen's file format for simplicial facets.</li>
     <li><a href="http://www.ann.jussieu.fr/frey/publications/RT-0253.pdf#page=33">.mesh</a> Medit's triangle surface mesh + tetrahedral volume mesh file format, see page 33, section 7.2.1</li>
     <li><a href="http://www.ann.jussieu.fr/frey/publications/RT-0253.pdf#page=33">.mesh</a> Medit's triangle surface mesh + tetrahedral volume mesh file format, see page 33, section 7.2.1</li>
-    <li><i>.node</i> List of points (vertices). Described indentically (upto
+    <li><i>.node</i> List of points (vertices). Described identically (upto
         accepted dimensions, use of attributes and boundary markers) by <a
         accepted dimensions, use of attributes and boundary markers) by <a
     href="https://www.cs.cmu.edu/~quake/triangle.node.html">Triangle</a>, <a
     href="https://www.cs.cmu.edu/~quake/triangle.node.html">Triangle</a>, <a
     href=http://tetgen.berlios.de/fformats.node.html>TetGen</a>, and <a
     href=http://tetgen.berlios.de/fformats.node.html>TetGen</a>, and <a
@@ -37,7 +37,7 @@
     href=https://en.wikipedia.org/wiki/Portable_Network_Graphics>.png</a>
     href=https://en.wikipedia.org/wiki/Portable_Network_Graphics>.png</a>
     Portable Network Graphics image file. IGLLIB (in the libiglpng extra)
     Portable Network Graphics image file. IGLLIB (in the libiglpng extra)
   supports png image files via the <a href=https://github.com/yig/yimg>yimg</a>
   supports png image files via the <a href=https://github.com/yig/yimg>yimg</a>
-  library. Alpha channels and compression are suppported.</li>
+  library. Alpha channels and compression are supported.</li>
     <li><i>.poly</i> Piecewise-linear complex. This format comes in many similar but importantly different flavors: 
     <li><i>.poly</i> Piecewise-linear complex. This format comes in many similar but importantly different flavors: 
       <a href="https://www.cs.cmu.edu/~quake/triangle.poly.html">triangle's</a>, <a href="http://tetgen.berlios.de/fformats.poly.html">tetgen's</a>, <a href="http://sparse-meshing.com/svr/0.2.1/format-poly.html">pyramid/SVR's</a></li>
       <a href="https://www.cs.cmu.edu/~quake/triangle.poly.html">triangle's</a>, <a href="http://tetgen.berlios.de/fformats.poly.html">tetgen's</a>, <a href="http://sparse-meshing.com/svr/0.2.1/format-poly.html">pyramid/SVR's</a></li>
     <li><a href=./rbr.html>.rbr</a> ASCII files for saving state of ReAntTweakBar</li>
     <li><a href=./rbr.html>.rbr</a> ASCII files for saving state of ReAntTweakBar</li>

+ 1 - 1
file-formats/tgf.html

@@ -11,7 +11,7 @@
     <hr>
     <hr>
     <p>
     <p>
 A .tgf file contains a graph of describing a set of control handles/structures:
 A .tgf file contains a graph of describing a set of control handles/structures:
-point controls, bones of a skelton and cages made of "cage edges".
+point controls, bones of a skeleton and cages made of "cage edges".
     </p>
     </p>
     <p>
     <p>
 The first part of the file consists of lines regarding each vertex of the graph. Each line reads:
 The first part of the file consists of lines regarding each vertex of the graph. Each line reads:

+ 1 - 1
file-formats/xml.html

@@ -31,7 +31,7 @@ STL containers: <b>std::array, std::vector, std::pair</b><br/>
 Eigen types: <b>Eigen::Matrix, Eigen::SparseMatrix</b><br/>
 Eigen types: <b>Eigen::Matrix, Eigen::SparseMatrix</b><br/>
 User defined types: <b>XMLSerializable*.</b><br/>
 User defined types: <b>XMLSerializable*.</b><br/>
 <br/>
 <br/>
-There can also be a hierachical structure like vector&lt;int&gt;, this will result in the following serialization:
+There can also be a hierarchical structure like vector&lt;int&gt;, this will result in the following serialization:
     </p>
     </p>
     <pre><code>&lt;group&gt;
     <pre><code>&lt;group&gt;
   &lt;vector size="3"&gt;
   &lt;vector size="3"&gt;

+ 60 - 57
include/igl/AABB.cpp

@@ -15,6 +15,7 @@
 #include "sort.h"
 #include "sort.h"
 #include "volume.h"
 #include "volume.h"
 #include "ray_box_intersect.h"
 #include "ray_box_intersect.h"
+#include "parallel_for.h"
 #include "ray_mesh_intersect.h"
 #include "ray_mesh_intersect.h"
 #include <iostream>
 #include <iostream>
 #include <iomanip>
 #include <iomanip>
@@ -27,7 +28,7 @@ template <typename DerivedV, int DIM>
 template <typename DerivedEle, typename Derivedbb_mins, typename Derivedbb_maxs, typename Derivedelements>
 template <typename DerivedEle, typename Derivedbb_mins, typename Derivedbb_maxs, typename Derivedelements>
 IGL_INLINE void igl::AABB<DerivedV,DIM>::init(
 IGL_INLINE void igl::AABB<DerivedV,DIM>::init(
     const Eigen::MatrixBase<DerivedV> & V,
     const Eigen::MatrixBase<DerivedV> & V,
-    const Eigen::MatrixBase<DerivedEle> & Ele, 
+    const Eigen::MatrixBase<DerivedEle> & Ele,
     const Eigen::MatrixBase<Derivedbb_mins> & bb_mins,
     const Eigen::MatrixBase<Derivedbb_mins> & bb_mins,
     const Eigen::MatrixBase<Derivedbb_maxs> & bb_maxs,
     const Eigen::MatrixBase<Derivedbb_maxs> & bb_maxs,
     const Eigen::MatrixBase<Derivedelements> & elements,
     const Eigen::MatrixBase<Derivedelements> & elements,
@@ -106,7 +107,7 @@ template <
   typename DerivedI>
   typename DerivedI>
 IGL_INLINE void igl::AABB<DerivedV,DIM>::init(
 IGL_INLINE void igl::AABB<DerivedV,DIM>::init(
     const Eigen::MatrixBase<DerivedV> & V,
     const Eigen::MatrixBase<DerivedV> & V,
-    const Eigen::MatrixBase<DerivedEle> & Ele, 
+    const Eigen::MatrixBase<DerivedEle> & Ele,
     const Eigen::MatrixBase<DerivedSI> & SI,
     const Eigen::MatrixBase<DerivedSI> & SI,
     const Eigen::MatrixBase<DerivedI> & I)
     const Eigen::MatrixBase<DerivedI> & I)
 {
 {
@@ -204,15 +205,15 @@ template <typename DerivedV, int DIM>
 template <typename DerivedEle, typename Derivedq>
 template <typename DerivedEle, typename Derivedq>
 IGL_INLINE std::vector<int> igl::AABB<DerivedV,DIM>::find(
 IGL_INLINE std::vector<int> igl::AABB<DerivedV,DIM>::find(
     const Eigen::MatrixBase<DerivedV> & V,
     const Eigen::MatrixBase<DerivedV> & V,
-    const Eigen::MatrixBase<DerivedEle> & Ele, 
+    const Eigen::MatrixBase<DerivedEle> & Ele,
     const Eigen::MatrixBase<Derivedq> & q,
     const Eigen::MatrixBase<Derivedq> & q,
     const bool first) const
     const bool first) const
 {
 {
   using namespace std;
   using namespace std;
   using namespace Eigen;
   using namespace Eigen;
-  assert(q.size() == DIM && 
+  assert(q.size() == DIM &&
       "Query dimension should match aabb dimension");
       "Query dimension should match aabb dimension");
-  assert(Ele.cols() == V.cols()+1 && 
+  assert(Ele.cols() == V.cols()+1 &&
       "AABB::find only makes sense for (d+1)-simplices");
       "AABB::find only makes sense for (d+1)-simplices");
   const Scalar epsilon = igl::EPS<Scalar>();
   const Scalar epsilon = igl::EPS<Scalar>();
   // Check if outside bounding box
   // Check if outside bounding box
@@ -250,7 +251,7 @@ IGL_INLINE std::vector<int> igl::AABB<DerivedV,DIM>::find(
           const Vector2S V2 = V.row(Ele(m_primitive,1));
           const Vector2S V2 = V.row(Ele(m_primitive,1));
           const Vector2S V3 = V.row(Ele(m_primitive,2));
           const Vector2S V3 = V.row(Ele(m_primitive,2));
           // Hack for now to keep templates simple. If becomes bottleneck
           // Hack for now to keep templates simple. If becomes bottleneck
-          // consider using std::enable_if_t 
+          // consider using std::enable_if_t
           const Vector2S q2 = q.head(2);
           const Vector2S q2 = q.head(2);
           a1 = doublearea_single(V1,V2,q2);
           a1 = doublearea_single(V1,V2,q2);
           a2 = doublearea_single(V2,V3,q2);
           a2 = doublearea_single(V2,V3,q2);
@@ -266,9 +267,9 @@ IGL_INLINE std::vector<int> igl::AABB<DerivedV,DIM>::find(
     a3 /= sum;
     a3 /= sum;
     a4 /= sum;
     a4 /= sum;
     if(
     if(
-        a1>=-epsilon && 
-        a2>=-epsilon && 
-        a3>=-epsilon && 
+        a1>=-epsilon &&
+        a2>=-epsilon &&
+        a3>=-epsilon &&
         a4>=-epsilon)
         a4>=-epsilon)
     {
     {
       return std::vector<int>(1,m_primitive);
       return std::vector<int>(1,m_primitive);
@@ -345,10 +346,10 @@ IGL_INLINE void igl::AABB<DerivedV,DIM>::serialize(
 
 
 template <typename DerivedV, int DIM>
 template <typename DerivedV, int DIM>
 template <typename DerivedEle>
 template <typename DerivedEle>
-IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar 
+IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar
 igl::AABB<DerivedV,DIM>::squared_distance(
 igl::AABB<DerivedV,DIM>::squared_distance(
   const Eigen::MatrixBase<DerivedV> & V,
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & p,
   const RowVectorDIMS & p,
   int & i,
   int & i,
   Eigen::PlainObjectBase<RowVectorDIMS> & c) const
   Eigen::PlainObjectBase<RowVectorDIMS> & c) const
@@ -359,10 +360,10 @@ igl::AABB<DerivedV,DIM>::squared_distance(
 
 
 template <typename DerivedV, int DIM>
 template <typename DerivedV, int DIM>
 template <typename DerivedEle>
 template <typename DerivedEle>
-IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar 
+IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar
 igl::AABB<DerivedV,DIM>::squared_distance(
 igl::AABB<DerivedV,DIM>::squared_distance(
   const Eigen::MatrixBase<DerivedV> & V,
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & p,
   const RowVectorDIMS & p,
   Scalar low_sqr_d,
   Scalar low_sqr_d,
   Scalar up_sqr_d,
   Scalar up_sqr_d,
@@ -393,7 +394,7 @@ igl::AABB<DerivedV,DIM>::squared_distance(
     {
     {
       int i_left;
       int i_left;
       RowVectorDIMS c_left = c;
       RowVectorDIMS c_left = c;
-      Scalar sqr_d_left = 
+      Scalar sqr_d_left =
         m_left->squared_distance(V,Ele,p,low_sqr_d,sqr_d,i_left,c_left);
         m_left->squared_distance(V,Ele,p,low_sqr_d,sqr_d,i_left,c_left);
       this->set_min(p,sqr_d_left,i_left,c_left,sqr_d,i,c);
       this->set_min(p,sqr_d_left,i_left,c_left,sqr_d,i,c);
       looked_left = true;
       looked_left = true;
@@ -401,8 +402,8 @@ igl::AABB<DerivedV,DIM>::squared_distance(
     const auto & look_right = [&]()
     const auto & look_right = [&]()
     {
     {
       int i_right;
       int i_right;
-      Eigen::PlainObjectBase<RowVectorDIMS> c_right = c;
-      Scalar sqr_d_right = 
+      RowVectorDIMS c_right = c;
+      Scalar sqr_d_right =
         m_right->squared_distance(V,Ele,p,low_sqr_d,sqr_d,i_right,c_right);
         m_right->squared_distance(V,Ele,p,low_sqr_d,sqr_d,i_right,c_right);
       this->set_min(p,sqr_d_right,i_right,c_right,sqr_d,i,c);
       this->set_min(p,sqr_d_right,i_right,c_right,sqr_d,i,c);
       looked_right = true;
       looked_right = true;
@@ -418,9 +419,9 @@ igl::AABB<DerivedV,DIM>::squared_distance(
       look_right();
       look_right();
     }
     }
     // if haven't looked left and could be less than current min, then look
     // if haven't looked left and could be less than current min, then look
-    Scalar left_up_sqr_d = 
+    Scalar left_up_sqr_d =
       m_left->m_box.squaredExteriorDistance(p.transpose());
       m_left->m_box.squaredExteriorDistance(p.transpose());
-    Scalar right_up_sqr_d = 
+    Scalar right_up_sqr_d =
       m_right->m_box.squaredExteriorDistance(p.transpose());
       m_right->m_box.squaredExteriorDistance(p.transpose());
     if(left_up_sqr_d < right_up_sqr_d)
     if(left_up_sqr_d < right_up_sqr_d)
     {
     {
@@ -449,10 +450,10 @@ igl::AABB<DerivedV,DIM>::squared_distance(
 
 
 template <typename DerivedV, int DIM>
 template <typename DerivedV, int DIM>
 template <typename DerivedEle>
 template <typename DerivedEle>
-IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar 
+IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar
 igl::AABB<DerivedV,DIM>::squared_distance(
 igl::AABB<DerivedV,DIM>::squared_distance(
   const Eigen::MatrixBase<DerivedV> & V,
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & p,
   const RowVectorDIMS & p,
   Scalar up_sqr_d,
   Scalar up_sqr_d,
   int & i,
   int & i,
@@ -464,13 +465,13 @@ igl::AABB<DerivedV,DIM>::squared_distance(
 template <typename DerivedV, int DIM>
 template <typename DerivedV, int DIM>
 template <
 template <
   typename DerivedEle,
   typename DerivedEle,
-  typename DerivedP, 
-  typename DerivedsqrD, 
-  typename DerivedI, 
+  typename DerivedP,
+  typename DerivedsqrD,
+  typename DerivedI,
   typename DerivedC>
   typename DerivedC>
 IGL_INLINE void igl::AABB<DerivedV,DIM>::squared_distance(
 IGL_INLINE void igl::AABB<DerivedV,DIM>::squared_distance(
   const Eigen::MatrixBase<DerivedV> & V,
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const Eigen::MatrixBase<DerivedP> & P,
   const Eigen::MatrixBase<DerivedP> & P,
   Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
   Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
   Eigen::PlainObjectBase<DerivedI> & I,
   Eigen::PlainObjectBase<DerivedI> & I,
@@ -482,35 +483,37 @@ IGL_INLINE void igl::AABB<DerivedV,DIM>::squared_distance(
   C.resizeLike(P);
   C.resizeLike(P);
   // O( #P * log #Ele ), where log #Ele is really the depth of this AABB
   // O( #P * log #Ele ), where log #Ele is really the depth of this AABB
   // hierarchy
   // hierarchy
-  for(int p = 0;p<P.rows();p++)
-  {
-    RowVectorDIMS Pp = P.row(p), c;
-    int Ip;
-    sqrD(p) = squared_distance(V,Ele,Pp,Ip,c);
-    I(p) = Ip;
-    C.row(p).head(DIM) = c;
-  }
+  //for(int p = 0;p<P.rows();p++)
+  igl::parallel_for(P.rows(),[&](int p)
+    {
+      RowVectorDIMS Pp = P.row(p), c;
+      int Ip;
+      sqrD(p) = squared_distance(V,Ele,Pp,Ip,c);
+      I(p) = Ip;
+      C.row(p).head(DIM) = c;
+    },
+    10000);
 }
 }
 
 
 template <typename DerivedV, int DIM>
 template <typename DerivedV, int DIM>
-template < 
+template <
   typename DerivedEle,
   typename DerivedEle,
   typename Derivedother_V,
   typename Derivedother_V,
   typename Derivedother_Ele,
   typename Derivedother_Ele,
-  typename DerivedsqrD, 
-  typename DerivedI, 
+  typename DerivedsqrD,
+  typename DerivedI,
   typename DerivedC>
   typename DerivedC>
 IGL_INLINE void igl::AABB<DerivedV,DIM>::squared_distance(
 IGL_INLINE void igl::AABB<DerivedV,DIM>::squared_distance(
   const Eigen::MatrixBase<DerivedV> & V,
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const AABB<Derivedother_V,DIM> & other,
   const AABB<Derivedother_V,DIM> & other,
   const Eigen::MatrixBase<Derivedother_V> & other_V,
   const Eigen::MatrixBase<Derivedother_V> & other_V,
-  const Eigen::MatrixBase<Derivedother_Ele> & other_Ele, 
+  const Eigen::MatrixBase<Derivedother_Ele> & other_Ele,
   Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
   Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
   Eigen::PlainObjectBase<DerivedI> & I,
   Eigen::PlainObjectBase<DerivedI> & I,
   Eigen::PlainObjectBase<DerivedC> & C) const
   Eigen::PlainObjectBase<DerivedC> & C) const
 {
 {
-  assert(other_Ele.cols() == 1 && 
+  assert(other_Ele.cols() == 1 &&
     "Only implemented for other as list of points");
     "Only implemented for other as list of points");
   assert(other_V.cols() == V.cols() && "other must match this dimension");
   assert(other_V.cols() == V.cols() && "other must match this dimension");
   sqrD.setConstant(other_Ele.rows(),1,std::numeric_limits<double>::infinity());
   sqrD.setConstant(other_Ele.rows(),1,std::numeric_limits<double>::infinity());
@@ -528,20 +531,20 @@ IGL_INLINE void igl::AABB<DerivedV,DIM>::squared_distance(
 }
 }
 
 
 template <typename DerivedV, int DIM>
 template <typename DerivedV, int DIM>
-template < 
+template <
   typename DerivedEle,
   typename DerivedEle,
   typename Derivedother_V,
   typename Derivedother_V,
   typename Derivedother_Ele,
   typename Derivedother_Ele,
-  typename DerivedsqrD, 
-  typename DerivedI, 
+  typename DerivedsqrD,
+  typename DerivedI,
   typename DerivedC>
   typename DerivedC>
-IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar 
+IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar
   igl::AABB<DerivedV,DIM>::squared_distance_helper(
   igl::AABB<DerivedV,DIM>::squared_distance_helper(
   const Eigen::MatrixBase<DerivedV> & V,
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const AABB<Derivedother_V,DIM> * other,
   const AABB<Derivedother_V,DIM> * other,
   const Eigen::MatrixBase<Derivedother_V> & other_V,
   const Eigen::MatrixBase<Derivedother_V> & other_V,
-  const Eigen::MatrixBase<Derivedother_Ele> & other_Ele, 
+  const Eigen::MatrixBase<Derivedother_Ele> & other_Ele,
   const Scalar /*up_sqr_d*/,
   const Scalar /*up_sqr_d*/,
   Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
   Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
   Eigen::PlainObjectBase<DerivedI> & I,
   Eigen::PlainObjectBase<DerivedI> & I,
@@ -584,7 +587,7 @@ IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar
     return sqr_d;
     return sqr_d;
   }
   }
 
 
-  //// Exact minimum squared distance between arbitary primitives inside this and
+  //// Exact minimum squared distance between arbitrary primitives inside this and
   //// othre's bounding boxes
   //// othre's bounding boxes
   //const auto & min_squared_distance = [&](
   //const auto & min_squared_distance = [&](
   //  const AABB<DerivedV,DIM> * A,
   //  const AABB<DerivedV,DIM> * A,
@@ -731,9 +734,9 @@ IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar
       //assert(mc == mm);
       //assert(mc == mm);
       // Only look left/right in this_list if can possible decrease somebody's
       // Only look left/right in this_list if can possible decrease somebody's
       // distance in this_tree.
       // distance in this_tree.
-      const Scalar min_this_other = min_squared_distance(this_tree,other_tree); 
+      const Scalar min_this_other = min_squared_distance(this_tree,other_tree);
       if(
       if(
-          min_this_other < sqr_d && 
+          min_this_other < sqr_d &&
           min_this_other < other_tree->m_low_sqr_d)
           min_this_other < other_tree->m_low_sqr_d)
       {
       {
         //cout<<"before: "<<other_low_sqr_d(child)<<endl;
         //cout<<"before: "<<other_low_sqr_d(child)<<endl;
@@ -764,7 +767,7 @@ template <typename DerivedV, int DIM>
 template <typename DerivedEle>
 template <typename DerivedEle>
 IGL_INLINE void igl::AABB<DerivedV,DIM>::leaf_squared_distance(
 IGL_INLINE void igl::AABB<DerivedV,DIM>::leaf_squared_distance(
   const Eigen::MatrixBase<DerivedV> & V,
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & p,
   const RowVectorDIMS & p,
   const Scalar low_sqr_d,
   const Scalar low_sqr_d,
   Scalar & sqr_d,
   Scalar & sqr_d,
@@ -789,7 +792,7 @@ template <typename DerivedV, int DIM>
 template <typename DerivedEle>
 template <typename DerivedEle>
 IGL_INLINE void igl::AABB<DerivedV,DIM>::leaf_squared_distance(
 IGL_INLINE void igl::AABB<DerivedV,DIM>::leaf_squared_distance(
   const Eigen::MatrixBase<DerivedV> & V,
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & p,
   const RowVectorDIMS & p,
   Scalar & sqr_d,
   Scalar & sqr_d,
   int & i,
   int & i,
@@ -801,7 +804,7 @@ IGL_INLINE void igl::AABB<DerivedV,DIM>::leaf_squared_distance(
 
 
 template <typename DerivedV, int DIM>
 template <typename DerivedV, int DIM>
 IGL_INLINE void igl::AABB<DerivedV,DIM>::set_min(
 IGL_INLINE void igl::AABB<DerivedV,DIM>::set_min(
-  const RowVectorDIMS & 
+  const RowVectorDIMS &
 #ifndef NDEBUG
 #ifndef NDEBUG
   p
   p
 #endif
 #endif
@@ -831,10 +834,10 @@ IGL_INLINE void igl::AABB<DerivedV,DIM>::set_min(
 
 
 template <typename DerivedV, int DIM>
 template <typename DerivedV, int DIM>
 template <typename DerivedEle>
 template <typename DerivedEle>
-IGL_INLINE bool 
+IGL_INLINE bool
 igl::AABB<DerivedV,DIM>::intersect_ray(
 igl::AABB<DerivedV,DIM>::intersect_ray(
   const Eigen::MatrixBase<DerivedV> & V,
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & origin,
   const RowVectorDIMS & origin,
   const RowVectorDIMS & dir,
   const RowVectorDIMS & dir,
   std::vector<igl::Hit> & hits) const
   std::vector<igl::Hit> & hits) const
@@ -874,10 +877,10 @@ igl::AABB<DerivedV,DIM>::intersect_ray(
 
 
 template <typename DerivedV, int DIM>
 template <typename DerivedV, int DIM>
 template <typename DerivedEle>
 template <typename DerivedEle>
-IGL_INLINE bool 
+IGL_INLINE bool
 igl::AABB<DerivedV,DIM>::intersect_ray(
 igl::AABB<DerivedV,DIM>::intersect_ray(
   const Eigen::MatrixBase<DerivedV> & V,
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & origin,
   const RowVectorDIMS & origin,
   const RowVectorDIMS & dir,
   const RowVectorDIMS & dir,
   igl::Hit & hit) const
   igl::Hit & hit) const
@@ -932,10 +935,10 @@ igl::AABB<DerivedV,DIM>::intersect_ray(
 
 
 template <typename DerivedV, int DIM>
 template <typename DerivedV, int DIM>
 template <typename DerivedEle>
 template <typename DerivedEle>
-IGL_INLINE bool 
+IGL_INLINE bool
 igl::AABB<DerivedV,DIM>::intersect_ray(
 igl::AABB<DerivedV,DIM>::intersect_ray(
   const Eigen::MatrixBase<DerivedV> & V,
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & origin,
   const RowVectorDIMS & origin,
   const RowVectorDIMS & dir,
   const RowVectorDIMS & dir,
   const Scalar _min_t,
   const Scalar _min_t,
@@ -1001,7 +1004,7 @@ igl::AABB<DerivedV,DIM>::intersect_ray(
 
 
 // This is a bullshit template because AABB annoyingly needs templates for bad
 // This is a bullshit template because AABB annoyingly needs templates for bad
 // combinations of 3D V with DIM=2 AABB
 // combinations of 3D V with DIM=2 AABB
-// 
+//
 // _Define_ as a no-op rather than monkeying around with the proper code above
 // _Define_ as a no-op rather than monkeying around with the proper code above
 //
 //
 // Meanwhile, GCC seems to have a bug. Let's see if GCC likes using explicit
 // Meanwhile, GCC seems to have a bug. Let's see if GCC likes using explicit

+ 130 - 0
include/igl/AtA_cached.cpp

@@ -0,0 +1,130 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "AtA_cached.h"
+
+#include <iostream>
+#include <vector>
+#include <utility>
+
+template <typename Scalar>
+IGL_INLINE void igl::AtA_cached_precompute(
+    const Eigen::SparseMatrix<Scalar>& A,
+    igl::AtA_cached_data& data,
+    Eigen::SparseMatrix<Scalar>& AtA)
+{
+  // 1 Compute At (this could be avoided, but performance-wise it will not make a difference)
+  std::vector<std::vector<int> > Col_RowPtr;
+  std::vector<std::vector<int> > Col_IndexPtr;
+
+  Col_RowPtr.resize(A.cols());
+  Col_IndexPtr.resize(A.cols());
+
+  for (unsigned k=0; k<A.outerSize(); ++k)
+  {
+    unsigned outer_index = *(A.outerIndexPtr()+k);
+    unsigned next_outer_index = (k+1 == A.outerSize()) ? A.nonZeros() : *(A.outerIndexPtr()+k+1); 
+    
+    for (unsigned l=outer_index; l<next_outer_index; ++l)
+    {
+      int col = k;
+      int row = *(A.innerIndexPtr()+l);
+      int value_index = l;
+      assert(col < A.cols());
+      assert(col >= 0);
+      assert(row < A.rows());
+      assert(row >= 0);
+      assert(value_index >= 0);
+      assert(value_index < A.nonZeros());
+
+      Col_RowPtr[col].push_back(row);
+      Col_IndexPtr[col].push_back(value_index);
+    }
+  }
+
+  Eigen::SparseMatrix<Scalar> At = A.transpose();
+  At.makeCompressed();
+  AtA = At * A;
+  AtA.makeCompressed();
+
+  assert(AtA.isCompressed());
+
+  // If weights are not provided, use 1
+  if (data.W.size() == 0)
+    data.W = Eigen::VectorXd::Ones(A.rows());
+  assert(data.W.size() == A.rows());
+
+  data.I_outer.reserve(AtA.outerSize());
+  data.I_row.reserve(2*AtA.nonZeros());
+  data.I_col.reserve(2*AtA.nonZeros());
+  data.I_w.reserve(2*AtA.nonZeros());
+
+  // 2 Construct the rules
+  for (unsigned k=0; k<AtA.outerSize(); ++k)
+  {
+    unsigned outer_index = *(AtA.outerIndexPtr()+k);
+    unsigned next_outer_index = (k+1 == AtA.outerSize()) ? AtA.nonZeros() : *(AtA.outerIndexPtr()+k+1); 
+    
+    for (unsigned l=outer_index; l<next_outer_index; ++l)
+    {
+      int col = k;
+      int row = *(AtA.innerIndexPtr()+l);
+      int value_index = l;
+      assert(col < AtA.cols());
+      assert(col >= 0);
+      assert(row < AtA.rows());
+      assert(row >= 0);
+      assert(value_index >= 0);
+      assert(value_index < AtA.nonZeros());
+
+      data.I_outer.push_back(data.I_row.size());
+
+      // Find correspondences
+      unsigned i=0;
+      unsigned j=0;
+      while (i<Col_RowPtr[row].size() && j<Col_RowPtr[col].size())
+      {
+          if (Col_RowPtr[row][i] == Col_RowPtr[col][j])
+          {
+            data.I_row.push_back(Col_IndexPtr[row][i]);
+            data.I_col.push_back(Col_IndexPtr[col][j]);
+            data.I_w.push_back(Col_RowPtr[col][j]);
+            ++i;
+            ++j;
+          } else 
+          if (Col_RowPtr[row][i] > Col_RowPtr[col][j])
+            ++j;
+          else
+            ++i;
+
+      }
+    }
+  }
+  data.I_outer.push_back(data.I_row.size()); // makes it more efficient to iterate later on
+
+  igl::AtA_cached(A,data,AtA);
+}
+
+template <typename Scalar>
+IGL_INLINE void igl::AtA_cached(
+    const Eigen::SparseMatrix<Scalar>& A,
+    const igl::AtA_cached_data& data,
+    Eigen::SparseMatrix<Scalar>& AtA)
+{
+  for (unsigned i=0; i<data.I_outer.size()-1; ++i)
+  {
+    *(AtA.valuePtr() + i) = 0;
+    for (unsigned j=data.I_outer[i]; j<data.I_outer[i+1]; ++j)
+      *(AtA.valuePtr() + i) += *(A.valuePtr() + data.I_row[j]) * data.W[data.I_w[j]] * *(A.valuePtr() + data.I_col[j]);
+  }
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::AtA_cached<double>(Eigen::SparseMatrix<double, 0, int> const&, igl::AtA_cached_data const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::AtA_cached_precompute<double>(Eigen::SparseMatrix<double, 0, int> const&, igl::AtA_cached_data&, Eigen::SparseMatrix<double, 0, int>&);
+#endif

+ 70 - 0
include/igl/AtA_cached.h

@@ -0,0 +1,70 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2017 Daniele Panozzo <daniele.panozzo@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ATA_CACHED_H
+#define IGL_ATA_CACHED_H
+#include "igl_inline.h"
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+namespace igl
+{  
+  struct AtA_cached_data
+  {
+    // Weights
+    Eigen::VectorXd W;
+
+    // Flatten composition rules
+    std::vector<int> I_row;
+    std::vector<int> I_col;
+    std::vector<int> I_w;
+
+    // For each entry of AtA, points to the beginning
+    // of the composition rules
+    std::vector<int> I_outer;
+  };
+
+  // Computes At * W * A, where A is sparse and W is diagonal. Divides the 
+  // construction in two phases, one
+  // for fixing the sparsity pattern, and one to populate it with values. Compared to
+  // evaluating it directly, this version is slower for the first time (since it requires a
+  // precomputation), but faster to the subsequent evaluations.
+  //
+  // Input:
+  //   A m x n sparse matrix
+  //   data stores the precomputed sparsity pattern, data.W contains the optional diagonal weights (stored as a dense vector). If W is not provided, it is replaced by the identity.
+  // Outputs:
+  //   AtA  m by m matrix computed as AtA * W * A
+  //
+  // Example:
+  // AtA_data = igl::AtA_cached_data();
+  // AtA_data.W = W;
+  // if (s.AtA.rows() == 0)
+  //   igl::AtA_cached_precompute(s.A,s.AtA_data,s.AtA);
+  // else
+  //   igl::AtA_cached(s.A,s.AtA_data,s.AtA);
+  template <typename Scalar>
+  IGL_INLINE void AtA_cached_precompute(
+    const Eigen::SparseMatrix<Scalar>& A,
+    AtA_cached_data& data,
+    Eigen::SparseMatrix<Scalar>& AtA
+    );
+
+  template <typename Scalar>
+  IGL_INLINE void AtA_cached(
+    const Eigen::SparseMatrix<Scalar>& A,
+    const AtA_cached_data& data,
+    Eigen::SparseMatrix<Scalar>& AtA
+    );
+  
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "AtA_cached.cpp"
+#endif
+
+#endif

+ 40 - 0
include/igl/Attribute.h

@@ -0,0 +1,40 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Jérémie Dumas <jeremie.dumas@ens-lyon.org>
+//
+// 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_ATTRIBUTE_H
+#define IGL_ATTRIBUTE_H
+
+#include <typeindex>
+
+namespace igl
+{
+
+struct AttributeBase
+{
+private:
+	std::type_index derived_type_;
+public:
+	AttributeBase(std::type_index t) : derived_type_(t) { }
+	virtual ~AttributeBase() = default;
+	std::type_index type() const { return derived_type_; }
+};
+
+// -----------------------------------------------------------------------------
+
+template<typename T>
+struct Attribute : public AttributeBase
+{
+	// Constructor
+	Attribute() : AttributeBase(typeid(T)) { }
+
+	// Data
+	T content_;
+};
+
+} // namespace igl
+
+#endif // IGL_ATTRIBUTE_H

+ 1 - 1
include/igl/Camera.h

@@ -23,7 +23,7 @@ namespace igl
 
 
   // A simple camera class. The camera stores projection parameters (field of
   // A simple camera class. The camera stores projection parameters (field of
   // view angle, aspect ratio, near and far clips) as well as a rigid
   // view angle, aspect ratio, near and far clips) as well as a rigid
-  // tranformation *of the camera as if it were also a scene object*. Thus, the
+  // transformation *of the camera as if it were also a scene object*. Thus, the
   // **inverse** of this rigid transformation is the modelview transformation.
   // **inverse** of this rigid transformation is the modelview transformation.
   class Camera
   class Camera
   {
   {

+ 1 - 1
include/igl/REDRUM.h

@@ -13,7 +13,7 @@
 // A: I guess the right way is to not use a macro but a proper function with
 // A: I guess the right way is to not use a macro but a proper function with
 // streams as input and output.
 // streams as input and output.
 
 
-// ANSI color codes for formating iostream style output
+// ANSI color codes for formatting iostream style output
 
 
 #ifdef IGL_REDRUM_NOOP
 #ifdef IGL_REDRUM_NOOP
 
 

+ 1 - 1
include/igl/SortableRow.h

@@ -15,7 +15,7 @@
 namespace igl
 namespace igl
 {
 {
   // Templates:
   // Templates:
-  //   T  should be a matrix that implments .size(), and operator(int i)
+  //   T  should be a matrix that implements .size(), and operator(int i)
   template <typename T>
   template <typename T>
   class SortableRow
   class SortableRow
   {
   {

+ 3 - 3
include/igl/WindingNumberTree.h

@@ -52,7 +52,7 @@ namespace igl
       MatrixXS SV;
       MatrixXS SV;
       // Facets in this bounding volume
       // Facets in this bounding volume
       MatrixXF F;
       MatrixXF F;
-      // Tesselated boundary curve
+      // Tessellated boundary curve
       MatrixXF cap;
       MatrixXF cap;
       // Upper Bound on radius of enclosing ball
       // Upper Bound on radius of enclosing ball
       typename DerivedV::Scalar radius;
       typename DerivedV::Scalar radius;
@@ -97,7 +97,7 @@ namespace igl
       // Same as above, but always computes winding number using exact method
       // Same as above, but always computes winding number using exact method
       // (sum over every facet)
       // (sum over every facet)
       inline typename DerivedV::Scalar winding_number_all(const Point & p) const;
       inline typename DerivedV::Scalar winding_number_all(const Point & p) const;
-      // Same as above, but always computes using sum over tesslated boundary
+      // Same as above, but always computes using sum over tessllated boundary
       inline typename DerivedV::Scalar winding_number_boundary(const Point & p) const;
       inline typename DerivedV::Scalar winding_number_boundary(const Point & p) const;
       //// Same as winding_number above, but if max_simple_abs_winding_number is
       //// Same as winding_number above, but if max_simple_abs_winding_number is
       //// less than some threshold min_max_w just return 0 (colloquially the "fast
       //// less than some threshold min_max_w just return 0 (colloquially the "fast
@@ -493,7 +493,7 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
   return 0;
   return 0;
 }
 }
 
 
-// Explicit instanciation of static variable
+// Explicit instantiation of static variable
 template <
 template <
   typename Point,
   typename Point,
   typename DerivedV, 
   typename DerivedV, 

+ 4 - 3
include/igl/adjacency_matrix.cpp

@@ -23,15 +23,16 @@ IGL_INLINE void igl::adjacency_matrix(
   typedef Triplet<T> IJV;
   typedef Triplet<T> IJV;
   vector<IJV > ijv;
   vector<IJV > ijv;
   ijv.reserve(F.size()*2);
   ijv.reserve(F.size()*2);
-  // Loop over faces
+  // Loop over **simplex** (i.e., **not quad**)
   for(int i = 0;i<F.rows();i++)
   for(int i = 0;i<F.rows();i++)
   {
   {
-    // Loop over this face
+    // Loop over this **simplex**
     for(int j = 0;j<F.cols();j++)
     for(int j = 0;j<F.cols();j++)
+    for(int k = j+1;k<F.cols();k++)
     {
     {
       // Get indices of edge: s --> d
       // Get indices of edge: s --> d
       Index s = F(i,j);
       Index s = F(i,j);
-      Index d = F(i,(j+1)%F.cols());
+      Index d = F(i,k);
       ijv.push_back(IJV(s,d,1));
       ijv.push_back(IJV(s,d,1));
       ijv.push_back(IJV(d,s,1));
       ijv.push_back(IJV(d,s,1));
     }
     }

+ 3 - 3
include/igl/arap_dof.cpp

@@ -34,7 +34,7 @@
 // defined if no early exit is supported, i.e., always take a fixed number of iterations
 // defined if no early exit is supported, i.e., always take a fixed number of iterations
 #define IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
 #define IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
 
 
-// A carefull derivation of this implementation is given in the corresponding
+// A careful derivation of this implementation is given in the corresponding
 // matlab function arap_dof.m
 // matlab function arap_dof.m
 template <typename LbsMatrixType, typename SSCALAR>
 template <typename LbsMatrixType, typename SSCALAR>
 IGL_INLINE bool igl::arap_dof_precomputation(
 IGL_INLINE bool igl::arap_dof_precomputation(
@@ -339,7 +339,7 @@ namespace igl
   }
   }
   
   
   // converts CSM_M_SSCALAR[0], CSM_M_SSCALAR[1], CSM_M_SSCALAR[2] into one
   // converts CSM_M_SSCALAR[0], CSM_M_SSCALAR[1], CSM_M_SSCALAR[2] into one
-  // "condensed" matrix CSM while checking we're not loosing any information by
+  // "condensed" matrix CSM while checking we're not losing any information by
   // this process; specifically, returns maximal difference from scaled 3x3
   // this process; specifically, returns maximal difference from scaled 3x3
   // identity blocks, which should be pretty small number
   // identity blocks, which should be pretty small number
   template <typename MatrixXS>
   template <typename MatrixXS>
@@ -449,7 +449,7 @@ namespace igl
   }
   }
   
   
   // converts "Solve1" the "rotations" part of FullSolve matrix (the first part)
   // converts "Solve1" the "rotations" part of FullSolve matrix (the first part)
-  // into one "condensed" matrix CSolve1 while checking we're not loosing any
+  // into one "condensed" matrix CSolve1 while checking we're not losing any
   // information by this process; specifically, returns maximal difference from
   // information by this process; specifically, returns maximal difference from
   // scaled 3x3 identity blocks, which should be pretty small number
   // scaled 3x3 identity blocks, which should be pretty small number
   template <typename MatrixXS>
   template <typename MatrixXS>

+ 1 - 1
include/igl/arap_dof.h

@@ -127,7 +127,7 @@ namespace igl
   //   L0  #handles * dim * dim+1 list of initial guess transformation entries,
   //   L0  #handles * dim * dim+1 list of initial guess transformation entries,
   //     also holds fixed transformation entries for fixed handles
   //     also holds fixed transformation entries for fixed handles
   //   max_iters  maximum number of iterations
   //   max_iters  maximum number of iterations
-  //   tol  stopping critera parameter. If variables (linear transformation
+  //   tol  stopping criteria parameter. If variables (linear transformation
   //     matrix entries) change by less than 'tol' the optimization terminates,
   //     matrix entries) change by less than 'tol' the optimization terminates,
   //       0.75 (weak tolerance)
   //       0.75 (weak tolerance)
   //       0.0 (extreme tolerance)
   //       0.0 (extreme tolerance)

+ 1 - 1
include/igl/bbw.h

@@ -49,7 +49,7 @@ namespace igl
   //   Ele  #Elements by simplex-size list of element indices
   //   Ele  #Elements by simplex-size list of element indices
   //   b  #b boundary indices into V
   //   b  #b boundary indices into V
   //   bc #b by #W list of boundary values
   //   bc #b by #W list of boundary values
-  //   data  object containing options, intial guess --> solution and results
+  //   data  object containing options, initial guess --> solution and results
   // Outputs:
   // Outputs:
   //   W  #V by #W list of *unnormalized* weights to normalize use
   //   W  #V by #W list of *unnormalized* weights to normalize use
   //    igl::normalize_row_sums(W,W);
   //    igl::normalize_row_sums(W,W);

+ 4 - 4
include/igl/bijective_composite_harmonic_mapping.h

@@ -29,7 +29,7 @@ namespace igl
   //   bc  #b by 2 list of boundary conditions corresponding to b
   //   bc  #b by 2 list of boundary conditions corresponding to b
   // Outputs:
   // Outputs:
   //   U  #V by 2 list of output mesh vertex locations
   //   U  #V by 2 list of output mesh vertex locations
-  // Returns true if and only if U contains a successfull bijectie mapping
+  // Returns true if and only if U contains a successful bijectie mapping
   //
   //
   // 
   // 
   template <
   template <
@@ -46,12 +46,12 @@ namespace igl
     Eigen::PlainObjectBase<DerivedU> & U);
     Eigen::PlainObjectBase<DerivedU> & U);
   //
   //
   // Inputs:
   // Inputs:
-  //   min_steps  mininum number of steps to take from V(b,:) to bc
-  //   max_steps  mininum number of steps to take from V(b,:) to bc (if
+  //   min_steps  minimum number of steps to take from V(b,:) to bc
+  //   max_steps  minimum number of steps to take from V(b,:) to bc (if
   //     max_steps == min_steps then no further number of steps will be tried)
   //     max_steps == min_steps then no further number of steps will be tried)
   //   num_inner_iters  number of iterations of harmonic solves to run after
   //   num_inner_iters  number of iterations of harmonic solves to run after
   //     for each morph step (to try to push flips back in)
   //     for each morph step (to try to push flips back in)
-  //   test_for_flips  wether to check if flips occured (and trigger more
+  //   test_for_flips  whether to check if flips occurred (and trigger more
   //     steps). if test_for_flips = false then this function always returns
   //     steps). if test_for_flips = false then this function always returns
   //     true
   //     true
   // 
   // 

+ 1 - 1
include/igl/boundary_conditions.cpp

@@ -146,7 +146,7 @@ IGL_INLINE bool igl::boundary_conditions(
     bc(bim[bci[i]],bcj[i]) = bcv[i];
     bc(bim[bci[i]],bcj[i]) = bcv[i];
   }
   }
 
 
-  // Normalize accross rows so that conditions sum to one
+  // Normalize across rows so that conditions sum to one
   for(i = 0;i<bc.rows();i++)
   for(i = 0;i<bc.rows();i++)
   {
   {
     double sum = bc.row(i).sum();
     double sum = bc.row(i).sum();

+ 1 - 1
include/igl/cat.h

@@ -25,7 +25,7 @@ namespace igl
   // Template:
   // Template:
   //   Scalar  scalar data type for sparse matrices like double or int
   //   Scalar  scalar data type for sparse matrices like double or int
   //   Mat  matrix type for all matrices (e.g. MatrixXd, SparseMatrix)
   //   Mat  matrix type for all matrices (e.g. MatrixXd, SparseMatrix)
-  //   MatC  matrix type for ouput matrix (e.g. MatrixXd) needs to support
+  //   MatC  matrix type for output matrix (e.g. MatrixXd) needs to support
   //     resize
   //     resize
   // Inputs:
   // Inputs:
   //   A  first input matrix
   //   A  first input matrix

+ 3 - 1
include/igl/colormap.cpp

@@ -1378,7 +1378,7 @@ IGL_INLINE void igl::colormap(
   Eigen::PlainObjectBase<DerivedC> & C)
   Eigen::PlainObjectBase<DerivedC> & C)
 {
 {
   const double min_z = normalize ? Z.minCoeff() : 0;
   const double min_z = normalize ? Z.minCoeff() : 0;
-  const double max_z = normalize ? Z.maxCoeff() : -1;
+  const double max_z = normalize ? Z.maxCoeff() : 1;
   return colormap(cm, Z, min_z, max_z, C);
   return colormap(cm, Z, min_z, max_z, C);
 }
 }
 
 
@@ -1429,4 +1429,6 @@ template void igl::colormap<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Mat
 template void igl::colormap<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::colormap<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 // generated by autoexplicit.sh
 // generated by autoexplicit.sh
 template void igl::colormap<Eigen::Array<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Array<int, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::colormap<Eigen::Array<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Array<int, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+
+template void igl::colormap<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
 #endif
 #endif

+ 32 - 2
include/igl/combine.cpp

@@ -7,19 +7,26 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "combine.h"
 #include "combine.h"
 #include <cassert>
 #include <cassert>
+
 template <
 template <
   typename DerivedVV, 
   typename DerivedVV, 
   typename DerivedFF, 
   typename DerivedFF, 
   typename DerivedV, 
   typename DerivedV, 
-  typename DerivedF>
+  typename DerivedF,
+  typename DerivedVsizes,
+  typename DerivedFsizes>
 IGL_INLINE void igl::combine(
 IGL_INLINE void igl::combine(
   const std::vector<DerivedVV> & VV,
   const std::vector<DerivedVV> & VV,
   const std::vector<DerivedFF> & FF,
   const std::vector<DerivedFF> & FF,
   Eigen::PlainObjectBase<DerivedV> & V,
   Eigen::PlainObjectBase<DerivedV> & V,
-  Eigen::PlainObjectBase<DerivedF> & F)
+  Eigen::PlainObjectBase<DerivedF> & F,
+  Eigen::PlainObjectBase<DerivedVsizes> & Vsizes,
+  Eigen::PlainObjectBase<DerivedFsizes> & Fsizes)
 {
 {
   assert(VV.size() == FF.size() && 
   assert(VV.size() == FF.size() && 
     "Lists of verex lists and face lists should be same size");
     "Lists of verex lists and face lists should be same size");
+  Vsizes.resize(VV.size());
+  Fsizes.resize(FF.size());
   // Dimension of vertex positions
   // Dimension of vertex positions
   const int dim = VV.size() > 0 ? VV[0].cols() : 0;
   const int dim = VV.size() > 0 ? VV[0].cols() : 0;
   // Simplex/element size
   // Simplex/element size
@@ -30,8 +37,10 @@ IGL_INLINE void igl::combine(
   {
   {
     const auto & Vi = VV[i];
     const auto & Vi = VV[i];
     const auto & Fi = FF[i];
     const auto & Fi = FF[i];
+    Vsizes(i) = Vi.rows();
     n+=Vi.rows();
     n+=Vi.rows();
     assert(dim == Vi.cols() && "All vertex lists should have same #columns");
     assert(dim == Vi.cols() && "All vertex lists should have same #columns");
+    Fsizes(i) = Fi.rows();
     m+=Fi.rows();
     m+=Fi.rows();
     assert(ss == Fi.cols() && "All face lists should have same #columns");
     assert(ss == Fi.cols() && "All face lists should have same #columns");
   }
   }
@@ -55,3 +64,24 @@ IGL_INLINE void igl::combine(
     assert(kf == F.rows());
     assert(kf == F.rows());
   }
   }
 }
 }
+
+template <
+  typename DerivedVV, 
+  typename DerivedFF, 
+  typename DerivedV, 
+  typename DerivedF>
+IGL_INLINE void igl::combine(
+  const std::vector<DerivedVV> & VV,
+  const std::vector<DerivedFF> & FF,
+  Eigen::PlainObjectBase<DerivedV> & V,
+  Eigen::PlainObjectBase<DerivedF> & F)
+{
+  Eigen::VectorXi Vsizes,Fsizes;
+  return igl::combine(VV,FF,V,F,Vsizes,Fsizes);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::combine<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1>, Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >&);
+template void igl::combine<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::vector<Eigen::Matrix<double, -1, 3, 1, -1, 3>, std::allocator<Eigen::Matrix<double, -1, 3, 1, -1, 3> > > const&, std::vector<Eigen::Matrix<int, -1, 3, 1, -1, 3>, std::allocator<Eigen::Matrix<int, -1, 3, 1, -1, 3> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+#endif

+ 19 - 2
include/igl/combine.h

@@ -14,8 +14,8 @@
 
 
 namespace igl
 namespace igl
 {
 {
-  // Combine k meshes into a single >=k connected component mesh with a single
-  // vertex list and face list. Similar to Maya's Combine operation.
+  // Concatenate k meshes into a single >=k connected component mesh with a
+  // single vertex list and face list. Similar to Maya's Combine operation. 
   //
   //
   // Inputs:
   // Inputs:
   //   VV  k-long list of lists of mesh vertex positions
   //   VV  k-long list of lists of mesh vertex positions
@@ -26,10 +26,27 @@ namespace igl
   //     vertex positions
   //     vertex positions
   //   F   FF[0].rows()+...+FF[k-1].rows() by FF[0].cols() list of mesh faces
   //   F   FF[0].rows()+...+FF[k-1].rows() by FF[0].cols() list of mesh faces
   //     indices into V
   //     indices into V
+  //   Vsizes  k list so that Vsizes(i) is the #vertices in the ith input
+  //   Fsizes  k list so that Fsizes(i) is the #faces in the ith input
   // Example:
   // Example:
   //   // Suppose you have mesh A (VA,FA) and mesh B (VB,FB)
   //   // Suppose you have mesh A (VA,FA) and mesh B (VB,FB)
   //   igl::combine<Eigen::MatrixXd,Eigen::MatrixXi>({VA,VB},{FA,FB},V,F);
   //   igl::combine<Eigen::MatrixXd,Eigen::MatrixXi>({VA,VB},{FA,FB},V,F);
   //
   //
+  //
+  template <
+    typename DerivedVV, 
+    typename DerivedFF, 
+    typename DerivedV, 
+    typename DerivedF,
+    typename DerivedVsizes,
+    typename DerivedFsizes>
+  IGL_INLINE void combine(
+    const std::vector<DerivedVV> & VV,
+    const std::vector<DerivedFF> & FF,
+    Eigen::PlainObjectBase<DerivedV> & V,
+    Eigen::PlainObjectBase<DerivedF> & F,
+    Eigen::PlainObjectBase<DerivedVsizes> & Vsizes,
+    Eigen::PlainObjectBase<DerivedFsizes> & Fsizes);
   template <
   template <
     typename DerivedVV, 
     typename DerivedVV, 
     typename DerivedFF, 
     typename DerivedFF, 

+ 1 - 1
include/igl/connect_boundary_to_infinity.h

@@ -11,7 +11,7 @@
 #include <Eigen/Core>
 #include <Eigen/Core>
 namespace igl
 namespace igl
 {
 {
-  // Connect all boundary edges to a ficticious point at infinity.
+  // Connect all boundary edges to a fictitious point at infinity.
   //
   //
   // Inputs:
   // Inputs:
   //   F  #F by 3 list of face indices into some V
   //   F  #F by 3 list of face indices into some V

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

@@ -236,7 +236,7 @@ namespace igl
 // a 2-manifold.
 // a 2-manifold.
 // A: But! It seems we could use CGAL::Triangulation_3. Though it won't be easy
 // A: But! It seems we could use CGAL::Triangulation_3. Though it won't be easy
 // to take advantage of functions like insert_in_facet because we want to
 // to take advantage of functions like insert_in_facet because we want to
-// constrain segments. Hmmm. Actualy Triangulation_3 doesn't look right...
+// constrain segments. Hmmm. Actually Triangulation_3 doesn't look right...
 
 
 // CGAL's box_self_intersection_d uses C-style function callbacks without
 // CGAL's box_self_intersection_d uses C-style function callbacks without
 // userdata. This is a leapfrog method for calling a member function. It should
 // userdata. This is a leapfrog method for calling a member function. It should

+ 41 - 4
include/igl/copyleft/cgal/assign_scalar.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
 // Copyright (C) 2015 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "assign_scalar.h"
 #include "assign_scalar.h"
 
 
@@ -97,3 +97,40 @@ IGL_INLINE void igl::copyleft::cgal::assign_scalar(
       d = next;
       d = next;
   } while (d < float(interval.second));
   } while (d < float(interval.second));
 }
 }
+
+#ifndef WIN32
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+  const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
+  CGAL::Simple_cartesian<mpq_class>::FT & d)
+{
+  d = cgal;
+}
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+  const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
+  double & d)
+{
+  const auto interval = CGAL::to_interval(cgal);
+  d = interval.first;
+  do {
+      const double next = nextafter(d, interval.second);
+      if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
+      d = next;
+  } while (d < interval.second);
+}
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+  const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
+  float& d)
+{
+  const auto interval = CGAL::to_interval(cgal);
+  d = interval.first;
+  do {
+      const float next = nextafter(d, float(interval.second));
+      if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
+      d = next;
+  } while (d < float(interval.second));
+}
+
+#endif // WIN32

+ 22 - 4
include/igl/copyleft/cgal/assign_scalar.h

@@ -1,15 +1,19 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
 // Copyright (C) 2015 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
 #ifndef IGL_COPYLEFT_CGAL_ASSIGN_SCALAR_H
 #ifndef IGL_COPYLEFT_CGAL_ASSIGN_SCALAR_H
 #define IGL_COPYLEFT_CGAL_ASSIGN_SCALAR_H
 #define IGL_COPYLEFT_CGAL_ASSIGN_SCALAR_H
 #include "../../igl_inline.h"
 #include "../../igl_inline.h"
 #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
 #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
 #include <CGAL/Exact_predicates_exact_constructions_kernel_with_sqrt.h>
 #include <CGAL/Exact_predicates_exact_constructions_kernel_with_sqrt.h>
+#ifndef WIN32
+#include <CGAL/gmpxx.h>
+#endif
+
 namespace igl
 namespace igl
 {
 {
   namespace copyleft
   namespace copyleft
@@ -38,6 +42,7 @@ namespace igl
       IGL_INLINE void assign_scalar(
       IGL_INLINE void assign_scalar(
         const float& c,
         const float& c,
         double& d);
         double& d);
+
       IGL_INLINE void assign_scalar(
       IGL_INLINE void assign_scalar(
         const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
         const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
         CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & d);
         CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & d);
@@ -47,6 +52,19 @@ namespace igl
       IGL_INLINE void assign_scalar(
       IGL_INLINE void assign_scalar(
         const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
         const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
         float& d);
         float& d);
+
+#ifndef WIN32
+      IGL_INLINE void assign_scalar(
+        const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
+        CGAL::Simple_cartesian<mpq_class>::FT & d);
+      IGL_INLINE void assign_scalar(
+        const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
+        double & d);
+      IGL_INLINE void assign_scalar(
+        const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
+        float& d);
+#endif // WIN32
+
     }
     }
   }
   }
 }
 }

+ 1 - 1
include/igl/copyleft/cgal/cell_adjacency.h

@@ -27,7 +27,7 @@ namespace igl
       //   num_cells        number of cells.
       //   num_cells        number of cells.
       //
       //
       // Outputs:
       // Outputs:
-      //   adjacency_list  #C array of list of adjcent cell informations.  If
+      //   adjacency_list  #C array of list of adjcent cell information.  If
       //                   cell i and cell j are adjacent via patch x, where i
       //                   cell i and cell j are adjacent via patch x, where i
       //                   is on the positive side of x, and j is on the
       //                   is on the positive side of x, and j is on the
       //                   negative side.  Then,
       //                   negative side.  Then,

+ 1 - 1
include/igl/copyleft/cgal/closest_facet.cpp

@@ -124,7 +124,7 @@ IGL_INLINE void igl::copyleft::cgal::closest_facet(
       case CGAL::COPLANAR:
       case CGAL::COPLANAR:
         // Warning:
         // Warning:
         // This can only happen if fid contains a boundary edge.
         // This can only happen if fid contains a boundary edge.
-        // Catergorized this ambiguous case as negative side.
+        // Categorized this ambiguous case as negative side.
         return false;
         return false;
       default:
       default:
         throw std::runtime_error("Unknown CGAL state.");
         throw std::runtime_error("Unknown CGAL state.");

+ 0 - 7
include/igl/copyleft/cgal/intersect_other.h

@@ -12,13 +12,6 @@
 
 
 #include <Eigen/Dense>
 #include <Eigen/Dense>
 
 
-#ifdef MEX
-#  include <mex.h>
-#  include <cassert>
-#  undef assert
-#  define assert( isOK ) ( (isOK) ? (void)0 : (void) mexErrMsgTxt(C_STR(__FILE__<<":"<<__LINE__<<": failed assertion `"<<#isOK<<"'"<<std::endl) ) )
-#endif
-
 namespace igl
 namespace igl
 {
 {
   namespace copyleft
   namespace copyleft

+ 6 - 27
include/igl/copyleft/cgal/mesh_boolean.cpp

@@ -15,6 +15,7 @@
 #include "relabel_small_immersed_cells.h"
 #include "relabel_small_immersed_cells.h"
 #include "remesh_self_intersections.h"
 #include "remesh_self_intersections.h"
 #include "string_to_mesh_boolean_type.h"
 #include "string_to_mesh_boolean_type.h"
+#include "../../combine.h"
 #include "../../cumsum.h"
 #include "../../cumsum.h"
 #include "../../extract_manifold_patches.h"
 #include "../../extract_manifold_patches.h"
 #include "../../get_seconds.h"
 #include "../../get_seconds.h"
@@ -137,33 +138,11 @@ IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
     Eigen::PlainObjectBase<DerivedFC > & FC,
     Eigen::PlainObjectBase<DerivedFC > & FC,
     Eigen::PlainObjectBase<DerivedJ > & J)
     Eigen::PlainObjectBase<DerivedJ > & J)
 {
 {
-  assert(Flist.size() == Vlist.size() && "#Vlist and #Flist should match");
-  const size_t num_inputs = Vlist.size();
-  // Gather sizes
-  Eigen::Matrix<size_t,Eigen::Dynamic,1> sizes(num_inputs);
-  int numf = 0;
-  int numv = 0;
-  for(int i = 0;i<num_inputs;i++)
-  {
-    sizes(i) = Flist[i].rows();
-    numf += Flist[i].rows();
-    numv += Vlist[i].rows();
-  }
-  // Combined mesh
-  DerivedV VV(numv,3);
-  DerivedF FF(numf,3);
-  {
-    int fk = 0;
-    int vk = 0;
-    for(int i = 0;i<num_inputs;i++)
-    {
-      FF.block(fk,0,Flist[i].rows(),3) = Flist[i].array() + vk;
-      fk += Flist[i].rows();
-      VV.block(vk,0,Vlist[i].rows(),3) = Vlist[i];
-      vk += Vlist[i].rows();
-    }
-  }
-  return mesh_boolean(VV,FF,sizes,wind_num_op,keep,VC,FC,J);
+  DerivedV VV;
+  DerivedF FF;
+  Eigen::Matrix<size_t,Eigen::Dynamic,1> Vsizes,Fsizes;
+  igl::combine(Vlist,Flist,VV,FF,Vsizes,Fsizes);
+  return mesh_boolean(VV,FF,Fsizes,wind_num_op,keep,VC,FC,J);
 }
 }
 
 
 template <
 template <

+ 2 - 1
include/igl/copyleft/cgal/minkowski_sum.cpp

@@ -106,6 +106,7 @@ IGL_INLINE void igl::copyleft::cgal::minkowski_sum(
     vJ[ee].resize(vG[ee].rows(),2);
     vJ[ee].resize(vG[ee].rows(),2);
     vJ[ee].col(0) = eJ.array() + (FA.rows()+1);
     vJ[ee].col(0) = eJ.array() + (FA.rows()+1);
     vJ[ee].col(1).setConstant(ee);
     vJ[ee].col(1).setConstant(ee);
+    offsets[ee+1] = offsets[ee] + vW[ee].rows();
   }
   }
   // Combine meshes
   // Combine meshes
   int n=0,m=0;
   int n=0,m=0;
@@ -141,7 +142,7 @@ IGL_INLINE void igl::copyleft::cgal::minkowski_sum(
       W,
       W,
       G,
       G,
       SJ);
       SJ);
-    J = slice(DerivedJ(J),SJ,1);
+    slice(DerivedJ(J),SJ,1,J);
   }
   }
 }
 }
 
 

+ 2 - 2
include/igl/copyleft/cgal/order_facets_around_edge.h

@@ -31,7 +31,7 @@ namespace igl
       //   V  #V by 3 list of vertices.
       //   V  #V by 3 list of vertices.
       //   F  #F by 3 list of faces
       //   F  #F by 3 list of faces
       //   s  Index of source vertex.
       //   s  Index of source vertex.
-      //   d  Index of desination vertex.
+      //   d  Index of destination vertex.
       //   adj_faces  List of adjacent face signed indices.
       //   adj_faces  List of adjacent face signed indices.
       // Output:
       // Output:
       //   order  List of face indices that orders adjacent faces around edge
       //   order  List of face indices that orders adjacent faces around edge
@@ -50,7 +50,7 @@ namespace igl
           Eigen::PlainObjectBase<DerivedI>& order,
           Eigen::PlainObjectBase<DerivedI>& order,
           bool debug=false);
           bool debug=false);
 
 
-      // This funciton is a wrapper around the one above.  Since the ordering
+      // This function is a wrapper around the one above.  Since the ordering
       // is circular, the pivot point is used to define a starting point.  So
       // is circular, the pivot point is used to define a starting point.  So
       // order[0] is the index into adj_face that is immediately after the
       // order[0] is the index into adj_face that is immediately after the
       // pivot face (s, d, pivot point) in clockwise order.
       // pivot face (s, d, pivot point) in clockwise order.

+ 1 - 1
include/igl/copyleft/cgal/outer_facet.h

@@ -26,7 +26,7 @@ namespace igl
         // See cgal::remesh_self_intersections.h for how to obtain such input.
         // See cgal::remesh_self_intersections.h for how to obtain such input.
         //
         //
         // This function differ from igl::outer_facet() in the fact this
         // This function differ from igl::outer_facet() in the fact this
-        // funciton is more robust because it does not rely on facet normals.
+        // function is more robust because it does not rely on facet normals.
         //
         //
         // Inputs:
         // Inputs:
         //   V  #V by 3 list of vertex positions
         //   V  #V by 3 list of vertex positions

+ 1 - 1
include/igl/copyleft/cgal/point_mesh_squared_distance.cpp

@@ -81,7 +81,7 @@ IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance_precompute(
   // accelerate_distance_queries doesn't seem actually to do _all_ of the
   // accelerate_distance_queries doesn't seem actually to do _all_ of the
   // precomputation. the tree (despite being const) will still do more
   // precomputation. the tree (despite being const) will still do more
   // precomputation and reorganizing on the first call of `closest_point` or
   // precomputation and reorganizing on the first call of `closest_point` or
-  // `closest_point_and_primitive`. Therefor, call it once here.
+  // `closest_point_and_primitive`. Therefore, call it once here.
   tree.closest_point_and_primitive(Point_3(0,0,0));
   tree.closest_point_and_primitive(Point_3(0,0,0));
 }
 }
 
 

+ 1 - 1
include/igl/copyleft/cgal/points_inside_component.cpp

@@ -321,7 +321,7 @@ IGL_INLINE void igl::copyleft::cgal::points_inside_component(
                 inside(i,0) = determine_point_face_orientation(V, F, I, query, fid);
                 inside(i,0) = determine_point_face_orientation(V, F, I, query, fid);
                 break;
                 break;
             default:
             default:
-                throw "Unknow closest element type!";
+                throw "Unknown closest element type!";
         }
         }
     }
     }
 }
 }

+ 4 - 3
include/igl/copyleft/cgal/propagate_winding_numbers.cpp

@@ -118,10 +118,11 @@ IGL_INLINE bool igl::copyleft::cgal::propagate_winding_numbers(
 #endif
 #endif
 
 
   bool valid = true;
   bool valid = true;
-  if (!piecewise_constant_winding_number(F, uE, uE2E)) 
+  // https://github.com/libigl/libigl/issues/674
+  if (!igl::piecewise_constant_winding_number(F, uE, uE2E)) 
   {
   {
-    assert(false && "Input mesh is not orientable");
-    std::cerr << "Input mesh is not orientable!" << std::endl;
+    assert(false && "Input mesh is not PWN");
+    std::cerr << "Input mesh is not PWN!" << std::endl;
     valid = false;
     valid = false;
   }
   }
 
 

+ 16 - 12
include/igl/copyleft/cgal/remesh_intersections.cpp

@@ -10,6 +10,7 @@
 #include "assign_scalar.h"
 #include "assign_scalar.h"
 #include "projected_cdt.h"
 #include "projected_cdt.h"
 #include "../../get_seconds.h"
 #include "../../get_seconds.h"
+#include "../../parallel_for.h"
 #include "../../LinSpaced.h"
 #include "../../LinSpaced.h"
 #include "../../unique_rows.h"
 #include "../../unique_rows.h"
 
 
@@ -375,18 +376,21 @@ IGL_INLINE void igl::copyleft::cgal::remesh_intersections(
     std::vector<std::vector<Point_3> > cdt_vertices(num_cdts);
     std::vector<std::vector<Point_3> > cdt_vertices(num_cdts);
     std::vector<std::vector<std::vector<Index> > > cdt_faces(num_cdts);
     std::vector<std::vector<std::vector<Index> > > cdt_faces(num_cdts);
 
 
-    const auto cdt = [&](const size_t first, const size_t last) 
+    //// Not clear whether this is safe because of reference counting on Point_3
+    //// objects...
+    //// 
+    //// I tried it and got random segfaults (via MATLAB). Seems this is not
+    //// safe.
+    //igl::parallel_for(num_cdts,[&](int i)
+    for (size_t i=0; i<num_cdts; i++) 
     {
     {
-      for (size_t i=first; i<last; i++) 
-      {
-        auto& vertices = cdt_vertices[i];
-        auto& faces = cdt_faces[i];
-        const auto& P = cdt_inputs[i].first;
-        const auto& involved_faces = cdt_inputs[i].second;
-        delaunay_triangulation(P, involved_faces, vertices, faces);
-      }
-    };
-    cdt(0, num_cdts);
+      auto& vertices = cdt_vertices[i];
+      auto& faces = cdt_faces[i];
+      const auto& P = cdt_inputs[i].first;
+      const auto& involved_faces = cdt_inputs[i].second;
+      delaunay_triangulation(P, involved_faces, vertices, faces);
+    }
+    //,1000);
 #ifdef REMESH_INTERSECTIONS_TIMING
 #ifdef REMESH_INTERSECTIONS_TIMING
     log_time("cdt");
     log_time("cdt");
 #endif
 #endif
@@ -449,7 +453,7 @@ IGL_INLINE void igl::copyleft::cgal::remesh_intersections(
           FF.data(), [&vv_to_unique](const typename DerivedFF::Scalar& a)
           FF.data(), [&vv_to_unique](const typename DerivedFF::Scalar& a)
           { return vv_to_unique[a]; });
           { return vv_to_unique[a]; });
       IM.resize(unique_vv.rows());
       IM.resize(unique_vv.rows());
-      // Have to use << instead of = becasue Eigen's PlainObjectBase is annoying
+      // Have to use << instead of = because Eigen's PlainObjectBase is annoying
       IM << igl::LinSpaced<
       IM << igl::LinSpaced<
         Eigen::Matrix<typename DerivedIM::Scalar, Eigen::Dynamic,1 >
         Eigen::Matrix<typename DerivedIM::Scalar, Eigen::Dynamic,1 >
         >(unique_vv.rows(), 0, unique_vv.rows()-1);
         >(unique_vv.rows(), 0, unique_vv.rows()-1);

+ 1 - 1
include/igl/copyleft/cgal/remesh_intersections.h

@@ -30,7 +30,7 @@ namespace igl
       //   offending #offending map taking face indices into F to pairs of order
       //   offending #offending map taking face indices into F to pairs of order
       //     of first finding and list of intersection objects from all
       //     of first finding and list of intersection objects from all
       //     intersections
       //     intersections
-      //   stitch_all  if true, merge all vertices with thte same coordiante.
+      //   stitch_all  if true, merge all vertices with the same coordinate.
       // Outputs:
       // Outputs:
       //   VV  #VV by 3 list of vertex positions, if stitch_all = false then
       //   VV  #VV by 3 list of vertex positions, if stitch_all = false then
       //     first #V vertices will always be V
       //     first #V vertices will always be V

+ 1 - 1
include/igl/copyleft/cgal/trim_with_solid.cpp

@@ -56,7 +56,7 @@ IGL_INLINE void igl::copyleft::cgal::trim_with_solid(
   igl::slice_mask(Eigen::MatrixXi(F),A,1,F);
   igl::slice_mask(Eigen::MatrixXi(F),A,1,F);
   igl::slice_mask(Eigen::VectorXi(P),A,1,P);
   igl::slice_mask(Eigen::VectorXi(P),A,1,P);
   igl::slice_mask(Eigen::VectorXi(J),A,1,J);
   igl::slice_mask(Eigen::VectorXi(J),A,1,J);
-  // Agregate representative query points for each patch
+  // Aggregate representative query points for each patch
   std::vector<bool> flag(num_patches);
   std::vector<bool> flag(num_patches);
   std::vector<std::vector<CGAL::Epeck::FT> > vQ;
   std::vector<std::vector<CGAL::Epeck::FT> > vQ;
   Eigen::VectorXi P2Q(num_patches);
   Eigen::VectorXi P2Q(num_patches);

+ 42 - 8
include/igl/copyleft/cgal/wire_mesh.cpp

@@ -18,6 +18,7 @@ IGL_INLINE void igl::copyleft::cgal::wire_mesh(
   const Eigen::MatrixBase<DerivedWE> & WE,
   const Eigen::MatrixBase<DerivedWE> & WE,
   const double th,
   const double th,
   const int poly_size,
   const int poly_size,
+  const bool solid,
   Eigen::PlainObjectBase<DerivedV> & V,
   Eigen::PlainObjectBase<DerivedV> & V,
   Eigen::PlainObjectBase<DerivedF> & F,
   Eigen::PlainObjectBase<DerivedF> & F,
   Eigen::PlainObjectBase<DerivedJ> & J)
   Eigen::PlainObjectBase<DerivedJ> & J)
@@ -68,6 +69,8 @@ IGL_INLINE void igl::copyleft::cgal::wire_mesh(
     A[WE(e,1)].emplace_back(e,1);
     A[WE(e,1)].emplace_back(e,1);
     typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
     typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
     const RowVector3S ev = WV.row(WE(e,1))-WV.row(WE(e,0));
     const RowVector3S ev = WV.row(WE(e,1))-WV.row(WE(e,0));
+    const Scalar len = ev.norm();
+    // Unit edge vector
     const RowVector3S uv = ev.normalized();
     const RowVector3S uv = ev.normalized();
     Eigen::Quaternion<Scalar> q;
     Eigen::Quaternion<Scalar> q;
     q = q.FromTwoVectors(RowVector3S(0,0,1),uv);
     q = q.FromTwoVectors(RowVector3S(0,0,1),uv);
@@ -78,9 +81,16 @@ IGL_INLINE void igl::copyleft::cgal::wire_mesh(
       // loop over endpoints
       // loop over endpoints
       for(int c = 0;c<2;c++)
       for(int c = 0;c<2;c++)
       {
       {
-        // Move to endpoint, offset by factor of thickness
+        // Direction moving along edge vector
+        const Scalar dir = c==0?1:-1;
+        // Amount (distance) to move along edge vector
+        // Start with factor of thickness;
+        // Max out amount at 1/3 of edge length so that there's always some
+        // amount of edge
+        Scalar dist = std::min(1.*th,len/3.0);
+        // Move to endpoint, offset by amount
         V.row(index(e,c,p)) = 
         V.row(index(e,c,p)) = 
-          qp+WV.row(WE(e,c)) + 1.*th*Scalar(1-2*c)*uv;
+          qp+WV.row(WE(e,c)) + dist*dir*uv;
       }
       }
     }
     }
   }
   }
@@ -166,12 +176,36 @@ IGL_INLINE void igl::copyleft::cgal::wire_mesh(
   }
   }
 
 
   list_to_matrix(vF,F);
   list_to_matrix(vF,F);
-  // Self-union to clean up 
-  igl::copyleft::cgal::mesh_boolean(
-    Eigen::MatrixXd(V),Eigen::MatrixXi(F),Eigen::MatrixXd(),Eigen::MatrixXi(),
-    "union",
-    V,F,J);
-  for(int j=0;j<J.size();j++) J(j) = vJ[J(j)];
+  if(solid)
+  {
+    // Self-union to clean up 
+    igl::copyleft::cgal::mesh_boolean(
+      Eigen::MatrixXd(V),Eigen::MatrixXi(F),Eigen::MatrixXd(),Eigen::MatrixXi(),
+      "union",
+      V,F,J);
+    for(int j=0;j<J.size();j++) J(j) = vJ[J(j)];
+  }else
+  {
+    list_to_matrix(vJ,J);
+  }
+}
+
+template <
+  typename DerivedWV,
+  typename DerivedWE,
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedJ>
+IGL_INLINE void igl::copyleft::cgal::wire_mesh(
+  const Eigen::MatrixBase<DerivedWV> & WV,
+  const Eigen::MatrixBase<DerivedWE> & WE,
+  const double th,
+  const int poly_size,
+  Eigen::PlainObjectBase<DerivedV> & V,
+  Eigen::PlainObjectBase<DerivedF> & F,
+  Eigen::PlainObjectBase<DerivedJ> & J)
+{
+  return wire_mesh(WV,WE,th,poly_size,true,V,F,J);
 }
 }
 
 
 #ifdef IGL_STATIC_LIBRARY
 #ifdef IGL_STATIC_LIBRARY

+ 35 - 16
include/igl/copyleft/cgal/wire_mesh.h

@@ -6,24 +6,26 @@ namespace igl
 {
 {
   namespace copyleft
   namespace copyleft
   {
   {
-    // Construct a "wire" or "wireframe" or "strut" surface mesh, given a
-    // one-dimensional network of straight edges.
-    //
-    // Inputs:
-    //   WV  #WV by 3 list of vertex positions
-    //   WE  #WE by 2 list of edge indices into WV
-    //   th  diameter thickness of wire 
-    //   poly_size  number of sides on each wire (e.g., 4 would produce wires by
-    //     connecting rectangular prisms).
-    // Outputs:
-    //   V  #V by 3 list of output vertices
-    //   F  #F by 3 list of output triangle indices into V
-    //   J  #F list of indices into [0,#WV+#WE) revealing "birth simplex" of
-    //     output faces J(j) < #WV means the face corresponds to the J(j)th
-    //     vertex in WV. J(j) >= #WV means the face corresponds to the
-    //     (J(j)-#WV)th edge in WE.
     namespace cgal
     namespace cgal
     {
     {
+      // Construct a "wire" or "wireframe" or "strut" surface mesh, given a
+      // one-dimensional network of straight edges.
+      //
+      // Inputs:
+      //   WV  #WV by 3 list of vertex positions
+      //   WE  #WE by 2 list of edge indices into WV
+      //   th  diameter thickness of wire 
+      //   poly_size  number of sides on each wire (e.g., 4 would produce wires by
+      //     connecting rectangular prisms).
+      //   solid  whether to resolve self-intersections to
+      //     create a "solid" output mesh (cf., [Zhou et al. 2016]
+      // Outputs:
+      //   V  #V by 3 list of output vertices
+      //   F  #F by 3 list of output triangle indices into V
+      //   J  #F list of indices into [0,#WV+#WE) revealing "birth simplex" of
+      //     output faces J(j) < #WV means the face corresponds to the J(j)th
+      //     vertex in WV. J(j) >= #WV means the face corresponds to the
+      //     (J(j)-#WV)th edge in WE.
       template <
       template <
         typename DerivedWV,
         typename DerivedWV,
         typename DerivedWE,
         typename DerivedWE,
@@ -35,9 +37,26 @@ namespace igl
         const Eigen::MatrixBase<DerivedWE> & WE,
         const Eigen::MatrixBase<DerivedWE> & WE,
         const double th,
         const double th,
         const int poly_size,
         const int poly_size,
+        const bool solid,
         Eigen::PlainObjectBase<DerivedV> & V,
         Eigen::PlainObjectBase<DerivedV> & V,
         Eigen::PlainObjectBase<DerivedF> & F,
         Eigen::PlainObjectBase<DerivedF> & F,
         Eigen::PlainObjectBase<DerivedJ> & J);
         Eigen::PlainObjectBase<DerivedJ> & J);
+      // Default with solid=true
+      template <
+        typename DerivedWV,
+        typename DerivedWE,
+        typename DerivedV,
+        typename DerivedF,
+        typename DerivedJ>
+      IGL_INLINE void wire_mesh(
+        const Eigen::MatrixBase<DerivedWV> & WV,
+        const Eigen::MatrixBase<DerivedWE> & WE,
+        const double th,
+        const int poly_size,
+        Eigen::PlainObjectBase<DerivedV> & V,
+        Eigen::PlainObjectBase<DerivedF> & F,
+        Eigen::PlainObjectBase<DerivedJ> & J);
+
     }
     }
   }
   }
 }
 }

+ 1 - 1
include/igl/copyleft/comiso/miq.h

@@ -43,7 +43,7 @@ namespace igl
     //   UV             #UV by 2 list of vertices in 2D
     //   UV             #UV by 2 list of vertices in 2D
     //   FUV            #FUV by 3 list of face indices in UV
     //   FUV            #FUV by 3 list of face indices in UV
     //
     //
-    // TODO: rename the parameters name in the cpp consistenly
+    // TODO: rename the parameters name in the cpp consistently
     //       improve the handling of hard_features, right now it might fail in difficult cases
     //       improve the handling of hard_features, right now it might fail in difficult cases
 
 
     template <typename DerivedV, typename DerivedF, typename DerivedU>
     template <typename DerivedV, typename DerivedF, typename DerivedU>

+ 1 - 1
include/igl/copyleft/comiso/nrosy.h

@@ -32,7 +32,7 @@ namespace igl
     //   w_soft  #S by 1 weight for the soft constraints (0-1)
     //   w_soft  #S by 1 weight for the soft constraints (0-1)
     //   bc_soft #S by 3 bc for soft constraints
     //   bc_soft #S by 3 bc for soft constraints
     //   N       the degree of the N-RoSy vector field
     //   N       the degree of the N-RoSy vector field
-    //   soft    the strenght of the soft contraints w.r.t. smoothness
+    //   soft    the strength of the soft constraints w.r.t. smoothness
     //           (0 -> smoothness only, 1->constraints only)
     //           (0 -> smoothness only, 1->constraints only)
     // Outputs:
     // Outputs:
     //   R       #F by 3 the representative vectors of the interpolated field
     //   R       #F by 3 the representative vectors of the interpolated field

+ 1 - 0
include/igl/copyleft/marching_cubes.cpp

@@ -211,6 +211,7 @@ public:
     if (num_vertices > vertices.rows())
     if (num_vertices > vertices.rows())
       vertices.conservativeResize(vertices.rows()+10000, Eigen::NoChange);
       vertices.conservativeResize(vertices.rows()+10000, Eigen::NoChange);
 
 
+    // Linear interpolation based on linearly interpolating values
     vertices.row(num_vertices-1)  = ((1.0f-t)*p0 + t*p1).template cast<typename Derivedvertices::Scalar>();
     vertices.row(num_vertices-1)  = ((1.0f-t)*p0 + t*p1).template cast<typename Derivedvertices::Scalar>();
     edge2vertex[EdgeKey(i0, i1)] = num_vertices-1;
     edge2vertex[EdgeKey(i0, i1)] = num_vertices-1;
 
 

+ 1 - 0
include/igl/copyleft/offset_surface.cpp

@@ -60,4 +60,5 @@ void igl::copyleft::offset_surface(
 // generated by autoexplicit.sh
 // generated by autoexplicit.sh
 template void igl::copyleft::offset_surface<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, double, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, double, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 template void igl::copyleft::offset_surface<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, double, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, double, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 template void igl::copyleft::offset_surface<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, float, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, float, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
 template void igl::copyleft::offset_surface<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, float, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, float, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::offset_surface<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 #endif
 #endif

+ 1 - 1
include/igl/copyleft/offset_surface.h

@@ -8,7 +8,7 @@ namespace igl
 {
 {
   namespace copyleft
   namespace copyleft
   {
   {
-    // Compute a triangulated offset surface using maching cubes on a gride of
+    // Compute a triangulated offset surface using matching cubes on a grid of
     // signed distance values from the input triangle mesh.
     // signed distance values from the input triangle mesh.
     //
     //
     // Inputs:
     // Inputs:

+ 1 - 1
include/igl/copyleft/opengl2/render_to_tga.h

@@ -20,7 +20,7 @@ namespace igl
     //   width  width of scene and resulting image
     //   width  width of scene and resulting image
     //   height height of scene and resulting image
     //   height height of scene and resulting image
     ///  alpha  whether to include alpha channel
     ///  alpha  whether to include alpha channel
-    // Returns true only if no errors occured
+    // Returns true only if no errors occurred
     //
     //
     // See also: png/render_to_png which is slower but writes .png files
     // See also: png/render_to_png which is slower but writes .png files
     IGL_INLINE bool render_to_tga(
     IGL_INLINE bool render_to_tga(

+ 1 - 1
include/igl/copyleft/tetgen/cdt.h

@@ -34,7 +34,7 @@ namespace igl
         // Flags to tetgen. Do not include the "c" flag here! {"Y"}
         // Flags to tetgen. Do not include the "c" flag here! {"Y"}
         std::string flags = "Y";
         std::string flags = "Y";
       };
       };
-      // Create a constrained delaunay tesselation containing convex hull of the
+      // Create a constrained delaunay tessellation containing convex hull of the
       // given **non-selfintersecting** mesh.
       // given **non-selfintersecting** mesh.
       //
       //
       // Inputs:
       // Inputs:

+ 2 - 2
include/igl/copyleft/tetgen/read_into_tetgenio.h

@@ -30,8 +30,8 @@ namespace igl
       //   .medit
       //   .medit
       //   .vtk
       //   .vtk
       //   etc.
       //   etc.
-      // Noteably it does not support .obj which is loaded by hand here (also
-      // demonstrating how to load points/faces programatically)
+      // Notably it does not support .obj which is loaded by hand here (also
+      // demonstrating how to load points/faces programmatically)
       //
       //
       // If the file extension is not recognized the filename is assumed to be
       // If the file extension is not recognized the filename is assumed to be
       // the basename of a collection describe a tetmesh, (of which at least
       // the basename of a collection describe a tetmesh, (of which at least

+ 1 - 1
include/igl/cotmatrix.h

@@ -16,7 +16,7 @@
 //  Used const references rather than copying the entire mesh 
 //  Used const references rather than copying the entire mesh 
 //    Alec 9 October 2011
 //    Alec 9 October 2011
 //  removed cotan (uniform weights) optional parameter it was building a buggy
 //  removed cotan (uniform weights) optional parameter it was building a buggy
-//    half of the uniform laplacian, please see adjacency_matrix istead 
+//    half of the uniform laplacian, please see adjacency_matrix instead 
 //    Alec 9 October 2011
 //    Alec 9 October 2011
 
 
 namespace igl 
 namespace igl 

+ 2 - 2
include/igl/cotmatrix_entries.cpp

@@ -35,10 +35,10 @@ IGL_INLINE void igl::cotmatrix_entries(
     case 3:
     case 3:
     {
     {
       // Triangles
       // Triangles
-      //Compute Squared Edge lenghts 
+      //Compute Squared Edge lengths 
       Matrix<typename DerivedC::Scalar,Dynamic,3> l2;
       Matrix<typename DerivedC::Scalar,Dynamic,3> l2;
       igl::squared_edge_lengths(V,F,l2);
       igl::squared_edge_lengths(V,F,l2);
-      //Compute Edge lenghts 
+      //Compute Edge lengths 
       Matrix<typename DerivedC::Scalar,Dynamic,3> l;
       Matrix<typename DerivedC::Scalar,Dynamic,3> l;
       l = l2.array().sqrt();
       l = l2.array().sqrt();
       
       

+ 1 - 1
include/igl/crouzeix_raviart_cotmatrix.cpp

@@ -19,7 +19,7 @@ void igl::crouzeix_raviart_cotmatrix(
   Eigen::PlainObjectBase<DerivedE> & E,
   Eigen::PlainObjectBase<DerivedE> & E,
   Eigen::PlainObjectBase<DerivedEMAP> & EMAP)
   Eigen::PlainObjectBase<DerivedEMAP> & EMAP)
 {
 {
-  // All occurances of directed "facets"
+  // All occurrences of directed "facets"
   Eigen::MatrixXi allE;
   Eigen::MatrixXi allE;
   oriented_facets(F,allE);
   oriented_facets(F,allE);
   Eigen::VectorXi _1;
   Eigen::VectorXi _1;

+ 1 - 1
include/igl/crouzeix_raviart_massmatrix.cpp

@@ -24,7 +24,7 @@ void igl::crouzeix_raviart_massmatrix(
     Eigen::PlainObjectBase<DerivedE> & E,
     Eigen::PlainObjectBase<DerivedE> & E,
     Eigen::PlainObjectBase<DerivedEMAP> & EMAP)
     Eigen::PlainObjectBase<DerivedEMAP> & EMAP)
 {
 {
-  // All occurances of directed "facets"
+  // All occurrences of directed "facets"
   Eigen::MatrixXi allE;
   Eigen::MatrixXi allE;
   oriented_facets(F,allE);
   oriented_facets(F,allE);
   Eigen::VectorXi _1;
   Eigen::VectorXi _1;

+ 3 - 3
include/igl/cut_mesh.cpp

@@ -70,11 +70,11 @@ namespace igl {
     IGL_INLINE void FindInitialPos(const int vert, int &edge, int &face);
     IGL_INLINE void FindInitialPos(const int vert, int &edge, int &face);
 
 
 
 
-    // intialize the mapping given an initial pos
+    // initialize the mapping given an initial pos
     // whih must be initialized with FindInitialPos
     // whih must be initialized with FindInitialPos
     IGL_INLINE void MapIndexes(const int  vert, const int edge_init, const int f_init);
     IGL_INLINE void MapIndexes(const int  vert, const int edge_init, const int f_init);
 
 
-    // intialize the mapping for a given vertex
+    // initialize the mapping for a given vertex
     IGL_INLINE void InitMappingSeam(const int vert);
     IGL_INLINE void InitMappingSeam(const int vert);
 
 
   };
   };
@@ -187,7 +187,7 @@ FindInitialPos(const int vert,
 
 
 
 
 
 
-///intialize the mapping given an initial pos
+///initialize the mapping given an initial pos
 ///whih must be initialized with FindInitialPos
 ///whih must be initialized with FindInitialPos
 template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
 template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
 IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
 IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::

+ 1 - 1
include/igl/directed_edge_parents.h

@@ -13,7 +13,7 @@
 
 
 namespace igl
 namespace igl
 {
 {
-  // Recover "parents" (preceeding edges) in a tree given just directed edges.
+  // Recover "parents" (preceding edges) in a tree given just directed edges.
   //
   //
   // Inputs:
   // Inputs:
   //   E  #E by 2 list of directed edges
   //   E  #E by 2 list of directed edges

+ 1 - 0
include/igl/edges.cpp

@@ -7,6 +7,7 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "edges.h"
 #include "edges.h"
 #include "adjacency_matrix.h"
 #include "adjacency_matrix.h"
+#include <iostream>
 
 
 template <typename DerivedF, typename DerivedE>
 template <typename DerivedF, typename DerivedE>
 IGL_INLINE void igl::edges(
 IGL_INLINE void igl::edges(

+ 4 - 4
include/igl/embree/EmbreeIntersector.h

@@ -209,7 +209,7 @@ inline void igl::embree::EmbreeIntersector::global_init()
   {
   {
     rtcInit();
     rtcInit();
     if(rtcGetError() != RTC_NO_ERROR)
     if(rtcGetError() != RTC_NO_ERROR)
-      std::cerr << "Embree: An error occured while initialiting embree core!" << std::endl;
+      std::cerr << "Embree: An error occurred while initializing embree core!" << std::endl;
 #ifdef IGL_VERBOSE
 #ifdef IGL_VERBOSE
     else
     else
       std::cerr << "Embree: core initialized." << std::endl;
       std::cerr << "Embree: core initialized." << std::endl;
@@ -324,7 +324,7 @@ inline void igl::embree::EmbreeIntersector::init(
   rtcCommit(scene);
   rtcCommit(scene);
 
 
   if(rtcGetError() != RTC_NO_ERROR)
   if(rtcGetError() != RTC_NO_ERROR)
-      std::cerr << "Embree: An error occured while initializing the provided geometry!" << endl;
+      std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
 #ifdef IGL_VERBOSE
 #ifdef IGL_VERBOSE
   else
   else
     std::cerr << "Embree: geometry added." << endl;
     std::cerr << "Embree: geometry added." << endl;
@@ -348,7 +348,7 @@ void igl::embree::EmbreeIntersector::deinit()
 
 
     if(rtcGetError() != RTC_NO_ERROR)
     if(rtcGetError() != RTC_NO_ERROR)
     {
     {
-        std::cerr << "Embree: An error occured while resetting!" << std::endl;
+        std::cerr << "Embree: An error occurred while resetting!" << std::endl;
     }
     }
 #ifdef IGL_VERBOSE
 #ifdef IGL_VERBOSE
     else
     else
@@ -374,7 +374,7 @@ inline bool igl::embree::EmbreeIntersector::intersectRay(
   rtcIntersect(scene,ray);
   rtcIntersect(scene,ray);
 #ifdef IGL_VERBOSE
 #ifdef IGL_VERBOSE
   if(rtcGetError() != RTC_NO_ERROR)
   if(rtcGetError() != RTC_NO_ERROR)
-      std::cerr << "Embree: An error occured while resetting!" << std::endl;
+      std::cerr << "Embree: An error occurred while resetting!" << std::endl;
 #endif
 #endif
 
 
   if((unsigned)ray.geomID != RTC_INVALID_GEOMETRY_ID)
   if((unsigned)ray.geomID != RTC_INVALID_GEOMETRY_ID)

+ 1 - 1
include/igl/exterior_edges.cpp

@@ -67,7 +67,7 @@ IGL_INLINE void igl::exterior_edges(
   {
   {
     int e = 0;
     int e = 0;
     const size_t nue = uE.rows();
     const size_t nue = uE.rows();
-    // Append each unique edge with a non-zero amount of signed occurances
+    // Append each unique edge with a non-zero amount of signed occurrences
     for(size_t ue = 0; ue<nue; ue++)
     for(size_t ue = 0; ue<nue; ue++)
     {
     {
       const int count = counts(ue);
       const int count = counts(ue);

+ 1 - 1
include/igl/exterior_edges.h

@@ -12,7 +12,7 @@
 namespace igl
 namespace igl
 {
 {
   // EXTERIOR_EDGES Determines boundary "edges" and also edges with an
   // EXTERIOR_EDGES Determines boundary "edges" and also edges with an
-  // odd number of occurances where seeing edge (i,j) counts as +1 and seeing
+  // odd number of occurrences where seeing edge (i,j) counts as +1 and seeing
   // the opposite edge (j,i) counts as -1
   // the opposite edge (j,i) counts as -1
   //
   //
   // Inputs:
   // Inputs:

+ 2 - 2
include/igl/facet_components.h

@@ -16,7 +16,7 @@ namespace igl
   //
   //
   // Inputs:
   // Inputs:
   //   F  #F by 3 list of triangle indices
   //   F  #F by 3 list of triangle indices
-  // Ouputs:
+  // Outputs:
   //   C  #F list of connected component ids
   //   C  #F list of connected component ids
   template <typename DerivedF, typename DerivedC>
   template <typename DerivedF, typename DerivedC>
   IGL_INLINE void facet_components(
   IGL_INLINE void facet_components(
@@ -25,7 +25,7 @@ namespace igl
   // Inputs:
   // Inputs:
   //   TT  #TT by 3 list of list of adjacency triangles (see
   //   TT  #TT by 3 list of list of adjacency triangles (see
   //   triangle_triangle_adjacency.h)
   //   triangle_triangle_adjacency.h)
-  // Ouputs:
+  // Outputs:
   //   C  #F list of connected component ids
   //   C  #F list of connected component ids
   //   counts #C list of number of facets in each components
   //   counts #C list of number of facets in each components
   template <
   template <

+ 1 - 1
include/igl/hausdorff.h

@@ -59,7 +59,7 @@ namespace igl
   //   V   3 by 3 list of corner positions so that V.row(i) is the position of the
   //   V   3 by 3 list of corner positions so that V.row(i) is the position of the
   //     ith corner
   //     ith corner
   //   dist_to_B  function taking the x,y,z coordinate of a query position and
   //   dist_to_B  function taking the x,y,z coordinate of a query position and
-  //     outputing the closest-point distance to some point-set B
+  //     outputting the closest-point distance to some point-set B
   // Outputs:
   // Outputs:
   //   l  lower bound on Hausdorff distance 
   //   l  lower bound on Hausdorff distance 
   //   u  upper bound on Hausdorff distance
   //   u  upper bound on Hausdorff distance

+ 6 - 6
include/igl/hessian.cpp

@@ -27,15 +27,15 @@ IGL_INLINE void igl::hessian(
     typedef typename Eigen::SparseMatrix<Scalar> SparseMat;
     typedef typename Eigen::SparseMatrix<Scalar> SparseMat;
     typedef typename Eigen::DiagonalMatrix
     typedef typename Eigen::DiagonalMatrix
                        <Scalar, Eigen::Dynamic, Eigen::Dynamic> DiagMat;
                        <Scalar, Eigen::Dynamic, Eigen::Dynamic> DiagMat;
-    
+
     int dim = V.cols();
     int dim = V.cols();
     assert((dim==2 || dim==3) &&
     assert((dim==2 || dim==3) &&
            "The dimension of the vertices should be 2 or 3");
            "The dimension of the vertices should be 2 or 3");
-    
+
     //Construct the combined gradient matric
     //Construct the combined gradient matric
     SparseMat G;
     SparseMat G;
-    igl::grad(Eigen::PlainObjectBase<DerivedV>(V),
-              Eigen::PlainObjectBase<DerivedF>(F),
+    igl::grad(DerivedV(V),
+              DerivedF(F),
               G, false);
               G, false);
     SparseMat GG(F.rows(), dim*V.rows());
     SparseMat GG(F.rows(), dim*V.rows());
     GG.reserve(G.nonZeros());
     GG.reserve(G.nonZeros());
@@ -43,12 +43,12 @@ IGL_INLINE void igl::hessian(
         GG.middleCols(i*G.cols(),G.cols()) = G.middleRows(i*F.rows(),F.rows());
         GG.middleCols(i*G.cols(),G.cols()) = G.middleRows(i*F.rows(),F.rows());
     SparseMat D;
     SparseMat D;
     igl::repdiag(GG,dim,D);
     igl::repdiag(GG,dim,D);
-    
+
     //Compute area matrix
     //Compute area matrix
     VecXd areas;
     VecXd areas;
     igl::doublearea(V, F, areas);
     igl::doublearea(V, F, areas);
     DiagMat A = (0.5*areas).replicate(dim,1).asDiagonal();
     DiagMat A = (0.5*areas).replicate(dim,1).asDiagonal();
-    
+
     //Compute FEM Hessian
     //Compute FEM Hessian
     H = D.transpose()*A*G;
     H = D.transpose()*A*G;
 }
 }

+ 8 - 8
include/igl/hessian_energy.cpp

@@ -25,35 +25,35 @@ IGL_INLINE void igl::hessian_energy(
     typedef typename Eigen::SparseMatrix<Scalar> SparseMat;
     typedef typename Eigen::SparseMatrix<Scalar> SparseMat;
     typedef typename Eigen::DiagonalMatrix
     typedef typename Eigen::DiagonalMatrix
                        <Scalar, Eigen::Dynamic, Eigen::Dynamic> DiagMat;
                        <Scalar, Eigen::Dynamic, Eigen::Dynamic> DiagMat;
-    
+
     int dim = V.cols();
     int dim = V.cols();
     assert((dim==2 || dim==3) &&
     assert((dim==2 || dim==3) &&
            "The dimension of the vertices should be 2 or 3");
            "The dimension of the vertices should be 2 or 3");
-    
+
     SparseMat M;
     SparseMat M;
     igl::massmatrix(V,F,igl::MASSMATRIX_TYPE_VORONOI,M);
     igl::massmatrix(V,F,igl::MASSMATRIX_TYPE_VORONOI,M);
-    
+
     //Kill non-interior DOFs
     //Kill non-interior DOFs
     VecXd Mint = M.diagonal();
     VecXd Mint = M.diagonal();
     std::vector<std::vector<int> > bdryLoop;
     std::vector<std::vector<int> > bdryLoop;
-    igl::boundary_loop(Eigen::PlainObjectBase<DerivedF>(F),bdryLoop);
+    igl::boundary_loop(DerivedF(F),bdryLoop);
     for(const std::vector<int>& loop : bdryLoop)
     for(const std::vector<int>& loop : bdryLoop)
         for(const int& bdryVert : loop)
         for(const int& bdryVert : loop)
             Mint(bdryVert) = 0.;
             Mint(bdryVert) = 0.;
-    
+
     //Invert Mint
     //Invert Mint
     for(int i=0; i<Mint.rows(); ++i)
     for(int i=0; i<Mint.rows(); ++i)
         if(Mint(i) > 0)
         if(Mint(i) > 0)
             Mint(i) = 1./Mint(i);
             Mint(i) = 1./Mint(i);
-    
+
     //Repeat Mint to form diaginal matrix
     //Repeat Mint to form diaginal matrix
     DiagMat stackedMinv = Mint.replicate(dim*dim,1).asDiagonal();
     DiagMat stackedMinv = Mint.replicate(dim*dim,1).asDiagonal();
-    
+
     //Compute squared Hessian
     //Compute squared Hessian
     SparseMat H;
     SparseMat H;
     igl::hessian(V,F,H);
     igl::hessian(V,F,H);
     Q = H.transpose()*stackedMinv*H;
     Q = H.transpose()*stackedMinv*H;
-    
+
 }
 }
 
 
 
 

+ 1 - 1
include/igl/histc.h

@@ -13,7 +13,7 @@
 
 
 namespace igl
 namespace igl
 {
 {
-  // Like matlab's histc. Count occurances of values in X between consecutive
+  // Like matlab's histc. Count occurrences of values in X between consecutive
   // entries in E
   // entries in E
   //
   //
   // Inputs:
   // Inputs:

+ 2 - 2
include/igl/integrable_polyvector_fields.h

@@ -15,7 +15,7 @@
 
 
 namespace igl {
 namespace igl {
   // Compute a curl-free frame field from user constraints, optionally starting
   // Compute a curl-free frame field from user constraints, optionally starting
-  // from a gived frame field (assumed to be interpolating the constraints).
+  // from a given frame field (assumed to be interpolating the constraints).
   // Implementation of the paper "Integrable PolyVector Fields", SIGGRAPH 2015.
   // Implementation of the paper "Integrable PolyVector Fields", SIGGRAPH 2015.
 
 
   // Set of parameters used during solve
   // Set of parameters used during solve
@@ -51,7 +51,7 @@ namespace igl {
                                                     igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &data);
                                                     igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &data);
 
 
 
 
-  // Given the current estimate of the field, performes one round of optimization
+  // Given the current estimate of the field, performs one round of optimization
   // iterations and updates the current estimate. The intermediate data is saved
   // iterations and updates the current estimate. The intermediate data is saved
   // and returned for the next iteration.
   // and returned for the next iteration.
   // Inputs:
   // Inputs:

+ 4 - 4
include/igl/is_boundary_edge.cpp

@@ -47,14 +47,14 @@ void igl::is_boundary_edge(
   MatrixXi uE;
   MatrixXi uE;
   VectorXi EMAP;
   VectorXi EMAP;
   unique_rows(sorted_EallE,uE,_,EMAP);
   unique_rows(sorted_EallE,uE,_,EMAP);
-  // Counts of occurances
+  // Counts of occurrences
   VectorXi N = VectorXi::Zero(uE.rows());
   VectorXi N = VectorXi::Zero(uE.rows());
   for(int e = 0;e<EMAP.rows();e++)
   for(int e = 0;e<EMAP.rows();e++)
   {
   {
     N(EMAP(e))++;
     N(EMAP(e))++;
   }
   }
   B.resize(E.rows());
   B.resize(E.rows());
-  // Look of occurances of 2: one for original and another for boundary
+  // Look of occurrences of 2: one for original and another for boundary
   for(int e = 0;e<E.rows();e++)
   for(int e = 0;e<E.rows();e++)
   {
   {
     B(e) = (N(EMAP(e)) == 2);
     B(e) = (N(EMAP(e)) == 2);
@@ -97,14 +97,14 @@ void igl::is_boundary_edge(
   sort(allE,2,true,sorted_allE,_);
   sort(allE,2,true,sorted_allE,_);
   // Determine unique undirected edges E and map to directed edges EMAP
   // Determine unique undirected edges E and map to directed edges EMAP
   unique_rows(sorted_allE,E,_,EMAP);
   unique_rows(sorted_allE,E,_,EMAP);
-  // Counts of occurances
+  // Counts of occurrences
   VectorXi N = VectorXi::Zero(E.rows());
   VectorXi N = VectorXi::Zero(E.rows());
   for(int e = 0;e<EMAP.rows();e++)
   for(int e = 0;e<EMAP.rows();e++)
   {
   {
     N(EMAP(e))++;
     N(EMAP(e))++;
   }
   }
   B.resize(E.rows());
   B.resize(E.rows());
-  // Look of occurances of 1
+  // Look of occurrences of 1
   for(int e = 0;e<E.rows();e++)
   for(int e = 0;e<E.rows();e++)
   {
   {
     B(e) = N(e) == 1;
     B(e) = N(e) == 1;

+ 1 - 1
include/igl/is_planar.h

@@ -13,7 +13,7 @@
 
 
 namespace igl
 namespace igl
 {
 {
-  // Determin if a set of points lies on the XY plane
+  // Determine if a set of points lies on the XY plane
   //
   //
   // Inputs:
   // Inputs:
   //   V  #V by dim list of vertex positions
   //   V  #V by dim list of vertex positions

+ 3 - 2
include/igl/is_stl.cpp

@@ -12,7 +12,7 @@ IGL_INLINE bool igl::is_stl(FILE * stl_file, bool & is_ascii)
   //
   //
   const auto perfect_size = [](FILE * stl_file)->bool
   const auto perfect_size = [](FILE * stl_file)->bool
   {
   {
-    stl_file = freopen(NULL,"rb",stl_file);
+    //stl_file = freopen(NULL,"rb",stl_file);
     // Read 80 header
     // Read 80 header
     char header[80];
     char header[80];
     if(fread(header,sizeof(char),80,stl_file)!=80)
     if(fread(header,sizeof(char),80,stl_file)!=80)
@@ -27,7 +27,8 @@ IGL_INLINE bool igl::is_stl(FILE * stl_file, bool & is_ascii)
     }
     }
     fseek(stl_file,0,SEEK_END);
     fseek(stl_file,0,SEEK_END);
     int file_size = ftell(stl_file);
     int file_size = ftell(stl_file);
-    stl_file = freopen(NULL,"r",stl_file);
+    fseek(stl_file,0,SEEK_SET);
+    //stl_file = freopen(NULL,"r",stl_file);
     return (file_size == 80 + 4 + (4*12 + 2) * num_tri);
     return (file_size == 80 + 4 + (4*12 + 2) * num_tri);
   };
   };
   // Specifically 80 character header
   // Specifically 80 character header

+ 4 - 1
include/igl/ismember.cpp

@@ -12,6 +12,7 @@
 #include "sortrows.h"
 #include "sortrows.h"
 #include "unique.h"
 #include "unique.h"
 #include "unique_rows.h"
 #include "unique_rows.h"
+#include <iostream>
 
 
 template <
 template <
   typename DerivedA,
   typename DerivedA,
@@ -153,10 +154,11 @@ IGL_INLINE void igl::ismember_rows(
     bool past = false;
     bool past = false;
     for(int a = 0;a<sA.rows();a++)
     for(int a = 0;a<sA.rows();a++)
     {
     {
+      assert(bi < sB.rows());
       while(!past && row_greater_than(a,bi))
       while(!past && row_greater_than(a,bi))
       {
       {
         bi++;
         bi++;
-        past = bi>=sB.size();
+        past = bi>=sB.rows();
       }
       }
       if(!past && (sA.row(a).array()==sB.row(bi).array()).all() )
       if(!past && (sA.row(a).array()==sB.row(bi).array()).all() )
       {
       {
@@ -179,4 +181,5 @@ template void igl::ismember<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix
 template void igl::ismember_rows<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Array<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::ismember_rows<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Array<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::ismember_rows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::ismember_rows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::ismember_rows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::ismember_rows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::ismember_rows<Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<int, 12, 4, 0, 12, 4>, Eigen::Array<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 4, 0, 12, 4> > const&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 #endif
 #endif

+ 2 - 0
include/igl/jet.cpp

@@ -88,4 +88,6 @@ template void igl::jet<float>(float, float&, float&, float&);
 template void igl::jet<Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::jet<Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::jet<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::jet<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::jet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template void igl::jet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+
+template void igl::jet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
 #endif
 #endif

+ 1 - 1
include/igl/lim/lim.h

@@ -59,7 +59,7 @@ namespace igl
     //--------------------------------------------------------------------------
     //--------------------------------------------------------------------------
     // Return values:
     // Return values:
     //  Succeeded : Successful optimization with fulfilled tolerance
     //  Succeeded : Successful optimization with fulfilled tolerance
-    //  LocalMinima : Convergenged to a local minima / tolerance not fullfilled
+    //  LocalMinima : Convergenged to a local minima / tolerance not fulfilled
     //  IterationLimit : Max iteration reached before tolerance was fulfilled
     //  IterationLimit : Max iteration reached before tolerance was fulfilled
     //  Infeasible : not feasible -> has inverted elements (decrease eps?)
     //  Infeasible : not feasible -> has inverted elements (decrease eps?)
   
   

+ 3 - 2
include/igl/list_to_matrix.cpp

@@ -162,13 +162,14 @@ template bool igl::list_to_matrix<int, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std
 template bool igl::list_to_matrix<unsigned long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(std::vector<unsigned long, std::allocator<unsigned long> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
 template bool igl::list_to_matrix<unsigned long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(std::vector<unsigned long, std::allocator<unsigned long> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
 
 
 #ifdef WIN32
 #ifdef WIN32
-template bool igl::list_to_matrix<unsigned long long,class Eigen::Matrix<int,-1,1,0,-1,1> >(class std::vector<unsigned long long,class std::allocator<unsigned long long> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,1,0,-1,1> > &);
 template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
-template bool igl::list_to_matrix<unsigned long, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::vector<unsigned long, std::allocator<unsigned long> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template bool igl::list_to_matrix<unsigned __int64, class Eigen::Matrix<int, -1, -1, 0, -1, -1> >(class std::vector<unsigned __int64, class std::allocator<unsigned __int64> > const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1> > &);
 template bool igl::list_to_matrix<unsigned __int64, class Eigen::Matrix<int, -1, -1, 0, -1, -1> >(class std::vector<unsigned __int64, class std::allocator<unsigned __int64> > const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1> > &);
+template bool igl::list_to_matrix<unsigned __int64,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class std::vector<unsigned __int64,class std::allocator<unsigned __int64> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
 template bool igl::list_to_matrix<unsigned __int64,class Eigen::Matrix<long,-1,1,0,-1,1> >(class std::vector<unsigned __int64,class std::allocator<unsigned __int64> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<long,-1,1,0,-1,1> > &);
 template bool igl::list_to_matrix<unsigned __int64,class Eigen::Matrix<long,-1,1,0,-1,1> >(class std::vector<unsigned __int64,class std::allocator<unsigned __int64> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<long,-1,1,0,-1,1> > &);
+template bool igl::list_to_matrix<unsigned long long,class Eigen::Matrix<int,-1,1,0,-1,1> >(class std::vector<unsigned long long,class std::allocator<unsigned long long> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,1,0,-1,1> > &);
+template bool igl::list_to_matrix<unsigned long, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::vector<unsigned long, std::allocator<unsigned long> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #endif
 #endif
 #endif
 #endif

+ 2 - 2
include/igl/matlab/validate_arg.h

@@ -16,9 +16,9 @@ namespace igl
     // Throw an error if arg i+1 is not a scalar
     // Throw an error if arg i+1 is not a scalar
     //
     //
     // Inputs:
     // Inputs:
-    //   i  index of current arguement
+    //   i  index of current argument
     //   nrhs  total number of arguments
     //   nrhs  total number of arguments
-    //   prhs  pointer to arguements array
+    //   prhs  pointer to arguments array
     //   name   name of current argument
     //   name   name of current argument
     IGL_INLINE void validate_arg_scalar(
     IGL_INLINE void validate_arg_scalar(
       const int i, const int nrhs, const mxArray * prhs[], const char * name);
       const int i, const int nrhs, const mxArray * prhs[], const char * name);

+ 3 - 3
include/igl/matlab_format.h

@@ -22,9 +22,9 @@ namespace igl
   // Templates:
   // Templates:
   //   DerivedM  e.g. derived from MatrixXd
   //   DerivedM  e.g. derived from MatrixXd
   // Input:
   // Input:
-  //   input  some matrix to be formated
+  //   input  some matrix to be formatted
   //   name  name of matrix
   //   name  name of matrix
-  // Returns  Formated matrix
+  // Returns  Formatted matrix
   //
   //
   // Example:
   // Example:
   // // M := [1 2 3;4 5 6];
   // // M := [1 2 3;4 5 6];
@@ -44,7 +44,7 @@ namespace igl
   IGL_INLINE const Eigen::WithFormat< DerivedM > matlab_format(
   IGL_INLINE const Eigen::WithFormat< DerivedM > matlab_format(
     const Eigen::DenseBase<DerivedM> & M,
     const Eigen::DenseBase<DerivedM> & M,
     const std::string name = "");
     const std::string name = "");
-  // Same but for sparse matrices. Print IJV format into an auxillary variable
+  // Same but for sparse matrices. Print IJV format into an auxiliary variable
   // and then print a call to sparse which will construct the sparse matrix
   // and then print a call to sparse which will construct the sparse matrix
   // Example:
   // Example:
   // // S := [0 2 3;4 5 0];
   // // S := [0 2 3;4 5 0];

+ 1 - 1
include/igl/min_quad_with_fixed.cpp

@@ -204,7 +204,7 @@ IGL_INLINE bool igl::min_quad_with_fixed_precompute(
       data.preY.resize(data.unknown_lagrange.size(),0);
       data.preY.resize(data.unknown_lagrange.size(),0);
     }
     }
 
 
-    // Positive definite and no equality constraints (Postive definiteness
+    // Positive definite and no equality constraints (Positive definiteness
     // implies symmetric)
     // implies symmetric)
 #ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
 #ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
     cout<<"    factorize"<<endl;
     cout<<"    factorize"<<endl;

+ 1 - 1
include/igl/mosek/bbw.h

@@ -30,7 +30,7 @@ namespace igl
     //   Ele  #Elements by simplex-size list of element indices
     //   Ele  #Elements by simplex-size list of element indices
     //   b  #b boundary indices into V
     //   b  #b boundary indices into V
     //   bc #b by #W list of boundary values
     //   bc #b by #W list of boundary values
-    //   data  object containing options, intial guess --> solution and results
+    //   data  object containing options, initial guess --> solution and results
     //   mosek_data  object containing mosek options
     //   mosek_data  object containing mosek options
     // Outputs:
     // Outputs:
     //   W  #V by #W list of *unnormalized* weights to normalize use
     //   W  #V by #W list of *unnormalized* weights to normalize use

+ 2 - 2
include/igl/mosek/mosek_linprog.cpp

@@ -79,9 +79,9 @@ IGL_INLINE bool igl::mosek::mosek_linprog(
     {
     {
       if(lxj == uxj)
       if(lxj == uxj)
       {
       {
-        k = MSK_BK_RA;
-      }else{
         k = MSK_BK_FX;
         k = MSK_BK_FX;
+      }else{
+        k = MSK_BK_RA;
       }
       }
     }else if(isfinite(lxj))
     }else if(isfinite(lxj))
     {
     {

+ 5 - 2
include/igl/mosek/mosek_quadprog.cpp

@@ -28,7 +28,10 @@ igl::mosek::MosekData::MosekData()
   // 1e-4 seems safe
   // 1e-4 seems safe
   // 1e-8 MOSEK DEFAULT SOLUTION
   // 1e-8 MOSEK DEFAULT SOLUTION
   douparam[MSK_DPAR_INTPNT_TOL_REL_GAP]=1e-8;
   douparam[MSK_DPAR_INTPNT_TOL_REL_GAP]=1e-8;
-  // Force using multiple threads, not sure if MOSEK is properly destorying
+#if MSK_VERSION_MAJOR >= 8
+  douparam[MSK_DPAR_INTPNT_QO_TOL_REL_GAP]=1e-12;
+#endif
+  // Force using multiple threads, not sure if MOSEK is properly destroying
   //extra threads...
   //extra threads...
 #if MSK_VERSION_MAJOR >= 7
 #if MSK_VERSION_MAJOR >= 7
   intparam[MSK_IPAR_NUM_THREADS] = 6;
   intparam[MSK_IPAR_NUM_THREADS] = 6;
@@ -50,7 +53,7 @@ igl::mosek::MosekData::MosekData()
   //   choose the right ordering method when really any of them are
   //   choose the right ordering method when really any of them are
   //   instantaneous
   //   instantaneous
   intparam[MSK_IPAR_INTPNT_ORDER_METHOD] = MSK_ORDER_METHOD_NONE;
   intparam[MSK_IPAR_INTPNT_ORDER_METHOD] = MSK_ORDER_METHOD_NONE;
-  // 1.0 means optimizer is very leniant about declaring model infeasible
+  // 1.0 means optimizer is very lenient about declaring model infeasible
   douparam[MSK_DPAR_INTPNT_TOL_INFEAS] = 1e-8;
   douparam[MSK_DPAR_INTPNT_TOL_INFEAS] = 1e-8;
   // Hard to say if this is doing anything, probably nothing dramatic
   // Hard to say if this is doing anything, probably nothing dramatic
   douparam[MSK_DPAR_INTPNT_TOL_PSAFE]= 1e2;
   douparam[MSK_DPAR_INTPNT_TOL_PSAFE]= 1e2;

+ 311 - 0
include/igl/opengl/MeshGL.cpp

@@ -0,0 +1,311 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "MeshGL.h"
+#include "bind_vertex_attrib_array.h"
+#include "create_shader_program.h"
+#include "destroy_shader_program.h"
+#include <iostream>
+
+IGL_INLINE void igl::opengl::MeshGL::init_buffers()
+{
+  // 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 = MeshGL::DIRTY_ALL;
+}
+
+IGL_INLINE void igl::opengl::MeshGL::free_buffers()
+{
+  if (is_initialized)
+  {
+    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);
+  }
+}
+
+IGL_INLINE void igl::opengl::MeshGL::bind_mesh()
+{
+  glBindVertexArray(vao_mesh);
+  glUseProgram(shader_mesh);
+  bind_vertex_attrib_array(shader_mesh,"position", vbo_V, V_vbo, dirty & MeshGL::DIRTY_POSITION);
+  bind_vertex_attrib_array(shader_mesh,"normal", vbo_V_normals, V_normals_vbo, dirty & MeshGL::DIRTY_NORMAL);
+  bind_vertex_attrib_array(shader_mesh,"Ka", vbo_V_ambient, V_ambient_vbo, dirty & MeshGL::DIRTY_AMBIENT);
+  bind_vertex_attrib_array(shader_mesh,"Kd", vbo_V_diffuse, V_diffuse_vbo, dirty & MeshGL::DIRTY_DIFFUSE);
+  bind_vertex_attrib_array(shader_mesh,"Ks", vbo_V_specular, V_specular_vbo, dirty & MeshGL::DIRTY_SPECULAR);
+  bind_vertex_attrib_array(shader_mesh,"texcoord", vbo_V_uv, V_uv_vbo, dirty & MeshGL::DIRTY_UV);
+
+  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_F);
+  if (dirty & MeshGL::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 & MeshGL::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);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_u, tex_v, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.data());
+  }
+  glUniform1i(glGetUniformLocation(shader_mesh,"tex"), 0);
+  dirty &= ~MeshGL::DIRTY_MESH;
+}
+
+IGL_INLINE void igl::opengl::MeshGL::bind_overlay_lines()
+{
+  bool is_dirty = dirty & MeshGL::DIRTY_OVERLAY_LINES;
+
+  glBindVertexArray(vao_overlay_lines);
+  glUseProgram(shader_overlay_lines);
+ bind_vertex_attrib_array(shader_overlay_lines,"position", vbo_lines_V, lines_V_vbo, is_dirty);
+ bind_vertex_attrib_array(shader_overlay_lines,"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 &= ~MeshGL::DIRTY_OVERLAY_LINES;
+}
+
+IGL_INLINE void igl::opengl::MeshGL::bind_overlay_points()
+{
+  bool is_dirty = dirty & MeshGL::DIRTY_OVERLAY_POINTS;
+
+  glBindVertexArray(vao_overlay_points);
+  glUseProgram(shader_overlay_points);
+ bind_vertex_attrib_array(shader_overlay_points,"position", vbo_points_V, points_V_vbo, is_dirty);
+ bind_vertex_attrib_array(shader_overlay_points,"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 &= ~MeshGL::DIRTY_OVERLAY_POINTS;
+}
+
+IGL_INLINE void igl::opengl::MeshGL::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.rows(), GL_UNSIGNED_INT, 0);
+
+  glDisable(GL_POLYGON_OFFSET_FILL);
+  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
+
+IGL_INLINE void igl::opengl::MeshGL::draw_overlay_lines()
+{
+  glDrawElements(GL_LINES, lines_F_vbo.rows(), GL_UNSIGNED_INT, 0);
+}
+
+IGL_INLINE void igl::opengl::MeshGL::draw_overlay_points()
+{
+  glDrawElements(GL_POINTS, points_F_vbo.rows(), GL_UNSIGNED_INT, 0);
+}
+
+IGL_INLINE void igl::opengl::MeshGL::init()
+{
+  if(is_initialized)
+  {
+    return;
+  }
+  is_initialized = true;
+  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 vec4 Ka;"
+  "in vec4 Kd;"
+  "in vec4 Ks;"
+  "in vec2 texcoord;"
+  "out vec2 texcoordi;"
+  "out vec4 Kai;"
+  "out vec4 Kdi;"
+  "out vec4 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 vec4 Ksi;"
+  "in vec4 Kdi;"
+  "in vec4 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 * vec3(Kai);"    // ambient intensity
+
+  "vec3 light_position_eye = vec3 (view * vec4 (light_position_world, 1.0));"
+  "vec3 vector_to_light_eye = light_position_eye - position_eye;"
+  "vec3 direction_to_light_eye = normalize (vector_to_light_eye);"
+  "float dot_prod = dot (direction_to_light_eye, normal_eye);"
+  "float clamped_dot_prod = max (dot_prod, 0.0);"
+  "vec3 Id = Ld * vec3(Kdi) * clamped_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 = float(abs(dot_prod)==dot_prod) * max (dot_prod_specular, 0.0);"
+  "float specular_factor = pow (dot_prod_specular, specular_exponent);"
+  "vec3 Is = Ls * vec3(Ksi) * specular_factor;"    // specular intensity
+  "vec4 color = vec4(lighting_factor * (Is + Id) + Ia + (1.0-lighting_factor) * vec3(Kdi),(Kai.a+Ksi.a+Kdi.a)/3);"
+  "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);"
+  "}";
+
+  init_buffers();
+  create_shader_program(
+    mesh_vertex_shader_string,
+    mesh_fragment_shader_string,
+    {},
+    shader_mesh);
+  create_shader_program(
+    overlay_vertex_shader_string,
+    overlay_fragment_shader_string,
+    {},
+    shader_overlay_lines);
+  create_shader_program(
+    overlay_vertex_shader_string,
+    overlay_point_fragment_shader_string,
+    {},
+    shader_overlay_points);
+}
+
+IGL_INLINE void igl::opengl::MeshGL::free()
+{
+  const auto free = [](GLuint & id)
+  {
+    if(id)
+    {
+      destroy_shader_program(id);
+      id = 0;
+    }
+  };
+
+  if (is_initialized)
+  {
+    free(shader_mesh);
+    free(shader_overlay_lines);
+    free(shader_overlay_points);
+    free_buffers();
+  }
+}

+ 44 - 28
include/igl/viewer/OpenGL_state.h → include/igl/opengl/MeshGL.h

@@ -5,32 +5,50 @@
 // This Source Code Form is subject to the terms of the Mozilla Public License
 // 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
 // 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
-#ifndef IGL_VIEWER_OPENGL_STATE_H
-#define IGL_VIEWER_OPENGL_STATE_H
+#ifndef IGL_OPENGL_MESHGL_H
+#define IGL_OPENGL_MESHGL_H
 
 
-// Coverts mesh data inside a igl::viewer::ViewerData class in an OpenGL compatible format
-// The class includes a shader and the opengl calls to plot the data
+// Coverts mesh data inside a igl::ViewerData class in an OpenGL
+// compatible format The class includes a shader and the opengl calls to plot
+// the data
 
 
 #include <igl/igl_inline.h>
 #include <igl/igl_inline.h>
-#include <igl/viewer/OpenGL_shader.h>
-#include <igl/viewer/ViewerData.h>
+#include <Eigen/Core>
 
 
 namespace igl
 namespace igl
 {
 {
-namespace viewer
+namespace opengl
 {
 {
 
 
-class OpenGL_state
+class MeshGL
 {
 {
 public:
 public:
   typedef unsigned int GLuint;
   typedef unsigned int GLuint;
 
 
+  enum DirtyFlags
+  {
+    DIRTY_NONE           = 0x0000,
+    DIRTY_POSITION       = 0x0001,
+    DIRTY_UV             = 0x0002,
+    DIRTY_NORMAL         = 0x0004,
+    DIRTY_AMBIENT        = 0x0008,
+    DIRTY_DIFFUSE        = 0x0010,
+    DIRTY_SPECULAR       = 0x0020,
+    DIRTY_TEXTURE        = 0x0040,
+    DIRTY_FACE           = 0x0080,
+    DIRTY_MESH           = 0x00FF,
+    DIRTY_OVERLAY_LINES  = 0x0100,
+    DIRTY_OVERLAY_POINTS = 0x0200,
+    DIRTY_ALL            = 0x03FF
+  };
+
+  bool is_initialized = false;
   GLuint vao_mesh;
   GLuint vao_mesh;
   GLuint vao_overlay_lines;
   GLuint vao_overlay_lines;
   GLuint vao_overlay_points;
   GLuint vao_overlay_points;
-  OpenGL_shader shader_mesh;
-  OpenGL_shader shader_overlay_lines;
-  OpenGL_shader shader_overlay_points;
+  GLuint shader_mesh;
+  GLuint shader_overlay_lines;
+  GLuint shader_overlay_points;
 
 
   GLuint vbo_V; // Vertices of the current mesh (#V x 3)
   GLuint vbo_V; // Vertices of the current mesh (#V x 3)
   GLuint vbo_V_uv; // UV coordinates for the current mesh (#V x 2)
   GLuint vbo_V_uv; // UV coordinates for the current mesh (#V x 2)
@@ -50,24 +68,25 @@ public:
   GLuint vbo_points_V_colors; // Color values of the point overlay
   GLuint vbo_points_V_colors; // Color values of the point overlay
 
 
   // Temporary copy of the content of each VBO
   // Temporary copy of the content of each VBO
-  Eigen::MatrixXf V_vbo;
-  Eigen::MatrixXf V_normals_vbo;
-  Eigen::MatrixXf V_ambient_vbo;
-  Eigen::MatrixXf V_diffuse_vbo;
-  Eigen::MatrixXf V_specular_vbo;
-  Eigen::MatrixXf V_uv_vbo;
-  Eigen::MatrixXf lines_V_vbo;
-  Eigen::MatrixXf lines_V_colors_vbo;
-  Eigen::MatrixXf points_V_vbo;
-  Eigen::MatrixXf points_V_colors_vbo;
+  typedef Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> RowMatrixXf;
+  RowMatrixXf V_vbo;
+  RowMatrixXf V_normals_vbo;
+  RowMatrixXf V_ambient_vbo;
+  RowMatrixXf V_diffuse_vbo;
+  RowMatrixXf V_specular_vbo;
+  RowMatrixXf V_uv_vbo;
+  RowMatrixXf lines_V_vbo;
+  RowMatrixXf lines_V_colors_vbo;
+  RowMatrixXf points_V_vbo;
+  RowMatrixXf points_V_colors_vbo;
 
 
   int tex_u;
   int tex_u;
   int tex_v;
   int tex_v;
   Eigen::Matrix<char,Eigen::Dynamic,1> tex;
   Eigen::Matrix<char,Eigen::Dynamic,1> tex;
 
 
-  Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic> F_vbo;
-  Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic> lines_F_vbo;
-  Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic> points_F_vbo;
+  Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> F_vbo;
+  Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> lines_F_vbo;
+  Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> points_F_vbo;
 
 
   // Marks dirty buffers that need to be uploaded to OpenGL
   // Marks dirty buffers that need to be uploaded to OpenGL
   uint32_t dirty;
   uint32_t dirty;
@@ -81,9 +100,6 @@ public:
   // Create a new set of OpenGL buffer objects
   // Create a new set of OpenGL buffer objects
   IGL_INLINE void init_buffers();
   IGL_INLINE void init_buffers();
 
 
-  // Update contents from a 'Data' instance
-  IGL_INLINE void set_data(const igl::viewer::ViewerData &data, bool invert_normals);
-
   // Bind the underlying OpenGL buffer objects for subsequent mesh draw calls
   // Bind the underlying OpenGL buffer objects for subsequent mesh draw calls
   IGL_INLINE void bind_mesh();
   IGL_INLINE void bind_mesh();
 
 
@@ -111,7 +127,7 @@ public:
 }
 }
 
 
 #ifndef IGL_STATIC_LIBRARY
 #ifndef IGL_STATIC_LIBRARY
-#  include "OpenGL_state.cpp"
+#  include "MeshGL.cpp"
 #endif
 #endif
 
 
 #endif
 #endif

+ 58 - 116
include/igl/viewer/ViewerCore.cpp → include/igl/opengl/ViewerCore.cpp

@@ -7,18 +7,19 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 // obtain one at http://mozilla.org/MPL/2.0/.
 
 
 #include "ViewerCore.h"
 #include "ViewerCore.h"
-#include <igl/quat_to_mat.h>
-#include <igl/snap_to_fixed_up.h>
-#include <igl/look_at.h>
-#include <igl/frustum.h>
-#include <igl/ortho.h>
-#include <igl/massmatrix.h>
-#include <igl/barycenter.h>
-#include <igl/PI.h>
+#include "gl.h"
+#include "../quat_to_mat.h"
+#include "../snap_to_fixed_up.h"
+#include "../look_at.h"
+#include "../frustum.h"
+#include "../ortho.h"
+#include "../massmatrix.h"
+#include "../barycenter.h"
+#include "../PI.h"
 #include <Eigen/Geometry>
 #include <Eigen/Geometry>
 #include <iostream>
 #include <iostream>
 
 
-IGL_INLINE void igl::viewer::ViewerCore::align_camera_center(
+IGL_INLINE void igl::opengl::ViewerCore::align_camera_center(
   const Eigen::MatrixXd& V,
   const Eigen::MatrixXd& V,
   const Eigen::MatrixXi& F)
   const Eigen::MatrixXi& F)
 {
 {
@@ -33,7 +34,7 @@ IGL_INLINE void igl::viewer::ViewerCore::align_camera_center(
   }
   }
 }
 }
 
 
-IGL_INLINE void igl::viewer::ViewerCore::get_scale_and_shift_to_fit_mesh(
+IGL_INLINE void igl::opengl::ViewerCore::get_scale_and_shift_to_fit_mesh(
   const Eigen::MatrixXd& V,
   const Eigen::MatrixXd& V,
   const Eigen::MatrixXi& F,
   const Eigen::MatrixXi& F,
   float& zoom,
   float& zoom,
@@ -53,7 +54,7 @@ IGL_INLINE void igl::viewer::ViewerCore::get_scale_and_shift_to_fit_mesh(
   return get_scale_and_shift_to_fit_mesh(BC,zoom,shift);
   return get_scale_and_shift_to_fit_mesh(BC,zoom,shift);
 }
 }
 
 
-IGL_INLINE void igl::viewer::ViewerCore::align_camera_center(
+IGL_INLINE void igl::opengl::ViewerCore::align_camera_center(
   const Eigen::MatrixXd& V)
   const Eigen::MatrixXd& V)
 {
 {
   if(V.rows() == 0)
   if(V.rows() == 0)
@@ -67,7 +68,7 @@ IGL_INLINE void igl::viewer::ViewerCore::align_camera_center(
   }
   }
 }
 }
 
 
-IGL_INLINE void igl::viewer::ViewerCore::get_scale_and_shift_to_fit_mesh(
+IGL_INLINE void igl::opengl::ViewerCore::get_scale_and_shift_to_fit_mesh(
   const Eigen::MatrixXd& V,
   const Eigen::MatrixXd& V,
   float& zoom,
   float& zoom,
   Eigen::Vector3f& shift)
   Eigen::Vector3f& shift)
@@ -84,7 +85,7 @@ IGL_INLINE void igl::viewer::ViewerCore::get_scale_and_shift_to_fit_mesh(
 }
 }
 
 
 
 
-IGL_INLINE void igl::viewer::ViewerCore::clear_framebuffers()
+IGL_INLINE void igl::opengl::ViewerCore::clear_framebuffers()
 {
 {
   glClearColor(background_color[0],
   glClearColor(background_color[0],
                background_color[1],
                background_color[1],
@@ -93,9 +94,8 @@ IGL_INLINE void igl::viewer::ViewerCore::clear_framebuffers()
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 }
 }
 
 
-IGL_INLINE void igl::viewer::ViewerCore::draw(
+IGL_INLINE void igl::opengl::ViewerCore::draw(
   ViewerData& data,
   ViewerData& data,
-  OpenGL_state& opengl,
   bool update_matrices)
   bool update_matrices)
 {
 {
   using namespace std;
   using namespace std;
@@ -112,10 +112,10 @@ IGL_INLINE void igl::viewer::ViewerCore::draw(
   /* Bind and potentially refresh mesh/line/point data */
   /* Bind and potentially refresh mesh/line/point data */
   if (data.dirty)
   if (data.dirty)
   {
   {
-    opengl.set_data(data, invert_normals);
-    data.dirty = ViewerData::DIRTY_NONE;
+    data.updateGL(data, data.invert_normals,data.meshgl);
+    data.dirty = MeshGL::DIRTY_NONE;
   }
   }
-  opengl.bind_mesh();
+  data.meshgl.bind_mesh();
 
 
   // Initialize uniform
   // Initialize uniform
   glViewport(viewport(0), viewport(1), viewport(2), viewport(3));
   glViewport(viewport(0), viewport(1), viewport(2), viewport(3));
@@ -162,21 +162,21 @@ IGL_INLINE void igl::viewer::ViewerCore::draw(
   }
   }
 
 
   // Send transformations to the GPU
   // 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");
+  GLint modeli = glGetUniformLocation(data.meshgl.shader_mesh,"model");
+  GLint viewi  = glGetUniformLocation(data.meshgl.shader_mesh,"view");
+  GLint proji  = glGetUniformLocation(data.meshgl.shader_mesh,"proj");
   glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
   glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
   glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
   glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
   glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
   glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
 
 
   // Light parameters
   // 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");
+  GLint specular_exponenti    = glGetUniformLocation(data.meshgl.shader_mesh,"specular_exponent");
+  GLint light_position_worldi = glGetUniformLocation(data.meshgl.shader_mesh,"light_position_world");
+  GLint lighting_factori      = glGetUniformLocation(data.meshgl.shader_mesh,"lighting_factor");
+  GLint fixed_colori          = glGetUniformLocation(data.meshgl.shader_mesh,"fixed_color");
+  GLint texture_factori       = glGetUniformLocation(data.meshgl.shader_mesh,"texture_factor");
 
 
-  glUniform1f(specular_exponenti, shininess);
+  glUniform1f(specular_exponenti, data.shininess);
   Vector3f rev_light = -1.*light_position;
   Vector3f rev_light = -1.*light_position;
   glUniform3fv(light_position_worldi, 1, rev_light.data());
   glUniform3fv(light_position_worldi, 1, rev_light.data());
   glUniform1f(lighting_factori, lighting_factor); // enables lighting
   glUniform1f(lighting_factori, lighting_factor); // enables lighting
@@ -185,108 +185,72 @@ IGL_INLINE void igl::viewer::ViewerCore::draw(
   if (data.V.rows()>0)
   if (data.V.rows()>0)
   {
   {
     // Render fill
     // Render fill
-    if (show_faces)
+    if (data.show_faces)
     {
     {
       // Texture
       // Texture
-      glUniform1f(texture_factori, show_texture ? 1.0f : 0.0f);
-      opengl.draw_mesh(true);
+      glUniform1f(texture_factori, data.show_texture ? 1.0f : 0.0f);
+      data.meshgl.draw_mesh(true);
       glUniform1f(texture_factori, 0.0f);
       glUniform1f(texture_factori, 0.0f);
     }
     }
 
 
     // Render wireframe
     // Render wireframe
-    if (show_lines)
+    if (data.show_lines)
     {
     {
-      glLineWidth(line_width);
-      glUniform4f(fixed_colori, line_color[0], line_color[1],
-        line_color[2], 1.0f);
-      opengl.draw_mesh(false);
+      glLineWidth(data.line_width);
+      glUniform4f(fixed_colori, 
+        data.line_color[0], 
+        data.line_color[1],
+        data.line_color[2], 1.0f);
+      data.meshgl.draw_mesh(false);
       glUniform4f(fixed_colori, 0.0f, 0.0f, 0.0f, 0.0f);
       glUniform4f(fixed_colori, 0.0f, 0.0f, 0.0f, 0.0f);
     }
     }
-
-#ifdef IGL_VIEWER_WITH_NANOGUI
-    if (show_vertid)
-    {
-      textrenderer.BeginDraw(view*model, proj, viewport, object_scale);
-      for (int i=0; i<data.V.rows(); ++i)
-        textrenderer.DrawText(data.V.row(i),data.V_normals.row(i),to_string(i));
-      textrenderer.EndDraw();
-    }
-
-    if (show_faceid)
-    {
-      textrenderer.BeginDraw(view*model, proj, viewport, 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();
-
-        textrenderer.DrawText(p, data.F_normals.row(i), to_string(i));
-      }
-      textrenderer.EndDraw();
-    }
-#endif
   }
   }
 
 
-  if (show_overlay)
+  if (data.show_overlay)
   {
   {
-    if (show_overlay_depth)
+    if (data.show_overlay_depth)
       glEnable(GL_DEPTH_TEST);
       glEnable(GL_DEPTH_TEST);
     else
     else
       glDisable(GL_DEPTH_TEST);
       glDisable(GL_DEPTH_TEST);
 
 
     if (data.lines.rows() > 0)
     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");
+      data.meshgl.bind_overlay_lines();
+      modeli = glGetUniformLocation(data.meshgl.shader_overlay_lines,"model");
+      viewi  = glGetUniformLocation(data.meshgl.shader_overlay_lines,"view");
+      proji  = glGetUniformLocation(data.meshgl.shader_overlay_lines,"proj");
 
 
       glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
       glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
       glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
       glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
       glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
       glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
       // This must be enabled, otherwise glLineWidth has no effect
       // This must be enabled, otherwise glLineWidth has no effect
       glEnable(GL_LINE_SMOOTH);
       glEnable(GL_LINE_SMOOTH);
-      glLineWidth(line_width);
+      glLineWidth(data.line_width);
 
 
-      opengl.draw_overlay_lines();
+      data.meshgl.draw_overlay_lines();
     }
     }
 
 
     if (data.points.rows() > 0)
     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");
+      data.meshgl.bind_overlay_points();
+      modeli = glGetUniformLocation(data.meshgl.shader_overlay_points,"model");
+      viewi  = glGetUniformLocation(data.meshgl.shader_overlay_points,"view");
+      proji  = glGetUniformLocation(data.meshgl.shader_overlay_points,"proj");
 
 
       glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
       glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
       glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
       glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
       glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
       glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
-      glPointSize(point_size);
+      glPointSize(data.point_size);
 
 
-      opengl.draw_overlay_points();
+      data.meshgl.draw_overlay_points();
     }
     }
 
 
-#ifdef IGL_VIEWER_WITH_NANOGUI
-    if (data.labels_positions.rows() > 0)
-    {
-      textrenderer.BeginDraw(view*model, proj, viewport, object_scale);
-      for (int i=0; i<data.labels_positions.rows(); ++i)
-        textrenderer.DrawText(data.labels_positions.row(i), Eigen::Vector3d(0.0,0.0,0.0),
-            data.labels_strings[i]);
-      textrenderer.EndDraw();
-    }
-#endif
-
     glEnable(GL_DEPTH_TEST);
     glEnable(GL_DEPTH_TEST);
   }
   }
 
 
 }
 }
 
 
-IGL_INLINE void igl::viewer::ViewerCore::draw_buffer(ViewerData& data,
-  OpenGL_state& opengl,
+IGL_INLINE void igl::opengl::ViewerCore::draw_buffer(ViewerData& data,
   bool update_matrices,
   bool update_matrices,
   Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
   Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
   Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
   Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
@@ -336,7 +300,7 @@ IGL_INLINE void igl::viewer::ViewerCore::draw_buffer(ViewerData& data,
   viewport << 0,0,x,y;
   viewport << 0,0,x,y;
 
 
   // Draw
   // Draw
-  draw(data,opengl,update_matrices);
+  draw(data,update_matrices);
 
 
   // Restore viewport
   // Restore viewport
   viewport = viewport_ori;
   viewport = viewport_ori;
@@ -371,8 +335,8 @@ IGL_INLINE void igl::viewer::ViewerCore::draw_buffer(ViewerData& data,
   glDeleteFramebuffers(1, &frameBuffer);
   glDeleteFramebuffers(1, &frameBuffer);
 }
 }
 
 
-IGL_INLINE void igl::viewer::ViewerCore::set_rotation_type(
-  const igl::viewer::ViewerCore::RotationType & value)
+IGL_INLINE void igl::opengl::ViewerCore::set_rotation_type(
+  const igl::opengl::ViewerCore::RotationType & value)
 {
 {
   using namespace Eigen;
   using namespace Eigen;
   using namespace std;
   using namespace std;
@@ -386,14 +350,10 @@ IGL_INLINE void igl::viewer::ViewerCore::set_rotation_type(
 }
 }
 
 
 
 
-IGL_INLINE igl::viewer::ViewerCore::ViewerCore()
+IGL_INLINE igl::opengl::ViewerCore::ViewerCore()
 {
 {
-  // Default shininess
-  shininess = 35.0f;
-
   // Default colors
   // Default colors
   background_color << 0.3f, 0.3f, 0.5f, 1.0f;
   background_color << 0.3f, 0.3f, 0.5f, 1.0f;
-  line_color << 0.0f, 0.0f, 0.0f, 1.0f;
 
 
   // Default lights settings
   // Default lights settings
   light_position << 0.0f, -0.30f, -5.0f;
   light_position << 0.0f, -0.30f, -5.0f;
@@ -417,36 +377,18 @@ IGL_INLINE igl::viewer::ViewerCore::ViewerCore()
   camera_center << 0, 0, 0;
   camera_center << 0, 0, 0;
   camera_up << 0, 1, 0;
   camera_up << 0, 1, 0;
 
 
-  // Default visualization options
-  show_faces = true;
-  show_lines = true;
-  invert_normals = false;
-  show_overlay = true;
-  show_overlay_depth = true;
-  show_vertid = false;
-  show_faceid = false;
-  show_texture = false;
   depth_test = true;
   depth_test = true;
 
 
-  // Default point size / line width
-  point_size = 30;
-  line_width = 0.5f;
   is_animating = false;
   is_animating = false;
   animation_max_fps = 30.;
   animation_max_fps = 30.;
 
 
   viewport.setZero();
   viewport.setZero();
 }
 }
 
 
-IGL_INLINE void igl::viewer::ViewerCore::init()
+IGL_INLINE void igl::opengl::ViewerCore::init()
 {
 {
-#ifdef IGL_VIEWER_WITH_NANOGUI
-  textrenderer.Init();
-#endif
 }
 }
 
 
-IGL_INLINE void igl::viewer::ViewerCore::shut()
+IGL_INLINE void igl::opengl::ViewerCore::shut()
 {
 {
-#ifdef IGL_VIEWER_WITH_NANOGUI
-  textrenderer.Shut();
-#endif
 }
 }

+ 62 - 100
include/igl/viewer/ViewerCore.h → include/igl/opengl/ViewerCore.h

@@ -5,14 +5,11 @@
 // This Source Code Form is subject to the terms of the Mozilla Public License
 // 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
 // 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
-#ifndef IGL_VIEWER_VIEWER_CORE_H
-#define IGL_VIEWER_VIEWER_CORE_H
+#ifndef IGL_OPENGL_VIEWERCORE_H
+#define IGL_OPENGL_VIEWERCORE_H
 
 
-#include <igl/viewer/OpenGL_state.h>
-#ifdef IGL_VIEWER_WITH_NANOGUI
-#include <igl/viewer/TextRenderer.h>
-#endif
-#include <igl/viewer/ViewerData.h>
+#include <igl/opengl/MeshGL.h>
+#include <igl/opengl/ViewerData.h>
 
 
 #include <igl/igl_inline.h>
 #include <igl/igl_inline.h>
 #include <Eigen/Geometry>
 #include <Eigen/Geometry>
@@ -20,7 +17,7 @@
 
 
 namespace igl
 namespace igl
 {
 {
-namespace viewer
+namespace opengl
 {
 {
 
 
 // Basic class of the 3D mesh viewer
 // Basic class of the 3D mesh viewer
@@ -73,10 +70,11 @@ public:
   IGL_INLINE void clear_framebuffers();
   IGL_INLINE void clear_framebuffers();
 
 
   // Draw everything
   // Draw everything
-  IGL_INLINE void draw(ViewerData& data, OpenGL_state& opengl, bool update_matrices = true);
+  //
+  // data cannot be const because it is being set to "clean"
+  IGL_INLINE void draw(ViewerData& data, bool update_matrices = true);
   IGL_INLINE void draw_buffer(
   IGL_INLINE void draw_buffer(
     ViewerData& data,
     ViewerData& data,
-    OpenGL_state& opengl,
     bool update_matrices,
     bool update_matrices,
     Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
     Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
     Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
     Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
@@ -95,17 +93,8 @@ public:
 
 
   // ------------------- Properties
   // ------------------- Properties
 
 
-#ifdef IGL_VIEWER_WITH_NANOGUI
-  // Text rendering helper
-  TextRenderer textrenderer;
-#endif
-
-  // Shape material
-  float shininess;
-
   // Colors
   // Colors
   Eigen::Vector4f background_color;
   Eigen::Vector4f background_color;
-  Eigen::Vector4f line_color;
 
 
   // Lighting
   // Lighting
   Eigen::Vector3f light_position;
   Eigen::Vector3f light_position;
@@ -119,7 +108,7 @@ public:
   float model_zoom;
   float model_zoom;
   Eigen::Vector3f model_translation;
   Eigen::Vector3f model_translation;
 
 
-  // Model viewing paramters (uv coordinates)
+  // Model viewing parameters (uv coordinates)
   float model_zoom_uv;
   float model_zoom_uv;
   Eigen::Vector3f model_translation_uv;
   Eigen::Vector3f model_translation_uv;
 
 
@@ -133,21 +122,8 @@ public:
   float camera_dnear;
   float camera_dnear;
   float camera_dfar;
   float camera_dfar;
 
 
-  // Visualization options
-  bool show_overlay;
-  bool show_overlay_depth;
-  bool show_texture;
-  bool show_faces;
-  bool show_lines;
-  bool show_vertid;
-  bool show_faceid;
-  bool invert_normals;
   bool depth_test;
   bool depth_test;
 
 
-  // Point size / line width
-  float point_size;
-  float line_width;
-
   // Animation
   // Animation
   bool is_animating;
   bool is_animating;
   double animation_max_fps;
   double animation_max_fps;
@@ -158,7 +134,8 @@ public:
   // Viewport size
   // Viewport size
   Eigen::Vector4f viewport;
   Eigen::Vector4f viewport;
 
 
-  // Save the OpenGL transformation matrices used for the previous rendering pass
+  // Save the OpenGL transformation matrices used for the previous rendering
+  // pass
   Eigen::Matrix4f view;
   Eigen::Matrix4f view;
   Eigen::Matrix4f model;
   Eigen::Matrix4f model;
   Eigen::Matrix4f proj;
   Eigen::Matrix4f proj;
@@ -169,76 +146,61 @@ public:
 }
 }
 }
 }
 
 
-#ifdef ENABLE_SERIALIZATION
 #include <igl/serialize.h>
 #include <igl/serialize.h>
 namespace igl {
 namespace igl {
-	namespace serialization {
-
-		inline void serialization(bool s, igl::viewer::ViewerCore& obj, std::vector<char>& buffer)
-		{
-			SERIALIZE_MEMBER(shininess);
-
-			SERIALIZE_MEMBER(background_color);
-			SERIALIZE_MEMBER(line_color);
-
-			SERIALIZE_MEMBER(light_position);
-			SERIALIZE_MEMBER(lighting_factor);
-
-			SERIALIZE_MEMBER(trackball_angle);
-			SERIALIZE_MEMBER(rotation_type);
-
-			SERIALIZE_MEMBER(model_zoom);
-			SERIALIZE_MEMBER(model_translation);
-
-			SERIALIZE_MEMBER(model_zoom_uv);
-			SERIALIZE_MEMBER(model_translation_uv);
-
-			SERIALIZE_MEMBER(camera_zoom);
-			SERIALIZE_MEMBER(orthographic);
-			SERIALIZE_MEMBER(camera_view_angle);
-			SERIALIZE_MEMBER(camera_dnear);
-			SERIALIZE_MEMBER(camera_dfar);
-			SERIALIZE_MEMBER(camera_eye);
-			SERIALIZE_MEMBER(camera_center);
-			SERIALIZE_MEMBER(camera_up);
-
-			SERIALIZE_MEMBER(show_faces);
-			SERIALIZE_MEMBER(show_lines);
-			SERIALIZE_MEMBER(invert_normals);
-			SERIALIZE_MEMBER(show_overlay);
-			SERIALIZE_MEMBER(show_overlay_depth);
-			SERIALIZE_MEMBER(show_vertid);
-			SERIALIZE_MEMBER(show_faceid);
-			SERIALIZE_MEMBER(show_texture);
-			SERIALIZE_MEMBER(depth_test);
-
-			SERIALIZE_MEMBER(point_size);
-			SERIALIZE_MEMBER(line_width);
-			SERIALIZE_MEMBER(is_animating);
-			SERIALIZE_MEMBER(animation_max_fps);
-
-			SERIALIZE_MEMBER(object_scale);
-
-			SERIALIZE_MEMBER(viewport);
-			SERIALIZE_MEMBER(view);
-			SERIALIZE_MEMBER(model);
-			SERIALIZE_MEMBER(proj);
-		}
-
-		template<>
-		inline void serialize(const igl::viewer::ViewerCore& obj, std::vector<char>& buffer)
-		{
-			serialization(true, const_cast<igl::viewer::ViewerCore&>(obj), buffer);
-		}
-
-		template<>
-		inline void deserialize(igl::viewer::ViewerCore& obj, const std::vector<char>& buffer)
-		{
-			serialization(false, obj, const_cast<std::vector<char>&>(buffer));
-		}
+  namespace serialization {
+
+    inline void serialization(bool s, igl::opengl::ViewerCore& obj, std::vector<char>& buffer)
+    {
+
+      SERIALIZE_MEMBER(background_color);
+
+      SERIALIZE_MEMBER(light_position);
+      SERIALIZE_MEMBER(lighting_factor);
+
+      SERIALIZE_MEMBER(trackball_angle);
+      SERIALIZE_MEMBER(rotation_type);
+
+      SERIALIZE_MEMBER(model_zoom);
+      SERIALIZE_MEMBER(model_translation);
+
+      SERIALIZE_MEMBER(model_zoom_uv);
+      SERIALIZE_MEMBER(model_translation_uv);
+
+      SERIALIZE_MEMBER(camera_zoom);
+      SERIALIZE_MEMBER(orthographic);
+      SERIALIZE_MEMBER(camera_view_angle);
+      SERIALIZE_MEMBER(camera_dnear);
+      SERIALIZE_MEMBER(camera_dfar);
+      SERIALIZE_MEMBER(camera_eye);
+      SERIALIZE_MEMBER(camera_center);
+      SERIALIZE_MEMBER(camera_up);
+
+      SERIALIZE_MEMBER(depth_test);
+      SERIALIZE_MEMBER(is_animating);
+      SERIALIZE_MEMBER(animation_max_fps);
+
+      SERIALIZE_MEMBER(object_scale);
+
+      SERIALIZE_MEMBER(viewport);
+      SERIALIZE_MEMBER(view);
+      SERIALIZE_MEMBER(model);
+      SERIALIZE_MEMBER(proj);
+    }
+
+    template<>
+    inline void serialize(const igl::opengl::ViewerCore& obj, std::vector<char>& buffer)
+    {
+      serialization(true, const_cast<igl::opengl::ViewerCore&>(obj), buffer);
+    }
+
+    template<>
+    inline void deserialize(igl::opengl::ViewerCore& obj, const std::vector<char>& buffer)
+    {
+      serialization(false, obj, const_cast<std::vector<char>&>(buffer));
+    }
   }
   }
 }
 }
-#endif
 
 
 #ifndef IGL_STATIC_LIBRARY
 #ifndef IGL_STATIC_LIBRARY
 #  include "ViewerCore.cpp"
 #  include "ViewerCore.cpp"

+ 689 - 0
include/igl/opengl/ViewerData.cpp

@@ -0,0 +1,689 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "ViewerData.h"
+
+#include "../per_face_normals.h"
+#include "../material_colors.h"
+#include "../parula.h"
+#include "../per_vertex_normals.h"
+
+#include <iostream>
+
+
+IGL_INLINE igl::opengl::ViewerData::ViewerData()
+: dirty(MeshGL::DIRTY_ALL),
+  show_faces(true),
+  show_lines(true),
+  invert_normals(false),
+  show_overlay(true),
+  show_overlay_depth(true),
+  show_vertid(false),
+  show_faceid(false),
+  show_texture(false),
+  point_size(30),
+  line_width(0.5f),
+  line_color(0,0,0,1),
+  shininess(35.0f)
+{
+  clear();
+};
+
+IGL_INLINE void igl::opengl::ViewerData::set_face_based(bool newvalue)
+{
+  if (face_based != newvalue)
+  {
+    face_based = newvalue;
+    dirty = MeshGL::DIRTY_ALL;
+  }
+}
+
+// Helpers that draws the most common meshes
+IGL_INLINE void igl::opengl::ViewerData::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 (V.rows() == 0 && F.rows() == 0)
+  {
+    V = V_temp;
+    F = _F;
+
+    compute_normals();
+    uniform_colors(
+      Eigen::Vector3d(GOLD_AMBIENT[0], GOLD_AMBIENT[1], GOLD_AMBIENT[2]),
+      Eigen::Vector3d(GOLD_DIFFUSE[0], GOLD_DIFFUSE[1], GOLD_DIFFUSE[2]),
+      Eigen::Vector3d(GOLD_SPECULAR[0], GOLD_SPECULAR[1], GOLD_SPECULAR[2]));
+
+    grid_texture();
+  }
+  else
+  {
+    if (_V.rows() == V.rows() && _F.rows() == F.rows())
+    {
+      V = V_temp;
+      F = _F;
+    }
+    else
+      cerr << "ERROR (set_mesh): The new mesh has a different number of vertices/faces. Please clear the mesh before plotting."<<endl;
+  }
+  dirty |= MeshGL::DIRTY_FACE | MeshGL::DIRTY_POSITION;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_vertices(const Eigen::MatrixXd& _V)
+{
+  V = _V;
+  assert(F.size() == 0 || F.maxCoeff() < V.rows());
+  dirty |= MeshGL::DIRTY_POSITION;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_normals(const Eigen::MatrixXd& N)
+{
+  using namespace std;
+  if (N.rows() == V.rows())
+  {
+    set_face_based(false);
+    V_normals = N;
+  }
+  else if (N.rows() == F.rows() || N.rows() == F.rows()*3)
+  {
+    set_face_based(true);
+    F_normals = N;
+  }
+  else
+    cerr << "ERROR (set_normals): Please provide a normal per face, per corner or per vertex."<<endl;
+  dirty |= MeshGL::DIRTY_NORMAL;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_colors(const Eigen::MatrixXd &C)
+{
+  using namespace std;
+  using namespace Eigen;
+  if(C.rows()>0 && C.cols() == 1)
+  {
+    Eigen::MatrixXd C3;
+    igl::parula(C,true,C3);
+    return set_colors(C3);
+  }
+  // Ambient color should be darker color
+  const auto ambient = [](const MatrixXd & C)->MatrixXd
+  {
+    MatrixXd T = 0.1*C;
+    T.col(3) = C.col(3);
+    return T;
+  };
+  // Specular color should be a less saturated and darker color: dampened
+  // highlights
+  const auto specular = [](const MatrixXd & C)->MatrixXd
+  {
+    const double grey = 0.3;
+    MatrixXd T = grey+0.1*(C.array()-grey);
+    T.col(3) = C.col(3);
+    return T;
+  };
+  if (C.rows() == 1)
+  {
+    for (unsigned i=0;i<V_material_diffuse.rows();++i)
+    {
+      if (C.cols() == 3)
+        V_material_diffuse.row(i) << C.row(0),1;
+      else if (C.cols() == 4)
+        V_material_diffuse.row(i) << C.row(0);
+    }
+    V_material_ambient = ambient(V_material_diffuse);
+    V_material_specular = specular(V_material_diffuse);
+
+    for (unsigned i=0;i<F_material_diffuse.rows();++i)
+    {
+      if (C.cols() == 3)
+        F_material_diffuse.row(i) << C.row(0),1;
+      else if (C.cols() == 4)
+        F_material_diffuse.row(i) << C.row(0);
+    }
+    F_material_ambient = ambient(F_material_diffuse);
+    F_material_specular = specular(F_material_diffuse);
+  }
+  else if (C.rows() == V.rows())
+  {
+    set_face_based(false);
+    for (unsigned i=0;i<V_material_diffuse.rows();++i)
+    {
+      if (C.cols() == 3)
+        V_material_diffuse.row(i) << C.row(i), 1;
+      else if (C.cols() == 4)
+        V_material_diffuse.row(i) << C.row(i);
+    }
+    V_material_ambient = ambient(V_material_diffuse);
+    V_material_specular = specular(V_material_diffuse);
+  }
+  else if (C.rows() == F.rows())
+  {
+    set_face_based(true);
+    for (unsigned i=0;i<F_material_diffuse.rows();++i)
+    {
+      if (C.cols() == 3)
+        F_material_diffuse.row(i) << C.row(i), 1;
+      else if (C.cols() == 4)
+        F_material_diffuse.row(i) << C.row(i);
+    }
+    F_material_ambient = ambient(F_material_diffuse);
+    F_material_specular = specular(F_material_diffuse);
+  }
+  else
+    cerr << "ERROR (set_colors): Please provide a single color, or a color per face or per vertex."<<endl;
+  dirty |= MeshGL::DIRTY_DIFFUSE;
+
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_uv(const Eigen::MatrixXd& UV)
+{
+  using namespace std;
+  if (UV.rows() == V.rows())
+  {
+    set_face_based(false);
+    V_uv = UV;
+  }
+  else
+    cerr << "ERROR (set_UV): Please provide uv per vertex."<<endl;;
+  dirty |= MeshGL::DIRTY_UV;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F)
+{
+  set_face_based(true);
+  V_uv = UV_V.block(0,0,UV_V.rows(),2);
+  F_uv = UV_F;
+  dirty |= MeshGL::DIRTY_UV;
+}
+
+
+IGL_INLINE void igl::opengl::ViewerData::set_texture(
+  const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
+  const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
+  const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B)
+{
+  texture_R = R;
+  texture_G = G;
+  texture_B = B;
+  texture_A = Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>::Constant(R.rows(),R.cols(),255);
+  dirty |= MeshGL::DIRTY_TEXTURE;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_texture(
+  const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
+  const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
+  const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
+  const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A)
+{
+  texture_R = R;
+  texture_G = G;
+  texture_B = B;
+  texture_A = A;
+  dirty |= MeshGL::DIRTY_TEXTURE;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_points(
+  const Eigen::MatrixXd& P,
+  const Eigen::MatrixXd& C)
+{
+  // clear existing points
+  points.resize(0,0);
+  add_points(P,C);
+}
+
+IGL_INLINE void igl::opengl::ViewerData::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 = points.rows();
+  points.conservativeResize(points.rows() + P_temp.rows(),6);
+  for (unsigned i=0; i<P_temp.rows(); ++i)
+    points.row(lastid+i) << P_temp.row(i), i<C.rows() ? C.row(i) : C.row(C.rows()-1);
+
+  dirty |= MeshGL::DIRTY_OVERLAY_POINTS;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_edges(
+  const Eigen::MatrixXd& P,
+  const Eigen::MatrixXi& E,
+  const Eigen::MatrixXd& C)
+{
+  using namespace Eigen;
+  lines.resize(E.rows(),9);
+  assert(C.cols() == 3);
+  for(int e = 0;e<E.rows();e++)
+  {
+    RowVector3d color;
+    if(C.size() == 3)
+    {
+      color<<C;
+    }else if(C.rows() == E.rows())
+    {
+      color<<C.row(e);
+    }
+    lines.row(e)<< P.row(E(e,0)), P.row(E(e,1)), color;
+  }
+  dirty |= MeshGL::DIRTY_OVERLAY_LINES;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::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 = lines.rows();
+  lines.conservativeResize(lines.rows() + P1_temp.rows(),9);
+  for (unsigned i=0; i<P1_temp.rows(); ++i)
+    lines.row(lastid+i) << P1_temp.row(i), P2_temp.row(i), i<C.rows() ? C.row(i) : C.row(C.rows()-1);
+
+  dirty |= MeshGL::DIRTY_OVERLAY_LINES;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::add_label(const Eigen::VectorXd& P,  const std::string& str)
+{
+  Eigen::RowVectorXd P_temp;
+
+  // If P only has two columns, pad with a column of zeros
+  if (P.size() == 2)
+  {
+    P_temp = Eigen::RowVectorXd::Zero(3);
+    P_temp << P.transpose(), 0;
+  }
+  else
+    P_temp = P;
+
+  int lastid = labels_positions.rows();
+  labels_positions.conservativeResize(lastid+1, 3);
+  labels_positions.row(lastid) = P_temp;
+  labels_strings.push_back(str);
+}
+
+IGL_INLINE void igl::opengl::ViewerData::clear()
+{
+  V                       = Eigen::MatrixXd (0,3);
+  F                       = Eigen::MatrixXi (0,3);
+
+  F_material_ambient      = Eigen::MatrixXd (0,4);
+  F_material_diffuse      = Eigen::MatrixXd (0,4);
+  F_material_specular     = Eigen::MatrixXd (0,4);
+
+  V_material_ambient      = Eigen::MatrixXd (0,4);
+  V_material_diffuse      = Eigen::MatrixXd (0,4);
+  V_material_specular     = Eigen::MatrixXd (0,4);
+
+  F_normals               = Eigen::MatrixXd (0,3);
+  V_normals               = Eigen::MatrixXd (0,3);
+
+  V_uv                    = Eigen::MatrixXd (0,2);
+  F_uv                    = Eigen::MatrixXi (0,3);
+
+  lines                   = Eigen::MatrixXd (0,9);
+  points                  = Eigen::MatrixXd (0,6);
+  labels_positions        = Eigen::MatrixXd (0,3);
+  labels_strings.clear();
+
+  face_based = false;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::compute_normals()
+{
+  igl::per_face_normals(V, F, F_normals);
+  igl::per_vertex_normals(V, F, F_normals, V_normals);
+  dirty |= MeshGL::DIRTY_NORMAL;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::uniform_colors(
+  const Eigen::Vector3d& ambient,
+  const Eigen::Vector3d& diffuse,
+  const Eigen::Vector3d& specular)
+{
+  Eigen::Vector4d ambient4;
+  Eigen::Vector4d diffuse4;
+  Eigen::Vector4d specular4;
+
+  ambient4 << ambient, 1;
+  diffuse4 << diffuse, 1;
+  specular4 << specular, 1;
+
+  uniform_colors(ambient4,diffuse4,specular4);
+}
+
+IGL_INLINE void igl::opengl::ViewerData::uniform_colors(
+  const Eigen::Vector4d& ambient,
+  const Eigen::Vector4d& diffuse,
+  const Eigen::Vector4d& specular)
+{
+  V_material_ambient.resize(V.rows(),4);
+  V_material_diffuse.resize(V.rows(),4);
+  V_material_specular.resize(V.rows(),4);
+
+  for (unsigned i=0; i<V.rows();++i)
+  {
+    V_material_ambient.row(i) = ambient;
+    V_material_diffuse.row(i) = diffuse;
+    V_material_specular.row(i) = specular;
+  }
+
+  F_material_ambient.resize(F.rows(),4);
+  F_material_diffuse.resize(F.rows(),4);
+  F_material_specular.resize(F.rows(),4);
+
+  for (unsigned i=0; i<F.rows();++i)
+  {
+    F_material_ambient.row(i) = ambient;
+    F_material_diffuse.row(i) = diffuse;
+    F_material_specular.row(i) = specular;
+  }
+  dirty |= MeshGL::DIRTY_SPECULAR | MeshGL::DIRTY_DIFFUSE | MeshGL::DIRTY_AMBIENT;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::grid_texture()
+{
+  // Don't do anything for an empty mesh
+  if(V.rows() == 0)
+  {
+    V_uv.resize(V.rows(),2);
+    return;
+  }
+  if (V_uv.rows() == 0)
+  {
+    V_uv = V.block(0, 0, V.rows(), 2);
+    V_uv.col(0) = V_uv.col(0).array() - V_uv.col(0).minCoeff();
+    V_uv.col(0) = V_uv.col(0).array() / V_uv.col(0).maxCoeff();
+    V_uv.col(1) = V_uv.col(1).array() - V_uv.col(1).minCoeff();
+    V_uv.col(1) = V_uv.col(1).array() / V_uv.col(1).maxCoeff();
+    V_uv = V_uv.array() * 10;
+    dirty |= MeshGL::DIRTY_TEXTURE;
+  }
+
+  unsigned size = 128;
+  unsigned size2 = size/2;
+  texture_R.resize(size, size);
+  for (unsigned i=0; i<size; ++i)
+  {
+    for (unsigned j=0; j<size; ++j)
+    {
+      texture_R(i,j) = 0;
+      if ((i<size2 && j<size2) || (i>=size2 && j>=size2))
+        texture_R(i,j) = 255;
+    }
+  }
+
+  texture_G = texture_R;
+  texture_B = texture_R;
+  texture_A = Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>::Constant(texture_R.rows(),texture_R.cols(),255);
+  dirty |= MeshGL::DIRTY_TEXTURE;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::updateGL(
+  const igl::opengl::ViewerData& data,
+  const bool invert_normals,
+  igl::opengl::MeshGL& meshgl
+  )
+{
+  if (!meshgl.is_initialized)
+  {
+    meshgl.init();
+  }
+
+  bool per_corner_uv = (data.F_uv.rows() == data.F.rows());
+  bool per_corner_normals = (data.F_normals.rows() == 3 * data.F.rows());
+
+  meshgl.dirty |= data.dirty;
+
+  // Input:
+  //   X  #F by dim quantity
+  // Output:
+  //   X_vbo  #F*3 by dim scattering per corner
+  const auto per_face = [&data](
+      const Eigen::MatrixXd & X,
+      MeshGL::RowMatrixXf & X_vbo)
+  {
+    assert(X.cols() == 4);
+    X_vbo.resize(data.F.rows()*3,4);
+    for (unsigned i=0; i<data.F.rows();++i)
+      for (unsigned j=0;j<3;++j)
+        X_vbo.row(i*3+j) = X.row(i).cast<float>();
+  };
+
+  // Input:
+  //   X  #V by dim quantity
+  // Output:
+  //   X_vbo  #F*3 by dim scattering per corner
+  const auto per_corner = [&data](
+      const Eigen::MatrixXd & X,
+      MeshGL::RowMatrixXf & X_vbo)
+  {
+    X_vbo.resize(data.F.rows()*3,X.cols());
+    for (unsigned i=0; i<data.F.rows();++i)
+      for (unsigned j=0;j<3;++j)
+        X_vbo.row(i*3+j) = X.row(data.F(i,j)).cast<float>();
+  };
+
+  if (!data.face_based)
+  {
+    if (!(per_corner_uv || per_corner_normals))
+    {
+      // Vertex positions
+      if (meshgl.dirty & MeshGL::DIRTY_POSITION)
+        meshgl.V_vbo = data.V.cast<float>();
+
+      // Vertex normals
+      if (meshgl.dirty & MeshGL::DIRTY_NORMAL)
+      {
+        meshgl.V_normals_vbo = data.V_normals.cast<float>();
+        if (invert_normals)
+          meshgl.V_normals_vbo = -meshgl.V_normals_vbo;
+      }
+
+      // Per-vertex material settings
+      if (meshgl.dirty & MeshGL::DIRTY_AMBIENT)
+        meshgl.V_ambient_vbo = data.V_material_ambient.cast<float>();
+      if (meshgl.dirty & MeshGL::DIRTY_DIFFUSE)
+        meshgl.V_diffuse_vbo = data.V_material_diffuse.cast<float>();
+      if (meshgl.dirty & MeshGL::DIRTY_SPECULAR)
+        meshgl.V_specular_vbo = data.V_material_specular.cast<float>();
+
+      // Face indices
+      if (meshgl.dirty & MeshGL::DIRTY_FACE)
+        meshgl.F_vbo = data.F.cast<unsigned>();
+
+      // Texture coordinates
+      if (meshgl.dirty & MeshGL::DIRTY_UV)
+        meshgl.V_uv_vbo = data.V_uv.cast<float>();
+    }
+    else
+    {
+
+      // Per vertex properties with per corner UVs
+      if (meshgl.dirty & MeshGL::DIRTY_POSITION)
+      {
+        per_corner(data.V,meshgl.V_vbo);
+      }
+
+      if (meshgl.dirty & MeshGL::DIRTY_AMBIENT)
+      {
+        meshgl.V_ambient_vbo.resize(4,data.F.rows()*3);
+        for (unsigned i=0; i<data.F.rows();++i)
+          for (unsigned j=0;j<3;++j)
+            meshgl.V_ambient_vbo.col (i*3+j) = data.V_material_ambient.row(data.F(i,j)).transpose().cast<float>();
+      }
+      if (meshgl.dirty & MeshGL::DIRTY_DIFFUSE)
+      {
+        meshgl.V_diffuse_vbo.resize(4,data.F.rows()*3);
+        for (unsigned i=0; i<data.F.rows();++i)
+          for (unsigned j=0;j<3;++j)
+            meshgl.V_diffuse_vbo.col (i*3+j) = data.V_material_diffuse.row(data.F(i,j)).transpose().cast<float>();
+      }
+      if (meshgl.dirty & MeshGL::DIRTY_SPECULAR)
+      {
+        meshgl.V_specular_vbo.resize(4,data.F.rows()*3);
+        for (unsigned i=0; i<data.F.rows();++i)
+          for (unsigned j=0;j<3;++j)
+            meshgl.V_specular_vbo.col(i*3+j) = data.V_material_specular.row(data.F(i,j)).transpose().cast<float>();
+      }
+
+      if (meshgl.dirty & MeshGL::DIRTY_NORMAL)
+      {
+        meshgl.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)
+
+            meshgl.V_normals_vbo.col (i*3+j) =
+                         per_corner_normals ?
+               data.F_normals.row(i*3+j).transpose().cast<float>() :
+               data.V_normals.row(data.F(i,j)).transpose().cast<float>();
+
+
+        if (invert_normals)
+          meshgl.V_normals_vbo = -meshgl.V_normals_vbo;
+      }
+
+      if (meshgl.dirty & MeshGL::DIRTY_FACE)
+      {
+        meshgl.F_vbo.resize(data.F.rows(),3);
+        for (unsigned i=0; i<data.F.rows();++i)
+          meshgl.F_vbo.row(i) << i*3+0, i*3+1, i*3+2;
+      }
+
+      if (meshgl.dirty & MeshGL::DIRTY_UV)
+      {
+        meshgl.V_uv_vbo.resize(data.F.rows()*3,2);
+        for (unsigned i=0; i<data.F.rows();++i)
+          for (unsigned j=0;j<3;++j)
+            meshgl.V_uv_vbo.row(i*3+j) =
+              data.V_uv.row(per_corner_uv ?
+                data.F_uv(i,j) : data.F(i,j)).cast<float>();
+      }
+    }
+  }
+  else
+  {
+    if (meshgl.dirty & MeshGL::DIRTY_POSITION)
+    {
+      per_corner(data.V,meshgl.V_vbo);
+    }
+    if (meshgl.dirty & MeshGL::DIRTY_AMBIENT)
+    {
+      per_face(data.F_material_ambient,meshgl.V_ambient_vbo);
+    }
+    if (meshgl.dirty & MeshGL::DIRTY_DIFFUSE)
+    {
+      per_face(data.F_material_diffuse,meshgl.V_diffuse_vbo);
+    }
+    if (meshgl.dirty & MeshGL::DIRTY_SPECULAR)
+    {
+      per_face(data.F_material_specular,meshgl.V_specular_vbo);
+    }
+
+    if (meshgl.dirty & MeshGL::DIRTY_NORMAL)
+    {
+      meshgl.V_normals_vbo.resize(data.F.rows()*3,3);
+      for (unsigned i=0; i<data.F.rows();++i)
+        for (unsigned j=0;j<3;++j)
+          meshgl.V_normals_vbo.row(i*3+j) =
+             per_corner_normals ?
+               data.F_normals.row(i*3+j).cast<float>() :
+               data.F_normals.row(i).cast<float>();
+
+      if (invert_normals)
+        meshgl.V_normals_vbo = -meshgl.V_normals_vbo;
+    }
+
+    if (meshgl.dirty & MeshGL::DIRTY_FACE)
+    {
+      meshgl.F_vbo.resize(data.F.rows(),3);
+      for (unsigned i=0; i<data.F.rows();++i)
+        meshgl.F_vbo.row(i) << i*3+0, i*3+1, i*3+2;
+    }
+
+    if (meshgl.dirty & MeshGL::DIRTY_UV)
+    {
+        meshgl.V_uv_vbo.resize(data.F.rows()*3,2);
+        for (unsigned i=0; i<data.F.rows();++i)
+          for (unsigned j=0;j<3;++j)
+            meshgl.V_uv_vbo.row(i*3+j) = data.V_uv.row(per_corner_uv ? data.F_uv(i,j) : data.F(i,j)).cast<float>();
+    }
+  }
+
+  if (meshgl.dirty & MeshGL::DIRTY_TEXTURE)
+  {
+    meshgl.tex_u = data.texture_R.rows();
+    meshgl.tex_v = data.texture_R.cols();
+    meshgl.tex.resize(data.texture_R.size()*4);
+    for (unsigned i=0;i<data.texture_R.size();++i)
+    {
+      meshgl.tex(i*4+0) = data.texture_R(i);
+      meshgl.tex(i*4+1) = data.texture_G(i);
+      meshgl.tex(i*4+2) = data.texture_B(i);
+      meshgl.tex(i*4+3) = data.texture_A(i);
+    }
+  }
+
+  if (meshgl.dirty & MeshGL::DIRTY_OVERLAY_LINES)
+  {
+    meshgl.lines_V_vbo.resize(data.lines.rows()*2,3);
+    meshgl.lines_V_colors_vbo.resize(data.lines.rows()*2,3);
+    meshgl.lines_F_vbo.resize(data.lines.rows()*2,1);
+    for (unsigned i=0; i<data.lines.rows();++i)
+    {
+      meshgl.lines_V_vbo.row(2*i+0) = data.lines.block<1, 3>(i, 0).cast<float>();
+      meshgl.lines_V_vbo.row(2*i+1) = data.lines.block<1, 3>(i, 3).cast<float>();
+      meshgl.lines_V_colors_vbo.row(2*i+0) = data.lines.block<1, 3>(i, 6).cast<float>();
+      meshgl.lines_V_colors_vbo.row(2*i+1) = data.lines.block<1, 3>(i, 6).cast<float>();
+      meshgl.lines_F_vbo(2*i+0) = 2*i+0;
+      meshgl.lines_F_vbo(2*i+1) = 2*i+1;
+    }
+  }
+
+  if (meshgl.dirty & MeshGL::DIRTY_OVERLAY_POINTS)
+  {
+    meshgl.points_V_vbo.resize(data.points.rows(),3);
+    meshgl.points_V_colors_vbo.resize(data.points.rows(),3);
+    meshgl.points_F_vbo.resize(data.points.rows(),1);
+    for (unsigned i=0; i<data.points.rows();++i)
+    {
+      meshgl.points_V_vbo.row(i) = data.points.block<1, 3>(i, 0).cast<float>();
+      meshgl.points_V_colors_vbo.row(i) = data.points.block<1, 3>(i, 3).cast<float>();
+      meshgl.points_F_vbo(i) = i;
+    }
+  }
+}

+ 127 - 77
include/igl/viewer/ViewerData.h → include/igl/opengl/ViewerData.h

@@ -5,46 +5,34 @@
 // This Source Code Form is subject to the terms of the Mozilla Public License
 // 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
 // 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
-#ifndef IGL_VIEWER_VIEWER_DATA_H
-#define IGL_VIEWER_VIEWER_DATA_H
+#ifndef IGL_VIEWERDATA_H
+#define IGL_VIEWERDATA_H
 
 
+#include "../igl_inline.h"
+#include "../Attribute.h"
+#include "MeshGL.h"
+#include <cassert>
 #include <cstdint>
 #include <cstdint>
-#include <vector>
-
 #include <Eigen/Core>
 #include <Eigen/Core>
+#include <memory>
+#include <vector>
 
 
-#include <igl/igl_inline.h>
-
+// Alec: This is a mesh class containing a variety of data types (normals,
+// overlays, material colors, etc.)
+//
 namespace igl
 namespace igl
 {
 {
-namespace viewer
-{
 
 
 // TODO: write documentation
 // TODO: write documentation
+namespace opengl
+{
 
 
 class ViewerData
 class ViewerData
 {
 {
 public:
 public:
   ViewerData();
   ViewerData();
 
 
-  enum DirtyFlags
-  {
-    DIRTY_NONE           = 0x0000,
-    DIRTY_POSITION       = 0x0001,
-    DIRTY_UV             = 0x0002,
-    DIRTY_NORMAL         = 0x0004,
-    DIRTY_AMBIENT        = 0x0008,
-    DIRTY_DIFFUSE        = 0x0010,
-    DIRTY_SPECULAR       = 0x0020,
-    DIRTY_TEXTURE        = 0x0040,
-    DIRTY_FACE           = 0x0080,
-    DIRTY_MESH           = 0x00FF,
-    DIRTY_OVERLAY_LINES  = 0x0100,
-    DIRTY_OVERLAY_POINTS = 0x0200,
-    DIRTY_ALL            = 0x03FF
-  };
-
-  // Empy all fields
+  // Empty all fields
   IGL_INLINE void clear();
   IGL_INLINE void clear();
 
 
   // Change the visualization mode, invalidating the cache if necessary
   // Change the visualization mode, invalidating the cache if necessary
@@ -186,66 +174,128 @@ public:
 
 
   // Enable per-face or per-vertex properties
   // Enable per-face or per-vertex properties
   bool face_based;
   bool face_based;
-  /*********************************/
+
+  // Visualization options
+  bool show_overlay;
+  bool show_overlay_depth;
+  bool show_texture;
+  bool show_faces;
+  bool show_lines;
+  bool show_vertid;
+  bool show_faceid;
+  bool invert_normals;
+
+  // Point size / line width
+  float point_size;
+  float line_width;
+  Eigen::Vector4f line_color;
+
+  // Shape material
+  float shininess;
+
+  // OpenGL representation of the mesh
+  igl::opengl::MeshGL meshgl;
+
+  // User-defined attribute
+  std::shared_ptr<AttributeBase> attr_ptr;
+
+  // Retrieve custom attribute
+  template<typename T> T & attr();
+  template<typename T> const T & attr() const;
+
+  // Update contents from a 'Data' instance
+  IGL_INLINE void updateGL(
+    const igl::opengl::ViewerData& data,
+    const bool invert_normals,
+    igl::opengl::MeshGL& meshgl);
 };
 };
 
 
-}
-}
+// -----------------------------------------------------------------------------
 
 
-#ifdef ENABLE_SERIALIZATION
-#include <igl/serialize.h>
-namespace igl {
-	namespace serialization {
-
-		inline void serialization(bool s, igl::viewer::ViewerData& obj, std::vector<char>& buffer)
-		{
-			SERIALIZE_MEMBER(V);
-			SERIALIZE_MEMBER(F);
-
-			SERIALIZE_MEMBER(F_normals);
-			SERIALIZE_MEMBER(F_material_ambient);
-			SERIALIZE_MEMBER(F_material_diffuse);
-			SERIALIZE_MEMBER(F_material_specular);
-
-			SERIALIZE_MEMBER(V_normals);
-			SERIALIZE_MEMBER(V_material_ambient);
-			SERIALIZE_MEMBER(V_material_diffuse);
-			SERIALIZE_MEMBER(V_material_specular);
-
-			SERIALIZE_MEMBER(V_uv);
-			SERIALIZE_MEMBER(F_uv);
-
-			SERIALIZE_MEMBER(texture_R);
-			SERIALIZE_MEMBER(texture_G);
-			SERIALIZE_MEMBER(texture_B);
-      SERIALIZE_MEMBER(texture_A);
-
-			SERIALIZE_MEMBER(lines);
-			SERIALIZE_MEMBER(points);
+// Retrieve custom attribute
+template<typename T>
+inline T & ViewerData::attr()
+{
+  if (!attr_ptr)
+  {
+    attr_ptr = std::make_shared<Attribute<T>>();
+  }
+  auto * derived = dynamic_cast<Attribute<T> *>(attr_ptr.get());
+  assert(derived && "Incompatible type requested for attribute");
+  return derived->content_;
+}
 
 
-			SERIALIZE_MEMBER(labels_positions);
-			SERIALIZE_MEMBER(labels_strings);
 
 
-			SERIALIZE_MEMBER(dirty);
+// Retrieve custom attribute
+template<typename T>
+inline const T & ViewerData::attr() const
+{
+  assert(attr_ptr);
+  const auto * derived = dynamic_cast<const Attribute<T> *>(attr_ptr.get());
+  assert(derived && "Incompatible type requested for attribute");
+  return derived->content_;
+}
 
 
-			SERIALIZE_MEMBER(face_based);
-		}
+} // namespace opengl
+} // namespace igl
 
 
-		template<>
-		inline void serialize(const igl::viewer::ViewerData& obj, std::vector<char>& buffer)
-		{
-			serialization(true, const_cast<igl::viewer::ViewerData&>(obj), buffer);
-		}
+////////////////////////////////////////////////////////////////////////////////
 
 
-		template<>
-		inline void deserialize(igl::viewer::ViewerData& obj, const std::vector<char>& buffer)
-		{
-			serialization(false, obj, const_cast<std::vector<char>&>(buffer));
-			obj.dirty = igl::viewer::ViewerData::DIRTY_ALL;
-		}
-	}
+#include <igl/serialize.h>
+namespace igl
+{
+  namespace serialization
+  {
+    inline void serialization(bool s, igl::opengl::ViewerData& obj, std::vector<char>& buffer)
+    {
+      SERIALIZE_MEMBER(V);
+      SERIALIZE_MEMBER(F);
+      SERIALIZE_MEMBER(F_normals);
+      SERIALIZE_MEMBER(F_material_ambient);
+      SERIALIZE_MEMBER(F_material_diffuse);
+      SERIALIZE_MEMBER(F_material_specular);
+      SERIALIZE_MEMBER(V_normals);
+      SERIALIZE_MEMBER(V_material_ambient);
+      SERIALIZE_MEMBER(V_material_diffuse);
+      SERIALIZE_MEMBER(V_material_specular);
+      SERIALIZE_MEMBER(V_uv);
+      SERIALIZE_MEMBER(F_uv);
+      SERIALIZE_MEMBER(texture_R);
+      SERIALIZE_MEMBER(texture_G);
+      SERIALIZE_MEMBER(texture_B);
+      SERIALIZE_MEMBER(texture_A);
+      SERIALIZE_MEMBER(lines);
+      SERIALIZE_MEMBER(points);
+      SERIALIZE_MEMBER(labels_positions);
+      SERIALIZE_MEMBER(labels_strings);
+      SERIALIZE_MEMBER(dirty);
+      SERIALIZE_MEMBER(face_based);
+      SERIALIZE_MEMBER(show_faces);
+      SERIALIZE_MEMBER(show_lines);
+      SERIALIZE_MEMBER(invert_normals);
+      SERIALIZE_MEMBER(show_overlay);
+      SERIALIZE_MEMBER(show_overlay_depth);
+      SERIALIZE_MEMBER(show_vertid);
+      SERIALIZE_MEMBER(show_faceid);
+      SERIALIZE_MEMBER(show_texture);
+      SERIALIZE_MEMBER(point_size);
+      SERIALIZE_MEMBER(line_width);
+      SERIALIZE_MEMBER(line_color);
+      SERIALIZE_MEMBER(shininess);
+    }
+    template<>
+    inline void serialize(const igl::opengl::ViewerData& obj, std::vector<char>& buffer)
+    {
+      serialization(true, const_cast<igl::opengl::ViewerData&>(obj), buffer);
+    }
+    template<>
+    inline void deserialize(igl::opengl::ViewerData& obj, const std::vector<char>& buffer)
+    {
+      serialization(false, obj, const_cast<std::vector<char>&>(buffer));
+      obj.dirty = igl::opengl::MeshGL::DIRTY_ALL;
+    }
+  }
 }
 }
-#endif
 
 
 #ifndef IGL_STATIC_LIBRARY
 #ifndef IGL_STATIC_LIBRARY
 #  include "ViewerData.cpp"
 #  include "ViewerData.cpp"

+ 24 - 0
include/igl/opengl/bind_vertex_attrib_array.cpp

@@ -0,0 +1,24 @@
+#include "bind_vertex_attrib_array.h"
+
+IGL_INLINE GLint igl::opengl::bind_vertex_attrib_array(
+  const GLuint program_shader,
+  const std::string &name, 
+  GLuint bufferID, 
+  const Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> &M, 
+  bool refresh)
+{
+  GLint id = glGetAttribLocation(program_shader, name.c_str());
+  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.cols(), GL_FLOAT, GL_FALSE, 0, 0);
+  glEnableVertexAttribArray(id);
+  return id;
+}

+ 32 - 0
include/igl/opengl/bind_vertex_attrib_array.h

@@ -0,0 +1,32 @@
+#ifndef IGL_OPENGL_BIND_VERTEX_ATTRIB_ARRAY_H
+#define IGL_OPENGL_BIND_VERTEX_ATTRIB_ARRAY_H
+#include "gl.h"
+#include "../igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+namespace igl
+{
+  namespace opengl
+  {
+    // Bind a per-vertex array attribute and refresh its contents from an Eigen
+    // matrix
+    //
+    // Inputs:
+    //   program_shader  id of shader program
+    //   name  name of attribute in vertex shader
+    //   bufferID  id of buffer to bind to
+    //   M  #V by dim matrix of per-vertex data
+    //   refresh  whether to actually call glBufferData or just bind the buffer
+    // Returns id of named attribute in shader
+    IGL_INLINE GLint bind_vertex_attrib_array(
+      const GLuint program_shader,
+      const std::string &name, 
+      GLuint bufferID, 
+      const Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> &M, 
+      bool refresh);
+  }
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "bind_vertex_attrib_array.cpp"
+#endif
+#endif

+ 6 - 25
include/igl/opengl/gl.h

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013, 2017 Alec Jacobson <alecjacobson@gmail.com>
 // Copyright (C) 2013, 2017 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
 #ifndef IGL_OPENGL_GL_H
 #ifndef IGL_OPENGL_GL_H
 #define IGL_OPENGL_GL_H
 #define IGL_OPENGL_GL_H
@@ -16,29 +16,10 @@
 //     #include "gl.h"
 //     #include "gl.h"
 // Instead of:
 // Instead of:
 //     #include <OpenGL/gl3.h>
 //     #include <OpenGL/gl3.h>
-// or 
+// or
 //     #include <GL/gl.h>
 //     #include <GL/gl.h>
 //
 //
 
 
-// For now this includes glu, glew and glext (perhaps these should be
-// separated)
-#ifdef _WIN32
-#    define NOMINMAX
-#    include <Windows.h>
-#    undef DrawText
-#    undef NOMINMAX
-#endif
-
-#ifndef __APPLE__
-#  define GLEW_STATIC
-#  include <GL/glew.h>
-#endif
-
-#ifdef __APPLE__
-#  include <OpenGL/gl3.h>
-#  define __gl_h_ /* Prevent inclusion of the old gl.h */
-#else
-#  include <GL/gl.h>
-#endif
+#include <glad/glad.h>
 
 
 #endif
 #endif

+ 6 - 6
include/igl/viewer/TextRenderer.cpp → include/igl/opengl/glfw/TextRenderer.cpp

@@ -19,9 +19,9 @@
 #include <nanovg_gl.h>
 #include <nanovg_gl.h>
 
 
 
 
-IGL_INLINE igl::viewer::TextRenderer::TextRenderer(): ctx(nullptr) {}
+IGL_INLINE igl::opengl::glfw::TextRenderer::TextRenderer(): ctx(nullptr) {}
 
 
-IGL_INLINE int igl::viewer::TextRenderer::Init()
+IGL_INLINE int igl::opengl::glfw::TextRenderer::Init()
 {
 {
   using namespace std;
   using namespace std;
   #ifdef NDEBUG
   #ifdef NDEBUG
@@ -36,7 +36,7 @@ IGL_INLINE int igl::viewer::TextRenderer::Init()
   return 0;
   return 0;
 }
 }
 
 
-IGL_INLINE int igl::viewer::TextRenderer::Shut()
+IGL_INLINE int igl::opengl::glfw::TextRenderer::Shut()
 {
 {
   using namespace std;
   using namespace std;
   if(ctx)
   if(ctx)
@@ -44,7 +44,7 @@ IGL_INLINE int igl::viewer::TextRenderer::Shut()
   return 0;
   return 0;
 }
 }
 
 
-IGL_INLINE void igl::viewer::TextRenderer::BeginDraw(
+IGL_INLINE void igl::opengl::glfw::TextRenderer::BeginDraw(
   const Eigen::Matrix4f &view,
   const Eigen::Matrix4f &view,
   const Eigen::Matrix4f &proj,
   const Eigen::Matrix4f &proj,
   const Eigen::Vector4f &_viewport,
   const Eigen::Vector4f &_viewport,
@@ -71,13 +71,13 @@ IGL_INLINE void igl::viewer::TextRenderer::BeginDraw(
   nvgBeginFrame(ctx,mSize[0],mSize[1],mPixelRatio);
   nvgBeginFrame(ctx,mSize[0],mSize[1],mPixelRatio);
 }
 }
 
 
-IGL_INLINE void igl::viewer::TextRenderer::EndDraw()
+IGL_INLINE void igl::opengl::glfw::TextRenderer::EndDraw()
 {
 {
   using namespace std;
   using namespace std;
   nvgEndFrame(ctx);
   nvgEndFrame(ctx);
 }
 }
 
 
-IGL_INLINE void igl::viewer::TextRenderer::DrawText(
+IGL_INLINE void igl::opengl::glfw::TextRenderer::DrawText(
   Eigen::Vector3d pos, Eigen::Vector3d normal, const std::string &text)
   Eigen::Vector3d pos, Eigen::Vector3d normal, const std::string &text)
 {
 {
   using namespace std;
   using namespace std;

+ 6 - 3
include/igl/viewer/TextRenderer.h → include/igl/opengl/glfw/TextRenderer.h

@@ -5,8 +5,8 @@
 // This Source Code Form is subject to the terms of the Mozilla Public License
 // 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
 // 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
-#ifndef IGL_VIEWER_TEXT_RENDERER_H
-#define IGL_VIEWER_TEXT_RENDERER_H
+#ifndef IGL_OPENGL_GLFW_TEXT_RENDERER_H
+#define IGL_OPENGL_GLFW_TEXT_RENDERER_H
 #ifdef IGL_VIEWER_WITH_NANOGUI
 #ifdef IGL_VIEWER_WITH_NANOGUI
 
 
 #include <Eigen/Dense>
 #include <Eigen/Dense>
@@ -18,7 +18,9 @@ struct NVGcontext;
 
 
 namespace igl
 namespace igl
 {
 {
-namespace viewer
+namespace opengl
+{
+namespace glfw
 {
 {
 
 
   class TextRenderer
   class TextRenderer
@@ -47,6 +49,7 @@ namespace viewer
 
 
 }
 }
 }
 }
+}
 
 
 #ifndef IGL_STATIC_LIBRARY
 #ifndef IGL_STATIC_LIBRARY
 #  include "TextRenderer.cpp"
 #  include "TextRenderer.cpp"

+ 0 - 0
include/igl/viewer/TextRenderer_fonts.cpp.REMOVED.git-id → include/igl/opengl/glfw/TextRenderer_fonts.cpp.REMOVED.git-id


+ 2 - 2
include/igl/viewer/TextRenderer_fonts.h → include/igl/opengl/glfw/TextRenderer_fonts.h

@@ -6,8 +6,8 @@
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
 
 
-#ifndef IGL_TEXT_RENDERER_FONTS_H
-#define IGL_TEXT_RENDERER_FONTS_H
+#ifndef IGL_OPENGL_GLFW_TEXT_RENDERER_FONTS_H
+#define IGL_OPENGL_GLFW_TEXT_RENDERER_FONTS_H
 
 
 #include <stdint.h>
 #include <stdint.h>
 
 

+ 301 - 419
include/igl/viewer/Viewer.cpp → include/igl/opengl/glfw/Viewer.cpp

@@ -6,40 +6,14 @@
 // v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
 
 
-// Must defined this before including Viewer.h
-#define IGL_VIEWER_VIEWER_CPP
 #include "Viewer.h"
 #include "Viewer.h"
 
 
-#ifdef _WIN32
-#  include <windows.h>
-#  undef max
-#  undef min
-#endif
-
 #include <chrono>
 #include <chrono>
 #include <thread>
 #include <thread>
 
 
-#ifndef __APPLE__
-#  define GLEW_STATIC
-#  include <GL/glew.h>
-#endif
-
-#ifdef __APPLE__
-#   include <OpenGL/gl3.h>
-#   define __gl_h_ /* Prevent inclusion of the old gl.h */
-#else
-#   include <GL/gl.h>
-#endif
-
 #include <Eigen/LU>
 #include <Eigen/LU>
 
 
-//#define GLFW_INCLUDE_GLU
-#if defined(__APPLE__)
-#define GLFW_INCLUDE_GLCOREARB
-#else
-#define GL_GLEXT_PROTOTYPES
-#endif
-
+#include "../gl.h"
 #include <GLFW/glfw3.h>
 #include <GLFW/glfw3.h>
 
 
 #include <cmath>
 #include <cmath>
@@ -52,11 +26,6 @@
 #include <limits>
 #include <limits>
 #include <cassert>
 #include <cassert>
 
 
-#ifdef IGL_VIEWER_WITH_NANOGUI
-#  include <nanogui/formhelper.h>
-#  include <nanogui/screen.h>
-#endif
-
 #include <igl/project.h>
 #include <igl/project.h>
 #include <igl/get_seconds.h>
 #include <igl/get_seconds.h>
 #include <igl/readOBJ.h>
 #include <igl/readOBJ.h>
@@ -73,47 +42,30 @@
 #include <igl/two_axis_valuator_fixed_up.h>
 #include <igl/two_axis_valuator_fixed_up.h>
 #include <igl/snap_to_canonical_view_quat.h>
 #include <igl/snap_to_canonical_view_quat.h>
 #include <igl/unproject.h>
 #include <igl/unproject.h>
-
-#ifdef ENABLE_SERIALIZATION
 #include <igl/serialize.h>
 #include <igl/serialize.h>
-#endif
 
 
 // Internal global variables used for glfw event handling
 // Internal global variables used for glfw event handling
-static igl::viewer::Viewer * __viewer;
+static igl::opengl::glfw::Viewer * __viewer;
 static double highdpi = 1;
 static double highdpi = 1;
 static double scroll_x = 0;
 static double scroll_x = 0;
 static double scroll_y = 0;
 static double scroll_y = 0;
 
 
 static void glfw_mouse_press(GLFWwindow* window, int button, int action, int modifier)
 static void glfw_mouse_press(GLFWwindow* window, int button, int action, int modifier)
 {
 {
-  bool tw_used =
-#ifdef IGL_VIEWER_WITH_NANOGUI
-    __viewer->screen->mouseButtonCallbackEvent(button,action,modifier);
-#else
-    false;
-#endif
 
 
-  igl::viewer::Viewer::MouseButton mb;
+  igl::opengl::glfw::Viewer::MouseButton mb;
 
 
   if (button == GLFW_MOUSE_BUTTON_1)
   if (button == GLFW_MOUSE_BUTTON_1)
-    mb = igl::viewer::Viewer::MouseButton::Left;
+    mb = igl::opengl::glfw::Viewer::MouseButton::Left;
   else if (button == GLFW_MOUSE_BUTTON_2)
   else if (button == GLFW_MOUSE_BUTTON_2)
-    mb = igl::viewer::Viewer::MouseButton::Right;
+    mb = igl::opengl::glfw::Viewer::MouseButton::Right;
   else //if (button == GLFW_MOUSE_BUTTON_3)
   else //if (button == GLFW_MOUSE_BUTTON_3)
-    mb = igl::viewer::Viewer::MouseButton::Middle;
+    mb = igl::opengl::glfw::Viewer::MouseButton::Middle;
 
 
   if (action == GLFW_PRESS)
   if (action == GLFW_PRESS)
-  {
-    if(!tw_used)
-    {
-      __viewer->mouse_down(mb,modifier);
-    }
-  } else
-  {
-    // Always call mouse_up on up
+    __viewer->mouse_down(mb,modifier);
+  else
     __viewer->mouse_up(mb,modifier);
     __viewer->mouse_up(mb,modifier);
-  }
-
 }
 }
 
 
 static void glfw_error_callback(int error, const char* description)
 static void glfw_error_callback(int error, const char* description)
@@ -123,14 +75,7 @@ static void glfw_error_callback(int error, const char* description)
 
 
 static void glfw_char_mods_callback(GLFWwindow* window, unsigned int codepoint, int modifier)
 static void glfw_char_mods_callback(GLFWwindow* window, unsigned int codepoint, int modifier)
 {
 {
-  // TODO: pass to nanogui (although it's also using physical key down/up
-  // rather than character codes...
-#ifdef IGL_VIEWER_WITH_NANOGUI
-  if(! __viewer->screen->charCallbackEvent(codepoint) )
-#endif
-  {
-    __viewer->key_pressed(codepoint, modifier);
-  }
+  __viewer->key_pressed(codepoint, modifier);
 }
 }
 
 
 static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int modifier)
 static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int modifier)
@@ -138,15 +83,10 @@ static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int act
   if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
   if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
     glfwSetWindowShouldClose(window, GL_TRUE);
     glfwSetWindowShouldClose(window, GL_TRUE);
 
 
-#ifdef IGL_VIEWER_WITH_NANOGUI
-  if (__viewer->screen->keyCallbackEvent(key,scancode,action,modifier) == false)
-#endif
-  {
-    if (action == GLFW_PRESS)
-      __viewer->key_down(key, modifier);
-    else if(action == GLFW_RELEASE)
-      __viewer->key_up(key, modifier);
-  }
+  if (action == GLFW_PRESS)
+    __viewer->key_down(key, modifier);
+  else if(action == GLFW_RELEASE)
+    __viewer->key_up(key, modifier);
 }
 }
 
 
 static void glfw_window_size(GLFWwindow* window, int width, int height)
 static void glfw_window_size(GLFWwindow* window, int width, int height)
@@ -156,20 +96,11 @@ static void glfw_window_size(GLFWwindow* window, int width, int height)
 
 
   __viewer->post_resize(w, h);
   __viewer->post_resize(w, h);
 
 
-  // TODO: repositioning of the nanogui
 }
 }
 
 
 static void glfw_mouse_move(GLFWwindow* window, double x, double y)
 static void glfw_mouse_move(GLFWwindow* window, double x, double y)
 {
 {
-  if(
-#ifdef IGL_VIEWER_WITH_NANOGUI
-      __viewer->screen->cursorPosCallbackEvent(x,y) == false &&
-#endif
-      true
-    )
-  {
-    __viewer->mouse_move(x*highdpi, y*highdpi);
-  }
+  __viewer->mouse_move(x*highdpi, y*highdpi);
 }
 }
 
 
 static void glfw_mouse_scroll(GLFWwindow* window, double x, double y)
 static void glfw_mouse_scroll(GLFWwindow* window, double x, double y)
@@ -178,95 +109,154 @@ static void glfw_mouse_scroll(GLFWwindow* window, double x, double y)
   scroll_x += x;
   scroll_x += x;
   scroll_y += y;
   scroll_y += y;
 
 
-#ifdef IGL_VIEWER_WITH_NANOGUI
-  if (__viewer->screen->scrollCallbackEvent(x,y) == false)
-#endif
-  {
-    __viewer->mouse_scroll(y);
-  }
+  __viewer->mouse_scroll(y);
 }
 }
 
 
 static void glfw_drop_callback(GLFWwindow *window,int count,const char **filenames)
 static void glfw_drop_callback(GLFWwindow *window,int count,const char **filenames)
 {
 {
-#ifdef IGL_VIEWER_WITH_NANOGUI
-  __viewer->screen->dropCallbackEvent(count,filenames);
-#endif
 }
 }
 
 
 namespace igl
 namespace igl
 {
 {
-namespace viewer
+namespace opengl
+{
+namespace glfw
 {
 {
-  IGL_INLINE void Viewer::init()
-  {
-#ifdef IGL_VIEWER_WITH_NANOGUI
-    using namespace nanogui;
-
-    ngui->setFixedSize(Eigen::Vector2i(60,20));
-
-    // Create nanogui widgets
-    /* nanogui::Window *window = */ ngui->addWindow(Eigen::Vector2i(10,10),"libIGL-Viewer");
-
-    // ---------------------- LOADING ----------------------
-
-  #ifdef ENABLE_SERIALIZATION
-    ngui->addGroup("Workspace");
-    ngui->addButton("Load",[&](){this->load_scene();});
-    ngui->addButton("Save",[&](){this->save_scene();});
-  #endif
 
 
-  #ifdef ENABLE_IO
-    ngui->addGroup("Mesh");
-    ngui->addButton("Load",[&](){this->open_dialog_load_mesh();});
-    ngui->addButton("Save",[&](){this->open_dialog_save_mesh();});
-  #endif
+  IGL_INLINE int Viewer::launch(bool resizable,bool fullscreen)
+  {
+    // TODO return values are being ignored...
+    launch_init(resizable,fullscreen);
+    launch_rendering(true);
+    launch_shut();
+    return EXIT_SUCCESS;
+  }
 
 
-    ngui->addGroup("Viewing Options");
-    ngui->addButton("Center object",[&](){this->core.align_camera_center(this->data.V,this->data.F);});
-    ngui->addButton("Snap canonical view",[&]()
+  IGL_INLINE int  Viewer::launch_init(bool resizable,bool fullscreen)
+  {
+    glfwSetErrorCallback(glfw_error_callback);
+    if (!glfwInit())
     {
     {
-      this->snap_to_canonical_quaternion();
-    });
-    ngui->addVariable("Zoom", core.camera_zoom);
-    ngui->addVariable("Orthographic view", core.orthographic);
-
-    ngui->addGroup("Draw options");
-
-    ngui->addVariable<bool>("Face-based", [&](bool checked)
+      return EXIT_FAILURE;
+    }
+    glfwWindowHint(GLFW_SAMPLES, 8);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+    #ifdef __APPLE__
+      glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+      glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+    #endif
+    if(fullscreen)
     {
     {
-      this->data.set_face_based(checked);
-    },[&]()
+      GLFWmonitor *monitor = glfwGetPrimaryMonitor();
+      const GLFWvidmode *mode = glfwGetVideoMode(monitor);
+      window = glfwCreateWindow(mode->width,mode->height,"libigl viewer",monitor,nullptr);
+    }
+    else
     {
     {
-      return this->data.face_based;
-    });
+      if (core.viewport.tail<2>().any()) {
+        window = glfwCreateWindow(core.viewport(2),core.viewport(3),"libigl viewer",nullptr,nullptr);
+      } else {
+        window = glfwCreateWindow(1280,800,"libigl viewer",nullptr,nullptr);
+      }
+    }
+    if (!window)
+    {
+      glfwTerminate();
+      return EXIT_FAILURE;
+    }
+    glfwMakeContextCurrent(window);
+    // Load OpenGL and its extensions
+    if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress))
+    {
+      printf("Failed to load OpenGL and its extensions\n");
+      return(-1);
+    }
+    printf("OpenGL Version %d.%d loaded\n", GLVersion.major, GLVersion.minor);
+    #if defined(DEBUG) || defined(_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 received: %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 FormScreen
+    __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);
+    glfwSetCharModsCallback(window,glfw_char_mods_callback);
+    glfwSetDropCallback(window,glfw_drop_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);
+    //opengl.init();
+    core.align_camera_center(data().V,data().F);
+    // Initialize IGL viewer
+    init();
+    return EXIT_SUCCESS;
+  }
+
 
 
-    ngui->addVariable("Show texture",core.show_texture);
 
 
-    ngui->addVariable<bool>("Invert normals",[&](bool checked)
+  IGL_INLINE bool Viewer::launch_rendering(bool loop)
+  {
+    // glfwMakeContextCurrent(window);
+    // Rendering loop
+    const int num_extra_frames = 5;
+    int frame_counter = 0;
+    while (!glfwWindowShouldClose(window))
     {
     {
-      this->data.dirty |= ViewerData::DIRTY_NORMAL;
-      this->core.invert_normals = checked;
-    },[&]()
+      double tic = get_seconds();
+      draw();
+      glfwSwapBuffers(window);
+      if(core.is_animating || frame_counter++ < num_extra_frames)
+      {
+        glfwPollEvents();
+        // In microseconds
+        double duration = 1000000.*(get_seconds()-tic);
+        const double min_duration = 1000000./core.animation_max_fps;
+        if(duration<min_duration)
+        {
+          std::this_thread::sleep_for(std::chrono::microseconds((int)(min_duration-duration)));
+        }
+      }
+      else
+      {
+        glfwWaitEvents();
+        frame_counter = 0;
+      }
+      if (!loop)
+        return !glfwWindowShouldClose(window);
+    }
+    return EXIT_SUCCESS;
+  }
+
+  IGL_INLINE void Viewer::launch_shut()
+  {
+    for(auto & data : data_list)
     {
     {
-      return this->core.invert_normals;
-    });
-
-    ngui->addVariable("Show overlay", core.show_overlay);
-    ngui->addVariable("Show overlay depth", core.show_overlay_depth);
-    ngui->addVariable("Background", (nanogui::Color &) core.background_color);
-    ngui->addVariable("Line color", (nanogui::Color &) core.line_color);
-    ngui->addVariable("Shininess", core.shininess);
-
-    ngui->addGroup("Overlays");
-    ngui->addVariable("Wireframe", core.show_lines);
-    ngui->addVariable("Fill", core.show_faces);
-    ngui->addVariable("Show vertex labels", core.show_vertid);
-    ngui->addVariable("Show faces labels", core.show_faceid);
-
-    screen->setVisible(true);
-    screen->performLayout();
-#endif
+      data.meshgl.free();
+    }
+    core.shut();
+    shutdown_plugins();
+    glfwDestroyWindow(window);
+    glfwTerminate();
+    return;
+  }
 
 
+  IGL_INLINE void Viewer::init()
+  {
     core.init();
     core.init();
 
 
     if (callback_init)
     if (callback_init)
@@ -276,14 +266,28 @@ namespace viewer
     init_plugins();
     init_plugins();
   }
   }
 
 
-  IGL_INLINE Viewer::Viewer()
+  IGL_INLINE void Viewer::init_plugins()
   {
   {
-    window = nullptr;
+    // Init all plugins
+    for (unsigned int i = 0; i<plugins.size(); ++i)
+    {
+      plugins[i]->init(this);
+    }
+  }
 
 
-#ifdef IGL_VIEWER_WITH_NANOGUI
-    ngui = nullptr;
-    screen = nullptr;
-#endif
+  IGL_INLINE void Viewer::shutdown_plugins()
+  {
+    for (unsigned int i = 0; i<plugins.size(); ++i)
+    {
+      plugins[i]->shutdown();
+    }
+  }
+
+  IGL_INLINE Viewer::Viewer():
+    data_list(1),
+    selected_data_index(0)
+  {
+    window = nullptr;
 
 
     // Temporary variables initialization
     // Temporary variables initialization
     down = false;
     down = false;
@@ -291,7 +295,7 @@ namespace viewer
     scroll_position = 0.0f;
     scroll_position = 0.0f;
 
 
     // Per face
     // Per face
-    data.set_face_based(false);
+    data().set_face_based(false);
 
 
     // C-style callbacks
     // C-style callbacks
     callback_init         = nullptr;
     callback_init         = nullptr;
@@ -315,7 +319,7 @@ namespace viewer
     callback_key_up_data        = nullptr;
     callback_key_up_data        = nullptr;
 
 
 #ifndef IGL_VIEWER_VIEWER_QUIET
 #ifndef IGL_VIEWER_VIEWER_QUIET
-    const std::string usage(R"(igl::viewer::Viewer usage:
+    const std::string usage(R"(igl::opengl::glfw::Viewer usage:
   [drag]  Rotate scene
   [drag]  Rotate scene
   A,a     Toggle animation (tight draw loop)
   A,a     Toggle animation (tight draw loop)
   F,f     Toggle face based
   F,f     Toggle face based
@@ -325,41 +329,22 @@ namespace viewer
   T,t     Toggle filled faces
   T,t     Toggle filled faces
   Z       Snap to canonical view
   Z       Snap to canonical view
   [,]     Toggle between rotation control types (trackball, two-axis
   [,]     Toggle between rotation control types (trackball, two-axis
-          valuator with fixed up, 2D mode with no rotation))"
-#ifdef IGL_VIEWER_WITH_NANOGUI
-		R"(
+          valuator with fixed up, 2D mode with no rotation))
+  <,>     Toggle between models
   ;       Toggle vertex labels
   ;       Toggle vertex labels
   :       Toggle face labels)"
   :       Toggle face labels)"
-#endif
 );
 );
     std::cout<<usage<<std::endl;
     std::cout<<usage<<std::endl;
 #endif
 #endif
   }
   }
 
 
-  IGL_INLINE void Viewer::init_plugins()
-  {
-    // Init all plugins
-    for (unsigned int i = 0; i<plugins.size(); ++i)
-    {
-      plugins[i]->init(this);
-    }
-  }
-
   IGL_INLINE Viewer::~Viewer()
   IGL_INLINE Viewer::~Viewer()
   {
   {
   }
   }
 
 
-  IGL_INLINE void Viewer::shutdown_plugins()
+  IGL_INLINE bool Viewer::load_mesh_from_file(
+      const std::string & mesh_file_name_string)
   {
   {
-    for (unsigned int i = 0; i<plugins.size(); ++i)
-    {
-      plugins[i]->shutdown();
-    }
-  }
-
-  IGL_INLINE 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
     // first try to load it with a plugin
     for (unsigned int i = 0; i<plugins.size(); ++i)
     for (unsigned int i = 0; i<plugins.size(); ++i)
@@ -370,12 +355,18 @@ namespace viewer
       }
       }
     }
     }
 
 
-    data.clear();
+    // Create new data slot and set to selected
+    if(!(data().F.rows() == 0  && data().V.rows() == 0))
+    {
+      append_mesh();
+    }
+    data().clear();
 
 
     size_t last_dot = mesh_file_name_string.rfind('.');
     size_t last_dot = mesh_file_name_string.rfind('.');
     if (last_dot == std::string::npos)
     if (last_dot == std::string::npos)
     {
     {
-      printf("Error: No file extension found in %s\n",mesh_file_name);
+      std::cerr<<"Error: No file extension found in "<<
+        mesh_file_name_string<<std::endl;
       return false;
       return false;
     }
     }
 
 
@@ -387,7 +378,7 @@ namespace viewer
       Eigen::MatrixXi F;
       Eigen::MatrixXi F;
       if (!igl::readOFF(mesh_file_name_string, V, F))
       if (!igl::readOFF(mesh_file_name_string, V, F))
         return false;
         return false;
-      data.set_mesh(V,F);
+      data().set_mesh(V,F);
     }
     }
     else if (extension == "obj" || extension =="OBJ")
     else if (extension == "obj" || extension =="OBJ")
     {
     {
@@ -407,8 +398,8 @@ namespace viewer
         return false;
         return false;
       }
       }
 
 
-      data.set_mesh(V,F);
-      data.set_uv(UV_V,UV_F);
+      data().set_mesh(V,F);
+      data().set_uv(UV_V,UV_F);
 
 
     }
     }
     else
     else
@@ -418,16 +409,16 @@ namespace viewer
       return false;
       return false;
     }
     }
 
 
-    data.compute_normals();
-    data.uniform_colors(Eigen::Vector3d(51.0/255.0,43.0/255.0,33.3/255.0),
+    data().compute_normals();
+    data().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,228.0/255.0,58.0/255.0),
                    Eigen::Vector3d(255.0/255.0,235.0/255.0,80.0/255.0));
                    Eigen::Vector3d(255.0/255.0,235.0/255.0,80.0/255.0));
-    if (data.V_uv.rows() == 0)
+    if (data().V_uv.rows() == 0)
     {
     {
-      data.grid_texture();
+      data().grid_texture();
     }
     }
 
 
-    core.align_camera_center(data.V,data.F);
+    core.align_camera_center(data().V,data().F);
 
 
     for (unsigned int i = 0; i<plugins.size(); ++i)
     for (unsigned int i = 0; i<plugins.size(); ++i)
       if (plugins[i]->post_load())
       if (plugins[i]->post_load())
@@ -436,10 +427,9 @@ namespace viewer
     return true;
     return true;
   }
   }
 
 
-  IGL_INLINE bool Viewer::save_mesh_to_file(const char* mesh_file_name)
+  IGL_INLINE bool Viewer::save_mesh_to_file(
+      const std::string & mesh_file_name_string)
   {
   {
-    std::string mesh_file_name_string(mesh_file_name);
-
     // first try to load it with a plugin
     // first try to load it with a plugin
     for (unsigned int i = 0; i<plugins.size(); ++i)
     for (unsigned int i = 0; i<plugins.size(); ++i)
       if (plugins[i]->save(mesh_file_name_string))
       if (plugins[i]->save(mesh_file_name_string))
@@ -449,13 +439,15 @@ namespace viewer
     if (last_dot == std::string::npos)
     if (last_dot == std::string::npos)
     {
     {
       // No file type determined
       // No file type determined
-      printf("Error: No file extension found in %s\n",mesh_file_name);
+      std::cerr<<"Error: No file extension found in "<<
+        mesh_file_name_string<<std::endl;
       return false;
       return false;
     }
     }
     std::string extension = mesh_file_name_string.substr(last_dot+1);
     std::string extension = mesh_file_name_string.substr(last_dot+1);
     if (extension == "off" || extension =="OFF")
     if (extension == "off" || extension =="OFF")
     {
     {
-      return igl::writeOFF(mesh_file_name_string,data.V,data.F);
+      return igl::writeOFF(
+        mesh_file_name_string,data().V,data().F);
     }
     }
     else if (extension == "obj" || extension =="OBJ")
     else if (extension == "obj" || extension =="OBJ")
     {
     {
@@ -465,8 +457,10 @@ namespace viewer
       Eigen::MatrixXd UV_V;
       Eigen::MatrixXd UV_V;
       Eigen::MatrixXi UV_F;
       Eigen::MatrixXi UV_F;
 
 
-      return igl::writeOBJ(mesh_file_name_string, data.V,
-          data.F, corner_normals, fNormIndices, UV_V, UV_F);
+      return igl::writeOBJ(mesh_file_name_string,
+          data().V,
+          data().F,
+          corner_normals, fNormIndices, UV_V, UV_F);
     }
     }
     else
     else
     {
     {
@@ -502,20 +496,20 @@ namespace viewer
       case 'F':
       case 'F':
       case 'f':
       case 'f':
       {
       {
-        data.set_face_based(!data.face_based);
+        data().set_face_based(!data().face_based);
         return true;
         return true;
       }
       }
       case 'I':
       case 'I':
       case 'i':
       case 'i':
       {
       {
-        data.dirty |= ViewerData::DIRTY_NORMAL;
-        core.invert_normals = !core.invert_normals;
+        data().dirty |= MeshGL::DIRTY_NORMAL;
+        data().invert_normals = !data().invert_normals;
         return true;
         return true;
       }
       }
       case 'L':
       case 'L':
       case 'l':
       case 'l':
       {
       {
-        core.show_lines = !core.show_lines;
+        data().show_lines = !data().show_lines;
         return true;
         return true;
       }
       }
       case 'O':
       case 'O':
@@ -527,7 +521,7 @@ namespace viewer
       case 'T':
       case 'T':
       case 't':
       case 't':
       {
       {
-        core.show_faces = !core.show_faces;
+        data().show_faces = !data().show_faces;
         return true;
         return true;
       }
       }
       case 'Z':
       case 'Z':
@@ -545,14 +539,19 @@ namespace viewer
 
 
         return true;
         return true;
       }
       }
-#ifdef IGL_VIEWER_WITH_NANOGUI
+      case '<':
+      case '>':
+      {
+        selected_data_index =
+          (selected_data_index + data_list.size() + (unicode_key=='>'?1:-1))%data_list.size();
+        return true;
+      }
       case ';':
       case ';':
-        core.show_vertid = !core.show_vertid;
+        data().show_vertid = !data().show_vertid;
         return true;
         return true;
       case ':':
       case ':':
-        core.show_faceid = !core.show_faceid;
+        data().show_faceid = !data().show_faceid;
         return true;
         return true;
-#endif
       default: break;//do nothing
       default: break;//do nothing
     }
     }
     return false;
     return false;
@@ -603,12 +602,12 @@ namespace viewer
 
 
     // Initialization code for the trackball
     // Initialization code for the trackball
     Eigen::RowVector3d center;
     Eigen::RowVector3d center;
-    if (data.V.rows() == 0)
+    if (data().V.rows() == 0)
     {
     {
       center << 0,0,0;
       center << 0,0,0;
     }else
     }else
     {
     {
-      center = data.V.colwise().sum()/data.V.rows();
+      center = data().V.colwise().sum()/data().V.rows();
     }
     }
 
 
     Eigen::Vector3f coord =
     Eigen::Vector3f coord =
@@ -767,35 +766,19 @@ namespace viewer
     return true;
     return true;
   }
   }
 
 
-  IGL_INLINE void Viewer::draw()
+  IGL_INLINE bool Viewer::load_scene()
   {
   {
-    using namespace std;
-    using namespace Eigen;
-
-    core.clear_framebuffers();
-
-    if (callback_pre_draw)
-      if (callback_pre_draw(*this))
-        return;
-
-    for (unsigned int i = 0; i<plugins.size(); ++i)
-      if (plugins[i]->pre_draw())
-        return;
-
-    core.draw(data,opengl);
-
-    if (callback_post_draw)
-      if (callback_post_draw(*this))
-        return;
-
-    for (unsigned int i = 0; i<plugins.size(); ++i)
-      if (plugins[i]->post_draw())
-        break;
+    std::string fname = igl::file_dialog_open();
+    if(fname.length() == 0)
+      return false;
+    return load_scene(fname);
+  }
 
 
-#ifdef IGL_VIEWER_WITH_NANOGUI
-	screen->drawContents();
-	screen->drawWidgets();
-#endif
+  IGL_INLINE bool Viewer::load_scene(std::string fname)
+  {
+    igl::deserialize(core,"Core",fname.c_str());
+    igl::deserialize(data(),"Data",fname.c_str());
+    return true;
   }
   }
 
 
   IGL_INLINE bool Viewer::save_scene()
   IGL_INLINE bool Viewer::save_scene()
@@ -803,55 +786,77 @@ namespace viewer
     std::string fname = igl::file_dialog_save();
     std::string fname = igl::file_dialog_save();
     if (fname.length() == 0)
     if (fname.length() == 0)
       return false;
       return false;
+    return save_scene(fname);
+  }
 
 
-#ifdef ENABLE_SERIALIZATION
-
+  IGL_INLINE bool Viewer::save_scene(std::string fname)
+  {
     igl::serialize(core,"Core",fname.c_str(),true);
     igl::serialize(core,"Core",fname.c_str(),true);
-
-#ifndef ENABLE_SERIALIZATION_CORE_ONLY
-    igl::serialize(data,"Data",fname.c_str());
-    for(unsigned int i = 0; i <plugins.size(); ++i)
-      igl::serialize(*plugins[i],plugins[i]->plugin_name,fname.c_str());
-#endif
-
-#endif
+    igl::serialize(data(),"Data",fname.c_str());
 
 
     return true;
     return true;
   }
   }
 
 
-  IGL_INLINE bool Viewer::load_scene()
+  IGL_INLINE void Viewer::draw()
   {
   {
-    std::string fname = igl::file_dialog_open();
-    if(fname.length() == 0)
-      return false;
-
-    return load_scene(fname);
-  }
+    using namespace std;
+    using namespace Eigen;
 
 
-  IGL_INLINE bool Viewer::load_scene(std::string fname)
-  {
-#ifdef ENABLE_SERIALIZATION
+    int width, height;
+    glfwGetFramebufferSize(window, &width, &height);
 
 
-    igl::deserialize(core,"Core",fname.c_str());
+    int width_window, height_window;
+    glfwGetWindowSize(window, &width_window, &height_window);
 
 
-#ifndef ENABLE_SERIALIZATION_CORE_ONLY
-    igl::deserialize(data,"Data",fname.c_str());
-    for(unsigned int i = 0; i <plugins.size(); ++i)
-      igl::deserialize(*plugins[i],plugins[i]->plugin_name,fname.c_str());
-#endif
+    auto highdpi_tmp = width/width_window;
 
 
-#endif
+    if(fabs(highdpi_tmp-highdpi)>1e-8)
+    {
+      post_resize(width, height);
+      highdpi=highdpi_tmp;
+    }
 
 
-    return true;
+    core.clear_framebuffers();
+    if (callback_pre_draw)
+    {
+      if (callback_pre_draw(*this))
+      {
+        return;
+      }
+    }
+    for (unsigned int i = 0; i<plugins.size(); ++i)
+    {
+      if (plugins[i]->pre_draw())
+      {
+        return;
+      }
+    }
+    for(int i = 0;i<data_list.size();i++)
+    {
+      core.draw(data_list[i]);
+    }
+    if (callback_post_draw)
+    {
+      if (callback_post_draw(*this))
+      {
+        return;
+      }
+    }
+    for (unsigned int i = 0; i<plugins.size(); ++i)
+    {
+      if (plugins[i]->post_draw())
+      {
+        break;
+      }
+    }
   }
   }
 
 
   IGL_INLINE void Viewer::resize(int w,int h)
   IGL_INLINE void Viewer::resize(int w,int h)
   {
   {
     if (window) {
     if (window) {
       glfwSetWindowSize(window, w/highdpi, h/highdpi);
       glfwSetWindowSize(window, w/highdpi, h/highdpi);
-    } else {
-      post_resize(w, h);
     }
     }
+    post_resize(w, h);
   }
   }
 
 
   IGL_INLINE void Viewer::post_resize(int w,int h)
   IGL_INLINE void Viewer::post_resize(int w,int h)
@@ -889,165 +894,42 @@ namespace viewer
     this->save_mesh_to_file(fname.c_str());
     this->save_mesh_to_file(fname.c_str());
   }
   }
 
 
-
-  IGL_INLINE int  Viewer::launch_init(bool resizable,bool fullscreen)
+  IGL_INLINE ViewerData& Viewer::data()
   {
   {
-    glfwSetErrorCallback(glfw_error_callback);
-    if (!glfwInit())
-      return EXIT_FAILURE;
-
-    glfwWindowHint(GLFW_SAMPLES, 8);
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
-
-    #ifdef __APPLE__
-      glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
-      glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
-    #endif
-
-    if(fullscreen)
-    {
-      GLFWmonitor *monitor = glfwGetPrimaryMonitor();
-      const GLFWvidmode *mode = glfwGetVideoMode(monitor);
-      window = glfwCreateWindow(mode->width,mode->height,"libigl viewer",monitor,nullptr);
-    }
-    else
-    {
-      if (core.viewport.tail<2>().any()) {
-        window = glfwCreateWindow(core.viewport(2),core.viewport(3),"libigl viewer",nullptr,nullptr);
-      } else {
-        window = glfwCreateWindow(1280,800,"libigl viewer",nullptr,nullptr);
-      }
-    }
-
-    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));
-      }
-      glGetError(); // pull and savely ignonre unhandled errors like GL_INVALID_ENUM
-      fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
-    #endif
-
-    #if defined(DEBUG) || defined(_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 FormScreen
-#ifdef IGL_VIEWER_WITH_NANOGUI
-    screen = new nanogui::Screen();
-    screen->initialize(window, false);
-    ngui = new nanogui::FormHelper(screen);
-#endif
-
-    __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);
-    glfwSetCharModsCallback(window,glfw_char_mods_callback);
-    glfwSetDropCallback(window,glfw_drop_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);
-
-    opengl.init();
-
-    core.align_camera_center(data.V,data.F);
-
-    // Initialize IGL viewer
-    init();
-    return EXIT_SUCCESS;
+    assert(!data_list.empty() && "data_list should never be empty");
+    assert(
+      (selected_data_index >= 0 && selected_data_index < data_list.size()) &&
+      "selected_data_index should be in bounds");
+    return data_list[selected_data_index];
   }
   }
 
 
-  IGL_INLINE bool Viewer::launch_rendering(bool loop)
+  IGL_INLINE size_t Viewer::append_mesh()
   {
   {
-    // glfwMakeContextCurrent(window);
-
-    // Rendering loop
-    while (!glfwWindowShouldClose(window))
-    {
-      double tic = get_seconds();
-      draw();
+    assert(data_list.size() >= 1);
 
 
-      glfwSwapBuffers(window);
-      if(core.is_animating)
-      {
-        glfwPollEvents();
-        // In microseconds
-        double duration = 1000000.*(get_seconds()-tic);
-        const double min_duration = 1000000./core.animation_max_fps;
-        if(duration<min_duration)
-        {
-          std::this_thread::sleep_for(std::chrono::microseconds((int)(min_duration-duration)));
-        }
-      }
-      else
-      {
-        glfwWaitEvents();
-      }
-
-      if (!loop)
-        return !glfwWindowShouldClose(window);
-    }
-    return EXIT_SUCCESS;
+    data_list.emplace_back();
+    selected_data_index = data_list.size()-1;
+    return data_list.size();
   }
   }
 
 
-  IGL_INLINE void Viewer::launch_shut()
+  IGL_INLINE bool Viewer::erase_mesh(const size_t index)
   {
   {
-    opengl.free();
-    core.shut();
-
-    shutdown_plugins();
-#ifdef IGL_VIEWER_WITH_NANOGUI
-    delete ngui;
-    //delete screen;
-    screen = nullptr;
-    ngui = nullptr;
-#endif
-
-    glfwDestroyWindow(window);
-    glfwTerminate();
-    return;
+    assert((index >= 0 && index < data_list.size()) && "index should be in bounds");
+    assert(data_list.size() >= 1);
+    if(data_list.size() == 1)
+    {
+      // Cannot remove last mesh
+      return false;
+    }
+    data_list[index].meshgl.free();
+    data_list.erase(data_list.begin() + index);
+    if(selected_data_index >= index && selected_data_index>0)
+    {
+      selected_data_index--;
+    }
+    return true;
   }
   }
 
 
-  IGL_INLINE int Viewer::launch(bool resizable,bool fullscreen)
-  {
-    // TODO return values are being ignored...
-    launch_init(resizable,fullscreen);
-    launch_rendering(true);
-    launch_shut();
-    return EXIT_SUCCESS;
-  }
+} // end namespace
 } // end namespace
 } // end namespace
 }
 }

+ 70 - 67
include/igl/viewer/Viewer.h → include/igl/opengl/glfw/Viewer.h

@@ -5,128 +5,131 @@
 // This Source Code Form is subject to the terms of the Mozilla Public License
 // 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
 // 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
-#ifndef IGL_VIEWER_VIEWER_H
-#define IGL_VIEWER_VIEWER_H
+#ifndef IGL_OPENGL_GLFW_VIEWER_H
+#define IGL_OPENGL_GLFW_VIEWER_H
 
 
 #ifndef IGL_OPENGL_4
 #ifndef IGL_OPENGL_4
 #define IGL_OPENGL_4
 #define IGL_OPENGL_4
 #endif
 #endif
 
 
-#include <vector>
-#include <string>
-#include <cstdint>
+#include "../../igl_inline.h"
+#include "../MeshGL.h"
+#include "../ViewerCore.h"
+#include "../ViewerData.h"
+#include "ViewerPlugin.h"
 
 
 #include <Eigen/Core>
 #include <Eigen/Core>
 #include <Eigen/Geometry>
 #include <Eigen/Geometry>
 
 
-#include <igl/igl_inline.h>
-
-#include "OpenGL_shader.h"
-#include "OpenGL_state.h"
-#include "ViewerCore.h"
-#include "ViewerData.h"
-#include "ViewerPlugin.h"
+#include <vector>
+#include <string>
+#include <cstdint>
 
 
 #define IGL_MOD_SHIFT           0x0001
 #define IGL_MOD_SHIFT           0x0001
 #define IGL_MOD_CONTROL         0x0002
 #define IGL_MOD_CONTROL         0x0002
 #define IGL_MOD_ALT             0x0004
 #define IGL_MOD_ALT             0x0004
 #define IGL_MOD_SUPER           0x0008
 #define IGL_MOD_SUPER           0x0008
 
 
-#ifdef IGL_VIEWER_WITH_NANOGUI
-namespace nanogui { class FormHelper; class Screen; }
-#endif
-
 struct GLFWwindow;
 struct GLFWwindow;
 
 
 namespace igl
 namespace igl
 {
 {
-namespace viewer
+namespace opengl
+{
+namespace glfw
 {
 {
   // GLFW-based mesh viewer
   // GLFW-based mesh viewer
   class Viewer
   class Viewer
   {
   {
   public:
   public:
-    GLFWwindow* window;
-
+    // UI Enumerations
+    enum class MouseButton {Left, Middle, Right};
+    enum class MouseMode { None, Rotation, Zoom, Pan, Translation} mouse_mode;
     IGL_INLINE int launch(bool resizable = true,bool fullscreen = false);
     IGL_INLINE int launch(bool resizable = true,bool fullscreen = false);
     IGL_INLINE int launch_init(bool resizable = true,bool fullscreen = false);
     IGL_INLINE int launch_init(bool resizable = true,bool fullscreen = false);
     IGL_INLINE bool launch_rendering(bool loop = true);
     IGL_INLINE bool launch_rendering(bool loop = true);
     IGL_INLINE void launch_shut();
     IGL_INLINE void launch_shut();
-
     IGL_INLINE void init();
     IGL_INLINE void init();
-
-    // Stores all the viewing options
-    ViewerCore core;
-
-    // Stores all the data that should be visualized
-    ViewerData data;
-
-    // Stores the vbos indices and opengl related settings
-    OpenGL_state opengl;
-
-    // List of registered plugins
-    std::vector<ViewerPlugin*> plugins;
     IGL_INLINE void init_plugins();
     IGL_INLINE void init_plugins();
     IGL_INLINE void shutdown_plugins();
     IGL_INLINE void shutdown_plugins();
-
-    // Temporary data stored when the mouse button is pressed
-    Eigen::Quaternionf down_rotation;
-    int current_mouse_x;
-    int current_mouse_y;
-    int down_mouse_x;
-    int down_mouse_y;
-    float down_mouse_z;
-    Eigen::Vector3f down_translation;
-    bool down;
-    bool hack_never_moved;
-
-#ifdef IGL_VIEWER_WITH_NANOGUI
-    nanogui::FormHelper* ngui;
-    nanogui::Screen* screen;
-#endif
-
-    // Keep track of the global position of the scrollwheel
-    float scroll_position;
-
-    // UI Enumerations
-    enum class MouseButton {Left, Middle, Right};
-    enum class MouseMode { None, Rotation, Zoom, Pan, Translation} mouse_mode;
-
     Viewer();
     Viewer();
     ~Viewer();
     ~Viewer();
-
     // Mesh IO
     // Mesh IO
-    IGL_INLINE bool load_mesh_from_file(const char* mesh_file_name);
-    IGL_INLINE bool save_mesh_to_file(const char* mesh_file_name);
-
+    IGL_INLINE bool load_mesh_from_file(const std::string & mesh_file_name);
+    IGL_INLINE bool   save_mesh_to_file(const std::string & mesh_file_name);
     // Callbacks
     // Callbacks
     IGL_INLINE bool key_pressed(unsigned int unicode_key,int modifier);
     IGL_INLINE bool key_pressed(unsigned int unicode_key,int modifier);
     IGL_INLINE bool key_down(int key,int modifier);
     IGL_INLINE bool key_down(int key,int modifier);
     IGL_INLINE bool key_up(int key,int modifier);
     IGL_INLINE bool key_up(int key,int modifier);
-
     IGL_INLINE bool mouse_down(MouseButton button,int modifier);
     IGL_INLINE bool mouse_down(MouseButton button,int modifier);
     IGL_INLINE bool mouse_up(MouseButton button,int modifier);
     IGL_INLINE bool mouse_up(MouseButton button,int modifier);
-
     IGL_INLINE bool mouse_move(int mouse_x,int mouse_y);
     IGL_INLINE bool mouse_move(int mouse_x,int mouse_y);
     IGL_INLINE bool mouse_scroll(float delta_y);
     IGL_INLINE bool mouse_scroll(float delta_y);
-
     // Scene IO
     // Scene IO
     IGL_INLINE bool load_scene();
     IGL_INLINE bool load_scene();
     IGL_INLINE bool load_scene(std::string fname);
     IGL_INLINE bool load_scene(std::string fname);
     IGL_INLINE bool save_scene();
     IGL_INLINE bool save_scene();
-
+    IGL_INLINE bool save_scene(std::string fname);
     // Draw everything
     // Draw everything
     IGL_INLINE void draw();
     IGL_INLINE void draw();
-
     // OpenGL context resize
     // OpenGL context resize
     IGL_INLINE void resize(int w,int h); // explicitly set window size
     IGL_INLINE void resize(int w,int h); // explicitly set window size
     IGL_INLINE void post_resize(int w,int h); // external resize due to user interaction
     IGL_INLINE void post_resize(int w,int h); // external resize due to user interaction
-
     // Helper functions
     // Helper functions
     IGL_INLINE void snap_to_canonical_quaternion();
     IGL_INLINE void snap_to_canonical_quaternion();
     IGL_INLINE void open_dialog_load_mesh();
     IGL_INLINE void open_dialog_load_mesh();
     IGL_INLINE void open_dialog_save_mesh();
     IGL_INLINE void open_dialog_save_mesh();
+    IGL_INLINE ViewerData& data();
+    // Append a new "slot" for a mesh (i.e., create empty entires at the end of
+    // the data_list and opengl_state_list.
+    //
+    // Returns number of meshes (always >= 1)
+    //
+    // Side Effects:
+    //   selected_data_index is set this newly created, last entry (i.e.,
+    //   #meshes-1)
+    IGL_INLINE size_t append_mesh();
+    // Erase a mesh (i.e., its corresponding data and state entires in data_list
+    // and opengl_state_list)
+    //
+    // Inputs:
+    //   index  index of mesh to erase
+    // Returns whether erasure was successful <=> cannot erase last mesh
+    //
+    // Side Effects:
+    //   If selected_data_index is greater than or equal to index then it is
+    //   decremented
+    // Example:
+    //   // Erase all mesh slots except first and clear remaining mesh
+    //   viewer.selected_data_index = viewer.data_list.size()-1;
+    //   while(viewer.erase_mesh(viewer.selected_data_index)){};
+    //   viewer.data().clear();
+    //
+    IGL_INLINE bool erase_mesh(const size_t index);
 
 
+    // Alec: I call this data_list instead of just data to avoid confusion with
+    // old "data" variable.
+    // Stores all the data that should be visualized
+    std::vector<ViewerData> data_list;
+
+    size_t selected_data_index;
+    GLFWwindow* window;
+    // Stores all the viewing options
+    ViewerCore core;
+    // List of registered plugins
+    std::vector<ViewerPlugin*> plugins;
+    // Temporary data stored when the mouse button is pressed
+    Eigen::Quaternionf down_rotation;
+    int current_mouse_x;
+    int current_mouse_y;
+    int down_mouse_x;
+    int down_mouse_y;
+    float down_mouse_z;
+    Eigen::Vector3f down_translation;
+    bool down;
+    bool hack_never_moved;
+    // Keep track of the global position of the scrollwheel
+    float scroll_position;
     // C++-style functions
     // C++-style functions
     //
     //
     // Returns **true** if action should be cancelled.
     // Returns **true** if action should be cancelled.
@@ -141,7 +144,6 @@ namespace viewer
     // THESE SHOULD BE DEPRECATED:
     // THESE SHOULD BE DEPRECATED:
     std::function<bool(Viewer& viewer, unsigned char key, int modifiers)> callback_key_down;
     std::function<bool(Viewer& viewer, unsigned char key, int modifiers)> callback_key_down;
     std::function<bool(Viewer& viewer, unsigned char key, int modifiers)> callback_key_up;
     std::function<bool(Viewer& viewer, unsigned char key, int modifiers)> callback_key_up;
-
     // Pointers to per-callback data
     // Pointers to per-callback data
     void* callback_init_data;
     void* callback_init_data;
     void* callback_pre_draw_data;
     void* callback_pre_draw_data;
@@ -160,6 +162,7 @@ namespace viewer
 
 
 } // end namespace
 } // end namespace
 } // end namespace
 } // end namespace
+} // end namespace
 
 
 #ifndef IGL_STATIC_LIBRARY
 #ifndef IGL_STATIC_LIBRARY
 #  include "Viewer.cpp"
 #  include "Viewer.cpp"

+ 6 - 5
include/igl/viewer/ViewerPlugin.h → include/igl/opengl/glfw/ViewerPlugin.h

@@ -5,8 +5,8 @@
 // This Source Code Form is subject to the terms of the Mozilla Public License
 // 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
 // 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/.
 // obtain one at http://mozilla.org/MPL/2.0/.
-#ifndef IGL_VIEWER_VIEWER_PLUGIN_H
-#define IGL_VIEWER_VIEWER_PLUGIN_H
+#ifndef IGL_OPENGL_GLFW_VIEWERPLUGIN_H
+#define IGL_OPENGL_GLFW_VIEWERPLUGIN_H
 
 
 // TODO:
 // TODO:
 // * create plugins/skeleton.h
 // * create plugins/skeleton.h
@@ -19,7 +19,9 @@
 
 
 namespace igl
 namespace igl
 {
 {
-namespace viewer
+namespace opengl
+{
+namespace glfw
 {
 {
 
 
 // Abstract class for plugins
 // Abstract class for plugins
@@ -160,7 +162,6 @@ protected:
   Viewer *viewer;
   Viewer *viewer;
 };
 };
 
 
-#ifdef ENABLE_SERIALIZATION
 namespace serialization
 namespace serialization
 {
 {
   inline void serialize(const ViewerPlugin& obj,std::vector<char>& buffer)
   inline void serialize(const ViewerPlugin& obj,std::vector<char>& buffer)
@@ -173,8 +174,8 @@ namespace serialization
     obj.deserialize(buffer);
     obj.deserialize(buffer);
   }
   }
 }
 }
-#endif
 
 
+}
 }
 }
 }
 }
 
 

+ 5 - 10
include/igl/opengl/glfw/background_window.cpp

@@ -17,16 +17,11 @@ IGL_INLINE bool igl::opengl::glfw::background_window(GLFWwindow* & window)
   window = glfwCreateWindow(1, 1,"", NULL, NULL);
   window = glfwCreateWindow(1, 1,"", NULL, NULL);
   if(!window) return false;
   if(!window) return false;
   glfwMakeContextCurrent(window);
   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));
-    }
-    glGetError(); // pull and savely ignonre unhandled errors like GL_INVALID_ENUM
-  #endif
+  if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress))
+  {
+    printf("Failed to load OpenGL and its extensions");
+  }
+  glGetError(); // pull and safely ignore unhandled errors like GL_INVALID_ENUM
   return true;
   return true;
 }
 }
 
 

+ 2 - 3
include/igl/opengl/glfw/background_window.h

@@ -1,9 +1,8 @@
 #ifndef IGL_OPENGL_GLFW_BACKGROUND_WINDOW_H
 #ifndef IGL_OPENGL_GLFW_BACKGROUND_WINDOW_H
 #define IGL_OPENGL_GLFW_BACKGROUND_WINDOW_H
 #define IGL_OPENGL_GLFW_BACKGROUND_WINDOW_H
 #include "../../igl_inline.h"
 #include "../../igl_inline.h"
-#include "../gl.h"
 
 
-#define GLFW_INCLUDE_GLU
+#include "../gl.h"
 #include <GLFW/glfw3.h>
 #include <GLFW/glfw3.h>
 
 
 namespace igl
 namespace igl
@@ -13,7 +12,7 @@ namespace igl
     namespace glfw
     namespace glfw
     {
     {
       // Create a background window with a valid core profile opengl context
       // Create a background window with a valid core profile opengl context
-      // set to current. 
+      // set to current.
       //
       //
       // After you're finished with this window you may call
       // After you're finished with this window you may call
       // `glfwDestroyWindow(window)`
       // `glfwDestroyWindow(window)`

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini