Переглянути джерело

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

Former-commit-id: 5aa1360ab8b43dab7ff8f6f757a4f23c2009d425
Jérémie Dumas 7 роки тому
батько
коміт
a5635bf05f
100 змінених файлів з 2405 додано та 1116 видалено
  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"]
 	path = external/embree
 	url = https://github.com/embree/embree.git
@@ -24,3 +19,15 @@
 [submodule "external/cork"]
 	path = external/cork
 	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
       script:
         - 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
         - mkdir build
         - cd build
@@ -63,5 +63,5 @@ matrix:
         - cd tutorial
         - mkdir build
         - cd build
-        - cmake -DLIBIGL_USE_STATIC_LIBRARY=ON -DLIBIGL_WITH_NANOGUI=ON ../
+        - cmake -DLIBIGL_USE_STATIC_LIBRARY=ON ../
         - make -j 2

+ 1 - 1
README.md

@@ -193,7 +193,7 @@ BibTeX entry:
   title = {{libigl}: A simple {C++} geometry processing library},
   author = {Alec Jacobson and Daniele Panozzo and others},
   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.0   | Better active set method support
 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.0   | XML serializer more stable and fixed bug in remove_duplicate_vertices
 0.1.8   | Embree and xml (windows only) extras

+ 2 - 2
file-formats/dmat.html

@@ -12,7 +12,7 @@
     <p>
 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
-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.
     </p>
     <h2>ASCII</h2>
@@ -33,7 +33,7 @@ Then there should be another header containing the size of the binary part:
     </p>
     <pre><code>[#cols] [#rows]</code></pre>
     <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.
     </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
     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><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
     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
@@ -37,7 +37,7 @@
     href=https://en.wikipedia.org/wiki/Portable_Network_Graphics>.png</a>
     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>
-  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: 
       <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>

+ 1 - 1
file-formats/tgf.html

@@ -11,7 +11,7 @@
     <hr>
     <p>
 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>
 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/>
 User defined types: <b>XMLSerializable*.</b><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>
     <pre><code>&lt;group&gt;
   &lt;vector size="3"&gt;

+ 60 - 57
include/igl/AABB.cpp

@@ -15,6 +15,7 @@
 #include "sort.h"
 #include "volume.h"
 #include "ray_box_intersect.h"
+#include "parallel_for.h"
 #include "ray_mesh_intersect.h"
 #include <iostream>
 #include <iomanip>
@@ -27,7 +28,7 @@ template <typename DerivedV, int DIM>
 template <typename DerivedEle, typename Derivedbb_mins, typename Derivedbb_maxs, typename Derivedelements>
 IGL_INLINE void igl::AABB<DerivedV,DIM>::init(
     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_maxs> & bb_maxs,
     const Eigen::MatrixBase<Derivedelements> & elements,
@@ -106,7 +107,7 @@ template <
   typename DerivedI>
 IGL_INLINE void igl::AABB<DerivedV,DIM>::init(
     const Eigen::MatrixBase<DerivedV> & V,
-    const Eigen::MatrixBase<DerivedEle> & Ele, 
+    const Eigen::MatrixBase<DerivedEle> & Ele,
     const Eigen::MatrixBase<DerivedSI> & SI,
     const Eigen::MatrixBase<DerivedI> & I)
 {
@@ -204,15 +205,15 @@ template <typename DerivedV, int DIM>
 template <typename DerivedEle, typename Derivedq>
 IGL_INLINE std::vector<int> igl::AABB<DerivedV,DIM>::find(
     const Eigen::MatrixBase<DerivedV> & V,
-    const Eigen::MatrixBase<DerivedEle> & Ele, 
+    const Eigen::MatrixBase<DerivedEle> & Ele,
     const Eigen::MatrixBase<Derivedq> & q,
     const bool first) const
 {
   using namespace std;
   using namespace Eigen;
-  assert(q.size() == DIM && 
+  assert(q.size() == DIM &&
       "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");
   const Scalar epsilon = igl::EPS<Scalar>();
   // 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 V3 = V.row(Ele(m_primitive,2));
           // 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);
           a1 = doublearea_single(V1,V2,q2);
           a2 = doublearea_single(V2,V3,q2);
@@ -266,9 +267,9 @@ IGL_INLINE std::vector<int> igl::AABB<DerivedV,DIM>::find(
     a3 /= sum;
     a4 /= sum;
     if(
-        a1>=-epsilon && 
-        a2>=-epsilon && 
-        a3>=-epsilon && 
+        a1>=-epsilon &&
+        a2>=-epsilon &&
+        a3>=-epsilon &&
         a4>=-epsilon)
     {
       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 DerivedEle>
-IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar 
+IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar
 igl::AABB<DerivedV,DIM>::squared_distance(
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & p,
   int & i,
   Eigen::PlainObjectBase<RowVectorDIMS> & c) const
@@ -359,10 +360,10 @@ igl::AABB<DerivedV,DIM>::squared_distance(
 
 template <typename DerivedV, int DIM>
 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(
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & p,
   Scalar low_sqr_d,
   Scalar up_sqr_d,
@@ -393,7 +394,7 @@ igl::AABB<DerivedV,DIM>::squared_distance(
     {
       int i_left;
       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);
       this->set_min(p,sqr_d_left,i_left,c_left,sqr_d,i,c);
       looked_left = true;
@@ -401,8 +402,8 @@ igl::AABB<DerivedV,DIM>::squared_distance(
     const auto & look_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);
       this->set_min(p,sqr_d_right,i_right,c_right,sqr_d,i,c);
       looked_right = true;
@@ -418,9 +419,9 @@ igl::AABB<DerivedV,DIM>::squared_distance(
       look_right();
     }
     // 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());
-    Scalar right_up_sqr_d = 
+    Scalar right_up_sqr_d =
       m_right->m_box.squaredExteriorDistance(p.transpose());
     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 DerivedEle>
-IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar 
+IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar
 igl::AABB<DerivedV,DIM>::squared_distance(
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & p,
   Scalar up_sqr_d,
   int & i,
@@ -464,13 +465,13 @@ igl::AABB<DerivedV,DIM>::squared_distance(
 template <typename DerivedV, int DIM>
 template <
   typename DerivedEle,
-  typename DerivedP, 
-  typename DerivedsqrD, 
-  typename DerivedI, 
+  typename DerivedP,
+  typename DerivedsqrD,
+  typename DerivedI,
   typename DerivedC>
 IGL_INLINE void igl::AABB<DerivedV,DIM>::squared_distance(
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const Eigen::MatrixBase<DerivedP> & P,
   Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
   Eigen::PlainObjectBase<DerivedI> & I,
@@ -482,35 +483,37 @@ IGL_INLINE void igl::AABB<DerivedV,DIM>::squared_distance(
   C.resizeLike(P);
   // O( #P * log #Ele ), where log #Ele is really the depth of this AABB
   // 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 < 
+template <
   typename DerivedEle,
   typename Derivedother_V,
   typename Derivedother_Ele,
-  typename DerivedsqrD, 
-  typename DerivedI, 
+  typename DerivedsqrD,
+  typename DerivedI,
   typename DerivedC>
 IGL_INLINE void igl::AABB<DerivedV,DIM>::squared_distance(
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const AABB<Derivedother_V,DIM> & other,
   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<DerivedI> & I,
   Eigen::PlainObjectBase<DerivedC> & C) const
 {
-  assert(other_Ele.cols() == 1 && 
+  assert(other_Ele.cols() == 1 &&
     "Only implemented for other as list of points");
   assert(other_V.cols() == V.cols() && "other must match this dimension");
   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 < 
+template <
   typename DerivedEle,
   typename Derivedother_V,
   typename Derivedother_Ele,
-  typename DerivedsqrD, 
-  typename DerivedI, 
+  typename DerivedsqrD,
+  typename DerivedI,
   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(
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const AABB<Derivedother_V,DIM> * other,
   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*/,
   Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
   Eigen::PlainObjectBase<DerivedI> & I,
@@ -584,7 +587,7 @@ IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar
     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
   //const auto & min_squared_distance = [&](
   //  const AABB<DerivedV,DIM> * A,
@@ -731,9 +734,9 @@ IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar
       //assert(mc == mm);
       // Only look left/right in this_list if can possible decrease somebody's
       // 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(
-          min_this_other < sqr_d && 
+          min_this_other < sqr_d &&
           min_this_other < other_tree->m_low_sqr_d)
       {
         //cout<<"before: "<<other_low_sqr_d(child)<<endl;
@@ -764,7 +767,7 @@ template <typename DerivedV, int DIM>
 template <typename DerivedEle>
 IGL_INLINE void igl::AABB<DerivedV,DIM>::leaf_squared_distance(
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & p,
   const Scalar low_sqr_d,
   Scalar & sqr_d,
@@ -789,7 +792,7 @@ template <typename DerivedV, int DIM>
 template <typename DerivedEle>
 IGL_INLINE void igl::AABB<DerivedV,DIM>::leaf_squared_distance(
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & p,
   Scalar & sqr_d,
   int & i,
@@ -801,7 +804,7 @@ IGL_INLINE void igl::AABB<DerivedV,DIM>::leaf_squared_distance(
 
 template <typename DerivedV, int DIM>
 IGL_INLINE void igl::AABB<DerivedV,DIM>::set_min(
-  const RowVectorDIMS & 
+  const RowVectorDIMS &
 #ifndef NDEBUG
   p
 #endif
@@ -831,10 +834,10 @@ IGL_INLINE void igl::AABB<DerivedV,DIM>::set_min(
 
 template <typename DerivedV, int DIM>
 template <typename DerivedEle>
-IGL_INLINE bool 
+IGL_INLINE bool
 igl::AABB<DerivedV,DIM>::intersect_ray(
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & origin,
   const RowVectorDIMS & dir,
   std::vector<igl::Hit> & hits) const
@@ -874,10 +877,10 @@ igl::AABB<DerivedV,DIM>::intersect_ray(
 
 template <typename DerivedV, int DIM>
 template <typename DerivedEle>
-IGL_INLINE bool 
+IGL_INLINE bool
 igl::AABB<DerivedV,DIM>::intersect_ray(
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & origin,
   const RowVectorDIMS & dir,
   igl::Hit & hit) const
@@ -932,10 +935,10 @@ igl::AABB<DerivedV,DIM>::intersect_ray(
 
 template <typename DerivedV, int DIM>
 template <typename DerivedEle>
-IGL_INLINE bool 
+IGL_INLINE bool
 igl::AABB<DerivedV,DIM>::intersect_ray(
   const Eigen::MatrixBase<DerivedV> & V,
-  const Eigen::MatrixBase<DerivedEle> & Ele, 
+  const Eigen::MatrixBase<DerivedEle> & Ele,
   const RowVectorDIMS & origin,
   const RowVectorDIMS & dir,
   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
 // combinations of 3D V with DIM=2 AABB
-// 
+//
 // _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

+ 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
   // 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.
   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
 // 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
 

+ 1 - 1
include/igl/SortableRow.h

@@ -15,7 +15,7 @@
 namespace igl
 {
   // 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>
   class SortableRow
   {

+ 3 - 3
include/igl/WindingNumberTree.h

@@ -52,7 +52,7 @@ namespace igl
       MatrixXS SV;
       // Facets in this bounding volume
       MatrixXF F;
-      // Tesselated boundary curve
+      // Tessellated boundary curve
       MatrixXF cap;
       // Upper Bound on radius of enclosing ball
       typename DerivedV::Scalar radius;
@@ -97,7 +97,7 @@ namespace igl
       // Same as above, but always computes winding number using exact method
       // (sum over every facet)
       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;
       //// 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
@@ -493,7 +493,7 @@ igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
   return 0;
 }
 
-// Explicit instanciation of static variable
+// Explicit instantiation of static variable
 template <
   typename Point,
   typename DerivedV, 

+ 4 - 3
include/igl/adjacency_matrix.cpp

@@ -23,15 +23,16 @@ IGL_INLINE void igl::adjacency_matrix(
   typedef Triplet<T> IJV;
   vector<IJV > ijv;
   ijv.reserve(F.size()*2);
-  // Loop over faces
+  // Loop over **simplex** (i.e., **not quad**)
   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 k = j+1;k<F.cols();k++)
     {
       // Get indices of edge: s --> d
       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(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
 #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
 template <typename LbsMatrixType, typename SSCALAR>
 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
-  // "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
   // identity blocks, which should be pretty small number
   template <typename MatrixXS>
@@ -449,7 +449,7 @@ namespace igl
   }
   
   // 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
   // scaled 3x3 identity blocks, which should be pretty small number
   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,
   //     also holds fixed transformation entries for fixed handles
   //   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,
   //       0.75 (weak 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
   //   b  #b boundary indices into V
   //   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:
   //   W  #V by #W list of *unnormalized* weights to normalize use
   //    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
   // Outputs:
   //   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 <
@@ -46,12 +46,12 @@ namespace igl
     Eigen::PlainObjectBase<DerivedU> & U);
   //
   // 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)
   //   num_inner_iters  number of iterations of harmonic solves to run after
   //     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
   //     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];
   }
 
-  // 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++)
   {
     double sum = bc.row(i).sum();

+ 1 - 1
include/igl/cat.h

@@ -25,7 +25,7 @@ namespace igl
   // Template:
   //   Scalar  scalar data type for sparse matrices like double or int
   //   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
   // Inputs:
   //   A  first input matrix

+ 3 - 1
include/igl/colormap.cpp

@@ -1378,7 +1378,7 @@ IGL_INLINE void igl::colormap(
   Eigen::PlainObjectBase<DerivedC> & C)
 {
   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);
 }
 
@@ -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> >&);
 // 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::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

+ 32 - 2
include/igl/combine.cpp

@@ -7,19 +7,26 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "combine.h"
 #include <cassert>
+
 template <
   typename DerivedVV, 
   typename DerivedFF, 
   typename DerivedV, 
-  typename DerivedF>
+  typename DerivedF,
+  typename DerivedVsizes,
+  typename DerivedFsizes>
 IGL_INLINE void igl::combine(
   const std::vector<DerivedVV> & VV,
   const std::vector<DerivedFF> & FF,
   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() && 
     "Lists of verex lists and face lists should be same size");
+  Vsizes.resize(VV.size());
+  Fsizes.resize(FF.size());
   // Dimension of vertex positions
   const int dim = VV.size() > 0 ? VV[0].cols() : 0;
   // Simplex/element size
@@ -30,8 +37,10 @@ IGL_INLINE void igl::combine(
   {
     const auto & Vi = VV[i];
     const auto & Fi = FF[i];
+    Vsizes(i) = Vi.rows();
     n+=Vi.rows();
     assert(dim == Vi.cols() && "All vertex lists should have same #columns");
+    Fsizes(i) = Fi.rows();
     m+=Fi.rows();
     assert(ss == Fi.cols() && "All face lists should have same #columns");
   }
@@ -55,3 +64,24 @@ IGL_INLINE void igl::combine(
     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
 {
-  // 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:
   //   VV  k-long list of lists of mesh vertex positions
@@ -26,10 +26,27 @@ namespace igl
   //     vertex positions
   //   F   FF[0].rows()+...+FF[k-1].rows() by FF[0].cols() list of mesh faces
   //     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:
   //   // Suppose you have mesh A (VA,FA) and mesh B (VB,FB)
   //   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 <
     typename DerivedVV, 
     typename DerivedFF, 

+ 1 - 1
include/igl/connect_boundary_to_infinity.h

@@ -11,7 +11,7 @@
 #include <Eigen/Core>
 namespace igl
 {
-  // Connect all boundary edges to a ficticious point at infinity.
+  // Connect all boundary edges to a fictitious point at infinity.
   //
   // Inputs:
   //   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: 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
-// 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
 // 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.
-// 
+//
 // 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/.
 #include "assign_scalar.h"
 
@@ -97,3 +97,40 @@ IGL_INLINE void igl::copyleft::cgal::assign_scalar(
       d = next;
   } 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.
-// 
+//
 // 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/.
 #ifndef IGL_COPYLEFT_CGAL_ASSIGN_SCALAR_H
 #define IGL_COPYLEFT_CGAL_ASSIGN_SCALAR_H
 #include "../../igl_inline.h"
 #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
 #include <CGAL/Exact_predicates_exact_constructions_kernel_with_sqrt.h>
+#ifndef WIN32
+#include <CGAL/gmpxx.h>
+#endif
+
 namespace igl
 {
   namespace copyleft
@@ -38,6 +42,7 @@ namespace igl
       IGL_INLINE void assign_scalar(
         const float& c,
         double& d);
+
       IGL_INLINE void assign_scalar(
         const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
         CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & d);
@@ -47,6 +52,19 @@ namespace igl
       IGL_INLINE void assign_scalar(
         const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
         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.
       //
       // 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
       //                   is on the positive side of x, and j is on the
       //                   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:
         // Warning:
         // 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;
       default:
         throw std::runtime_error("Unknown CGAL state.");

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

@@ -12,13 +12,6 @@
 
 #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 copyleft

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

@@ -15,6 +15,7 @@
 #include "relabel_small_immersed_cells.h"
 #include "remesh_self_intersections.h"
 #include "string_to_mesh_boolean_type.h"
+#include "../../combine.h"
 #include "../../cumsum.h"
 #include "../../extract_manifold_patches.h"
 #include "../../get_seconds.h"
@@ -137,33 +138,11 @@ IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
     Eigen::PlainObjectBase<DerivedFC > & FC,
     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 <

+ 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].col(0) = eJ.array() + (FA.rows()+1);
     vJ[ee].col(1).setConstant(ee);
+    offsets[ee+1] = offsets[ee] + vW[ee].rows();
   }
   // Combine meshes
   int n=0,m=0;
@@ -141,7 +142,7 @@ IGL_INLINE void igl::copyleft::cgal::minkowski_sum(
       W,
       G,
       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.
       //   F  #F by 3 list of faces
       //   s  Index of source vertex.
-      //   d  Index of desination vertex.
+      //   d  Index of destination vertex.
       //   adj_faces  List of adjacent face signed indices.
       // Output:
       //   order  List of face indices that orders adjacent faces around edge
@@ -50,7 +50,7 @@ namespace igl
           Eigen::PlainObjectBase<DerivedI>& order,
           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
       // order[0] is the index into adj_face that is immediately after the
       // 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.
         //
         // 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:
         //   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
   // precomputation. the tree (despite being const) will still do more
   // 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));
 }
 

+ 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);
                 break;
             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
 
   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;
   }
 

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

@@ -10,6 +10,7 @@
 #include "assign_scalar.h"
 #include "projected_cdt.h"
 #include "../../get_seconds.h"
+#include "../../parallel_for.h"
 #include "../../LinSpaced.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<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
     log_time("cdt");
 #endif
@@ -449,7 +453,7 @@ IGL_INLINE void igl::copyleft::cgal::remesh_intersections(
           FF.data(), [&vv_to_unique](const typename DerivedFF::Scalar& a)
           { return vv_to_unique[a]; });
       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<
         Eigen::Matrix<typename DerivedIM::Scalar, Eigen::Dynamic,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
       //     of first finding and list of intersection objects from all
       //     intersections
-      //   stitch_all  if true, merge all vertices with thte same coordiante.
+      //   stitch_all  if true, merge all vertices with the same coordinate.
       // Outputs:
       //   VV  #VV by 3 list of vertex positions, if stitch_all = false then
       //     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::VectorXi(P),A,1,P);
   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<std::vector<CGAL::Epeck::FT> > vQ;
   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 double th,
   const int poly_size,
+  const bool solid,
   Eigen::PlainObjectBase<DerivedV> & V,
   Eigen::PlainObjectBase<DerivedF> & F,
   Eigen::PlainObjectBase<DerivedJ> & J)
@@ -68,6 +69,8 @@ IGL_INLINE void igl::copyleft::cgal::wire_mesh(
     A[WE(e,1)].emplace_back(e,1);
     typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
     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();
     Eigen::Quaternion<Scalar> q;
     q = q.FromTwoVectors(RowVector3S(0,0,1),uv);
@@ -78,9 +81,16 @@ IGL_INLINE void igl::copyleft::cgal::wire_mesh(
       // loop over endpoints
       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)) = 
-          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);
-  // 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

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

@@ -6,24 +6,26 @@ namespace igl
 {
   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
     {
+      // 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 <
         typename DerivedWV,
         typename DerivedWE,
@@ -35,9 +37,26 @@ namespace igl
         const Eigen::MatrixBase<DerivedWE> & WE,
         const double th,
         const int poly_size,
+        const bool solid,
         Eigen::PlainObjectBase<DerivedV> & V,
         Eigen::PlainObjectBase<DerivedF> & F,
         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
     //   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
 
     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)
     //   bc_soft #S by 3 bc for soft constraints
     //   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)
     // Outputs:
     //   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())
       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>();
     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
 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<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

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

@@ -8,7 +8,7 @@ namespace igl
 {
   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.
     //
     // Inputs:

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

@@ -20,7 +20,7 @@ namespace igl
     //   width  width of scene and resulting image
     //   height height of scene and resulting image
     ///  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
     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"}
         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.
       //
       // Inputs:

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

@@ -30,8 +30,8 @@ namespace igl
       //   .medit
       //   .vtk
       //   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
       // 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 
 //    Alec 9 October 2011
 //  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
 
 namespace igl 

+ 2 - 2
include/igl/cotmatrix_entries.cpp

@@ -35,10 +35,10 @@ IGL_INLINE void igl::cotmatrix_entries(
     case 3:
     {
       // Triangles
-      //Compute Squared Edge lenghts 
+      //Compute Squared Edge lengths 
       Matrix<typename DerivedC::Scalar,Dynamic,3> l2;
       igl::squared_edge_lengths(V,F,l2);
-      //Compute Edge lenghts 
+      //Compute Edge lengths 
       Matrix<typename DerivedC::Scalar,Dynamic,3> l;
       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<DerivedEMAP> & EMAP)
 {
-  // All occurances of directed "facets"
+  // All occurrences of directed "facets"
   Eigen::MatrixXi allE;
   oriented_facets(F,allE);
   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<DerivedEMAP> & EMAP)
 {
-  // All occurances of directed "facets"
+  // All occurrences of directed "facets"
   Eigen::MatrixXi allE;
   oriented_facets(F,allE);
   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);
 
 
-    // intialize the mapping given an initial pos
+    // initialize the mapping given an initial pos
     // whih must be initialized with FindInitialPos
     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);
 
   };
@@ -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
 template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename 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
 {
-  // Recover "parents" (preceeding edges) in a tree given just directed edges.
+  // Recover "parents" (preceding edges) in a tree given just directed edges.
   //
   // Inputs:
   //   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/.
 #include "edges.h"
 #include "adjacency_matrix.h"
+#include <iostream>
 
 template <typename DerivedF, typename DerivedE>
 IGL_INLINE void igl::edges(

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

@@ -209,7 +209,7 @@ inline void igl::embree::EmbreeIntersector::global_init()
   {
     rtcInit();
     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
     else
       std::cerr << "Embree: core initialized." << std::endl;
@@ -324,7 +324,7 @@ inline void igl::embree::EmbreeIntersector::init(
   rtcCommit(scene);
 
   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
   else
     std::cerr << "Embree: geometry added." << endl;
@@ -348,7 +348,7 @@ void igl::embree::EmbreeIntersector::deinit()
 
     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
     else
@@ -374,7 +374,7 @@ inline bool igl::embree::EmbreeIntersector::intersectRay(
   rtcIntersect(scene,ray);
 #ifdef IGL_VERBOSE
   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
 
   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;
     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++)
     {
       const int count = counts(ue);

+ 1 - 1
include/igl/exterior_edges.h

@@ -12,7 +12,7 @@
 namespace igl
 {
   // 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
   //
   // Inputs:

+ 2 - 2
include/igl/facet_components.h

@@ -16,7 +16,7 @@ namespace igl
   //
   // Inputs:
   //   F  #F by 3 list of triangle indices
-  // Ouputs:
+  // Outputs:
   //   C  #F list of connected component ids
   template <typename DerivedF, typename DerivedC>
   IGL_INLINE void facet_components(
@@ -25,7 +25,7 @@ namespace igl
   // Inputs:
   //   TT  #TT by 3 list of list of adjacency triangles (see
   //   triangle_triangle_adjacency.h)
-  // Ouputs:
+  // Outputs:
   //   C  #F list of connected component ids
   //   counts #C list of number of facets in each components
   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
   //     ith corner
   //   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:
   //   l  lower 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::DiagonalMatrix
                        <Scalar, Eigen::Dynamic, Eigen::Dynamic> DiagMat;
-    
+
     int dim = V.cols();
     assert((dim==2 || dim==3) &&
            "The dimension of the vertices should be 2 or 3");
-    
+
     //Construct the combined gradient matric
     SparseMat G;
-    igl::grad(Eigen::PlainObjectBase<DerivedV>(V),
-              Eigen::PlainObjectBase<DerivedF>(F),
+    igl::grad(DerivedV(V),
+              DerivedF(F),
               G, false);
     SparseMat GG(F.rows(), dim*V.rows());
     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());
     SparseMat D;
     igl::repdiag(GG,dim,D);
-    
+
     //Compute area matrix
     VecXd areas;
     igl::doublearea(V, F, areas);
     DiagMat A = (0.5*areas).replicate(dim,1).asDiagonal();
-    
+
     //Compute FEM Hessian
     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::DiagonalMatrix
                        <Scalar, Eigen::Dynamic, Eigen::Dynamic> DiagMat;
-    
+
     int dim = V.cols();
     assert((dim==2 || dim==3) &&
            "The dimension of the vertices should be 2 or 3");
-    
+
     SparseMat M;
     igl::massmatrix(V,F,igl::MASSMATRIX_TYPE_VORONOI,M);
-    
+
     //Kill non-interior DOFs
     VecXd Mint = M.diagonal();
     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 int& bdryVert : loop)
             Mint(bdryVert) = 0.;
-    
+
     //Invert Mint
     for(int i=0; i<Mint.rows(); ++i)
         if(Mint(i) > 0)
             Mint(i) = 1./Mint(i);
-    
+
     //Repeat Mint to form diaginal matrix
     DiagMat stackedMinv = Mint.replicate(dim*dim,1).asDiagonal();
-    
+
     //Compute squared Hessian
     SparseMat H;
     igl::hessian(V,F,H);
     Q = H.transpose()*stackedMinv*H;
-    
+
 }
 
 

+ 1 - 1
include/igl/histc.h

@@ -13,7 +13,7 @@
 
 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
   //
   // Inputs:

+ 2 - 2
include/igl/integrable_polyvector_fields.h

@@ -15,7 +15,7 @@
 
 namespace igl {
   // 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.
 
   // Set of parameters used during solve
@@ -51,7 +51,7 @@ namespace igl {
                                                     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
   // and returned for the next iteration.
   // Inputs:

+ 4 - 4
include/igl/is_boundary_edge.cpp

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

+ 1 - 1
include/igl/is_planar.h

@@ -13,7 +13,7 @@
 
 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:
   //   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
   {
-    stl_file = freopen(NULL,"rb",stl_file);
+    //stl_file = freopen(NULL,"rb",stl_file);
     // Read 80 header
     char header[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);
     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);
   };
   // Specifically 80 character header

+ 4 - 1
include/igl/ismember.cpp

@@ -12,6 +12,7 @@
 #include "sortrows.h"
 #include "unique.h"
 #include "unique_rows.h"
+#include <iostream>
 
 template <
   typename DerivedA,
@@ -153,10 +154,11 @@ IGL_INLINE void igl::ismember_rows(
     bool past = false;
     for(int a = 0;a<sA.rows();a++)
     {
+      assert(bi < sB.rows());
       while(!past && row_greater_than(a,bi))
       {
         bi++;
-        past = bi>=sB.size();
+        past = bi>=sB.rows();
       }
       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<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<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

+ 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<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

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

@@ -59,7 +59,7 @@ namespace igl
     //--------------------------------------------------------------------------
     // Return values:
     //  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
     //  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> >&);
 
 #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<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<__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 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

+ 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
     //
     // Inputs:
-    //   i  index of current arguement
+    //   i  index of current argument
     //   nrhs  total number of arguments
-    //   prhs  pointer to arguements array
+    //   prhs  pointer to arguments array
     //   name   name of current argument
     IGL_INLINE void validate_arg_scalar(
       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:
   //   DerivedM  e.g. derived from MatrixXd
   // Input:
-  //   input  some matrix to be formated
+  //   input  some matrix to be formatted
   //   name  name of matrix
-  // Returns  Formated matrix
+  // Returns  Formatted matrix
   //
   // Example:
   // // M := [1 2 3;4 5 6];
@@ -44,7 +44,7 @@ namespace igl
   IGL_INLINE const Eigen::WithFormat< DerivedM > matlab_format(
     const Eigen::DenseBase<DerivedM> & M,
     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
   // Example:
   // // 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);
     }
 
-    // Positive definite and no equality constraints (Postive definiteness
+    // Positive definite and no equality constraints (Positive definiteness
     // implies symmetric)
 #ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
     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
     //   b  #b boundary indices into V
     //   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
     // Outputs:
     //   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)
       {
-        k = MSK_BK_RA;
-      }else{
         k = MSK_BK_FX;
+      }else{
+        k = MSK_BK_RA;
       }
     }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-8 MOSEK DEFAULT SOLUTION
   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...
 #if MSK_VERSION_MAJOR >= 7
   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
   //   instantaneous
   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;
   // Hard to say if this is doing anything, probably nothing dramatic
   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
 // 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_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/viewer/OpenGL_shader.h>
-#include <igl/viewer/ViewerData.h>
+#include <Eigen/Core>
 
 namespace igl
 {
-namespace viewer
+namespace opengl
 {
 
-class OpenGL_state
+class MeshGL
 {
 public:
   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_overlay_lines;
   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_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
 
   // 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_v;
   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
   uint32_t dirty;
@@ -81,9 +100,6 @@ public:
   // Create a new set of OpenGL buffer objects
   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
   IGL_INLINE void bind_mesh();
 
@@ -111,7 +127,7 @@ public:
 }
 
 #ifndef IGL_STATIC_LIBRARY
-#  include "OpenGL_state.cpp"
+#  include "MeshGL.cpp"
 #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/.
 
 #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 <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::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::MatrixXi& F,
   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);
 }
 
-IGL_INLINE void igl::viewer::ViewerCore::align_camera_center(
+IGL_INLINE void igl::opengl::ViewerCore::align_camera_center(
   const Eigen::MatrixXd& V)
 {
   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,
   float& zoom,
   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],
                background_color[1],
@@ -93,9 +94,8 @@ IGL_INLINE void igl::viewer::ViewerCore::clear_framebuffers()
   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,
-  OpenGL_state& opengl,
   bool update_matrices)
 {
   using namespace std;
@@ -112,10 +112,10 @@ IGL_INLINE void igl::viewer::ViewerCore::draw(
   /* Bind and potentially refresh mesh/line/point data */
   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
   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
-  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(viewi, 1, GL_FALSE, view.data());
   glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
 
   // Light parameters
-  GLint specular_exponenti    = opengl.shader_mesh.uniform("specular_exponent");
-  GLint light_position_worldi = opengl.shader_mesh.uniform("light_position_world");
-  GLint lighting_factori      = opengl.shader_mesh.uniform("lighting_factor");
-  GLint fixed_colori          = opengl.shader_mesh.uniform("fixed_color");
-  GLint texture_factori       = opengl.shader_mesh.uniform("texture_factor");
+  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;
   glUniform3fv(light_position_worldi, 1, rev_light.data());
   glUniform1f(lighting_factori, lighting_factor); // enables lighting
@@ -185,108 +185,72 @@ IGL_INLINE void igl::viewer::ViewerCore::draw(
   if (data.V.rows()>0)
   {
     // Render fill
-    if (show_faces)
+    if (data.show_faces)
     {
       // 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);
     }
 
     // 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);
     }
-
-#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);
     else
       glDisable(GL_DEPTH_TEST);
 
     if (data.lines.rows() > 0)
     {
-      opengl.bind_overlay_lines();
-      modeli = opengl.shader_overlay_lines.uniform("model");
-      viewi  = opengl.shader_overlay_lines.uniform("view");
-      proji  = opengl.shader_overlay_lines.uniform("proj");
+      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(viewi, 1, GL_FALSE, view.data());
       glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
       // This must be enabled, otherwise glLineWidth has no effect
       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)
     {
-      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(viewi, 1, GL_FALSE, view.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);
   }
 
 }
 
-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,
   Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
   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;
 
   // Draw
-  draw(data,opengl,update_matrices);
+  draw(data,update_matrices);
 
   // Restore viewport
   viewport = viewport_ori;
@@ -371,8 +335,8 @@ IGL_INLINE void igl::viewer::ViewerCore::draw_buffer(ViewerData& data,
   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 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
   background_color << 0.3f, 0.3f, 0.5f, 1.0f;
-  line_color << 0.0f, 0.0f, 0.0f, 1.0f;
 
   // Default lights settings
   light_position << 0.0f, -0.30f, -5.0f;
@@ -417,36 +377,18 @@ IGL_INLINE igl::viewer::ViewerCore::ViewerCore()
   camera_center << 0, 0, 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;
 
-  // Default point size / line width
-  point_size = 30;
-  line_width = 0.5f;
   is_animating = false;
   animation_max_fps = 30.;
 
   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
 // 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_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 <Eigen/Geometry>
@@ -20,7 +17,7 @@
 
 namespace igl
 {
-namespace viewer
+namespace opengl
 {
 
 // Basic class of the 3D mesh viewer
@@ -73,10 +70,11 @@ public:
   IGL_INLINE void clear_framebuffers();
 
   // 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(
     ViewerData& data,
-    OpenGL_state& opengl,
     bool update_matrices,
     Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
     Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
@@ -95,17 +93,8 @@ public:
 
   // ------------------- Properties
 
-#ifdef IGL_VIEWER_WITH_NANOGUI
-  // Text rendering helper
-  TextRenderer textrenderer;
-#endif
-
-  // Shape material
-  float shininess;
-
   // Colors
   Eigen::Vector4f background_color;
-  Eigen::Vector4f line_color;
 
   // Lighting
   Eigen::Vector3f light_position;
@@ -119,7 +108,7 @@ public:
   float model_zoom;
   Eigen::Vector3f model_translation;
 
-  // Model viewing paramters (uv coordinates)
+  // Model viewing parameters (uv coordinates)
   float model_zoom_uv;
   Eigen::Vector3f model_translation_uv;
 
@@ -133,21 +122,8 @@ public:
   float camera_dnear;
   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;
 
-  // Point size / line width
-  float point_size;
-  float line_width;
-
   // Animation
   bool is_animating;
   double animation_max_fps;
@@ -158,7 +134,8 @@ public:
   // Viewport size
   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 model;
   Eigen::Matrix4f proj;
@@ -169,76 +146,61 @@ public:
 }
 }
 
-#ifdef ENABLE_SERIALIZATION
 #include <igl/serialize.h>
 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
 #  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
 // 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_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 <vector>
-
 #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 viewer
-{
 
 // TODO: write documentation
+namespace opengl
+{
 
 class ViewerData
 {
 public:
   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();
 
   // Change the visualization mode, invalidating the cache if necessary
@@ -186,66 +174,128 @@ public:
 
   // Enable per-face or per-vertex properties
   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
 #  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.
-// 
+//
 // 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/.
 #ifndef IGL_OPENGL_GL_H
 #define IGL_OPENGL_GL_H
@@ -16,29 +16,10 @@
 //     #include "gl.h"
 // Instead of:
 //     #include <OpenGL/gl3.h>
-// or 
+// or
 //     #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

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

@@ -19,9 +19,9 @@
 #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;
   #ifdef NDEBUG
@@ -36,7 +36,7 @@ IGL_INLINE int igl::viewer::TextRenderer::Init()
   return 0;
 }
 
-IGL_INLINE int igl::viewer::TextRenderer::Shut()
+IGL_INLINE int igl::opengl::glfw::TextRenderer::Shut()
 {
   using namespace std;
   if(ctx)
@@ -44,7 +44,7 @@ IGL_INLINE int igl::viewer::TextRenderer::Shut()
   return 0;
 }
 
-IGL_INLINE void igl::viewer::TextRenderer::BeginDraw(
+IGL_INLINE void igl::opengl::glfw::TextRenderer::BeginDraw(
   const Eigen::Matrix4f &view,
   const Eigen::Matrix4f &proj,
   const Eigen::Vector4f &_viewport,
@@ -71,13 +71,13 @@ IGL_INLINE void igl::viewer::TextRenderer::BeginDraw(
   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;
   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)
 {
   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
 // 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_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
 
 #include <Eigen/Dense>
@@ -18,7 +18,9 @@ struct NVGcontext;
 
 namespace igl
 {
-namespace viewer
+namespace opengl
+{
+namespace glfw
 {
 
   class TextRenderer
@@ -47,6 +49,7 @@ namespace viewer
 
 }
 }
+}
 
 #ifndef IGL_STATIC_LIBRARY
 #  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
 // 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>
 

+ 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
 // obtain one at http://mozilla.org/MPL/2.0/.
 
-// Must defined this before including Viewer.h
-#define IGL_VIEWER_VIEWER_CPP
 #include "Viewer.h"
 
-#ifdef _WIN32
-#  include <windows.h>
-#  undef max
-#  undef min
-#endif
-
 #include <chrono>
 #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>
 
-//#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 <cmath>
@@ -52,11 +26,6 @@
 #include <limits>
 #include <cassert>
 
-#ifdef IGL_VIEWER_WITH_NANOGUI
-#  include <nanogui/formhelper.h>
-#  include <nanogui/screen.h>
-#endif
-
 #include <igl/project.h>
 #include <igl/get_seconds.h>
 #include <igl/readOBJ.h>
@@ -73,47 +42,30 @@
 #include <igl/two_axis_valuator_fixed_up.h>
 #include <igl/snap_to_canonical_view_quat.h>
 #include <igl/unproject.h>
-
-#ifdef ENABLE_SERIALIZATION
 #include <igl/serialize.h>
-#endif
 
 // 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 scroll_x = 0;
 static double scroll_y = 0;
 
 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)
-    mb = igl::viewer::Viewer::MouseButton::Left;
+    mb = igl::opengl::glfw::Viewer::MouseButton::Left;
   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)
-    mb = igl::viewer::Viewer::MouseButton::Middle;
+    mb = igl::opengl::glfw::Viewer::MouseButton::Middle;
 
   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);
-  }
-
 }
 
 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)
 {
-  // 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)
@@ -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)
     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)
@@ -156,20 +96,11 @@ static void glfw_window_size(GLFWwindow* window, int width, int height)
 
   __viewer->post_resize(w, h);
 
-  // TODO: repositioning of the nanogui
 }
 
 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)
@@ -178,95 +109,154 @@ static void glfw_mouse_scroll(GLFWwindow* window, double x, double y)
   scroll_x += x;
   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)
 {
-#ifdef IGL_VIEWER_WITH_NANOGUI
-  __viewer->screen->dropCallbackEvent(count,filenames);
-#endif
 }
 
 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();
 
     if (callback_init)
@@ -276,14 +266,28 @@ namespace viewer
     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
     down = false;
@@ -291,7 +295,7 @@ namespace viewer
     scroll_position = 0.0f;
 
     // Per face
-    data.set_face_based(false);
+    data().set_face_based(false);
 
     // C-style callbacks
     callback_init         = nullptr;
@@ -315,7 +319,7 @@ namespace viewer
     callback_key_up_data        = nullptr;
 
 #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
   A,a     Toggle animation (tight draw loop)
   F,f     Toggle face based
@@ -325,41 +329,22 @@ namespace viewer
   T,t     Toggle filled faces
   Z       Snap to canonical view
   [,]     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 face labels)"
-#endif
 );
     std::cout<<usage<<std::endl;
 #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 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
     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('.');
     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;
     }
 
@@ -387,7 +378,7 @@ namespace viewer
       Eigen::MatrixXi F;
       if (!igl::readOFF(mesh_file_name_string, V, F))
         return false;
-      data.set_mesh(V,F);
+      data().set_mesh(V,F);
     }
     else if (extension == "obj" || extension =="OBJ")
     {
@@ -407,8 +398,8 @@ namespace viewer
         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
@@ -418,16 +409,16 @@ namespace viewer
       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,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)
       if (plugins[i]->post_load())
@@ -436,10 +427,9 @@ namespace viewer
     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
     for (unsigned int i = 0; i<plugins.size(); ++i)
       if (plugins[i]->save(mesh_file_name_string))
@@ -449,13 +439,15 @@ namespace viewer
     if (last_dot == std::string::npos)
     {
       // 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;
     }
     std::string extension = mesh_file_name_string.substr(last_dot+1);
     if (extension == "off" || extension =="OFF")
     {
-      return igl::writeOFF(mesh_file_name_string,data.V,data.F);
+      return igl::writeOFF(
+        mesh_file_name_string,data().V,data().F);
     }
     else if (extension == "obj" || extension =="OBJ")
     {
@@ -465,8 +457,10 @@ namespace viewer
       Eigen::MatrixXd UV_V;
       Eigen::MatrixXi UV_F;
 
-      return igl::writeOBJ(mesh_file_name_string, data.V,
-          data.F, corner_normals, fNormIndices, UV_V, UV_F);
+      return igl::writeOBJ(mesh_file_name_string,
+          data().V,
+          data().F,
+          corner_normals, fNormIndices, UV_V, UV_F);
     }
     else
     {
@@ -502,20 +496,20 @@ namespace viewer
       case 'F':
       case 'f':
       {
-        data.set_face_based(!data.face_based);
+        data().set_face_based(!data().face_based);
         return true;
       }
       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;
       }
       case 'L':
       case 'l':
       {
-        core.show_lines = !core.show_lines;
+        data().show_lines = !data().show_lines;
         return true;
       }
       case 'O':
@@ -527,7 +521,7 @@ namespace viewer
       case 'T':
       case 't':
       {
-        core.show_faces = !core.show_faces;
+        data().show_faces = !data().show_faces;
         return true;
       }
       case 'Z':
@@ -545,14 +539,19 @@ namespace viewer
 
         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 ';':
-        core.show_vertid = !core.show_vertid;
+        data().show_vertid = !data().show_vertid;
         return true;
       case ':':
-        core.show_faceid = !core.show_faceid;
+        data().show_faceid = !data().show_faceid;
         return true;
-#endif
       default: break;//do nothing
     }
     return false;
@@ -603,12 +602,12 @@ namespace viewer
 
     // Initialization code for the trackball
     Eigen::RowVector3d center;
-    if (data.V.rows() == 0)
+    if (data().V.rows() == 0)
     {
       center << 0,0,0;
     }else
     {
-      center = data.V.colwise().sum()/data.V.rows();
+      center = data().V.colwise().sum()/data().V.rows();
     }
 
     Eigen::Vector3f coord =
@@ -767,35 +766,19 @@ namespace viewer
     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()
@@ -803,55 +786,77 @@ namespace viewer
     std::string fname = igl::file_dialog_save();
     if (fname.length() == 0)
       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);
-
-#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;
   }
 
-  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)
   {
     if (window) {
       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)
@@ -889,165 +894,42 @@ namespace viewer
     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
 }

+ 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
 // 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_VIEWER_VIEWER_H
-#define IGL_VIEWER_VIEWER_H
+#ifndef IGL_OPENGL_GLFW_VIEWER_H
+#define IGL_OPENGL_GLFW_VIEWER_H
 
 #ifndef IGL_OPENGL_4
 #define IGL_OPENGL_4
 #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/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_CONTROL         0x0002
 #define IGL_MOD_ALT             0x0004
 #define IGL_MOD_SUPER           0x0008
 
-#ifdef IGL_VIEWER_WITH_NANOGUI
-namespace nanogui { class FormHelper; class Screen; }
-#endif
-
 struct GLFWwindow;
 
 namespace igl
 {
-namespace viewer
+namespace opengl
+{
+namespace glfw
 {
   // GLFW-based mesh viewer
   class Viewer
   {
   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_init(bool resizable = true,bool fullscreen = false);
     IGL_INLINE bool launch_rendering(bool loop = true);
     IGL_INLINE void launch_shut();
-
     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 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();
-
     // 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
     IGL_INLINE bool key_pressed(unsigned int unicode_key,int modifier);
     IGL_INLINE bool key_down(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_up(MouseButton button,int modifier);
-
     IGL_INLINE bool mouse_move(int mouse_x,int mouse_y);
     IGL_INLINE bool mouse_scroll(float delta_y);
-
     // Scene IO
     IGL_INLINE bool load_scene();
     IGL_INLINE bool load_scene(std::string fname);
     IGL_INLINE bool save_scene();
-
+    IGL_INLINE bool save_scene(std::string fname);
     // Draw everything
     IGL_INLINE void draw();
-
     // OpenGL context resize
     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
-
     // Helper functions
     IGL_INLINE void snap_to_canonical_quaternion();
     IGL_INLINE void open_dialog_load_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
     //
     // Returns **true** if action should be cancelled.
@@ -141,7 +144,6 @@ namespace viewer
     // 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_up;
-
     // Pointers to per-callback data
     void* callback_init_data;
     void* callback_pre_draw_data;
@@ -160,6 +162,7 @@ namespace viewer
 
 } // end namespace
 } // end namespace
+} // end namespace
 
 #ifndef IGL_STATIC_LIBRARY
 #  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
 // 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_VIEWER_VIEWER_PLUGIN_H
-#define IGL_VIEWER_VIEWER_PLUGIN_H
+#ifndef IGL_OPENGL_GLFW_VIEWERPLUGIN_H
+#define IGL_OPENGL_GLFW_VIEWERPLUGIN_H
 
 // TODO:
 // * create plugins/skeleton.h
@@ -19,7 +19,9 @@
 
 namespace igl
 {
-namespace viewer
+namespace opengl
+{
+namespace glfw
 {
 
 // Abstract class for plugins
@@ -160,7 +162,6 @@ protected:
   Viewer *viewer;
 };
 
-#ifdef ENABLE_SERIALIZATION
 namespace serialization
 {
   inline void serialize(const ViewerPlugin& obj,std::vector<char>& buffer)
@@ -173,8 +174,8 @@ namespace serialization
     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);
   if(!window) return false;
   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;
 }
 

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

@@ -1,9 +1,8 @@
 #ifndef IGL_OPENGL_GLFW_BACKGROUND_WINDOW_H
 #define IGL_OPENGL_GLFW_BACKGROUND_WINDOW_H
 #include "../../igl_inline.h"
-#include "../gl.h"
 
-#define GLFW_INCLUDE_GLU
+#include "../gl.h"
 #include <GLFW/glfw3.h>
 
 namespace igl
@@ -13,7 +12,7 @@ namespace igl
     namespace glfw
     {
       // 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
       // `glfwDestroyWindow(window)`

Деякі файли не було показано, через те що забагато файлів було змінено