Browse Source

merge

Former-commit-id: 1798003120710b3428e42911b72293065cb866a3
Alec Jacobson 7 years ago
parent
commit
54953fe376
100 changed files with 3376 additions and 3567 deletions
  1. 12 5
      .gitmodules
  2. 3 3
      .travis.yml
  3. 7 7
      include/igl/AtA_cached.cpp
  4. 8 6
      include/igl/AtA_cached.h
  5. 40 0
      include/igl/Attribute.h
  6. 2 0
      include/igl/colormap.cpp
  7. 2 1
      include/igl/copyleft/cgal/minkowski_sum.cpp
  8. 2 0
      include/igl/jet.cpp
  9. 2 2
      include/igl/mosek/mosek_linprog.cpp
  10. 311 0
      include/igl/opengl/MeshGL.cpp
  11. 44 28
      include/igl/opengl/MeshGL.h
  12. 58 116
      include/igl/opengl/ViewerCore.cpp
  13. 61 99
      include/igl/opengl/ViewerCore.h
  14. 689 0
      include/igl/opengl/ViewerData.cpp
  15. 126 76
      include/igl/opengl/ViewerData.h
  16. 24 0
      include/igl/opengl/bind_vertex_attrib_array.cpp
  17. 32 0
      include/igl/opengl/bind_vertex_attrib_array.h
  18. 6 25
      include/igl/opengl/gl.h
  19. 6 6
      include/igl/opengl/glfw/TextRenderer.cpp
  20. 6 3
      include/igl/opengl/glfw/TextRenderer.h
  21. 0 0
      include/igl/opengl/glfw/TextRenderer_fonts.cpp.REMOVED.git-id
  22. 2 2
      include/igl/opengl/glfw/TextRenderer_fonts.h
  23. 301 420
      include/igl/opengl/glfw/Viewer.cpp
  24. 70 67
      include/igl/opengl/glfw/Viewer.h
  25. 6 5
      include/igl/opengl/glfw/ViewerPlugin.h
  26. 5 10
      include/igl/opengl/glfw/background_window.cpp
  27. 2 3
      include/igl/opengl/glfw/background_window.h
  28. 74 0
      include/igl/opengl/glfw/imgui/ImGuiHelpers.h
  29. 378 0
      include/igl/opengl/glfw/imgui/ImGuiMenu.cpp
  30. 104 0
      include/igl/opengl/glfw/imgui/ImGuiMenu.h
  31. 12 9
      include/igl/opengl/glfw/map_texture.cpp
  32. 4 0
      include/igl/opengl/glfw/map_texture.h
  33. 9 2
      include/igl/opengl/load_shader.cpp
  34. 6 1
      include/igl/opengl/load_shader.h
  35. 5 5
      include/igl/opengl2/gl.h
  36. 1 1
      include/igl/per_corner_normals.h
  37. 1 1
      include/igl/serialize.h
  38. 11 9
      include/igl/slice_cached.cpp
  39. 16 15
      include/igl/slice_cached.h
  40. 7 7
      include/igl/slim.cpp
  41. 10 10
      include/igl/sparse_cached.cpp
  42. 11 8
      include/igl/sparse_cached.h
  43. 0 173
      include/igl/viewer/OpenGL_shader.cpp
  44. 0 98
      include/igl/viewer/OpenGL_shader.h
  45. 0 493
      include/igl/viewer/OpenGL_state.cpp
  46. 0 33
      include/igl/viewer/TODOs.txt
  47. 0 422
      include/igl/viewer/ViewerData.cpp
  48. 0 3
      optional/CMakeLists.txt
  49. 5 6
      python/CMakeLists.txt
  50. 470 0
      python/modules/py_igl_opengl_glfw.cpp
  51. 0 452
      python/modules/py_igl_viewer.cpp
  52. 4 0
      python/modules/py_typedefs.h
  53. 4 4
      python/python_shared.cpp
  54. 3 4
      python/tutorial/102_DrawMesh.py
  55. 7 7
      python/tutorial/103_Events.py
  56. 4 4
      python/tutorial/104_Colors.py
  57. 23 23
      python/tutorial/105_Overlays.py
  58. 8 8
      python/tutorial/201_Normals.py
  59. 4 4
      python/tutorial/202_GaussianCurvature.py
  60. 7 7
      python/tutorial/203_CurvatureDirections.py
  61. 6 6
      python/tutorial/204_Gradient.py
  62. 6 6
      python/tutorial/205_Laplacian.py
  63. 4 4
      python/tutorial/301_Slice.py
  64. 4 4
      python/tutorial/302_Sort.py
  65. 5 5
      python/tutorial/303_LaplaceEquation.py
  66. 8 8
      python/tutorial/304_LinearEqualityConstraints.py
  67. 6 6
      python/tutorial/305_QuadraticProgramming.py
  68. 6 6
      python/tutorial/306_EigenDecomposition.py
  69. 8 8
      python/tutorial/401_BiharmonicDeformation.py
  70. 8 8
      python/tutorial/402_PolyharmonicDeformation.py
  71. 11 11
      python/tutorial/403_BoundedBiharmonicWeights.py
  72. 10 10
      python/tutorial/404_DualQuaternionSkinning.py
  73. 7 7
      python/tutorial/405_AsRigidAsPossible.py
  74. 9 9
      python/tutorial/501_HarmonicParam.py
  75. 9 9
      python/tutorial/502_LSCMParam.py
  76. 9 9
      python/tutorial/503_ARAPParam.py
  77. 11 11
      python/tutorial/504_NRosyDesign.py
  78. 37 37
      python/tutorial/505_MIQ.py
  79. 16 16
      python/tutorial/509_Planarization.py
  80. 4 4
      python/tutorial/604_Triangle.py
  81. 10 10
      python/tutorial/605_Tetgen.py
  82. 6 6
      python/tutorial/606_AmbientOcclusion.py
  83. 10 10
      python/tutorial/607_ScreenCapture.py
  84. 6 6
      python/tutorial/609_Boolean.py
  85. 1 1
      python/tutorial/702_WindingNumber.py
  86. 1 1
      python/tutorial/704_SignedDistance.py
  87. 1 1
      python/tutorial/708_Picking.py
  88. 1 1
      python/tutorial/709_VectorFieldVisualizer.py
  89. 0 534
      shared/cmake/CMakeLists.txt
  90. 32 44
      shared/cmake/libigl.cmake
  91. 1 1
      tutorial/102_DrawMesh/CMakeLists.txt
  92. 3 3
      tutorial/102_DrawMesh/main.cpp
  93. 1 1
      tutorial/103_Events/CMakeLists.txt
  94. 8 8
      tutorial/103_Events/main.cpp
  95. 1 1
      tutorial/104_Colors/CMakeLists.txt
  96. 4 4
      tutorial/104_Colors/main.cpp
  97. 1 1
      tutorial/105_Overlays/CMakeLists.txt
  98. 7 7
      tutorial/105_Overlays/main.cpp
  99. 1 1
      tutorial/106_ViewerMenu/CMakeLists.txt
  100. 82 49
      tutorial/106_ViewerMenu/main.cpp

+ 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

+ 7 - 7
include/igl/AtA_cached.cpp

@@ -14,8 +14,8 @@
 template <typename Scalar>
 IGL_INLINE void igl::AtA_cached_precompute(
     const Eigen::SparseMatrix<Scalar>& A,
-    Eigen::SparseMatrix<Scalar>& AtA,
-    igl::AtA_cached_data& data)
+    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;
@@ -106,14 +106,14 @@ IGL_INLINE void igl::AtA_cached_precompute(
   }
   data.I_outer.push_back(data.I_row.size()); // makes it more efficient to iterate later on
 
-  igl::AtA_cached(A,AtA,data);
+  igl::AtA_cached(A,data,AtA);
 }
 
 template <typename Scalar>
 IGL_INLINE void igl::AtA_cached(
     const Eigen::SparseMatrix<Scalar>& A,
-    Eigen::SparseMatrix<Scalar>& AtA,
-    const igl::AtA_cached_data& data)
+    const igl::AtA_cached_data& data,
+    Eigen::SparseMatrix<Scalar>& AtA)
 {
   for (unsigned i=0; i<data.I_outer.size()-1; ++i)
   {
@@ -125,6 +125,6 @@ IGL_INLINE void igl::AtA_cached(
 
 
 #ifdef IGL_STATIC_LIBRARY
-template void igl::AtA_cached<double>(Eigen::SparseMatrix<double, 0, int> const&, Eigen::SparseMatrix<double, 0, int>&, igl::AtA_cached_data const&);
-template void igl::AtA_cached_precompute<double>(Eigen::SparseMatrix<double, 0, int> const&, Eigen::SparseMatrix<double, 0, int>&, igl::AtA_cached_data&);
+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

+ 8 - 6
include/igl/AtA_cached.h

@@ -44,20 +44,22 @@ namespace igl
   // AtA_data = igl::AtA_cached_data();
   // AtA_data.W = W;
   // if (s.AtA.rows() == 0)
-  //   igl::AtA_cached_precompute(s.A,s.AtA,s.AtA_data);
+  //   igl::AtA_cached_precompute(s.A,s.AtA_data,s.AtA);
   // else
-  //   igl::AtA_cached(s.A,s.AtA,s.AtA_data);
+  //   igl::AtA_cached(s.A,s.AtA_data,s.AtA);
   template <typename Scalar>
   IGL_INLINE void AtA_cached_precompute(
     const Eigen::SparseMatrix<Scalar>& A,
-    Eigen::SparseMatrix<Scalar>& AtA,
-    AtA_cached_data& data);
+    AtA_cached_data& data,
+    Eigen::SparseMatrix<Scalar>& AtA
+    );
 
   template <typename Scalar>
   IGL_INLINE void AtA_cached(
     const Eigen::SparseMatrix<Scalar>& A,
-    Eigen::SparseMatrix<Scalar>& AtA,
-    const AtA_cached_data& data);
+    const AtA_cached_data& data,
+    Eigen::SparseMatrix<Scalar>& AtA
+    );
   
 }
 

+ 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

+ 2 - 0
include/igl/colormap.cpp

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

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

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

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

+ 61 - 99
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;
@@ -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;
+    }
+  }
+}

+ 126 - 76
include/igl/viewer/ViewerData.h → include/igl/opengl/ViewerData.h

@@ -5,45 +5,33 @@
 // 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
-  };
-
   // Empty all fields
   IGL_INLINE void clear();
 
@@ -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 - 420
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,36 +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
-	ngui->refresh();
-	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()
@@ -804,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)
@@ -890,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 safely ignore 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 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
-#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 safely ignore 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)`

+ 74 - 0
include/igl/opengl/glfw/imgui/ImGuiHelpers.h

@@ -0,0 +1,74 @@
+// 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_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H
+#define IGL_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H
+
+////////////////////////////////////////////////////////////////////////////////
+#include <imgui/imgui.h>
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <functional>
+////////////////////////////////////////////////////////////////////////////////
+
+// Extend ImGui by populating its namespace directly
+//
+// Code snippets taken from there:
+// https://eliasdaler.github.io/using-imgui-with-sfml-pt2/
+namespace ImGui
+{
+
+static auto vector_getter = [](void* vec, int idx, const char** out_text)
+{
+	auto& vector = *static_cast<std::vector<std::string>*>(vec);
+	if (idx < 0 || idx >= static_cast<int>(vector.size())) { return false; }
+	*out_text = vector.at(idx).c_str();
+	return true;
+};
+
+inline bool Combo(const char* label, int* idx, std::vector<std::string>& values)
+{
+	if (values.empty()) { return false; }
+	return Combo(label, idx, vector_getter,
+		static_cast<void*>(&values), values.size());
+}
+
+inline bool Combo(const char* label, int* idx, std::function<const char *(int)> getter, int items_count)
+{
+	auto func = [](void* data, int i, const char** out_text) {
+		auto &getter = *reinterpret_cast<std::function<const char *(int)> *>(data);
+		const char *s = getter(i);
+		if (s) { *out_text = s; return true; }
+		else { return false; }
+	};
+	return Combo(label, idx, func, reinterpret_cast<void *>(&getter), items_count);
+}
+
+inline bool ListBox(const char* label, int* idx, std::vector<std::string>& values)
+{
+	if (values.empty()) { return false; }
+	return ListBox(label, idx, vector_getter,
+		static_cast<void*>(&values), values.size());
+}
+
+inline bool InputText(const char* label, std::string &str, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL)
+{
+  char buf[1024];
+  std::fill_n(buf, 1024, 0);
+  std::copy_n(str.begin(), std::min(1024, (int) str.size()), buf);
+  if (ImGui::InputText(label, buf, 1024, flags, callback, user_data))
+  {
+    str = std::string(buf);
+    return true;
+  }
+  return false;
+}
+
+} // namespace ImGui
+
+#endif // IGL_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H

+ 378 - 0
include/igl/opengl/glfw/imgui/ImGuiMenu.cpp

@@ -0,0 +1,378 @@
+// 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/.
+////////////////////////////////////////////////////////////////////////////////
+#include "ImGuiMenu.h"
+#include <igl/project.h>
+#include <imgui/imgui.h>
+#include <imgui_impl_glfw_gl3.h>
+#include <imgui_fonts_droid_sans.h>
+#include <GLFW/glfw3.h>
+#include <iostream>
+////////////////////////////////////////////////////////////////////////////////
+
+namespace igl
+{
+namespace opengl
+{
+namespace glfw
+{
+namespace imgui
+{
+
+IGL_INLINE void ImGuiMenu::init(igl::opengl::glfw::Viewer *_viewer)
+{
+  ViewerPlugin::init(_viewer);
+  // Setup ImGui binding
+  if (_viewer)
+  {
+    if (context_ == nullptr)
+    {
+      context_ = ImGui::CreateContext();
+    }
+    ImGui_ImplGlfwGL3_Init(viewer->window, false);
+    ImGui::GetIO().IniFilename = nullptr;
+    ImGui::StyleColorsDark();
+    ImGuiStyle& style = ImGui::GetStyle();
+    style.FrameRounding = 5.0f;
+    reload_font();
+  }
+}
+
+IGL_INLINE void ImGuiMenu::reload_font(int font_size)
+{
+  hidpi_scaling_ = hidpi_scaling();
+  pixel_ratio_ = pixel_ratio();
+  ImGuiIO& io = ImGui::GetIO();
+  io.Fonts->Clear();
+  io.Fonts->AddFontFromMemoryCompressedTTF(droid_sans_compressed_data,
+    droid_sans_compressed_size, font_size * hidpi_scaling_);
+  io.FontGlobalScale = 1.0 / pixel_ratio_;
+}
+
+IGL_INLINE void ImGuiMenu::shutdown()
+{
+  // Cleanup
+  ImGui_ImplGlfwGL3_Shutdown();
+  ImGui::DestroyContext(context_);
+  context_ = nullptr;
+}
+
+IGL_INLINE bool ImGuiMenu::pre_draw()
+{
+  glfwPollEvents();
+
+  // Check whether window dpi has changed
+  float scaling = hidpi_scaling();
+  if (std::abs(scaling - hidpi_scaling_) > 1e-5)
+  {
+    reload_font();
+    ImGui_ImplGlfwGL3_InvalidateDeviceObjects();
+  }
+
+  ImGui_ImplGlfwGL3_NewFrame();
+  return false;
+}
+
+IGL_INLINE bool ImGuiMenu::post_draw()
+{
+  draw_menu();
+  ImGui::Render();
+  return false;
+}
+
+IGL_INLINE void ImGuiMenu::post_resize(int width, int height)
+{
+  if (context_)
+  {
+    ImGui::GetIO().DisplaySize.x = float(width);
+    ImGui::GetIO().DisplaySize.y = float(height);
+  }
+}
+
+// Mouse IO
+IGL_INLINE bool ImGuiMenu::mouse_down(int button, int modifier)
+{
+  ImGui_ImplGlfwGL3_MouseButtonCallback(viewer->window, button, GLFW_PRESS, modifier);
+  return ImGui::GetIO().WantCaptureMouse;
+}
+
+IGL_INLINE bool ImGuiMenu::mouse_up(int button, int modifier)
+{
+  return ImGui::GetIO().WantCaptureMouse;
+}
+
+IGL_INLINE bool ImGuiMenu::mouse_move(int mouse_x, int mouse_y)
+{
+  return ImGui::GetIO().WantCaptureMouse;
+}
+
+IGL_INLINE bool ImGuiMenu::mouse_scroll(float delta_y)
+{
+  ImGui_ImplGlfwGL3_ScrollCallback(viewer->window, 0.f, delta_y);
+  return ImGui::GetIO().WantCaptureMouse;
+}
+
+// Keyboard IO
+IGL_INLINE bool ImGuiMenu::key_pressed(unsigned int key, int modifiers)
+{
+  ImGui_ImplGlfwGL3_CharCallback(nullptr, key);
+  return ImGui::GetIO().WantCaptureKeyboard;
+}
+
+IGL_INLINE bool ImGuiMenu::key_down(int key, int modifiers)
+{
+  ImGui_ImplGlfwGL3_KeyCallback(viewer->window, key, 0, GLFW_PRESS, modifiers);
+  return ImGui::GetIO().WantCaptureKeyboard;
+}
+
+IGL_INLINE bool ImGuiMenu::key_up(int key, int modifiers)
+{
+  ImGui_ImplGlfwGL3_KeyCallback(viewer->window, key, 0, GLFW_RELEASE, modifiers);
+  return ImGui::GetIO().WantCaptureKeyboard;
+}
+
+// Draw menu
+IGL_INLINE void ImGuiMenu::draw_menu()
+{
+  // Text labels
+  draw_labels_window();
+
+  // Viewer settings
+  float menu_width = 180.f * menu_scaling();
+  ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiSetCond_FirstUseEver);
+  ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f), ImGuiSetCond_FirstUseEver);
+  ImGui::SetNextWindowSizeConstraints(ImVec2(menu_width, -1.0f), ImVec2(menu_width, -1.0f));
+  bool _viewer_menu_visible = true;
+  ImGui::Begin(
+      "Viewer", &_viewer_menu_visible,
+      ImGuiWindowFlags_NoSavedSettings
+      | ImGuiWindowFlags_AlwaysAutoResize
+  );
+  ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.4f);
+  if (draw_viewer_menu_func) { draw_viewer_menu_func(); }
+  else { draw_viewer_menu(); }
+  ImGui::PopItemWidth();
+  ImGui::End();
+
+  // Other windows
+  if (draw_custom_window_func) { draw_custom_window_func(); }
+  else { draw_custom_window(); }
+}
+
+IGL_INLINE void ImGuiMenu::draw_viewer_menu()
+{
+  // Workspace
+  if (ImGui::CollapsingHeader("Workspace", ImGuiTreeNodeFlags_DefaultOpen))
+  {
+    ImGui::Columns(2, nullptr, false);
+    if (ImGui::Button("Load##Workspace", ImVec2(-1, 0)))
+    {
+      viewer->load_scene();
+    }
+    ImGui::NextColumn();
+    if (ImGui::Button("Save##Workspace", ImVec2(-1, 0)))
+    {
+      viewer->save_scene();
+    }
+    ImGui::Columns(1);
+  }
+
+  // Mesh
+  if (ImGui::CollapsingHeader("Mesh", ImGuiTreeNodeFlags_DefaultOpen))
+  {
+    ImGui::Columns(2, nullptr, false);
+    if (ImGui::Button("Load##Mesh", ImVec2(-1, 0)))
+    {
+      viewer->open_dialog_load_mesh();
+    }
+    ImGui::NextColumn();
+    if (ImGui::Button("Save##Mesh", ImVec2(-1, 0)))
+    {
+      viewer->open_dialog_save_mesh();
+    }
+    ImGui::Columns(1);
+  }
+
+  // Viewing options
+  if (ImGui::CollapsingHeader("Viewing Options", ImGuiTreeNodeFlags_DefaultOpen))
+  {
+    if (ImGui::Button("Center object", ImVec2(-1, 0)))
+    {
+      viewer->core.align_camera_center(viewer->data().V, viewer->data().F);
+    }
+    if (ImGui::Button("Snap canonical view", ImVec2(-1, 0)))
+    {
+      viewer->snap_to_canonical_quaternion();
+    }
+
+    // Zoom
+    ImGui::PushItemWidth(80 * menu_scaling());
+    ImGui::DragFloat("Zoom", &(viewer->core.camera_zoom), 0.05f, 0.1f, 20.0f);
+
+    // Select rotation type
+    static int rotation_type = static_cast<int>(viewer->core.rotation_type);
+    static Eigen::Quaternionf trackball_angle = Eigen::Quaternionf::Identity();
+    static bool orthographic = true;
+    if (ImGui::Combo("Camera Type", &rotation_type, "Trackball\0Two Axes\0002D Mode\0\0"))
+    {
+      using RT = igl::opengl::ViewerCore::RotationType;
+      auto new_type = static_cast<RT>(rotation_type);
+      if (new_type != viewer->core.rotation_type)
+      {
+        if (new_type == RT::ROTATION_TYPE_NO_ROTATION)
+        {
+          trackball_angle = viewer->core.trackball_angle;
+          orthographic = viewer->core.orthographic;
+          viewer->core.trackball_angle = Eigen::Quaternionf::Identity();
+          viewer->core.orthographic = true;
+        }
+        else if (viewer->core.rotation_type == RT::ROTATION_TYPE_NO_ROTATION)
+        {
+          viewer->core.trackball_angle = trackball_angle;
+          viewer->core.orthographic = orthographic;
+        }
+        viewer->core.set_rotation_type(new_type);
+      }
+    }
+
+    // Orthographic view
+    ImGui::Checkbox("Orthographic view", &(viewer->core.orthographic));
+    ImGui::PopItemWidth();
+  }
+
+  // Draw options
+  if (ImGui::CollapsingHeader("Draw Options", ImGuiTreeNodeFlags_DefaultOpen))
+  {
+    if (ImGui::Checkbox("Face-based", &(viewer->data().face_based)))
+    {
+      viewer->data().set_face_based(viewer->data().face_based);
+    }
+    ImGui::Checkbox("Show texture", &(viewer->data().show_texture));
+    if (ImGui::Checkbox("Invert normals", &(viewer->data().invert_normals)))
+    {
+      viewer->data().dirty |= igl::opengl::MeshGL::DIRTY_NORMAL;
+    }
+    ImGui::Checkbox("Show overlay", &(viewer->data().show_overlay));
+    ImGui::Checkbox("Show overlay depth", &(viewer->data().show_overlay_depth));
+    ImGui::ColorEdit4("Background", viewer->core.background_color.data(),
+        ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_PickerHueWheel);
+    ImGui::ColorEdit4("Line color", viewer->data().line_color.data(),
+        ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_PickerHueWheel);
+    ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.3f);
+    ImGui::DragFloat("Shininess", &(viewer->data().shininess), 0.05f, 0.0f, 100.0f);
+    ImGui::PopItemWidth();
+  }
+
+  // Overlays
+  if (ImGui::CollapsingHeader("Overlays", ImGuiTreeNodeFlags_DefaultOpen))
+  {
+    ImGui::Checkbox("Wireframe", &(viewer->data().show_lines));
+    ImGui::Checkbox("Fill", &(viewer->data().show_faces));
+    ImGui::Checkbox("Show vertex labels", &(viewer->data().show_vertid));
+    ImGui::Checkbox("Show faces labels", &(viewer->data().show_faceid));
+  }
+}
+
+IGL_INLINE void ImGuiMenu::draw_labels_window()
+{
+  // Text labels
+  ImGui::SetNextWindowPos(ImVec2(0,0), ImGuiSetCond_Always);
+  ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize, ImGuiSetCond_Always);
+  bool visible = true;
+  ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0,0,0,0));
+  ImGui::Begin("ViewerLabels", &visible,
+      ImGuiWindowFlags_NoTitleBar
+      | ImGuiWindowFlags_NoResize
+      | ImGuiWindowFlags_NoMove
+      | ImGuiWindowFlags_NoScrollbar
+      | ImGuiWindowFlags_NoScrollWithMouse
+      | ImGuiWindowFlags_NoCollapse
+      | ImGuiWindowFlags_NoSavedSettings
+      | ImGuiWindowFlags_NoInputs);
+  for (const auto & data : viewer->data_list)
+  {
+    draw_labels(data);
+  }
+  ImGui::End();
+  ImGui::PopStyleColor();
+}
+
+IGL_INLINE void ImGuiMenu::draw_labels(const igl::opengl::ViewerData &data)
+{
+  if (data.show_vertid)
+  {
+    for (int i = 0; i < data.V.rows(); ++i)
+    {
+      draw_text(data.V.row(i), data.V_normals.row(i), std::to_string(i));
+    }
+  }
+
+  if (data.show_faceid)
+  {
+    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 /= (double) data.F.cols();
+
+      draw_text(p, data.F_normals.row(i), std::to_string(i));
+    }
+  }
+
+  if (data.labels_positions.rows() > 0)
+  {
+    for (int i = 0; i < data.labels_positions.rows(); ++i)
+    {
+      draw_text(data.labels_positions.row(i), Eigen::Vector3d(0.0,0.0,0.0),
+        data.labels_strings[i]);
+    }
+  }
+}
+
+IGL_INLINE void ImGuiMenu::draw_text(Eigen::Vector3d pos, Eigen::Vector3d normal, const std::string &text)
+{
+  Eigen::Matrix4f view_matrix = viewer->core.view * viewer->core.model;
+  pos += normal * 0.005f * viewer->core.object_scale;
+  Eigen::Vector3f coord = igl::project(Eigen::Vector3f(pos.cast<float>()),
+    view_matrix, viewer->core.proj, viewer->core.viewport);
+
+  // Draw text labels slightly bigger than normal text
+  ImDrawList* drawList = ImGui::GetWindowDrawList();
+  drawList->AddText(ImGui::GetFont(), ImGui::GetFontSize() * 1.2,
+      ImVec2(coord[0]/pixel_ratio_, (viewer->core.viewport[3] - coord[1])/pixel_ratio_),
+      ImGui::GetColorU32(ImVec4(0, 0, 10, 255)),
+      &text[0], &text[0] + text.size());
+}
+
+IGL_INLINE float ImGuiMenu::pixel_ratio()
+{
+  // Computes pixel ratio for hidpi devices
+  int buf_size[2];
+  int win_size[2];
+  GLFWwindow* window = glfwGetCurrentContext();
+  glfwGetFramebufferSize(window, &buf_size[0], &buf_size[1]);
+  glfwGetWindowSize(window, &win_size[0], &win_size[1]);
+  return (float) buf_size[0] / (float) win_size[0];
+}
+
+IGL_INLINE float ImGuiMenu::hidpi_scaling()
+{
+  // Computes scaling factor for hidpi devices
+  float xscale, yscale;
+  GLFWwindow* window = glfwGetCurrentContext();
+  glfwGetWindowContentScale(window, &xscale, &yscale);
+  return 0.5 * (xscale + yscale);
+}
+
+} // end namespace
+} // end namespace
+} // end namespace
+} // end namespace

+ 104 - 0
include/igl/opengl/glfw/imgui/ImGuiMenu.h

@@ -0,0 +1,104 @@
+// 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_OPENGL_GLFW_IMGUI_IMGUIMENU_H
+#define IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H
+
+////////////////////////////////////////////////////////////////////////////////
+#include <igl/opengl/glfw/Viewer.h>
+#include <igl/opengl/glfw/ViewerPlugin.h>
+#include <igl/igl_inline.h>
+////////////////////////////////////////////////////////////////////////////////
+
+// Forward declarations
+struct ImGuiContext;
+
+namespace igl
+{
+namespace opengl
+{
+namespace glfw
+{
+namespace imgui
+{
+
+class ImGuiMenu : public igl::opengl::glfw::ViewerPlugin
+{
+protected:
+  // Hidpi scaling to be used for text rendering.
+  float hidpi_scaling_;
+
+  // Ratio between the framebuffer size and the window size.
+  // May be different from the hipdi scaling!
+  float pixel_ratio_;
+
+  // ImGui Context
+  ImGuiContext * context_ = nullptr;
+
+public:
+  IGL_INLINE virtual void init(igl::opengl::glfw::Viewer *_viewer) override;
+
+  IGL_INLINE virtual void reload_font(int font_size = 13);
+
+  IGL_INLINE virtual void shutdown() override;
+
+  IGL_INLINE virtual bool pre_draw() override;
+
+  IGL_INLINE  virtual bool post_draw() override;
+
+  IGL_INLINE virtual void post_resize(int width, int height) override;
+
+  // Mouse IO
+  IGL_INLINE virtual bool mouse_down(int button, int modifier) override;
+
+  IGL_INLINE virtual bool mouse_up(int button, int modifier) override;
+
+  IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y) override;
+
+  IGL_INLINE virtual bool mouse_scroll(float delta_y) override;
+
+  // Keyboard IO
+  IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers) override;
+
+  IGL_INLINE virtual bool key_down(int key, int modifiers) override;
+
+  IGL_INLINE virtual bool key_up(int key, int modifiers) override;
+
+  // Draw menu
+  IGL_INLINE virtual void draw_menu();
+
+  IGL_INLINE virtual void draw_viewer_menu();
+
+  IGL_INLINE virtual void draw_custom_window() { }
+
+  // Easy-to-customize callbacks
+  std::function<void(void)> draw_viewer_menu_func;
+  std::function<void(void)> draw_custom_window_func;
+
+  IGL_INLINE void draw_labels_window();
+
+  IGL_INLINE void draw_labels(const igl::opengl::ViewerData &data);
+
+  IGL_INLINE void draw_text(Eigen::Vector3d pos, Eigen::Vector3d normal, const std::string &text);
+
+  IGL_INLINE float pixel_ratio();
+
+  IGL_INLINE float hidpi_scaling();
+
+  float menu_scaling() { return hidpi_scaling_ / pixel_ratio_; }
+};
+
+} // end namespace
+} // end namespace
+} // end namespace
+} // end namespace
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "ImGuiMenu.cpp"
+#endif
+
+#endif // IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H

+ 12 - 9
include/igl/opengl/glfw/map_texture.cpp

@@ -1,14 +1,15 @@
+#ifdef IGL_OPENGL_4
+
 #include "map_texture.h"
 #include "background_window.h"
 #include "../create_shader_program.h"
-#include "../gl.h"
 
-#define GLFW_INCLUDE_GLU
+#include "../gl.h"
 #include <GLFW/glfw3.h>
 
 #include <iostream>
 #include <string>
-  
+
 template <typename DerivedV, typename DerivedF, typename DerivedU>
 IGL_INLINE bool igl::opengl::glfw::map_texture(
   const Eigen::MatrixBase<DerivedV> & _V,
@@ -26,7 +27,7 @@ IGL_INLINE bool igl::opengl::glfw::map_texture(
   return map_texture(_V,_F,_U,in_data,w,h,nc,out_data,out_w,out_h,out_nc);
 }
 
-  
+
 template <typename DerivedV, typename DerivedF, typename DerivedU>
 IGL_INLINE bool igl::opengl::glfw::map_texture(
   const Eigen::MatrixBase<DerivedV> & _V,
@@ -47,7 +48,7 @@ IGL_INLINE bool igl::opengl::glfw::map_texture(
     glfwTerminate();
     return false;
   };
-  // Force inputs to be RowMajor at the cost of a copy 
+  // Force inputs to be RowMajor at the cost of a copy
   Eigen::Matrix<
     double,
     DerivedV::RowsAtCompileTime,
@@ -71,7 +72,7 @@ IGL_INLINE bool igl::opengl::glfw::map_texture(
   }
 
   // Compile each shader
-  std::string vertex_shader = dim == 2 ? 
+  std::string vertex_shader = dim == 2 ?
     R"(
 #version 330 core
 layout(location = 0) in vec2 position;
@@ -106,7 +107,7 @@ void main()
   color = texture(tex,tex_coord_f).rgb;
 }
 )";
-  GLuint prog_id = 
+  GLuint prog_id =
     igl::opengl::create_shader_program(vertex_shader,fragment_shader,{});
   glUniform1i(glGetUniformLocation(prog_id, "tex"),0);
   // Generate and attach buffers to vertex array
@@ -129,7 +130,7 @@ void main()
   glBufferData(GL_ARRAY_BUFFER, sizeof(double)*V.size(), V.data(), GL_STATIC_DRAW);
   glVertexAttribLPointer(1, V.cols(), GL_DOUBLE, V.cols() * sizeof(GLdouble), (GLvoid*)0);
   glBindVertexArray(0);
-  glBindBuffer(GL_ARRAY_BUFFER, 0); 
+  glBindBuffer(GL_ARRAY_BUFFER, 0);
   glBindVertexArray(0);
   // Prepare texture
   GLuint in_tex;
@@ -162,7 +163,7 @@ void main()
     GLenum bufs[1] = {GL_COLOR_ATTACHMENT0};
     glDrawBuffers(1, bufs);
   }
-  if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 
+  if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
   {
     fail("framebuffer setup failed.");
   }
@@ -206,3 +207,5 @@ void main()
 // generated by autoexplicit.sh
 template bool igl::opengl::glfw::map_texture<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, unsigned char const*, int, int, int, std::vector<unsigned char, std::allocator<unsigned char> >&);
 #endif
+
+#endif // IGL_OPENGL_4

+ 4 - 0
include/igl/opengl/glfw/map_texture.h

@@ -1,6 +1,8 @@
 #ifndef IGL_OPENGL_GLFW_MAP_TEXTURE_H
 #define IGL_OPENGL_GLFW_MAP_TEXTURE_H
 
+#ifdef IGL_OPENGL_4
+
 #include "../../igl_inline.h"
 #include <Eigen/Core>
 #include <vector>
@@ -56,4 +58,6 @@ namespace igl
 #  include "map_texture.cpp"
 #endif
 
+#endif // IGL_OPENGL_4
+
 #endif

+ 9 - 2
include/igl/opengl/load_shader.cpp

@@ -10,8 +10,14 @@
 // Copyright Denis Kovacs 4/10/08
 #include "print_shader_info_log.h"
 #include <cstdio>
-IGL_INLINE GLuint igl::opengl::load_shader(const char *src,const GLenum type)
+IGL_INLINE GLuint igl::opengl::load_shader(
+  const std::string & src,const GLenum type)
 {
+  if(src.empty())
+  {
+    return (GLuint) 0;
+  }
+
   GLuint s = glCreateShader(type);
   if(s == 0)
   {
@@ -19,7 +25,8 @@ IGL_INLINE GLuint igl::opengl::load_shader(const char *src,const GLenum type)
     return 0;
   }
   // Pass shader source string
-  glShaderSource(s, 1, &src, NULL);
+  const char *c = src.c_str();
+  glShaderSource(s, 1, &c, NULL);
   glCompileShader(s);
   // Print info log (if any)
   igl::opengl::print_shader_info_log(s);

+ 6 - 1
include/igl/opengl/load_shader.h

@@ -9,12 +9,14 @@
 #define IGL_OPENGL_LOAD_SHADER_H
 #include "../igl_inline.h" 
 #include "gl.h"
+#include <string>
 
 namespace igl
 {
   namespace opengl
   {
     // Creates and compiles a shader from a given string
+    //
     // Inputs:
     //   src  string containing GLSL shader code
     //   type  GLSL type of shader, one of:
@@ -22,7 +24,10 @@ namespace igl
     //     GL_FRAGMENT_SHADER
     //     GL_GEOMETRY_SHADER
     // Returns  index id of the newly created shader, 0 on error
-    IGL_INLINE GLuint load_shader(const char *src,const GLenum type);
+    // 
+    // Will immediately return 0 if src is empty.
+    IGL_INLINE GLuint load_shader(
+      const std::string & src,const GLenum type);
   }
 }
 

+ 5 - 5
include/igl/opengl2/gl.h

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 #ifndef IGL_OPENGL2_GL_H
 #define IGL_OPENGL2_GL_H
@@ -16,7 +16,7 @@
 //     #include "gl.h"
 // Instead of:
 //     #include <OpenGL/gl.h>
-// or 
+// or
 //     #include <GL/gl.h>
 //
 

+ 1 - 1
include/igl/per_corner_normals.h

@@ -16,7 +16,7 @@ namespace igl
   // Compute vertex normals via vertex position list, face list
   // Inputs:
   //   V  #V by 3 eigen Matrix of mesh vertex 3D positions
-  //   F  #F by 3 eigne Matrix of face (triangle) indices
+  //   F  #F by 3 eigen Matrix of face (triangle) indices
   //   corner_threshold  threshold in degrees on sharp angles
   // Output:
   //   CN  #F*3 by 3 eigen Matrix of mesh vertex 3D normals, where the normal

+ 1 - 1
include/igl/serialize.h

@@ -1254,5 +1254,5 @@ namespace igl
     }
   }
 }
- 
+
 #endif

+ 11 - 9
include/igl/slice_cached.cpp

@@ -10,15 +10,16 @@
 #include <iostream>
 #include <vector>
 #include <utility>
-#include <igl/slice.h>
+#include "slice.h"
 
-template <typename TX, typename TY>
+template <typename TX, typename TY, typename DerivedI>
 IGL_INLINE void igl::slice_cached_precompute(
   const Eigen::SparseMatrix<TX>& X,
   const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
   const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
-  Eigen::SparseMatrix<TY>& Y,
-  Eigen::VectorXi& data)
+  Eigen::MatrixBase<DerivedI>& data,
+  Eigen::SparseMatrix<TY>& Y
+  )
 {
   // Create a sparse matrix whose entries are the ids
   Eigen::SparseMatrix<unsigned> TS = X.template cast<unsigned>();
@@ -39,17 +40,18 @@ IGL_INLINE void igl::slice_cached_precompute(
   }
 }
 
-template <typename TX, typename TY>
+template <typename TX, typename TY, typename DerivedI>
 IGL_INLINE void igl::slice_cached(
   const Eigen::SparseMatrix<TX>& X,
-  Eigen::SparseMatrix<TY>& Y,
-  const Eigen::VectorXi& data)
+  const Eigen::MatrixBase<DerivedI>& data,
+  Eigen::SparseMatrix<TY>& Y
+  )
 {
   for (unsigned i=0; i<data.size(); ++i)
     *(Y.valuePtr() + i) = *(X.valuePtr() + data[i]);
 }
 
 #ifdef IGL_STATIC_LIBRARY
-template void igl::slice_cached_precompute<double, double>(Eigen::SparseMatrix<double, 0, int> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int>&, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
-template void igl::slice_cached<double, double>(Eigen::SparseMatrix<double, 0, int> const&, Eigen::SparseMatrix<double, 0, int>&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&);
+template void igl::slice_cached<double, double, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::slice_cached_precompute<double, double, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::SparseMatrix<double, 0, int>&);
 #endif

+ 16 - 15
include/igl/slice_cached.h

@@ -41,24 +41,25 @@ namespace igl
   // // Fast version
   // static VectorXi data; // static or saved in a global state
   // if (data.size() == 0)
-  //   igl::slice_cached_precompute(L,in,in,L_sliced,data);
+  //   igl::slice_cached_precompute(L,in,in,data,L_sliced);
   // else
-  //   igl::slice_cached(L,L_sliced,temp);
+  //   igl::slice_cached(L,data,L_sliced);
 
-  template <typename TX, typename TY>
-  IGL_INLINE void slice_cached_precompute(
-    const Eigen::SparseMatrix<TX>& X,
-    const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
-    const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
-    Eigen::SparseMatrix<TY>& Y,
-    Eigen::VectorXi& data);
-
-  template <typename TX, typename TY>
-  IGL_INLINE void slice_cached(
-    const Eigen::SparseMatrix<TX>& X,
-    Eigen::SparseMatrix<TY>& Y,
-    const Eigen::VectorXi& data);
+template <typename TX, typename TY, typename DerivedI>
+IGL_INLINE void slice_cached_precompute(
+  const Eigen::SparseMatrix<TX>& X,
+  const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+  const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
+  Eigen::MatrixBase<DerivedI>& data,
+  Eigen::SparseMatrix<TY>& Y
+  );
 
+template <typename TX, typename TY, typename DerivedI>
+IGL_INLINE void slice_cached(
+  const Eigen::SparseMatrix<TX>& X,
+  const Eigen::MatrixBase<DerivedI>& data,
+  Eigen::SparseMatrix<TY>& Y
+  );
 }
 
 #ifndef IGL_STATIC_LIBRARY

+ 7 - 7
include/igl/slim.cpp

@@ -34,9 +34,9 @@
 #include <Eigen/SparseCholesky>
 #include <Eigen/IterativeLinearSolvers>
 
-#include <igl/Timer.h>
-#include <igl/sparse_cached.h>
-#include <igl/AtA_cached.h>
+#include "Timer.h"
+#include "sparse_cached.h"
+#include "AtA_cached.h"
 
 #ifdef CHOLMOD
 #include <Eigen/CholmodSupport>
@@ -505,10 +505,10 @@ namespace igl
       if (s.A.rows() == 0)
       {
         s.A = Eigen::SparseMatrix<double>(s.dim * s.dim * s.f_n, s.dim * s.v_n);
-        igl::sparse_cached_precompute(IJV,s.A,s.A_data);
+        igl::sparse_cached_precompute(IJV,s.A_data,s.A);
       }
       else
-        igl::sparse_cached(IJV,s.A,s.A_data);
+        igl::sparse_cached(IJV,s.A_data,s.A);
       #else
       Eigen::SparseMatrix<double> A(s.dim * s.dim * s.f_n, s.dim * s.v_n);
       buildA(s,IJV);
@@ -534,9 +534,9 @@ namespace igl
       #ifdef SLIM_CACHED
       s.AtA_data.W = s.WGL_M;
       if (s.AtA.rows() == 0)
-        igl::AtA_cached_precompute(s.A,s.AtA,s.AtA_data);
+        igl::AtA_cached_precompute(s.A,s.AtA_data,s.AtA);
       else
-        igl::AtA_cached(s.A,s.AtA,s.AtA_data);
+        igl::AtA_cached(s.A,s.AtA_data,s.AtA);
 
       L = s.AtA + s.proximal_p * id_m; //add also a proximal 
       L.makeCompressed();

+ 10 - 10
include/igl/sparse_cached.cpp

@@ -18,8 +18,8 @@ template <typename DerivedI, typename Scalar>
 IGL_INLINE void igl::sparse_cached_precompute(
   const Eigen::MatrixBase<DerivedI> & I,
   const Eigen::MatrixBase<DerivedI> & J,
-  Eigen::SparseMatrix<Scalar>& X,
-  Eigen::VectorXi& data)
+  Eigen::VectorXi& data,
+  Eigen::SparseMatrix<Scalar>& X)
 {
   // Generates the triplets
   std::vector<Eigen::Triplet<double> > t(I.size());
@@ -33,8 +33,8 @@ IGL_INLINE void igl::sparse_cached_precompute(
 template <typename Scalar>
 IGL_INLINE void igl::sparse_cached_precompute(
   const std::vector<Eigen::Triplet<Scalar> >& triplets,
-  Eigen::SparseMatrix<Scalar>& X,
-  Eigen::VectorXi& data)
+  Eigen::VectorXi& data,
+  Eigen::SparseMatrix<Scalar>& X)
 {
     // Construct an empty sparse matrix
     X.setFromTriplets(triplets.begin(),triplets.end());
@@ -84,8 +84,8 @@ IGL_INLINE void igl::sparse_cached_precompute(
 template <typename Scalar>
 IGL_INLINE void igl::sparse_cached(
   const std::vector<Eigen::Triplet<Scalar> >& triplets,
-  Eigen::SparseMatrix<Scalar>& X,
-  const Eigen::VectorXi& data)
+  const Eigen::VectorXi& data,
+  Eigen::SparseMatrix<Scalar>& X)
 {
   assert(triplets.size() == data.size());
 
@@ -101,8 +101,8 @@ IGL_INLINE void igl::sparse_cached(
 template <typename DerivedV, typename Scalar>
 IGL_INLINE void igl::sparse_cached(
   const Eigen::MatrixBase<DerivedV>& V,
-  Eigen::SparseMatrix<Scalar>& X,
-  const Eigen::VectorXi& data)
+  const Eigen::VectorXi& data,
+  Eigen::SparseMatrix<Scalar>& X)
 {
   assert(V.size() == data.size());
 
@@ -117,6 +117,6 @@ IGL_INLINE void igl::sparse_cached(
 
 
 #ifdef IGL_STATIC_LIBRARY
-template void igl::sparse_cached_precompute<double>(std::vector<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index>, std::allocator<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index> > > const&, Eigen::SparseMatrix<double, 0, int>&, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
-template void igl::sparse_cached<double>(std::vector<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index>, std::allocator<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index> > > const&, Eigen::SparseMatrix<double, 0, int>&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&);
+template void igl::sparse_cached<double>(std::vector<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index>, std::allocator<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index> > > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::sparse_cached_precompute<double>(std::vector<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index>, std::allocator<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index> > > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1>&, Eigen::SparseMatrix<double, 0, int>&);
 #endif

+ 11 - 8
include/igl/sparse_cached.h

@@ -52,26 +52,29 @@ namespace igl
   IGL_INLINE void sparse_cached_precompute(
     const Eigen::MatrixBase<DerivedI> & I,
     const Eigen::MatrixBase<DerivedI> & J,
-    Eigen::SparseMatrix<Scalar>& X,
-    Eigen::VectorXi& data);
+    Eigen::VectorXi& data,
+    Eigen::SparseMatrix<Scalar>& X
+    );
   
   template <typename Scalar>
   IGL_INLINE void sparse_cached_precompute(
     const std::vector<Eigen::Triplet<Scalar> >& triplets,
-    Eigen::SparseMatrix<Scalar>& X,
-    Eigen::VectorXi& data);
+    Eigen::VectorXi& data,
+    Eigen::SparseMatrix<Scalar>& X
+    );
 
   template <typename Scalar>
   IGL_INLINE void sparse_cached(
     const std::vector<Eigen::Triplet<Scalar> >& triplets,
-    Eigen::SparseMatrix<Scalar>& X,
-    const Eigen::VectorXi& data);
+    const Eigen::VectorXi& data,
+    Eigen::SparseMatrix<Scalar>& X);
 
   template <typename DerivedV, typename Scalar>
   IGL_INLINE void sparse_cached(
     const Eigen::MatrixBase<DerivedV>& V,
-    Eigen::SparseMatrix<Scalar>& X,
-    const Eigen::VectorXi& data);
+    const Eigen::VectorXi& data,
+    Eigen::SparseMatrix<Scalar>& X
+    );
   
 }
 

+ 0 - 173
include/igl/viewer/OpenGL_shader.cpp

@@ -1,173 +0,0 @@
-// This file is part of libigl, a simple c++ geometry processing library.
-//
-// Copyright (C) 2014 Wenzel Jacob <wenzel@inf.ethz.ch>
-//
-// 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 "OpenGL_shader.h"
-
-#include <iostream>
-#include <fstream>
-
-IGL_INLINE bool igl::viewer::OpenGL_shader::init_from_files(
-  const std::string &vertex_shader_filename,
-  const std::string &fragment_shader_filename,
-  const std::string &fragment_data_name,
-  const std::string &geometry_shader_filename,
-  int geometry_shader_max_vertices)
-{
-  auto file_to_string = [](const std::string &filename)->std::string
-  {
-    std::ifstream t(filename);
-    return std::string((std::istreambuf_iterator<char>(t)),
-                        std::istreambuf_iterator<char>());
-  };
-
-  return init(
-    file_to_string(vertex_shader_filename),
-    file_to_string(fragment_shader_filename),
-    fragment_data_name,
-    file_to_string(geometry_shader_filename),
-    geometry_shader_max_vertices
- );
-}
-
-IGL_INLINE bool igl::viewer::OpenGL_shader::init(
-  const std::string &vertex_shader_string,
-  const std::string &fragment_shader_string,
-  const std::string &fragment_data_name,
-  const std::string &geometry_shader_string,
-  int geometry_shader_max_vertices)
-{
-  using namespace std;
-  vertex_shader = create_shader_helper(GL_VERTEX_SHADER, vertex_shader_string);
-  geometry_shader = create_shader_helper(GL_GEOMETRY_SHADER, geometry_shader_string);
-  fragment_shader = create_shader_helper(GL_FRAGMENT_SHADER, fragment_shader_string);
-
-  if (!vertex_shader || !fragment_shader)
-    return false;
-
-  program_shader = glCreateProgram();
-
-  glAttachShader(program_shader, vertex_shader);
-  glAttachShader(program_shader, fragment_shader);
-
-  if (geometry_shader)
-  {
-    glAttachShader(program_shader, geometry_shader);
-
-    /* This covers only basic cases and may need to be modified */
-    glProgramParameteri(program_shader, GL_GEOMETRY_INPUT_TYPE, GL_TRIANGLES);
-    glProgramParameteri(program_shader, GL_GEOMETRY_OUTPUT_TYPE, GL_TRIANGLES);
-    glProgramParameteri(program_shader, GL_GEOMETRY_VERTICES_OUT, geometry_shader_max_vertices);
-  }
-
-  glBindFragDataLocation(program_shader, 0, fragment_data_name.c_str());
-  glLinkProgram(program_shader);
-
-  GLint status;
-  glGetProgramiv(program_shader, GL_LINK_STATUS, &status);
-
-  if (status != GL_TRUE)
-  {
-    char buffer[512];
-    glGetProgramInfoLog(program_shader, 512, NULL, buffer);
-    cerr << "Linker error: " << endl << buffer << endl;
-    program_shader = 0;
-    return false;
-  }
-
-  return true;
-}
-
-IGL_INLINE void igl::viewer::OpenGL_shader::bind()
-{
-  glUseProgram(program_shader);
-}
-
-IGL_INLINE GLint igl::viewer::OpenGL_shader::attrib(const std::string &name) const
-{
-  return glGetAttribLocation(program_shader, name.c_str());
-}
-
-IGL_INLINE GLint igl::viewer::OpenGL_shader::uniform(const std::string &name) const
-{
-  return glGetUniformLocation(program_shader, name.c_str());
-}
-
-IGL_INLINE GLint igl::viewer::OpenGL_shader::bindVertexAttribArray(
-  const std::string &name, GLuint bufferID, const Eigen::MatrixXf &M, bool refresh) const
-{
-  GLint id = attrib(name);
-  if (id < 0)
-    return id;
-  if (M.size() == 0)
-  {
-    glDisableVertexAttribArray(id);
-    return id;
-  }
-  glBindBuffer(GL_ARRAY_BUFFER, bufferID);
-  if (refresh)
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*M.size(), M.data(), GL_DYNAMIC_DRAW);
-  glVertexAttribPointer(id, M.rows(), GL_FLOAT, GL_FALSE, 0, 0);
-  glEnableVertexAttribArray(id);
-  return id;
-}
-
-IGL_INLINE void igl::viewer::OpenGL_shader::free()
-{
-  if (program_shader)
-  {
-    glDeleteProgram(program_shader);
-    program_shader = 0;
-  }
-  if (vertex_shader)
-  {
-    glDeleteShader(vertex_shader);
-    vertex_shader = 0;
-  }
-  if (fragment_shader)
-  {
-    glDeleteShader(fragment_shader);
-    fragment_shader = 0;
-  }
-  if (geometry_shader)
-  {
-    glDeleteShader(geometry_shader);
-    geometry_shader = 0;
-  }
-}
-
-IGL_INLINE GLuint igl::viewer::OpenGL_shader::create_shader_helper(GLint type, const std::string &shader_string)
-{
-  using namespace std;
-  if (shader_string.empty())
-    return (GLuint) 0;
-
-  GLuint id = glCreateShader(type);
-  const char *shader_string_const = shader_string.c_str();
-  glShaderSource(id, 1, &shader_string_const, NULL);
-  glCompileShader(id);
-
-  GLint status;
-  glGetShaderiv(id, GL_COMPILE_STATUS, &status);
-
-  if (status != GL_TRUE)
-  {
-    char buffer[512];
-    if (type == GL_VERTEX_SHADER)
-      cerr << "Vertex shader:" << endl;
-    else if (type == GL_FRAGMENT_SHADER)
-      cerr << "Fragment shader:" << endl;
-    else if (type == GL_GEOMETRY_SHADER)
-      cerr << "Geometry shader:" << endl;
-    cerr << shader_string << endl << endl;
-    glGetShaderInfoLog(id, 512, NULL, buffer);
-    cerr << "Error: " << endl << buffer << endl;
-    return (GLuint) 0;
-  }
-
-  return id;
-}

+ 0 - 98
include/igl/viewer/OpenGL_shader.h

@@ -1,98 +0,0 @@
-// This file is part of libigl, a simple c++ geometry processing library.
-//
-// Copyright (C) 2014 Wenzel Jacob <wenzel@inf.ethz.ch>
-//
-// 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_SHADER_H
-#define IGL_VIEWER_OPENGL_SHADER_H
-
-#include <igl/igl_inline.h>
-#include <string>
-#include <Eigen/Core>
-
-#ifdef _WIN32
-#  include <windows.h>
-#  undef max
-#  undef min
-#  undef DrawText
-#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
-
-namespace igl
-{
-namespace viewer
-{
-
-// This class wraps an OpenGL program composed of three shaders
-// TODO: write documentation
-
-class OpenGL_shader
-{
-public:
-  typedef unsigned int GLuint;
-  typedef int GLint;
-
-  GLuint vertex_shader;
-  GLuint fragment_shader;
-  GLuint geometry_shader;
-  GLuint program_shader;
-
-  IGL_INLINE OpenGL_shader() : vertex_shader(0), fragment_shader(0),
-    geometry_shader(0), program_shader(0) { }
-
-  // Create a new shader from the specified source strings
-  IGL_INLINE bool init(const std::string &vertex_shader_string,
-    const std::string &fragment_shader_string,
-    const std::string &fragment_data_name,
-    const std::string &geometry_shader_string = "",
-    int geometry_shader_max_vertices = 3);
-
-  // Create a new shader from the specified files on disk
-  IGL_INLINE bool init_from_files(const std::string &vertex_shader_filename,
-    const std::string &fragment_shader_filename,
-    const std::string &fragment_data_name,
-    const std::string &geometry_shader_filename = "",
-    int geometry_shader_max_vertices = 3);
-
-  // Select this shader for subsequent draw calls
-  IGL_INLINE void bind();
-
-  // Release all OpenGL objects
-  IGL_INLINE void free();
-
-  // Return the OpenGL handle of a named shader attribute (-1 if it does not exist)
-  IGL_INLINE GLint attrib(const std::string &name) const;
-
-  // Return the OpenGL handle of a uniform attribute (-1 if it does not exist)
-  IGL_INLINE GLint uniform(const std::string &name) const;
-
-  // Bind a per-vertex array attribute and refresh its contents from an Eigen amtrix
-  IGL_INLINE GLint bindVertexAttribArray(const std::string &name, GLuint bufferID,
-    const Eigen::MatrixXf &M, bool refresh) const;
-
-  IGL_INLINE GLuint create_shader_helper(GLint type, const std::string &shader_string);
-
-};
-
-}
-}
-
-#ifndef IGL_STATIC_LIBRARY
-#  include "OpenGL_shader.cpp"
-#endif
-
-#endif

+ 0 - 493
include/igl/viewer/OpenGL_state.cpp

@@ -1,493 +0,0 @@
-// 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 "OpenGL_state.h"
-#include "ViewerData.h"
-
-IGL_INLINE void igl::viewer::OpenGL_state::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 = ViewerData::DIRTY_ALL;
-}
-
-IGL_INLINE void igl::viewer::OpenGL_state::free_buffers()
-{
-  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::viewer::OpenGL_state::set_data(const igl::viewer::ViewerData &data, bool invert_normals)
-{
-  bool per_corner_uv = (data.F_uv.rows() == data.F.rows());
-  bool per_corner_normals = (data.F_normals.rows() == 3 * data.F.rows());
-
-  dirty |= data.dirty;
-
-  if (!data.face_based)
-  {
-    if (!(per_corner_uv || per_corner_normals))
-    {
-      // Vertex positions
-      if (dirty & ViewerData::DIRTY_POSITION)
-        V_vbo = (data.V.transpose()).cast<float>();
-
-      // Vertex normals
-      if (dirty & ViewerData::DIRTY_NORMAL)
-      {
-        V_normals_vbo = (data.V_normals.transpose()).cast<float>();
-        if (invert_normals)
-          V_normals_vbo = -V_normals_vbo;
-      }
-
-      // Per-vertex material settings
-      if (dirty & ViewerData::DIRTY_AMBIENT)
-        V_ambient_vbo = (data.V_material_ambient.transpose()).cast<float>();
-      if (dirty & ViewerData::DIRTY_DIFFUSE)
-        V_diffuse_vbo = (data.V_material_diffuse.transpose()).cast<float>();
-      if (dirty & ViewerData::DIRTY_SPECULAR)
-        V_specular_vbo = (data.V_material_specular.transpose()).cast<float>();
-
-      // Face indices
-      if (dirty & ViewerData::DIRTY_FACE)
-        F_vbo = (data.F.transpose()).cast<unsigned>();
-
-      // Texture coordinates
-      if (dirty & ViewerData::DIRTY_UV)
-        V_uv_vbo = (data.V_uv.transpose()).cast<float>();
-    }
-    else
-    {
-      // Per vertex properties with per corner UVs
-      if (dirty & ViewerData::DIRTY_POSITION)
-      {
-        V_vbo.resize(3,data.F.rows()*3);
-        for (unsigned i=0; i<data.F.rows();++i)
-          for (unsigned j=0;j<3;++j)
-            V_vbo.col(i*3+j) = data.V.row(data.F(i,j)).transpose().cast<float>();
-      }
-
-      if (dirty & ViewerData::DIRTY_AMBIENT)
-      {
-        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)
-            V_ambient_vbo.col (i*3+j) = data.V_material_ambient.row(data.F(i,j)).transpose().cast<float>();
-      }
-
-      if (dirty & ViewerData::DIRTY_DIFFUSE)
-      {
-        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)
-            V_diffuse_vbo.col (i*3+j) = data.V_material_diffuse.row(data.F(i,j)).transpose().cast<float>();
-      }
-
-      if (dirty & ViewerData::DIRTY_SPECULAR)
-      {
-        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)
-            V_specular_vbo.col(i*3+j) = data.V_material_specular.row(data.F(i,j)).transpose().cast<float>();
-      }
-
-      if (dirty & ViewerData::DIRTY_NORMAL)
-      {
-        V_normals_vbo.resize(3,data.F.rows()*3);
-        for (unsigned i=0; i<data.F.rows();++i)
-          for (unsigned j=0;j<3;++j)
-          
-            V_normals_vbo.col (i*3+j) = 
-                         per_corner_normals ?
-               data.F_normals.row(i*3+j).transpose().cast<float>() :
-               data.V_normals.row(data.F(i,j)).transpose().cast<float>();
-
-
-        if (invert_normals)
-          V_normals_vbo = -V_normals_vbo;
-      }
-
-      if (dirty & ViewerData::DIRTY_FACE)
-      {
-        F_vbo.resize(3,data.F.rows());
-        for (unsigned i=0; i<data.F.rows();++i)
-          F_vbo.col(i) << i*3+0, i*3+1, i*3+2;
-      }
-
-      if (dirty & ViewerData::DIRTY_UV)
-      {
-        V_uv_vbo.resize(2,data.F.rows()*3);
-        for (unsigned i=0; i<data.F.rows();++i)
-          for (unsigned j=0;j<3;++j)
-            V_uv_vbo.col(i*3+j) = data.V_uv.row(per_corner_uv ? data.F_uv(i,j) : data.F(i,j)).transpose().cast<float>();
-      }
-    }
-  }
-  else
-  {
-    if (dirty & ViewerData::DIRTY_POSITION)
-    {
-      V_vbo.resize(3,data.F.rows()*3);
-      for (unsigned i=0; i<data.F.rows();++i)
-        for (unsigned j=0;j<3;++j)
-          V_vbo.col(i*3+j) = data.V.row(data.F(i,j)).transpose().cast<float>();
-    }
-
-    if (dirty & ViewerData::DIRTY_AMBIENT)
-    {
-      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)
-          V_ambient_vbo.col (i*3+j) = data.F_material_ambient.row(i).transpose().cast<float>();
-    }
-
-    if (dirty & ViewerData::DIRTY_DIFFUSE)
-    {
-      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)
-          V_diffuse_vbo.col (i*3+j) = data.F_material_diffuse.row(i).transpose().cast<float>();
-    }
-
-    if (dirty & ViewerData::DIRTY_SPECULAR)
-    {
-      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)
-          V_specular_vbo.col(i*3+j) = data.F_material_specular.row(i).transpose().cast<float>();
-    }
-
-    if (dirty & ViewerData::DIRTY_NORMAL)
-    {
-      V_normals_vbo.resize(3,data.F.rows()*3);
-      for (unsigned i=0; i<data.F.rows();++i)
-        for (unsigned j=0;j<3;++j)
-          V_normals_vbo.col (i*3+j) =
-             per_corner_normals ?
-               data.F_normals.row(i*3+j).transpose().cast<float>() :
-               data.F_normals.row(i).transpose().cast<float>();
-
-      if (invert_normals)
-        V_normals_vbo = -V_normals_vbo;
-    }
-
-    if (dirty & ViewerData::DIRTY_FACE)
-    {
-      F_vbo.resize(3,data.F.rows());
-      for (unsigned i=0; i<data.F.rows();++i)
-        F_vbo.col(i) << i*3+0, i*3+1, i*3+2;
-    }
-
-    if (dirty & ViewerData::DIRTY_UV)
-    {
-        V_uv_vbo.resize(2,data.F.rows()*3);
-        for (unsigned i=0; i<data.F.rows();++i)
-          for (unsigned j=0;j<3;++j)
-            V_uv_vbo.col(i*3+j) = data.V_uv.row(per_corner_uv ? data.F_uv(i,j) : data.F(i,j)).transpose().cast<float>();
-    }
-  }
-
-  if (dirty & ViewerData::DIRTY_TEXTURE)
-  {
-    tex_u = data.texture_R.rows();
-    tex_v = data.texture_R.cols();
-    tex.resize(data.texture_R.size()*4);
-    for (unsigned i=0;i<data.texture_R.size();++i)
-    {
-      tex(i*4+0) = data.texture_R(i);
-      tex(i*4+1) = data.texture_G(i);
-      tex(i*4+2) = data.texture_B(i);
-      tex(i*4+3) = data.texture_A(i);
-    }
-  }
-
-  if (dirty & ViewerData::DIRTY_OVERLAY_LINES)
-  {
-    lines_V_vbo.resize(3, data.lines.rows()*2);
-    lines_V_colors_vbo.resize(3, data.lines.rows()*2);
-    lines_F_vbo.resize(1, data.lines.rows()*2);
-    for (unsigned i=0; i<data.lines.rows();++i)
-    {
-      lines_V_vbo.col(2*i+0) = data.lines.block<1, 3>(i, 0).transpose().cast<float>();
-      lines_V_vbo.col(2*i+1) = data.lines.block<1, 3>(i, 3).transpose().cast<float>();
-      lines_V_colors_vbo.col(2*i+0) = data.lines.block<1, 3>(i, 6).transpose().cast<float>();
-      lines_V_colors_vbo.col(2*i+1) = data.lines.block<1, 3>(i, 6).transpose().cast<float>();
-      lines_F_vbo(2*i+0) = 2*i+0;
-      lines_F_vbo(2*i+1) = 2*i+1;
-    }
-  }
-
-  if (dirty & ViewerData::DIRTY_OVERLAY_POINTS)
-  {
-    points_V_vbo.resize(3, data.points.rows());
-    points_V_colors_vbo.resize(3, data.points.rows());
-    points_F_vbo.resize(1, data.points.rows());
-    for (unsigned i=0; i<data.points.rows();++i)
-    {
-      points_V_vbo.col(i) = data.points.block<1, 3>(i, 0).transpose().cast<float>();
-      points_V_colors_vbo.col(i) = data.points.block<1, 3>(i, 3).transpose().cast<float>();
-      points_F_vbo(i) = i;
-    }
-  }
-}
-
-IGL_INLINE void igl::viewer::OpenGL_state::bind_mesh()
-{
-  glBindVertexArray(vao_mesh);
-  shader_mesh.bind();
-  shader_mesh.bindVertexAttribArray("position", vbo_V, V_vbo, dirty & ViewerData::DIRTY_POSITION);
-  shader_mesh.bindVertexAttribArray("normal", vbo_V_normals, V_normals_vbo, dirty & ViewerData::DIRTY_NORMAL);
-  shader_mesh.bindVertexAttribArray("Ka", vbo_V_ambient, V_ambient_vbo, dirty & ViewerData::DIRTY_AMBIENT);
-  shader_mesh.bindVertexAttribArray("Kd", vbo_V_diffuse, V_diffuse_vbo, dirty & ViewerData::DIRTY_DIFFUSE);
-  shader_mesh.bindVertexAttribArray("Ks", vbo_V_specular, V_specular_vbo, dirty & ViewerData::DIRTY_SPECULAR);
-  shader_mesh.bindVertexAttribArray("texcoord", vbo_V_uv, V_uv_vbo, dirty & ViewerData::DIRTY_UV);
-
-  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_F);
-  if (dirty & ViewerData::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 & ViewerData::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(shader_mesh.uniform("tex"), 0);
-  dirty &= ~ViewerData::DIRTY_MESH;
-}
-
-IGL_INLINE void igl::viewer::OpenGL_state::bind_overlay_lines()
-{
-  bool is_dirty = dirty & ViewerData::DIRTY_OVERLAY_LINES;
-
-  glBindVertexArray(vao_overlay_lines);
-  shader_overlay_lines.bind();
-  shader_overlay_lines.bindVertexAttribArray("position", vbo_lines_V, lines_V_vbo, is_dirty);
-  shader_overlay_lines.bindVertexAttribArray("color", vbo_lines_V_colors, lines_V_colors_vbo, is_dirty);
-
-  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_lines_F);
-  if (is_dirty)
-    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*lines_F_vbo.size(), lines_F_vbo.data(), GL_DYNAMIC_DRAW);
-
-  dirty &= ~ViewerData::DIRTY_OVERLAY_LINES;
-}
-
-IGL_INLINE void igl::viewer::OpenGL_state::bind_overlay_points()
-{
-  bool is_dirty = dirty & ViewerData::DIRTY_OVERLAY_POINTS;
-
-  glBindVertexArray(vao_overlay_points);
-  shader_overlay_points.bind();
-  shader_overlay_points.bindVertexAttribArray("position", vbo_points_V, points_V_vbo, is_dirty);
-  shader_overlay_points.bindVertexAttribArray("color", vbo_points_V_colors, points_V_colors_vbo, is_dirty);
-
-  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_points_F);
-  if (is_dirty)
-    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*points_F_vbo.size(), points_F_vbo.data(), GL_DYNAMIC_DRAW);
-
-  dirty &= ~ViewerData::DIRTY_OVERLAY_POINTS;
-}
-
-IGL_INLINE void igl::viewer::OpenGL_state::draw_mesh(bool solid)
-{
-  glPolygonMode(GL_FRONT_AND_BACK, solid ? GL_FILL : GL_LINE);
-
-  /* Avoid Z-buffer fighting between filled triangles & wireframe lines */
-  if (solid)
-  {
-    glEnable(GL_POLYGON_OFFSET_FILL);
-    glPolygonOffset(1.0, 1.0);
-  }
-  glDrawElements(GL_TRIANGLES, 3*F_vbo.cols(), GL_UNSIGNED_INT, 0);
-
-  glDisable(GL_POLYGON_OFFSET_FILL);
-  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-}
-
-IGL_INLINE void igl::viewer::OpenGL_state::draw_overlay_lines()
-{
-  glDrawElements(GL_LINES, lines_F_vbo.cols(), GL_UNSIGNED_INT, 0);
-}
-
-IGL_INLINE void igl::viewer::OpenGL_state::draw_overlay_points()
-{
-  glDrawElements(GL_POINTS, points_F_vbo.cols(), GL_UNSIGNED_INT, 0);
-}
-
-IGL_INLINE void igl::viewer::OpenGL_state::init()
-{
-  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();
-  shader_mesh.init(mesh_vertex_shader_string,
-      mesh_fragment_shader_string, "outColor");
-  shader_overlay_lines.init(overlay_vertex_shader_string,
-      overlay_fragment_shader_string, "outColor");
-  shader_overlay_points.init(overlay_vertex_shader_string,
-      overlay_point_fragment_shader_string, "outColor");
-}
-
-IGL_INLINE void igl::viewer::OpenGL_state::free()
-{
-  shader_mesh.free();
-  shader_overlay_lines.free();
-  shader_overlay_points.free();
-  free_buffers();
-}

+ 0 - 33
include/igl/viewer/TODOs.txt

@@ -1,33 +0,0 @@
-- `align_and_center_object` continues to zoom out on repeated calls
-- trackball_angle should be a quaternion
-- data.lines, data.points should not concatenate colors with coordinates
-- snap to canonical recenters origin but trackball does not
-- rewrite in libigl style
-- separate various class into their own .h/.cpp pairs
-- remove use of double underscores (http://stackoverflow.com/a/224420/148668)
-- document inputs and outputs to all functions
-- document all member fields
-- document all classes
-- light direction is backwards
-- remove global variables (not threadsafe)
-- encapsulate (in igl namespace) and move static/global functions, use lambdas?
-- preface macros with "IGL_"
-- trackball mouseup captured by tweakbar
-- zoom with pan rather than scaling
-- refresh draw while resizing
-- use constructor initializer list rather than complicated constructor
-- support per-element alpha values
-+ snap to canonical view key shortcut is not working
-+ resize TwBar with window
-+ trackball should be able to drag over TwBar
-+ don't zoom on horizontal scale
-+ remove global `using namespace std`
-+ remove `#define IGL_HEADER_ONLY`
-+ guard `#undef max`
-+ fix all -Wsign-compare
-+ missing `#include <iostream>`
-+ missing `#include <fstream>`
-+ fix all -Wunused-but-set-variable
-+ makefile for libiglviewer.a
-+ Viewer.h should include Viewer.cpp
-+ depth test for overlays cannot be disabled

+ 0 - 422
include/igl/viewer/ViewerData.cpp

@@ -1,422 +0,0 @@
-// 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 <iostream>
-
-#include <igl/per_face_normals.h>
-#include <igl/material_colors.h>
-#include <igl/parula.h>
-#include <igl/per_vertex_normals.h>
-
-IGL_INLINE igl::viewer::ViewerData::ViewerData()
-: dirty(DIRTY_ALL)
-{
-  clear();
-};
-
-IGL_INLINE void igl::viewer::ViewerData::set_face_based(bool newvalue)
-{
-  if (face_based != newvalue)
-  {
-    face_based = newvalue;
-    dirty = DIRTY_ALL;
-  }
-}
-
-// Helpers that draws the most common meshes
-IGL_INLINE void igl::viewer::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 |= DIRTY_FACE | DIRTY_POSITION;
-}
-
-IGL_INLINE void igl::viewer::ViewerData::set_vertices(const Eigen::MatrixXd& _V)
-{
-  V = _V;
-  assert(F.size() == 0 || F.maxCoeff() < V.rows());
-  dirty |= DIRTY_POSITION;
-}
-
-IGL_INLINE void igl::viewer::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 |= DIRTY_NORMAL;
-}
-
-IGL_INLINE void igl::viewer::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)
-    {
-      V_material_diffuse.row(i) << C.row(0),1;
-    }
-    V_material_ambient = ambient(V_material_diffuse);
-    V_material_specular = specular(V_material_diffuse);
-
-    for (unsigned i=0;i<F_material_diffuse.rows();++i)
-    {
-      F_material_diffuse.row(i) << C.row(0),1;
-    }
-    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)
-    {
-      V_material_diffuse.row(i) << C.row(i),1;
-    }
-    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)
-    {
-      F_material_diffuse.row(i) << C.row(i),1;
-    }
-    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 |= DIRTY_DIFFUSE;
-
-}
-
-IGL_INLINE void igl::viewer::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 |= DIRTY_UV;
-}
-
-IGL_INLINE void igl::viewer::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 |= DIRTY_UV;
-}
-
-
-IGL_INLINE void igl::viewer::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 |= DIRTY_TEXTURE;
-}
-
-IGL_INLINE void igl::viewer::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 |= DIRTY_TEXTURE;
-}
-
-IGL_INLINE void igl::viewer::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::viewer::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 |= DIRTY_OVERLAY_POINTS;
-}
-
-IGL_INLINE void igl::viewer::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 |= DIRTY_OVERLAY_LINES;
-}
-
-IGL_INLINE void igl::viewer::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 |= DIRTY_OVERLAY_LINES;
-}
-
-IGL_INLINE void igl::viewer::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::viewer::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::viewer::ViewerData::compute_normals()
-{
-  igl::per_face_normals(V, F, F_normals);
-  igl::per_vertex_normals(V, F, F_normals, V_normals);
-  dirty |= DIRTY_NORMAL;
-}
-
-IGL_INLINE void igl::viewer::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::viewer::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 |= DIRTY_SPECULAR | DIRTY_DIFFUSE | DIRTY_AMBIENT;
-}
-
-IGL_INLINE void igl::viewer::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 |= 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 |= DIRTY_TEXTURE;
-}

+ 0 - 3
optional/CMakeLists.txt

@@ -33,9 +33,6 @@ find_package(MATLAB QUIET)
 option(LIBIGL_WITH_MATLAB           "Use Matlab"         "${MATLAB_FOUND}")
 find_package(MOSEK  QUIET)
 option(LIBIGL_WITH_MOSEK            "Use MOSEK"          "${MOSEK_FOUND}")
-### Nanogui is off by default because it has many dependencies and generates
-### many issues
-option(LIBIGL_WITH_NANOGUI          "Use Nanogui menu"   OFF)
 option(LIBIGL_WITH_OPENGL           "Use OpenGL"         ON)
 option(LIBIGL_WITH_OPENGL_GLFW      "Use GLFW"           ON)
 option(LIBIGL_WITH_PNG              "Use PNG"            ON)

+ 5 - 6
python/CMakeLists.txt

@@ -23,12 +23,11 @@ if(UNIX)
 endif()
 
 ## include pybind
-set(PYBIND11_DIR ${PROJECT_SOURCE_DIR}/../external/nanogui/ext/pybind11 CACHE PATH "Path to pybind11")
+set(PYBIND11_DIR ${PROJECT_SOURCE_DIR}/../external/pybind11 CACHE PATH "Path to pybind11")
 add_subdirectory(${PYBIND11_DIR} pybind11)
 
 ## include libigl
 option(LIBIGL_USE_STATIC_LIBRARY "Use LibIGL as static library" OFF)
-option(LIBIGL_WITH_VIEWER           "Use OpenGL viewer"  ON)
 option(LIBIGL_WITH_OPENGL           "Use viewer"         ON)
 option(LIBIGL_WITH_OPENGL_GLFW      "Use GLFW"           ON)
 option(LIBIGL_WITH_NANOGUI          "Use Nanogui menu"   OFF)
@@ -64,10 +63,10 @@ pybind11_add_module(pyigl
 target_include_directories(pyigl PUBLIC igl::core)
 
 ## Optional modules
-if(LIBIGL_WITH_VIEWER)
-  target_sources(pyigl PRIVATE "modules/py_igl_viewer.cpp")
-  target_compile_definitions(pyigl PUBLIC -DPY_VIEWER)
-  target_link_libraries(pyigl PUBLIC igl::viewer)
+if(LIBIGL_WITH_OPENGL_GLFW)
+  target_sources(pyigl PRIVATE "modules/py_igl_opengl_glfw.cpp")
+  target_compile_definitions(pyigl PUBLIC -DPY_GLFW)
+  target_link_libraries(pyigl PUBLIC igl::opengl igl::opengl_glfw)
 endif()
 
 if(LIBIGL_WITH_COMISO)

+ 470 - 0
python/modules/py_igl_opengl_glfw.cpp

@@ -0,0 +1,470 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Sebastian Koch <s.koch@tu-berlin.de> and 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 <Eigen/Dense>
+#include <Eigen/Sparse>
+
+#include "../python_shared.h"
+#include <igl/opengl/glfw/Viewer.h>
+#include <igl/opengl/ViewerCore.h>
+#include <igl/opengl/ViewerData.h>
+#include <igl/opengl/MeshGL.h>
+#include <igl/serialize.h>
+#ifdef IGL_VIEWER_WITH_NANOGUI
+#include "../../../external/nanogui/include/nanogui/formhelper.h"
+#include "../../../external/nanogui/include/nanogui/screen.h"
+#endif
+
+void python_export_igl_glfw(py::module &m)
+{
+
+  py::module me = m.def_submodule(
+    "glfw", "GLFW Mesh viewer");
+
+/////////////////////// DATA
+
+py::class_<igl::opengl::ViewerData> viewerdata_class(me, "ViewerData");
+
+py::enum_<igl::opengl::MeshGL::DirtyFlags>(viewerdata_class, "DirtyFlags")
+    .value("DIRTY_NONE", igl::opengl::MeshGL::DIRTY_NONE)
+    .value("DIRTY_POSITION", igl::opengl::MeshGL::DIRTY_POSITION)
+    .value("DIRTY_UV", igl::opengl::MeshGL::DIRTY_UV)
+    .value("DIRTY_NORMAL", igl::opengl::MeshGL::DIRTY_NORMAL)
+    .value("DIRTY_AMBIENT", igl::opengl::MeshGL::DIRTY_AMBIENT)
+    .value("DIRTY_DIFFUSE", igl::opengl::MeshGL::DIRTY_DIFFUSE)
+    .value("DIRTY_SPECULAR", igl::opengl::MeshGL::DIRTY_SPECULAR)
+    .value("DIRTY_TEXTURE", igl::opengl::MeshGL::DIRTY_TEXTURE)
+    .value("DIRTY_FACE", igl::opengl::MeshGL::DIRTY_FACE)
+    .value("DIRTY_MESH", igl::opengl::MeshGL::DIRTY_MESH)
+    .value("DIRTY_OVERLAY_LINES", igl::opengl::MeshGL::DIRTY_OVERLAY_LINES)
+    .value("DIRTY_OVERLAY_POINTS", igl::opengl::MeshGL::DIRTY_OVERLAY_POINTS)
+    .value("DIRTY_ALL", igl::opengl::MeshGL::DIRTY_ALL)
+    .export_values();
+
+
+    viewerdata_class
+    .def(py::init<>())
+    .def("set_mesh", &igl::opengl::ViewerData::set_mesh)
+    .def("set_colors", &igl::opengl::ViewerData::set_colors)
+    .def("clear", &igl::opengl::ViewerData::clear)
+    .def("set_face_based", &igl::opengl::ViewerData::set_face_based)
+
+    .def("set_vertices", &igl::opengl::ViewerData::set_vertices)
+    .def("set_normals", &igl::opengl::ViewerData::set_normals)
+
+    .def("set_uv",
+       (void (igl::opengl::ViewerData::*) (const Eigen::MatrixXd &)) &igl::opengl::ViewerData::set_uv
+    )
+
+    .def("set_uv",
+       (void (igl::opengl::ViewerData::*) (const Eigen::MatrixXd &, const Eigen::MatrixXi&)) &igl::opengl::ViewerData::set_uv
+    )
+
+    .def("set_texture",
+       (void (igl::opengl::ViewerData::*) (
+         const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>&,
+         const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>&,
+         const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>&)
+       ) &igl::opengl::ViewerData::set_texture
+    )
+
+    .def("set_texture",
+       (void (igl::opengl::ViewerData::*) (
+         const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>&,
+         const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>&,
+         const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>&,
+         const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>&)
+       ) &igl::opengl::ViewerData::set_texture
+    )
+
+    .def("set_points", &igl::opengl::ViewerData::set_points)
+    .def("add_points", &igl::opengl::ViewerData::add_points)
+    .def("set_edges", &igl::opengl::ViewerData::set_edges)
+    .def("add_edges", &igl::opengl::ViewerData::add_edges)
+
+    .def("add_label", [] (igl::opengl::ViewerData& data, const Eigen::MatrixXd& P,  const std::string& str)
+    {
+      assert_is_VectorX("P",P);
+      data.add_label(P,str);
+    })
+
+    .def("compute_normals", &igl::opengl::ViewerData::compute_normals)
+
+    .def("uniform_colors", [] (igl::opengl::ViewerData& data, const Eigen::MatrixXd& ambient, const Eigen::MatrixXd& diffuse, const Eigen::MatrixXd& specular)
+    {
+      if (ambient.cols() == 3)
+      {
+        assert_is_Vector3("ambient",ambient);
+        assert_is_Vector3("diffuse",diffuse);
+        assert_is_Vector3("specular",specular);
+        Eigen::Vector3d vambient = ambient;
+        Eigen::Vector3d vdiffuse = diffuse;
+        Eigen::Vector3d vspecular = specular;
+        data.uniform_colors(vambient,vdiffuse, vspecular);
+      }
+
+      if (ambient.cols() == 4)
+      {
+        assert_is_Vector4("ambient",ambient);
+        assert_is_Vector4("diffuse",diffuse);
+        assert_is_Vector4("specular",specular);
+        Eigen::Vector4d vambient = ambient;
+        Eigen::Vector4d vdiffuse = diffuse;
+        Eigen::Vector4d vspecular = specular;
+        data.uniform_colors(vambient,vdiffuse,vspecular);
+      }
+
+    })
+
+    .def("grid_texture", &igl::opengl::ViewerData::grid_texture)
+
+    .def_readwrite("V", &igl::opengl::ViewerData::V)
+    .def_readwrite("F", &igl::opengl::ViewerData::F)
+
+    .def_readwrite("F_normals", &igl::opengl::ViewerData::F_normals)
+    .def_readwrite("F_material_ambient", &igl::opengl::ViewerData::F_material_ambient)
+    .def_readwrite("F_material_diffuse", &igl::opengl::ViewerData::F_material_diffuse)
+    .def_readwrite("F_material_specular", &igl::opengl::ViewerData::F_material_specular)
+
+    .def_readwrite("V_normals", &igl::opengl::ViewerData::V_normals)
+    .def_readwrite("V_material_ambient", &igl::opengl::ViewerData::V_material_ambient)
+    .def_readwrite("V_material_diffuse", &igl::opengl::ViewerData::V_material_diffuse)
+    .def_readwrite("V_material_specular", &igl::opengl::ViewerData::V_material_specular)
+
+    .def_readwrite("V_uv", &igl::opengl::ViewerData::V_uv)
+    .def_readwrite("F_uv", &igl::opengl::ViewerData::F_uv)
+
+    .def_readwrite("texture_R", &igl::opengl::ViewerData::texture_R)
+    .def_readwrite("texture_G", &igl::opengl::ViewerData::texture_G)
+    .def_readwrite("texture_B", &igl::opengl::ViewerData::texture_B)
+
+    .def_readwrite("lines", &igl::opengl::ViewerData::lines)
+    .def_readwrite("points", &igl::opengl::ViewerData::points)
+    .def_readwrite("labels_positions", &igl::opengl::ViewerData::labels_positions)
+    .def_readwrite("labels_strings", &igl::opengl::ViewerData::labels_strings)
+    // .def_readwrite("dirty", &igl::opengl::MeshGL::dirty)
+    .def_readwrite("face_based", &igl::opengl::ViewerData::face_based)
+    .def("serialize", [](igl::opengl::ViewerData& data)
+    {
+      std::vector<char> a;
+      igl::serialize(data,"Data",a);
+      return a;
+    })
+
+    .def("deserialize", [](igl::opengl::ViewerData& data, const std::vector<char>& a)
+    {
+      igl::deserialize(data,"Data",a);
+      return;
+    })
+
+    .def_readwrite("shininess",&igl::opengl::ViewerData::shininess)
+
+    .def_property("line_color",
+    [](const igl::opengl::ViewerData& data) {return Eigen::MatrixXd(data.line_color.cast<double>());},
+    [](igl::opengl::ViewerData& data, const Eigen::MatrixXd& v)
+    {
+      assert_is_Vector4("line_color",v);
+      data.line_color = Eigen::Vector4f(v.cast<float>());
+    })
+
+    .def_readwrite("show_overlay",&igl::opengl::ViewerData::show_overlay)
+    .def_readwrite("show_overlay_depth",&igl::opengl::ViewerData::show_overlay_depth)
+    .def_readwrite("show_texture",&igl::opengl::ViewerData::show_texture)
+    .def_readwrite("show_faces",&igl::opengl::ViewerData::show_faces)
+
+    .def_readwrite("show_lines",&igl::opengl::ViewerData::show_lines)
+    .def_readwrite("show_vertid",&igl::opengl::ViewerData::show_vertid)
+    .def_readwrite("show_faceid",&igl::opengl::ViewerData::show_faceid)
+    .def_readwrite("invert_normals",&igl::opengl::ViewerData::invert_normals)
+
+    .def_readwrite("point_size",&igl::opengl::ViewerData::point_size)
+    .def_readwrite("line_width",&igl::opengl::ViewerData::line_width)
+
+    ;
+
+//////////////////////// OPENGL_State
+
+// py::class_<igl::opengl::State> opengl_state_class(me, "OpenGL_state");
+
+//     opengl_state_class
+//     .def(py::init<>())
+//     .def("init", &igl::opengl::State::init)
+
+//     ;
+
+//////////////////////// CORE
+
+py::class_<igl::opengl::ViewerCore> viewercore_class(me, "ViewerCore");
+
+    py::enum_<igl::opengl::ViewerCore::RotationType>(viewercore_class, "RotationType")
+        .value("ROTATION_TYPE_TRACKBALL", igl::opengl::ViewerCore::ROTATION_TYPE_TRACKBALL)
+        .value("ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP", igl::opengl::ViewerCore::ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP)
+        .value("NUM_ROTATION_TYPES", igl::opengl::ViewerCore::NUM_ROTATION_TYPES)
+        .export_values();
+
+    viewercore_class
+    .def(py::init<>())
+    //.def("align_camera_center", [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F){return core.align_camera_center(V,F);})
+    .def("init", &igl::opengl::ViewerCore::init)
+    .def("shut", &igl::opengl::ViewerCore::shut)
+    //.def("InitSerialization", &igl::opengl::ViewerCore::InitSerialization)
+    .def("align_camera_center",
+       (void (igl::opengl::ViewerCore::*) (const Eigen::MatrixXd &, const Eigen::MatrixXi &)) &igl::opengl::ViewerCore::align_camera_center
+    )
+
+    .def("align_camera_center",
+       (void (igl::opengl::ViewerCore::*) (const Eigen::MatrixXd &)) &igl::opengl::ViewerCore::align_camera_center
+    )
+
+    .def("clear_framebuffers",&igl::opengl::ViewerCore::clear_framebuffers)
+    .def("draw",&igl::opengl::ViewerCore::draw)
+    .def("draw_buffer",&igl::opengl::ViewerCore::draw_buffer)
+
+    .def_property("background_color",
+    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.background_color.cast<double>());},
+    [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
+    {
+      assert_is_Vector4("background_color",v);
+      core.background_color << Eigen::Vector4f(v.cast<float>());
+    })
+
+    .def_property("light_position",
+    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.light_position.cast<double>());},
+    [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
+    {
+      assert_is_Vector3("light_position",v);
+      core.light_position = Eigen::Vector3f(v.cast<float>());
+    })
+
+    .def_readwrite("lighting_factor",&igl::opengl::ViewerCore::lighting_factor)
+    .def_readwrite("model_zoom",&igl::opengl::ViewerCore::model_zoom)
+
+    .def_property("trackball_angle",
+    [](const igl::opengl::ViewerCore& core) {return Eigen::Quaterniond(core.trackball_angle.cast<double>());},
+    [](igl::opengl::ViewerCore& core, const Eigen::Quaterniond& q)
+    {
+      core.trackball_angle = Eigen::Quaternionf(q.cast<float>());
+    })
+
+    .def_property("model_translation",
+    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.model_translation.cast<double>());},
+    [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
+    {
+      assert_is_Vector3("model_translation",v);
+      core.model_translation = Eigen::Vector3f(v.cast<float>());
+    })
+
+    .def_readwrite("model_zoom_uv",&igl::opengl::ViewerCore::model_zoom_uv)
+
+    .def_property("model_translation_uv",
+    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.model_translation_uv.cast<double>());},
+    [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
+    {
+      assert_is_Vector3("model_translation_uv",v);
+      core.model_translation_uv = Eigen::Vector3f(v.cast<float>());
+    })
+
+    .def_readwrite("camera_zoom",&igl::opengl::ViewerCore::camera_zoom)
+    .def_readwrite("orthographic",&igl::opengl::ViewerCore::orthographic)
+
+    .def_property("camera_eye",
+    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.camera_eye.cast<double>());},
+    [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
+    {
+      assert_is_Vector3("camera_eye",v);
+      core.camera_eye = Eigen::Vector3f(v.cast<float>());
+    })
+
+    .def_property("camera_up",
+    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.camera_up.cast<double>());},
+    [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
+    {
+      assert_is_Vector3("camera_up",v);
+      core.camera_up = Eigen::Vector3f(v.cast<float>());
+    })
+
+    .def_property("camera_center",
+    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.camera_center.cast<double>());},
+    [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
+    {
+      assert_is_Vector3("camera_center",v);
+      core.camera_center = Eigen::Vector3f(v.cast<float>());
+    })
+
+    .def_readwrite("camera_view_angle",&igl::opengl::ViewerCore::camera_view_angle)
+
+    .def_readwrite("camera_dnear",&igl::opengl::ViewerCore::camera_dnear)
+    .def_readwrite("camera_dfar",&igl::opengl::ViewerCore::camera_dfar)
+
+    .def_readwrite("depth_test",&igl::opengl::ViewerCore::depth_test)
+
+    .def_readwrite("is_animating",&igl::opengl::ViewerCore::is_animating)
+    .def_readwrite("animation_max_fps",&igl::opengl::ViewerCore::animation_max_fps)
+
+    .def_readwrite("object_scale",&igl::opengl::ViewerCore::object_scale)
+
+    .def_property("viewport",
+    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.viewport.cast<double>());},
+    [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
+    {
+      assert_is_Vector4("viewport",v);
+      core.viewport = Eigen::Vector4f(v.cast<float>());
+    })
+
+    .def_property("view",
+    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.view.cast<double>());},
+    [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
+    {
+      assert_is_Matrix4("view",v);
+      core.view = Eigen::Matrix4f(v.cast<float>());
+    })
+
+    .def_property("model",
+    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.model.cast<double>());},
+    [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
+    {
+      assert_is_Matrix4("model",v);
+      core.model = Eigen::Matrix4f(v.cast<float>());
+    })
+
+    .def_property("proj",
+    [](const igl::opengl::ViewerCore& core) {return Eigen::MatrixXd(core.proj.cast<double>());},
+    [](igl::opengl::ViewerCore& core, const Eigen::MatrixXd& v)
+    {
+      assert_is_Matrix4("proj",v);
+      core.proj = Eigen::Matrix4f(v.cast<float>());
+    })
+
+    .def_readwrite("rotation_type",&igl::opengl::ViewerCore::rotation_type)
+
+    .def("serialize", [](igl::opengl::ViewerCore& core)
+    {
+      std::vector<char> a;
+      igl::serialize(core,"Core",a);
+      return a;
+    })
+
+    .def("deserialize", [](igl::opengl::ViewerCore& core, const std::vector<char>& a)
+    {
+      igl::deserialize(core,"Core",a);
+      return;
+    })
+
+    // TODO: wrap this!
+    // Eigen::Quaternionf trackball_angle;
+    ;
+
+///////////////////////// VIEWER
+
+// UI Enumerations
+    py::class_<igl::opengl::glfw::Viewer> viewer_class(me, "Viewer");
+
+//    #ifdef IGL_VIEWER_WITH_NANOGUI
+//    py::object fh = (py::object) py::module::import("nanogui").attr("FormHelper");
+//    py::class_<nanogui::FormHelper> form_helper_class(me, "FormHelper", fh);
+
+//    py::object screen = (py::object) py::module::import("nanogui").attr("Screen");
+//    py::class_<nanogui::Screen> screen_class(me, "Screen", screen);
+//    #endif
+
+    py::enum_<igl::opengl::glfw::Viewer::MouseButton>(viewer_class, "MouseButton")
+        .value("Left", igl::opengl::glfw::Viewer::MouseButton::Left)
+        .value("Middle", igl::opengl::glfw::Viewer::MouseButton::Middle)
+        .value("Right", igl::opengl::glfw::Viewer::MouseButton::Right)
+        .export_values();
+
+    viewer_class
+    .def(py::init<>())
+    //.def_readwrite("data", &igl::opengl::glfw::Viewer::data)
+   
+    // .def_property("data",
+    // [](igl::opengl::glfw::Viewer& viewer) {return viewer.data();},
+    // [](igl::opengl::glfw::Viewer& viewer, const igl::opengl::ViewerData& data)
+    // {
+    //   viewer.data() = data;
+    // })
+
+    .def("data", &igl::opengl::glfw::Viewer::data,pybind11::return_value_policy::reference)
+
+    .def_readwrite("core", &igl::opengl::glfw::Viewer::core)
+    //.def_readwrite("opengl", &igl::opengl::glfw::Viewer::opengl)
+
+    #ifdef IGL_VIEWER_WITH_NANOGUI
+    .def_readwrite("ngui", &igl::opengl::glfw::Viewer::ngui)
+    .def_readwrite("screen", &igl::opengl::glfw::Viewer::screen)
+    #endif
+
+    .def("launch", &igl::opengl::glfw::Viewer::launch, py::arg("resizable") = true, py::arg("fullscreen") = false)
+    .def("launch_init", &igl::opengl::glfw::Viewer::launch_init, py::arg("resizable") = true, py::arg("fullscreen") = false)
+    .def("launch_rendering", &igl::opengl::glfw::Viewer::launch_rendering, py::arg("loop") = true)
+    .def("launch_shut", &igl::opengl::glfw::Viewer::launch_shut)
+    .def("init", &igl::opengl::glfw::Viewer::init)
+    .def("serialize", [](igl::opengl::glfw::Viewer& viewer)
+    {
+      std::vector<char> a;
+      igl::serialize(viewer.core,"Core",a);
+      //igl::serialize(viewer.data,"Data",a); TODO
+
+      return a;
+    })
+
+    .def("deserialize", [](igl::opengl::glfw::Viewer& viewer, const std::vector<char>& a)
+    {
+      igl::deserialize(viewer.core,"Core",a);
+      //igl::deserialize(viewer.data,"Data",a);
+      return;
+    })
+
+    // Scene IO
+    .def("load_scene", [](igl::opengl::glfw::Viewer& viewer)
+    {
+      viewer.load_scene();
+    })
+
+    .def("load_scene", [](igl::opengl::glfw::Viewer& viewer, std::string str)
+    {
+      viewer.load_scene(str);
+    })
+
+    .def("save_scene", [](igl::opengl::glfw::Viewer& viewer)
+    {
+      viewer.save_scene();
+    })
+
+    .def("save_scene", [](igl::opengl::glfw::Viewer& viewer, std::string str)
+    {
+      viewer.save_scene(str);
+    })
+
+    // Draw everything
+    .def("draw", &igl::opengl::glfw::Viewer::draw)
+
+    // OpenGL context resize
+    .def("resize", &igl::opengl::glfw::Viewer::resize)
+
+    // Helper functions
+    .def("snap_to_canonical_quaternion", &igl::opengl::glfw::Viewer::snap_to_canonical_quaternion)
+    .def("open_dialog_load_mesh", &igl::opengl::glfw::Viewer::open_dialog_load_mesh)
+    .def("open_dialog_save_mesh", &igl::opengl::glfw::Viewer::open_dialog_save_mesh)
+
+    // Input handling
+    .def_readwrite("current_mouse_x", &igl::opengl::glfw::Viewer::current_mouse_x)
+    .def_readwrite("current_mouse_y", &igl::opengl::glfw::Viewer::current_mouse_y)
+
+    // Callbacks
+    .def_readwrite("callback_init", &igl::opengl::glfw::Viewer::callback_init)
+    .def_readwrite("callback_pre_draw", &igl::opengl::glfw::Viewer::callback_pre_draw)
+    .def_readwrite("callback_post_draw", &igl::opengl::glfw::Viewer::callback_post_draw)
+    .def_readwrite("callback_mouse_down", &igl::opengl::glfw::Viewer::callback_mouse_down)
+    .def_readwrite("callback_mouse_up", &igl::opengl::glfw::Viewer::callback_mouse_up)
+    .def_readwrite("callback_mouse_move", &igl::opengl::glfw::Viewer::callback_mouse_move)
+    .def_readwrite("callback_mouse_scroll", &igl::opengl::glfw::Viewer::callback_mouse_scroll)
+    .def_readwrite("callback_key_pressed", &igl::opengl::glfw::Viewer::callback_key_pressed)
+    .def_readwrite("callback_key_down", &igl::opengl::glfw::Viewer::callback_key_down)
+    .def_readwrite("callback_key_up", &igl::opengl::glfw::Viewer::callback_key_up)
+    ;
+}

+ 0 - 452
python/modules/py_igl_viewer.cpp

@@ -1,452 +0,0 @@
-// This file is part of libigl, a simple c++ geometry processing library.
-//
-// Copyright (C) 2017 Sebastian Koch <s.koch@tu-berlin.de> and 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 <Eigen/Dense>
-#include <Eigen/Sparse>
-
-#include "../python_shared.h"
-#define ENABLE_SERIALIZATION
-#include <igl/viewer/Viewer.h>
-#include <igl/viewer/ViewerCore.h>
-#include <igl/viewer/ViewerData.h>
-#include <igl/viewer/OpenGL_state.h>
-#include <igl/serialize.h>
-#ifdef IGL_VIEWER_WITH_NANOGUI
-#include "../../../external/nanogui/include/nanogui/formhelper.h"
-#include "../../../external/nanogui/include/nanogui/screen.h"
-#endif
-
-void python_export_igl_viewer(py::module &m)
-{
-
-  py::module me = m.def_submodule(
-    "viewer", "Mesh viewer");
-
-/////////////////////// DATA
-
-py::class_<igl::viewer::ViewerData> viewerdata_class(me, "ViewerData");
-
-py::enum_<igl::viewer::ViewerData::DirtyFlags>(viewerdata_class, "DirtyFlags")
-    .value("DIRTY_NONE", igl::viewer::ViewerData::DIRTY_NONE)
-    .value("DIRTY_POSITION", igl::viewer::ViewerData::DIRTY_POSITION)
-    .value("DIRTY_UV", igl::viewer::ViewerData::DIRTY_UV)
-    .value("DIRTY_NORMAL", igl::viewer::ViewerData::DIRTY_NORMAL)
-    .value("DIRTY_AMBIENT", igl::viewer::ViewerData::DIRTY_AMBIENT)
-    .value("DIRTY_DIFFUSE", igl::viewer::ViewerData::DIRTY_DIFFUSE)
-    .value("DIRTY_SPECULAR", igl::viewer::ViewerData::DIRTY_SPECULAR)
-    .value("DIRTY_TEXTURE", igl::viewer::ViewerData::DIRTY_TEXTURE)
-    .value("DIRTY_FACE", igl::viewer::ViewerData::DIRTY_FACE)
-    .value("DIRTY_MESH", igl::viewer::ViewerData::DIRTY_MESH)
-    .value("DIRTY_OVERLAY_LINES", igl::viewer::ViewerData::DIRTY_OVERLAY_LINES)
-    .value("DIRTY_OVERLAY_POINTS", igl::viewer::ViewerData::DIRTY_OVERLAY_POINTS)
-    .value("DIRTY_ALL", igl::viewer::ViewerData::DIRTY_ALL)
-    .export_values();
-
-
-    viewerdata_class
-    .def(py::init<>())
-    .def("set_mesh", &igl::viewer::ViewerData::set_mesh)
-    .def("set_colors", &igl::viewer::ViewerData::set_colors)
-    .def("clear", &igl::viewer::ViewerData::clear)
-    .def("set_face_based", &igl::viewer::ViewerData::set_face_based)
-
-    .def("set_vertices", &igl::viewer::ViewerData::set_vertices)
-    .def("set_normals", &igl::viewer::ViewerData::set_normals)
-
-    .def("set_uv",
-       (void (igl::viewer::ViewerData::*) (const Eigen::MatrixXd &)) &igl::viewer::ViewerData::set_uv
-    )
-
-    .def("set_uv",
-       (void (igl::viewer::ViewerData::*) (const Eigen::MatrixXd &, const Eigen::MatrixXi&)) &igl::viewer::ViewerData::set_uv
-    )
-
-    .def("set_texture",
-       (void (igl::viewer::ViewerData::*) (
-         const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>&,
-         const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>&,
-         const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>&)
-       ) &igl::viewer::ViewerData::set_texture
-    )
-
-    .def("set_texture",
-       (void (igl::viewer::ViewerData::*) (
-         const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>&,
-         const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>&,
-         const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>&,
-         const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>&)
-       ) &igl::viewer::ViewerData::set_texture
-    )
-
-    .def("set_points", &igl::viewer::ViewerData::set_points)
-    .def("add_points", &igl::viewer::ViewerData::add_points)
-    .def("set_edges", &igl::viewer::ViewerData::set_edges)
-    .def("add_edges", &igl::viewer::ViewerData::add_edges)
-
-    .def("add_label", [] (igl::viewer::ViewerData& data, const Eigen::MatrixXd& P,  const std::string& str)
-    {
-      assert_is_VectorX("P",P);
-      data.add_label(P,str);
-    })
-
-    .def("compute_normals", &igl::viewer::ViewerData::compute_normals)
-
-    .def("uniform_colors", [] (igl::viewer::ViewerData& data, const Eigen::MatrixXd& ambient, const Eigen::MatrixXd& diffuse, const Eigen::MatrixXd& specular)
-    {
-      if (ambient.cols() == 3)
-      {
-        assert_is_Vector3("ambient",ambient);
-        assert_is_Vector3("diffuse",diffuse);
-        assert_is_Vector3("specular",specular);
-        Eigen::Vector3d vambient = ambient;
-        Eigen::Vector3d vdiffuse = diffuse;
-        Eigen::Vector3d vspecular = specular;
-        data.uniform_colors(vambient,vdiffuse, vspecular);
-      }
-
-      if (ambient.cols() == 4)
-      {
-        assert_is_Vector4("ambient",ambient);
-        assert_is_Vector4("diffuse",diffuse);
-        assert_is_Vector4("specular",specular);
-        Eigen::Vector4d vambient = ambient;
-        Eigen::Vector4d vdiffuse = diffuse;
-        Eigen::Vector4d vspecular = specular;
-        data.uniform_colors(vambient,vdiffuse,vspecular);
-      }
-
-    })
-
-    .def("grid_texture", &igl::viewer::ViewerData::grid_texture)
-
-    .def_readwrite("V", &igl::viewer::ViewerData::V)
-    .def_readwrite("F", &igl::viewer::ViewerData::F)
-
-    .def_readwrite("F_normals", &igl::viewer::ViewerData::F_normals)
-    .def_readwrite("F_material_ambient", &igl::viewer::ViewerData::F_material_ambient)
-    .def_readwrite("F_material_diffuse", &igl::viewer::ViewerData::F_material_diffuse)
-    .def_readwrite("F_material_specular", &igl::viewer::ViewerData::F_material_specular)
-
-    .def_readwrite("V_normals", &igl::viewer::ViewerData::V_normals)
-    .def_readwrite("V_material_ambient", &igl::viewer::ViewerData::V_material_ambient)
-    .def_readwrite("V_material_diffuse", &igl::viewer::ViewerData::V_material_diffuse)
-    .def_readwrite("V_material_specular", &igl::viewer::ViewerData::V_material_specular)
-
-    .def_readwrite("V_uv", &igl::viewer::ViewerData::V_uv)
-    .def_readwrite("F_uv", &igl::viewer::ViewerData::F_uv)
-
-    .def_readwrite("texture_R", &igl::viewer::ViewerData::texture_R)
-    .def_readwrite("texture_G", &igl::viewer::ViewerData::texture_G)
-    .def_readwrite("texture_B", &igl::viewer::ViewerData::texture_B)
-
-    .def_readwrite("lines", &igl::viewer::ViewerData::lines)
-    .def_readwrite("points", &igl::viewer::ViewerData::points)
-    .def_readwrite("labels_positions", &igl::viewer::ViewerData::labels_positions)
-    .def_readwrite("labels_strings", &igl::viewer::ViewerData::labels_strings)
-    .def_readwrite("dirty", &igl::viewer::ViewerData::dirty)
-    .def_readwrite("face_based", &igl::viewer::ViewerData::face_based)
-    .def("serialize", [](igl::viewer::ViewerData& data)
-    {
-      std::vector<char> a;
-      igl::serialize(data,"Data",a);
-      return a;
-    })
-
-    .def("deserialize", [](igl::viewer::ViewerData& data, const std::vector<char>& a)
-    {
-      igl::deserialize(data,"Data",a);
-      return;
-    })
-
-    ;
-
-//////////////////////// OPENGL_State
-
-py::class_<igl::viewer::OpenGL_state> opengl_state_class(me, "OpenGL_state");
-
-    opengl_state_class
-    .def(py::init<>())
-    .def("init", &igl::viewer::OpenGL_state::init)
-
-    ;
-
-//////////////////////// CORE
-
-py::class_<igl::viewer::ViewerCore> viewercore_class(me, "ViewerCore");
-
-    py::enum_<igl::viewer::ViewerCore::RotationType>(viewercore_class, "RotationType")
-        .value("ROTATION_TYPE_TRACKBALL", igl::viewer::ViewerCore::ROTATION_TYPE_TRACKBALL)
-        .value("ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP", igl::viewer::ViewerCore::ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP)
-        .value("NUM_ROTATION_TYPES", igl::viewer::ViewerCore::NUM_ROTATION_TYPES)
-        .export_values();
-
-    viewercore_class
-    .def(py::init<>())
-    //.def("align_camera_center", [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& V, const Eigen::MatrixXi& F){return core.align_camera_center(V,F);})
-    .def("init", &igl::viewer::ViewerCore::init)
-    .def("shut", &igl::viewer::ViewerCore::shut)
-    //.def("InitSerialization", &igl::viewer::ViewerCore::InitSerialization)
-    .def("align_camera_center",
-       (void (igl::viewer::ViewerCore::*) (const Eigen::MatrixXd &, const Eigen::MatrixXi &)) &igl::viewer::ViewerCore::align_camera_center
-    )
-
-    .def("align_camera_center",
-       (void (igl::viewer::ViewerCore::*) (const Eigen::MatrixXd &)) &igl::viewer::ViewerCore::align_camera_center
-    )
-
-    .def("clear_framebuffers",&igl::viewer::ViewerCore::clear_framebuffers)
-    .def("draw",&igl::viewer::ViewerCore::draw)
-    .def("draw_buffer",&igl::viewer::ViewerCore::draw_buffer)
-
-    .def_readwrite("shininess",&igl::viewer::ViewerCore::shininess)
-
-    .def_property("background_color",
-    [](const igl::viewer::ViewerCore& core) {return Eigen::MatrixXd(core.background_color.cast<double>());},
-    [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& v)
-    {
-      assert_is_Vector4("background_color",v);
-      core.background_color << Eigen::Vector4f(v.cast<float>());
-    })
-
-    .def_property("line_color",
-    [](const igl::viewer::ViewerCore& core) {return Eigen::MatrixXd(core.line_color.cast<double>());},
-    [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& v)
-    {
-      assert_is_Vector4("line_color",v);
-      core.line_color = Eigen::Vector4f(v.cast<float>());
-    })
-
-    .def_property("light_position",
-    [](const igl::viewer::ViewerCore& core) {return Eigen::MatrixXd(core.light_position.cast<double>());},
-    [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& v)
-    {
-      assert_is_Vector3("light_position",v);
-      core.light_position = Eigen::Vector3f(v.cast<float>());
-    })
-
-    .def_readwrite("lighting_factor",&igl::viewer::ViewerCore::lighting_factor)
-    .def_readwrite("model_zoom",&igl::viewer::ViewerCore::model_zoom)
-
-    .def_property("trackball_angle",
-    [](const igl::viewer::ViewerCore& core) {return Eigen::Quaterniond(core.trackball_angle.cast<double>());},
-    [](igl::viewer::ViewerCore& core, const Eigen::Quaterniond& q)
-    {
-      core.trackball_angle = Eigen::Quaternionf(q.cast<float>());
-    })
-
-    .def_property("model_translation",
-    [](const igl::viewer::ViewerCore& core) {return Eigen::MatrixXd(core.model_translation.cast<double>());},
-    [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& v)
-    {
-      assert_is_Vector3("model_translation",v);
-      core.model_translation = Eigen::Vector3f(v.cast<float>());
-    })
-
-    .def_readwrite("model_zoom_uv",&igl::viewer::ViewerCore::model_zoom_uv)
-
-    .def_property("model_translation_uv",
-    [](const igl::viewer::ViewerCore& core) {return Eigen::MatrixXd(core.model_translation_uv.cast<double>());},
-    [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& v)
-    {
-      assert_is_Vector3("model_translation_uv",v);
-      core.model_translation_uv = Eigen::Vector3f(v.cast<float>());
-    })
-
-    .def_readwrite("camera_zoom",&igl::viewer::ViewerCore::camera_zoom)
-    .def_readwrite("orthographic",&igl::viewer::ViewerCore::orthographic)
-
-    .def_property("camera_eye",
-    [](const igl::viewer::ViewerCore& core) {return Eigen::MatrixXd(core.camera_eye.cast<double>());},
-    [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& v)
-    {
-      assert_is_Vector3("camera_eye",v);
-      core.camera_eye = Eigen::Vector3f(v.cast<float>());
-    })
-
-    .def_property("camera_up",
-    [](const igl::viewer::ViewerCore& core) {return Eigen::MatrixXd(core.camera_up.cast<double>());},
-    [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& v)
-    {
-      assert_is_Vector3("camera_up",v);
-      core.camera_up = Eigen::Vector3f(v.cast<float>());
-    })
-
-    .def_property("camera_center",
-    [](const igl::viewer::ViewerCore& core) {return Eigen::MatrixXd(core.camera_center.cast<double>());},
-    [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& v)
-    {
-      assert_is_Vector3("camera_center",v);
-      core.camera_center = Eigen::Vector3f(v.cast<float>());
-    })
-
-    .def_readwrite("camera_view_angle",&igl::viewer::ViewerCore::camera_view_angle)
-
-    .def_readwrite("camera_dnear",&igl::viewer::ViewerCore::camera_dnear)
-    .def_readwrite("camera_dfar",&igl::viewer::ViewerCore::camera_dfar)
-
-    .def_readwrite("show_overlay",&igl::viewer::ViewerCore::show_overlay)
-    .def_readwrite("show_overlay_depth",&igl::viewer::ViewerCore::show_overlay_depth)
-    .def_readwrite("show_texture",&igl::viewer::ViewerCore::show_texture)
-    .def_readwrite("show_faces",&igl::viewer::ViewerCore::show_faces)
-
-    .def_readwrite("show_lines",&igl::viewer::ViewerCore::show_lines)
-    .def_readwrite("show_vertid",&igl::viewer::ViewerCore::show_vertid)
-    .def_readwrite("show_faceid",&igl::viewer::ViewerCore::show_faceid)
-    .def_readwrite("invert_normals",&igl::viewer::ViewerCore::invert_normals)
-    .def_readwrite("depth_test",&igl::viewer::ViewerCore::depth_test)
-
-    .def_readwrite("point_size",&igl::viewer::ViewerCore::point_size)
-    .def_readwrite("line_width",&igl::viewer::ViewerCore::line_width)
-
-    .def_readwrite("is_animating",&igl::viewer::ViewerCore::is_animating)
-    .def_readwrite("animation_max_fps",&igl::viewer::ViewerCore::animation_max_fps)
-
-    .def_readwrite("object_scale",&igl::viewer::ViewerCore::object_scale)
-
-    .def_property("viewport",
-    [](const igl::viewer::ViewerCore& core) {return Eigen::MatrixXd(core.viewport.cast<double>());},
-    [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& v)
-    {
-      assert_is_Vector4("viewport",v);
-      core.viewport = Eigen::Vector4f(v.cast<float>());
-    })
-
-    .def_property("view",
-    [](const igl::viewer::ViewerCore& core) {return Eigen::MatrixXd(core.view.cast<double>());},
-    [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& v)
-    {
-      assert_is_Matrix4("view",v);
-      core.view = Eigen::Matrix4f(v.cast<float>());
-    })
-
-    .def_property("model",
-    [](const igl::viewer::ViewerCore& core) {return Eigen::MatrixXd(core.model.cast<double>());},
-    [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& v)
-    {
-      assert_is_Matrix4("model",v);
-      core.model = Eigen::Matrix4f(v.cast<float>());
-    })
-
-    .def_property("proj",
-    [](const igl::viewer::ViewerCore& core) {return Eigen::MatrixXd(core.proj.cast<double>());},
-    [](igl::viewer::ViewerCore& core, const Eigen::MatrixXd& v)
-    {
-      assert_is_Matrix4("proj",v);
-      core.proj = Eigen::Matrix4f(v.cast<float>());
-    })
-
-    .def_readwrite("rotation_type",&igl::viewer::ViewerCore::rotation_type)
-
-    .def("serialize", [](igl::viewer::ViewerCore& core)
-    {
-      std::vector<char> a;
-      igl::serialize(core,"Core",a);
-      return a;
-    })
-
-    .def("deserialize", [](igl::viewer::ViewerCore& core, const std::vector<char>& a)
-    {
-      igl::deserialize(core,"Core",a);
-      return;
-    })
-
-    // TODO: wrap this!
-    // Eigen::Quaternionf trackball_angle;
-    ;
-
-///////////////////////// VIEWER
-
-// UI Enumerations
-    py::class_<igl::viewer::Viewer> viewer_class(me, "Viewer");
-
-//    #ifdef IGL_VIEWER_WITH_NANOGUI
-//    py::object fh = (py::object) py::module::import("nanogui").attr("FormHelper");
-//    py::class_<nanogui::FormHelper> form_helper_class(me, "FormHelper", fh);
-
-//    py::object screen = (py::object) py::module::import("nanogui").attr("Screen");
-//    py::class_<nanogui::Screen> screen_class(me, "Screen", screen);
-//    #endif
-
-    py::enum_<igl::viewer::Viewer::MouseButton>(viewer_class, "MouseButton")
-        .value("Left", igl::viewer::Viewer::MouseButton::Left)
-        .value("Middle", igl::viewer::Viewer::MouseButton::Middle)
-        .value("Right", igl::viewer::Viewer::MouseButton::Right)
-        .export_values();
-
-    viewer_class
-    .def(py::init<>())
-    .def_readwrite("data", &igl::viewer::Viewer::data)
-    .def_readwrite("core", &igl::viewer::Viewer::core)
-    .def_readwrite("opengl", &igl::viewer::Viewer::opengl)
-
-    #ifdef IGL_VIEWER_WITH_NANOGUI
-    .def_readwrite("ngui", &igl::viewer::Viewer::ngui)
-    .def_readwrite("screen", &igl::viewer::Viewer::screen)
-    #endif
-
-    .def("launch", &igl::viewer::Viewer::launch, py::arg("resizable") = true, py::arg("fullscreen") = false)
-    .def("launch_init", &igl::viewer::Viewer::launch_init, py::arg("resizable") = true, py::arg("fullscreen") = false)
-    .def("launch_rendering", &igl::viewer::Viewer::launch_rendering, py::arg("loop") = true)
-    .def("launch_shut", &igl::viewer::Viewer::launch_shut)
-    .def("init", &igl::viewer::Viewer::init)
-    .def("serialize", [](igl::viewer::Viewer& viewer)
-    {
-      std::vector<char> a;
-      igl::serialize(viewer.core,"Core",a);
-      igl::serialize(viewer.data,"Data",a);
-
-      return a;
-    })
-
-    .def("deserialize", [](igl::viewer::Viewer& viewer, const std::vector<char>& a)
-    {
-      igl::deserialize(viewer.core,"Core",a);
-      igl::deserialize(viewer.data,"Data",a);
-      return;
-    })
-
-    // Scene IO
-    .def("load_scene", [](igl::viewer::Viewer& viewer)
-    {
-      viewer.load_scene();
-    })
-
-    .def("load_scene", [](igl::viewer::Viewer& viewer, std::string str)
-    {
-      viewer.load_scene(str);
-    })
-
-    .def("save_scene", &igl::viewer::Viewer::save_scene)
-
-    // Draw everything
-    .def("draw", &igl::viewer::Viewer::draw)
-
-    // OpenGL context resize
-    .def("resize", &igl::viewer::Viewer::resize)
-
-    // Helper functions
-    .def("snap_to_canonical_quaternion", &igl::viewer::Viewer::snap_to_canonical_quaternion)
-    .def("open_dialog_load_mesh", &igl::viewer::Viewer::open_dialog_load_mesh)
-    .def("open_dialog_save_mesh", &igl::viewer::Viewer::open_dialog_save_mesh)
-
-    // Input handling
-    .def_readwrite("current_mouse_x", &igl::viewer::Viewer::current_mouse_x)
-    .def_readwrite("current_mouse_y", &igl::viewer::Viewer::current_mouse_y)
-
-    // Callbacks
-    .def_readwrite("callback_init", &igl::viewer::Viewer::callback_init)
-    .def_readwrite("callback_pre_draw", &igl::viewer::Viewer::callback_pre_draw)
-    .def_readwrite("callback_post_draw", &igl::viewer::Viewer::callback_post_draw)
-    .def_readwrite("callback_mouse_down", &igl::viewer::Viewer::callback_mouse_down)
-    .def_readwrite("callback_mouse_up", &igl::viewer::Viewer::callback_mouse_up)
-    .def_readwrite("callback_mouse_move", &igl::viewer::Viewer::callback_mouse_move)
-    .def_readwrite("callback_mouse_scroll", &igl::viewer::Viewer::callback_mouse_scroll)
-    .def_readwrite("callback_key_pressed", &igl::viewer::Viewer::callback_key_pressed)
-    .def_readwrite("callback_key_down", &igl::viewer::Viewer::callback_key_down)
-    .def_readwrite("callback_key_up", &igl::viewer::Viewer::callback_key_up)
-    ;
-}

+ 4 - 0
python/modules/py_typedefs.h

@@ -7,6 +7,10 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include <pybind11/pybind11.h>
 #include <pybind11/stl_bind.h>
+#include <pybind11/stl.h>
+#include <pybind11/complex.h>
+#include <pybind11/functional.h>
+#include <pybind11/chrono.h>
 
 typedef std::vector<Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > RotationList;
 PYBIND11_MAKE_OPAQUE(RotationList)

+ 4 - 4
python/python_shared.cpp

@@ -13,8 +13,8 @@
 extern void python_export_vector(py::module &);
 extern void python_export_igl(py::module &);
 
-#ifdef PY_VIEWER
-extern void python_export_igl_viewer(py::module &);
+#ifdef PY_GLFW
+extern void python_export_igl_glfw(py::module &);
 #endif
 
 #ifdef PY_COMISO
@@ -168,8 +168,8 @@ PYBIND11_PLUGIN(pyigl) {
     python_export_igl(m);
 
 
-    #ifdef PY_VIEWER
-    python_export_igl_viewer(m);
+    #ifdef PY_GLFW
+    python_export_igl_glfw(m);
     #endif
 
     #ifdef PY_COMISO

+ 3 - 4
python/tutorial/102_DrawMesh.py

@@ -13,16 +13,15 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
-
 # Load a mesh in OFF format
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 igl.readOFF(TUTORIAL_SHARED_PATH + "beetle.off", V, F)
 
 # Plot the mesh
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V, F)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V, F)
 viewer.launch()

+ 7 - 7
python/tutorial/103_Events.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -28,15 +28,15 @@ def key_pressed(viewer, key, modifier):
 
     if key == ord('1'):
         # # Clear should be called before drawing the mesh
-        viewer.data.clear()
+        viewer.data().clear()
         # # Draw_mesh creates or updates the vertices and faces of the displayed mesh.
         # # If a mesh is already displayed, draw_mesh returns an error if the given V and
         # # F have size different than the current ones
-        viewer.data.set_mesh(V1, F1)
+        viewer.data().set_mesh(V1, F1)
         viewer.core.align_camera_center(V1,F1)
     elif key == ord('2'):
-        viewer.data.clear()
-        viewer.data.set_mesh(V2, F2)
+        viewer.data().clear()
+        viewer.data().set_mesh(V2, F2)
         viewer.core.align_camera_center(V2,F2)
     return False
 
@@ -48,10 +48,10 @@ igl.readOFF(TUTORIAL_SHARED_PATH + "fertility.off", V2, F2)
 print("1 Switch to bump mesh")
 print("2 Switch to fertility mesh")
 
-viewer = igl.viewer.Viewer()
+viewer = igl.glfw.Viewer()
 
 # Register a keyboard callback that allows to switch between
 # the two loaded meshes
 viewer.callback_key_pressed = key_pressed
-viewer.data.set_mesh(V1, F1)
+viewer.data().set_mesh(V1, F1)
 viewer.launch()

+ 4 - 4
python/tutorial/104_Colors.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -25,8 +25,8 @@ C = igl.eigen.MatrixXd()
 igl.readOFF(TUTORIAL_SHARED_PATH + "screwdriver.off", V, F)
 
 # Plot the mesh
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V, F)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V, F)
 
 # Use the z coordinate as a scalar field over the surface
 Z = V.col(2)
@@ -35,7 +35,7 @@ Z = V.col(2)
 igl.jet(Z, True, C)
 
 # Add per-vertex colors
-viewer.data.set_colors(C)
+viewer.data().set_colors(C)
 
 # Launch the viewer
 viewer.launch()

+ 23 - 23
python/tutorial/105_Overlays.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -41,43 +41,43 @@ V_box = igl.eigen.MatrixXd(
     ]
 )
 
-E_box = igl.eigen.MatrixXi(
-    [
-        [0, 1],
-        [1, 2],
-        [2, 3],
-        [3, 0],
-        [4, 5],
-        [5, 6],
-        [6, 7],
-        [7, 4],
-        [0, 4],
-        [1, 5],
-        [2, 6],
-        [7, 3]
-    ]
-)
+E_box = igl.eigen.MatrixXd(
+        [
+            [0, 1],
+            [1, 2],
+            [2, 3],
+            [3, 0],
+            [4, 5],
+            [5, 6],
+            [6, 7],
+            [7, 4],
+            [0, 4],
+            [1, 5],
+            [2, 6],
+            [7, 3]
+        ]
+).castint()
 
 # Plot the mesh
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V, F)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V, F)
 
 # Plot the corners of the bounding box as points
-viewer.data.add_points(V_box, igl.eigen.MatrixXd([[1, 0, 0]]))
+viewer.data().add_points(V_box, igl.eigen.MatrixXd([[1, 0, 0]]))
 
 # Plot the edges of the bounding box
 for i in range(0, E_box.rows()):
-    viewer.data.add_edges(
+    viewer.data().add_edges(
         V_box.row(E_box[i, 0]),
         V_box.row(E_box[i, 1]),
         igl.eigen.MatrixXd([[1, 0, 0]]))
 
 # Plot labels with the coordinates of bounding box vertices
 l1 = 'x: ' + str(m[0, 0]) + ' y: ' + str(m[0, 1]) + ' z: ' + str(m[0, 2])
-viewer.data.add_label(m.transpose(), l1)
+viewer.data().add_label(m.transpose(), l1)
 
 l2 = 'x: ' + str(M[0, 0]) + ' y: ' + str(M[0, 1]) + ' z: ' + str(M[0, 2])
-viewer.data.add_label(M.transpose(), l2)
+viewer.data().add_label(M.transpose(), l2)
 
 # Launch the viewer
 viewer.launch()

+ 8 - 8
python/tutorial/201_Normals.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -28,13 +28,13 @@ N_corners = igl.eigen.MatrixXd()
 # This function is called every time a keyboard button is pressed
 def key_pressed(viewer, key, modifier):
     if key == ord('1'):
-        viewer.data.set_normals(N_faces)
+        viewer.data().set_normals(N_faces)
         return True
     elif key == ord('2'):
-        viewer.data.set_normals(N_vertices)
+        viewer.data().set_normals(N_vertices)
         return True
     elif key == ord('3'):
-        viewer.data.set_normals(N_corners)
+        viewer.data().set_normals(N_corners)
         return True
     return False
 
@@ -55,11 +55,11 @@ N_corners = igl.eigen.MatrixXd()
 igl.per_corner_normals(V, F, 20, N_corners)
 
 # Plot the mesh
-viewer = igl.viewer.Viewer()
+viewer = igl.glfw.Viewer()
 viewer.callback_key_pressed = key_pressed
-viewer.core.show_lines = False
-viewer.data.set_mesh(V, F)
-viewer.data.set_normals(N_faces)
+viewer.data().show_lines = False
+viewer.data().set_mesh(V, F)
+viewer.data().set_normals(N_faces)
 print("Press '1' for per-face normals.")
 print("Press '2' for per-vertex normals.")
 print("Press '3' for per-corner normals.")

+ 4 - 4
python/tutorial/202_GaussianCurvature.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -31,7 +31,7 @@ C = igl.eigen.MatrixXd()
 igl.jet(K, True, C)
 
 # Plot the mesh with pseudocolors
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V, F)
-viewer.data.set_colors(C)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V, F)
+viewer.data().set_colors(C)
 viewer.launch()

+ 7 - 7
python/tutorial/203_CurvatureDirections.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -50,14 +50,14 @@ igl.principal_curvature(V, F, PD1, PD2, PV1, PV2)
 # Mean curvature
 H = 0.5 * (PV1 + PV2)
 
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V, F)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V, F)
 
 # Compute pseudocolor
 C = igl.eigen.MatrixXd()
 igl.parula(H, True, C)
 
-viewer.data.set_colors(C)
+viewer.data().set_colors(C)
 
 # Average edge length for sizing
 avg = igl.avg_edge_length(V, F)
@@ -66,12 +66,12 @@ avg = igl.avg_edge_length(V, F)
 red = igl.eigen.MatrixXd([[0.8, 0.2, 0.2]])
 blue = igl.eigen.MatrixXd([[0.2, 0.2, 0.8]])
 
-viewer.data.add_edges(V + PD1 * avg, V - PD1 * avg, blue)
+viewer.data().add_edges(V + PD1 * avg, V - PD1 * avg, blue)
 
 # Draw a red segment parallel to the maximal curvature direction
-viewer.data.add_edges(V + PD2 * avg, V - PD2 * avg, red)
+viewer.data().add_edges(V + PD2 * avg, V - PD2 * avg, red)
 
 # Hide wireframe
-viewer.core.show_lines = False
+viewer.data().show_lines = False
 
 viewer.launch()

+ 6 - 6
python/tutorial/204_Gradient.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -38,8 +38,8 @@ GU = (G * U).MapMatrix(F.rows(), 3)
 # Compute gradient magnitude
 GU_mag = GU.rowwiseNorm()
 
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V, F)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V, F)
 
 # Compute pseudocolor for original function
 C = igl.eigen.MatrixXd()
@@ -49,7 +49,7 @@ igl.jet(U, True, C)
 # Or for gradient magnitude
 # igl.jet(GU_mag,True,C)
 
-viewer.data.set_colors(C)
+viewer.data().set_colors(C)
 
 # Average edge length divided by average gradient (for scaling)
 max_size = igl.avg_edge_length(V, F) / GU_mag.mean()
@@ -59,9 +59,9 @@ BC = igl.eigen.MatrixXd()
 igl.barycenter(V, F, BC)
 
 black = igl.eigen.MatrixXd([[0.0, 0.0, 0.0]])
-viewer.data.add_edges(BC, BC + max_size * GU, black)
+viewer.data().add_edges(BC, BC + max_size * GU, black)
 
 # Hide wireframe
-viewer.core.show_lines = False
+viewer.data().show_lines = False
 
 viewer.launch()

+ 6 - 6
python/tutorial/205_Laplacian.py

@@ -14,7 +14,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -23,7 +23,7 @@ U = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 
 L = igl.eigen.SparseMatrixd()
-viewer = igl.viewer.Viewer()
+viewer = igl.glfw.Viewer()
 
 # Load a mesh in OFF format
 igl.readOFF(TUTORIAL_SHARED_PATH + "cow.off", V, F)
@@ -97,8 +97,8 @@ def key_pressed(viewer, key, modifier):
         return False
 
     # Send new positions, update normals, recenter
-    viewer.data.set_vertices(U)
-    viewer.data.compute_normals()
+    viewer.data().set_vertices(U)
+    viewer.data().compute_normals()
     viewer.core.align_camera_center(U, F)
     return True
 
@@ -110,8 +110,8 @@ C = N.rowwiseNormalized() * 0.5 + 0.5
 
 # Initialize smoothing with base mesh
 U = V
-viewer.data.set_mesh(U, F)
-viewer.data.set_colors(C)
+viewer.data().set_mesh(U, F)
+viewer.data().set_colors(C)
 viewer.callback_key_pressed = key_pressed
 
 print("Press [space] to smooth.")

+ 4 - 4
python/tutorial/301_Slice.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 V = igl.eigen.MatrixXd()
@@ -44,7 +44,7 @@ R = igl.eigen.MatrixXd([[1.0, 0.3, 0.3]]).replicate(K.rows(), 1)
 igl.slice_into(R, K, 1, C)
 
 # Plot the mesh with pseudocolors
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V, F)
-viewer.data.set_colors(C)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V, F)
+viewer.data().set_colors(C)
 viewer.launch()

+ 4 - 4
python/tutorial/302_Sort.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -45,7 +45,7 @@ C = igl.eigen.MatrixXd()
 igl.jet(J.castdouble(), True, C)
 
 # Plot the mesh with pseudocolors
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V, F)
-viewer.data.set_colors(C)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V, F)
+viewer.data().set_colors(C)
 viewer.launch()

+ 5 - 5
python/tutorial/303_LaplaceEquation.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 V = igl.eigen.MatrixXd()
@@ -82,8 +82,8 @@ C = igl.eigen.MatrixXd()
 igl.jet(Z, True, C)
 
 # Plot the mesh with pseudocolors
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V, F)
-viewer.core.show_lines = False
-viewer.data.set_colors(C)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V, F)
+viewer.data().show_lines = False
+viewer.data().set_colors(C)
 viewer.launch()

+ 8 - 8
python/tutorial/304_LinearEqualityConstraints.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -24,7 +24,7 @@ igl.readOFF(TUTORIAL_SHARED_PATH + "cheburashka.off", V, F)
 
 # Two fixed points
 # Left hand, left foot
-b = igl.eigen.MatrixXi([[4331], [5957]])
+b = igl.eigen.MatrixXd([[4331], [5957]]).castint()
 bc = igl.eigen.MatrixXd([[1], [-1]])
 
 # Construct Laplacian and mass matrix
@@ -82,10 +82,10 @@ igl.jet(Z, min_z, max_z, C)
 igl.jet(Z_const, min_z, max_z, C_const)
 
 # Plot the mesh with pseudocolors
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V, F)
-viewer.core.show_lines = False
-viewer.data.set_colors(C)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V, F)
+viewer.data().show_lines = False
+viewer.data().set_colors(C)
 
 
 def key_down(viewer, key, mode):
@@ -93,9 +93,9 @@ def key_down(viewer, key, mode):
         global toggle, C, C_const
 
         if toggle:
-            viewer.data.set_colors(C)
+            viewer.data().set_colors(C)
         else:
-            viewer.data.set_colors(C_const)
+            viewer.data().set_colors(C_const)
 
         toggle = not toggle
         return True

+ 6 - 6
python/tutorial/305_QuadraticProgramming.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -40,7 +40,7 @@ def solve(viewer):
 
     C = igl.eigen.MatrixXd()
     igl.jet(Z, 0, 1, C)
-    viewer.data.set_colors(C)
+    viewer.data().set_colors(C)
 
 
 def key_down(viewer, key, mod):
@@ -65,13 +65,13 @@ F = igl.eigen.MatrixXi()
 igl.readOFF(TUTORIAL_SHARED_PATH + "cheburashka.off", V, F)
 
 # Plot the mesh
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V, F)
-viewer.core.show_lines = False
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V, F)
+viewer.data().show_lines = False
 viewer.callback_key_down = key_down
 
 # One fixed point on belly
-b = igl.eigen.MatrixXi([[2556]])
+b = igl.eigen.MatrixXd([[2556]]).castint()
 bc = igl.eigen.MatrixXd([[1]])
 
 # Construct Laplacian and mass matrix

+ 6 - 6
python/tutorial/306_EigenDecomposition.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -45,7 +45,7 @@ if not igl.eigs(L, M, k + 1, igl.EIGS_TYPE_SM, U, D):
 
 U = (U - U.minCoeff()) / (U.maxCoeff() - U.minCoeff())
 
-viewer = igl.viewer.Viewer()
+viewer = igl.glfw.Viewer()
 
 
 def key_down(viewer, key, mod):
@@ -63,14 +63,14 @@ def key_down(viewer, key, mod):
         if twod:
             V.setcol(2, Z)
 
-        viewer.data.set_mesh(V, F)
-        viewer.data.compute_normals()
-        viewer.data.set_colors(C)
+        viewer.data().set_mesh(V, F)
+        viewer.data().compute_normals()
+        viewer.data().set_colors(C)
         return True
     return False
 
 
 viewer.callback_key_down = key_down
 viewer.callback_key_down(viewer, ord(' '), 0)
-viewer.core.show_lines = False
+viewer.data().show_lines = False
 viewer.launch()

+ 8 - 8
python/tutorial/401_BiharmonicDeformation.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 bc_frac = 1.0
@@ -47,8 +47,8 @@ def pre_draw(viewer):
     else:
         igl.harmonic(V, F, b, U_bc_anim, 2, U)
 
-    viewer.data.set_vertices(U)
-    viewer.data.compute_normals()
+    viewer.data().set_vertices(U)
+    viewer.data().compute_normals()
     return False
 
 
@@ -73,7 +73,7 @@ igl.readDMAT(TUTORIAL_SHARED_PATH + "decimated-max-selection.dmat", S)
 
 S = S.castint()
 
-b = igl.eigen.MatrixXi([[t[0] for t in [(i, S[i]) for i in range(0, V.rows())] if t[1] >= 0]]).transpose()
+b = igl.eigen.MatrixXd([[t[0] for t in [(i, S[i]) for i in range(0, V.rows())] if t[1] >= 0]]).transpose().castint()
 
 # Boundary conditions directly on deformed positions
 U_bc.resize(b.rows(), V.cols())
@@ -104,10 +104,10 @@ for f in range(0, F.rows()):
         C.setRow(f, gold)
 
 # Plot the mesh with pseudocolors
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(U, F)
-viewer.core.show_lines = False
-viewer.data.set_colors(C)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(U, F)
+viewer.data().show_lines = False
+viewer.data().set_colors(C)
 # viewer.core.trackball_angle = igl.eigen.Quaterniond(sqrt(2.0),0,sqrt(2.0),0)
 # viewer.core.trackball_angle.normalize()
 

+ 8 - 8
python/tutorial/402_PolyharmonicDeformation.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -41,8 +41,8 @@ def pre_draw(viewer):
         resolve = False
 
     U.setCol(2, z_max * Z)
-    viewer.data.set_vertices(U)
-    viewer.data.compute_normals()
+    viewer.data().set_vertices(U)
+    viewer.data().compute_normals()
 
     if viewer.core.is_animating:
         z_max += z_dir
@@ -77,7 +77,7 @@ is_outer = [Vrn[i] - 1.00 > -1e-15 for i in range(0, V.rows())]
 is_inner = [Vrn[i] - 0.15 < 1e-15 for i in range(0, V.rows())]
 in_b = [is_outer[i] or is_inner[i] for i in range(0, len(is_outer))]
 
-b = igl.eigen.MatrixXi([[i for i in range(0, V.rows()) if (in_b[i])]]).transpose()
+b = igl.eigen.MatrixXd([[i for i in range(0, V.rows()) if (in_b[i])]]).transpose().castint()
 
 bc.resize(b.size(), 1)
 
@@ -96,10 +96,10 @@ for f in range(0, F.rows()):
         C.setRow(f, gold)
 
 # Plot the mesh with pseudocolors
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(U, F)
-viewer.core.show_lines = False
-viewer.data.set_colors(C)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(U, F)
+viewer.data().show_lines = False
+viewer.data().set_colors(C)
 viewer.core.trackball_angle = igl.eigen.Quaterniond(0.81,-0.58,-0.03,-0.03)
 viewer.core.trackball_angle.normalize()
 viewer.callback_pre_draw = pre_draw

+ 11 - 11
python/tutorial/403_BoundedBiharmonicWeights.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies, print_usage
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -47,9 +47,9 @@ def pre_draw(viewer):
         BET = igl.eigen.MatrixXi()
         igl.deform_skeleton(C, BE, T, CT, BET)
 
-        viewer.data.set_vertices(U)
-        viewer.data.set_edges(CT, BET, sea_green)
-        viewer.data.compute_normals()
+        viewer.data().set_vertices(U)
+        viewer.data().set_edges(CT, BET, sea_green)
+        viewer.data().compute_normals()
         anim_t += anim_t_dir
         anim_t_dir *= -1.0 if (0.0 >= anim_t or anim_t >= 1.0) else 1.0
 
@@ -76,7 +76,7 @@ def set_color(viewer):
     global selected, W
     C = igl.eigen.MatrixXd()
     igl.jet(W.col(selected), True, C)
-    viewer.data.set_colors(C)
+    viewer.data().set_colors(C)
 
 
 if __name__ == "__main__":
@@ -137,13 +137,13 @@ if __name__ == "__main__":
     igl.lbs_matrix(V, W, M)
 
     # Plot the mesh with pseudocolors
-    viewer = igl.viewer.Viewer()
-    viewer.data.set_mesh(U, F)
+    viewer = igl.glfw.Viewer()
+    viewer.data().set_mesh(U, F)
     set_color(viewer)
-    viewer.data.set_edges(C, BE, sea_green)
-    viewer.core.show_lines = False
-    viewer.core.show_overlay_depth = False
-    viewer.core.line_width = 1
+    viewer.data().set_edges(C, BE, sea_green)
+    viewer.data().show_lines = False
+    viewer.data().show_overlay_depth = False
+    viewer.data().line_width = 1
     viewer.core.trackball_angle.normalize()
     viewer.callback_pre_draw = pre_draw
     viewer.callback_key_down = key_down

+ 10 - 10
python/tutorial/404_DualQuaternionSkinning.py

@@ -16,7 +16,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies, print_usage
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -57,9 +57,9 @@ def pre_draw(viewer):
         BET = igl.eigen.MatrixXi()
         igl.deform_skeleton(C, BE, T, CT, BET)
 
-        viewer.data.set_vertices(U)
-        viewer.data.set_edges(CT, BET, sea_green)
-        viewer.data.compute_normals()
+        viewer.data().set_vertices(U)
+        viewer.data().set_edges(CT, BET, sea_green)
+        viewer.data().compute_normals()
         if viewer.core.is_animating:
             anim_t += anim_t_dir
         else:
@@ -132,12 +132,12 @@ if __name__ == "__main__":
     igl.lbs_matrix(V, W, M)
 
     # Plot the mesh with pseudocolors
-    viewer = igl.viewer.Viewer()
-    viewer.data.set_mesh(U, F)
-    viewer.data.set_edges(C, BE, sea_green)
-    viewer.core.show_lines = False
-    viewer.core.show_overlay_depth = False
-    viewer.core.line_width = 1
+    viewer = igl.glfw.Viewer()
+    viewer.data().set_mesh(U, F)
+    viewer.data().set_edges(C, BE, sea_green)
+    viewer.data().show_lines = False
+    viewer.data().show_overlay_depth = False
+    viewer.data().line_width = 1
     viewer.core.trackball_angle.normalize()
     viewer.callback_pre_draw = pre_draw
     viewer.callback_key_down = key_down

+ 7 - 7
python/tutorial/405_AsRigidAsPossible.py

@@ -14,7 +14,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -55,8 +55,8 @@ def pre_draw(viewer):
             bc[i, 0] += r * sin(0.35 * anim_t * 2. * pi)
 
     igl.arap_solve(bc, arap_data, U)
-    viewer.data.set_vertices(U)
-    viewer.data.compute_normals()
+    viewer.data().set_vertices(U)
+    viewer.data().compute_normals()
 
     if viewer.core.is_animating:
         anim_t += anim_t_dir
@@ -77,7 +77,7 @@ igl.readDMAT(TUTORIAL_SHARED_PATH + "decimated-knight-selection.dmat", S)
 
 # Vertices in selection
 
-b = igl.eigen.MatrixXi([[t[0] for t in [(i, S[i]) for i in range(0, V.rows())] if t[1] >= 0]]).transpose()
+b = igl.eigen.MatrixXd([[t[0] for t in [(i, S[i]) for i in range(0, V.rows())] if t[1] >= 0]]).transpose().castint()
 
 # Centroid
 mid = 0.5 * (V.colwiseMaxCoeff() + V.colwiseMinCoeff())
@@ -98,9 +98,9 @@ for f in range(0, F.rows()):
         C.setRow(f, gold)
 
 # Plot the mesh with pseudocolors
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(U, F)
-viewer.data.set_colors(C)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(U, F)
+viewer.data().set_colors(C)
 viewer.callback_pre_draw = pre_draw
 viewer.callback_key_down = key_down
 viewer.core.is_animating = True

+ 9 - 9
python/tutorial/501_HarmonicParam.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -25,13 +25,13 @@ V_uv = igl.eigen.MatrixXd()
 def key_down(viewer, key, modifier):
     if key == ord('1'):
         # Plot the 3D mesh
-        viewer.data.set_mesh(V, F)
+        viewer.data().set_mesh(V, F)
         viewer.core.align_camera_center(V, F)
     elif key == ord('2'):
         # Plot the mesh in 2D using the UV coordinates as vertex coordinates
-        viewer.data.set_mesh(V_uv, F)
+        viewer.data().set_mesh(V_uv, F)
         viewer.core.align_camera_center(V_uv, F)
-    viewer.data.compute_normals()
+    viewer.data().compute_normals()
     return False
 
 
@@ -53,16 +53,16 @@ igl.harmonic(V, F, bnd, bnd_uv, 1, V_uv)
 V_uv *= 5
 
 # Plot the mesh
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V, F)
-viewer.data.set_uv(V_uv)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V, F)
+viewer.data().set_uv(V_uv)
 viewer.callback_key_down = key_down
 
 # Disable wireframe
-viewer.core.show_lines = False
+viewer.data().show_lines = False
 
 # Draw checkerboard texture
-viewer.core.show_texture = True
+viewer.data().show_texture = True
 
 # Launch the viewer
 viewer.launch()

+ 9 - 9
python/tutorial/502_LSCMParam.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -25,13 +25,13 @@ V_uv = igl.eigen.MatrixXd()
 def key_down(viewer, key, modifier):
     if key == ord('1'):
         # Plot the 3D mesh
-        viewer.data.set_mesh(V, F)
+        viewer.data().set_mesh(V, F)
         viewer.core.align_camera_center(V, F)
     elif key == ord('2'):
         # Plot the mesh in 2D using the UV coordinates as vertex coordinates
-        viewer.data.set_mesh(V_uv, F)
+        viewer.data().set_mesh(V_uv, F)
         viewer.core.align_camera_center(V_uv, F)
-    viewer.data.compute_normals()
+    viewer.data().compute_normals()
     return False
 
 
@@ -54,16 +54,16 @@ igl.lscm(V, F, b, bc, V_uv)
 V_uv *= 5
 
 # Plot the mesh
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V, F)
-viewer.data.set_uv(V_uv)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V, F)
+viewer.data().set_uv(V_uv)
 viewer.callback_key_down = key_down
 
 # Disable wireframe
-viewer.core.show_lines = False
+viewer.data().show_lines = False
 
 # Draw checkerboard texture
-viewer.core.show_texture = True
+viewer.data().show_texture = True
 
 # Launch the viewer
 viewer.launch()

+ 9 - 9
python/tutorial/503_ARAPParam.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
@@ -35,13 +35,13 @@ def key_down(viewer, key, modifier):
         V_uv = initial_guess
 
     if show_uv:
-        viewer.data.set_mesh(V_uv, F)
+        viewer.data().set_mesh(V_uv, F)
         viewer.core.align_camera_center(V_uv, F)
     else:
-        viewer.data.set_mesh(V, F)
+        viewer.data().set_mesh(V, F)
         viewer.core.align_camera_center(V, F)
 
-    viewer.data.compute_normals()
+    viewer.data().compute_normals()
     return False
 
 
@@ -77,16 +77,16 @@ igl.arap_solve(bc, arap_data, V_uv)
 V_uv *= 20
 
 # Plot the mesh
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V, F)
-viewer.data.set_uv(V_uv)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V, F)
+viewer.data().set_uv(V_uv)
 viewer.callback_key_down = key_down
 
 # Disable wireframe
-viewer.core.show_lines = False
+viewer.data().show_lines = False
 
 # Draw checkerboard texture
-viewer.core.show_texture = True
+viewer.data().show_texture = True
 
 # Launch the viewer
 viewer.launch()

+ 11 - 11
python/tutorial/504_NRosyDesign.py

@@ -14,7 +14,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["comiso", "viewer"]
+dependencies = ["comiso", "glfw"]
 check_dependencies(dependencies)
 
 
@@ -59,8 +59,8 @@ def representative_to_nrosy(V, F, R, N, Y):
 # The constrained faces (b) are colored in red.
 def plot_mesh_nrosy(viewer, V, F, N, PD1, S, b):
     # Clear the mesh
-    viewer.data.clear()
-    viewer.data.set_mesh(V, F)
+    viewer.data().clear()
+    viewer.data().set_mesh(V, F)
 
     # Expand the representative vectors in the full vector set and plot them as lines
     avg = igl.avg_edge_length(V, F)
@@ -75,20 +75,20 @@ def plot_mesh_nrosy(viewer, V, F, N, PD1, S, b):
         for j in range(0, N):
             Be.setRow(i * N + j, B.row(i))
 
-    viewer.data.add_edges(Be, Be + Y * (avg / 2), igl.eigen.MatrixXd([[0, 0, 1]]))
+    viewer.data().add_edges(Be, Be + Y * (avg / 2), igl.eigen.MatrixXd([[0, 0, 1]]))
 
     # Plot the singularities as colored dots (red for negative, blue for positive)
     for i in range(0, S.size()):
         if S[i] < -0.001:
-            viewer.data.add_points(V.row(i), igl.eigen.MatrixXd([[1, 0, 0]]))
+            viewer.data().add_points(V.row(i), igl.eigen.MatrixXd([[1, 0, 0]]))
         elif S[i] > 0.001:
-            viewer.data.add_points(V.row(i), igl.eigen.MatrixXd([[0, 1, 0]]));
+            viewer.data().add_points(V.row(i), igl.eigen.MatrixXd([[0, 1, 0]]));
 
     # Highlight in red the constrained faces
     C = igl.eigen.MatrixXd.Constant(F.rows(), 3, 1)
     for i in range(0, b.size()):
         C.setRow(b[i], igl.eigen.MatrixXd([[1, 0, 0]]))
-    viewer.data.set_colors(C)
+    viewer.data().set_colors(C)
 
 
 # It allows to change the degree of the field when a number is pressed
@@ -110,20 +110,20 @@ def key_down(viewer, key, modifier):
 igl.readOFF(TUTORIAL_SHARED_PATH + "bumpy.off", V, F)
 
 # Threshold faces with high anisotropy
-b = igl.eigen.MatrixXi([[0]])
+b = igl.eigen.MatrixXd([[0]]).castint()
 bc = igl.eigen.MatrixXd([[1, 1, 1]])
 
-viewer = igl.viewer.Viewer()
+viewer = igl.glfw.Viewer()
 
 # Interpolate the field and plot
 key_down(viewer, ord('4'), 0)
 
 # Plot the mesh
-viewer.data.set_mesh(V, F)
+viewer.data().set_mesh(V, F)
 viewer.callback_key_down = key_down
 
 # Disable wireframe
-viewer.core.show_lines = False
+viewer.data().show_lines = False
 
 # Launch the viewer
 viewer.launch()

+ 37 - 37
python/tutorial/505_MIQ.py

@@ -14,7 +14,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["comiso", "viewer"]
+dependencies = ["comiso", "glfw"]
 check_dependencies(dependencies)
 
 
@@ -97,37 +97,37 @@ def key_down(viewer, key, modifier):
     if key < ord('1') or key > ord('8'):
         return False
 
-    viewer.data.clear()
-    viewer.core.show_lines = False
-    viewer.core.show_texture = False
+    viewer.data().clear()
+    viewer.data().show_lines = False
+    viewer.data().show_texture = False
 
     if key == ord('1'):
         # Cross field
-        viewer.data.set_mesh(V, F)
-        viewer.data.add_edges(B - global_scale * X1 if extend_arrows else B, B + global_scale * X1,
+        viewer.data().set_mesh(V, F)
+        viewer.data().add_edges(B - global_scale * X1 if extend_arrows else B, B + global_scale * X1,
                               igl.eigen.MatrixXd([[1, 0, 0]]))
-        viewer.data.add_edges(B - global_scale * X2 if extend_arrows else B, B + global_scale * X2,
+        viewer.data().add_edges(B - global_scale * X2 if extend_arrows else B, B + global_scale * X2,
                               igl.eigen.MatrixXd([[0, 0, 1]]))
 
     if key == ord('2'):
         # Bisector field
-        viewer.data.set_mesh(V, F)
-        viewer.data.add_edges(B - global_scale * BIS1 if extend_arrows else B, B + global_scale * BIS1,
+        viewer.data().set_mesh(V, F)
+        viewer.data().add_edges(B - global_scale * BIS1 if extend_arrows else B, B + global_scale * BIS1,
                               igl.eigen.MatrixXd([[1, 0, 0]]))
-        viewer.data.add_edges(B - global_scale * BIS2 if extend_arrows else B, B + global_scale * BIS2,
+        viewer.data().add_edges(B - global_scale * BIS2 if extend_arrows else B, B + global_scale * BIS2,
                               igl.eigen.MatrixXd([[0, 0, 1]]))
 
     if key == ord('3'):
         # Bisector field combed
-        viewer.data.set_mesh(V, F)
-        viewer.data.add_edges(B - global_scale * BIS1_combed if extend_arrows else B, B + global_scale * BIS1_combed,
+        viewer.data().set_mesh(V, F)
+        viewer.data().add_edges(B - global_scale * BIS1_combed if extend_arrows else B, B + global_scale * BIS1_combed,
                               igl.eigen.MatrixXd([[1, 0, 0]]))
-        viewer.data.add_edges(B - global_scale * BIS2_combed if extend_arrows else B, B + global_scale * BIS2_combed,
+        viewer.data().add_edges(B - global_scale * BIS2_combed if extend_arrows else B, B + global_scale * BIS2_combed,
                               igl.eigen.MatrixXd([[0, 0, 1]]))
 
     if key == ord('4'):
         # Singularities and cuts
-        viewer.data.set_mesh(V, F)
+        viewer.data().set_mesh(V, F)
 
         # Plot cuts
         l_count = Seams.sum()
@@ -141,22 +141,22 @@ def key_down(viewer, key, modifier):
                     P2.setRow(l_count - 1, V.row(F[i, (j + 1) % 3]))
                     l_count -= 1
 
-        viewer.data.add_edges(P1, P2, igl.eigen.MatrixXd([[1, 0, 0]]))
+        viewer.data().add_edges(P1, P2, igl.eigen.MatrixXd([[1, 0, 0]]))
 
         # Plot the singularities as colored dots (red for negative, blue for positive)
         for i in range(0, singularityIndex.size()):
             if 2 > singularityIndex[i] > 0:
-                viewer.data.add_points(V.row(i), igl.eigen.MatrixXd([[1, 0, 0]]))
+                viewer.data().add_points(V.row(i), igl.eigen.MatrixXd([[1, 0, 0]]))
             elif singularityIndex[i] > 2:
-                viewer.data.add_points(V.row(i), igl.eigen.MatrixXd([[1, 0, 0]]))
+                viewer.data().add_points(V.row(i), igl.eigen.MatrixXd([[1, 0, 0]]))
 
     if key == ord('5'):
         # Singularities and cuts, original field
         # Singularities and cuts
-        viewer.data.set_mesh(V, F)
-        viewer.data.add_edges(B - global_scale * X1_combed if extend_arrows else B, B + global_scale * X1_combed,
+        viewer.data().set_mesh(V, F)
+        viewer.data().add_edges(B - global_scale * X1_combed if extend_arrows else B, B + global_scale * X1_combed,
                               igl.eigen.MatrixXd([[1, 0, 0]]))
-        viewer.data.add_edges(B - global_scale * X2_combed if extend_arrows else B, B + global_scale * X2_combed,
+        viewer.data().add_edges(B - global_scale * X2_combed if extend_arrows else B, B + global_scale * X2_combed,
                               igl.eigen.MatrixXd([[0, 0, 1]]))
 
         # Plot cuts
@@ -172,38 +172,38 @@ def key_down(viewer, key, modifier):
                     P2.setRow(l_count - 1, V.row(F[i, (j + 1) % 3]))
                     l_count -= 1
 
-        viewer.data.add_edges(P1, P2, igl.eigen.MatrixXd([[1, 0, 0]]))
+        viewer.data().add_edges(P1, P2, igl.eigen.MatrixXd([[1, 0, 0]]))
 
         # Plot the singularities as colored dots (red for negative, blue for positive)
         for i in range(0, singularityIndex.size()):
             if 2 > singularityIndex[i] > 0:
-                viewer.data.add_points(V.row(i), igl.eigen.MatrixXd([[1, 0, 0]]))
+                viewer.data().add_points(V.row(i), igl.eigen.MatrixXd([[1, 0, 0]]))
             elif singularityIndex[i] > 2:
-                viewer.data.add_points(V.row(i), igl.eigen.MatrixXd([[0, 1, 0]]))
+                viewer.data().add_points(V.row(i), igl.eigen.MatrixXd([[0, 1, 0]]))
 
     if key == ord('6'):
         # Global parametrization UV
-        viewer.data.set_mesh(UV, FUV)
-        viewer.data.set_uv(UV)
-        viewer.core.show_lines = True
+        viewer.data().set_mesh(UV, FUV)
+        viewer.data().set_uv(UV)
+        viewer.data().show_lines = True
 
     if key == ord('7'):
         # Global parametrization in 3D
-        viewer.data.set_mesh(V, F)
-        viewer.data.set_uv(UV, FUV)
-        viewer.core.show_texture = True
+        viewer.data().set_mesh(V, F)
+        viewer.data().set_uv(UV, FUV)
+        viewer.data().show_texture = True
 
     if key == ord('8'):
         # Global parametrization in 3D with seams
-        viewer.data.set_mesh(V, F)
-        viewer.data.set_uv(UV_seams, FUV_seams)
-        viewer.core.show_texture = True
+        viewer.data().set_mesh(V, F)
+        viewer.data().set_uv(UV_seams, FUV_seams)
+        viewer.data().show_texture = True
 
-    viewer.data.set_colors(igl.eigen.MatrixXd([[1, 1, 1]]))
+    viewer.data().set_colors(igl.eigen.MatrixXd([[1, 1, 1]]))
 
-    viewer.data.set_texture(texture_R, texture_B, texture_G)
+    viewer.data().set_texture(texture_R, texture_B, texture_G)
 
-    viewer.core.align_camera_center(viewer.data.V, viewer.data.F)
+    viewer.core.align_camera_center(viewer.data().V, viewer.data().F)
 
     return False
 
@@ -218,7 +218,7 @@ igl.barycenter(V, F, B)
 global_scale = .5 * igl.avg_edge_length(V, F)
 
 # Contrain one face
-b = igl.eigen.MatrixXi([[0]])
+b = igl.eigen.MatrixXd([[0]]).castint()
 bc = igl.eigen.MatrixXd([[1, 0, 0]])
 
 # Create a smooth 4-RoSy field
@@ -267,7 +267,7 @@ igl.comiso.miq(V, F, X1_combed, X2_combed, MMatch, isSingularity, Seams, UV_seam
                stiffness, direct_round, iterations, 5, False)
 
 # Plot the mesh
-viewer = igl.viewer.Viewer()
+viewer = igl.glfw.Viewer()
 
 # Replace the standard texture with an integer shift invariant texture
 (texture_R, texture_G, texture_B) = line_texture()

+ 16 - 16
python/tutorial/509_Planarization.py

@@ -13,11 +13,11 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 
-viewer = igl.viewer.Viewer()
+viewer = igl.glfw.Viewer()
 
 # Quad mesh generated from conjugate field
 VQC = igl.eigen.MatrixXd()
@@ -40,7 +40,7 @@ PQC3plan = igl.eigen.MatrixXd()
 def key_down(viewer, key, modifier):
     if key == ord('1'):
         # Draw the triangulated quad mesh
-        viewer.data.set_mesh(VQC, FQCtri)
+        viewer.data().set_mesh(VQC, FQCtri)
 
         # Assign a color to each quad that corresponds to its planarity
         planarity = igl.eigen.MatrixXd()
@@ -50,17 +50,17 @@ def key_down(viewer, key, modifier):
         C = igl.eigen.MatrixXd(FQCtri.rows(), 3)
         C.setTopRows(Ct.rows(), Ct)
         C.setBottomRows(Ct.rows(), Ct)
-        viewer.data.set_colors(C)
+        viewer.data().set_colors(C)
 
         # Plot a line for each edge of the quad mesh
-        viewer.data.add_edges(PQC0, PQC1, igl.eigen.MatrixXd([[0, 0, 0]]))
-        viewer.data.add_edges(PQC1, PQC2, igl.eigen.MatrixXd([[0, 0, 0]]))
-        viewer.data.add_edges(PQC2, PQC3, igl.eigen.MatrixXd([[0, 0, 0]]))
-        viewer.data.add_edges(PQC3, PQC0, igl.eigen.MatrixXd([[0, 0, 0]]))
+        viewer.data().add_edges(PQC0, PQC1, igl.eigen.MatrixXd([[0, 0, 0]]))
+        viewer.data().add_edges(PQC1, PQC2, igl.eigen.MatrixXd([[0, 0, 0]]))
+        viewer.data().add_edges(PQC2, PQC3, igl.eigen.MatrixXd([[0, 0, 0]]))
+        viewer.data().add_edges(PQC3, PQC0, igl.eigen.MatrixXd([[0, 0, 0]]))
 
     elif key == ord('2'):
         # Draw the planar quad mesh
-        viewer.data.set_mesh(VQCplan, FQCtri)
+        viewer.data().set_mesh(VQCplan, FQCtri)
 
         # Assign a color to each quad that corresponds to its planarity
         planarity = igl.eigen.MatrixXd()
@@ -70,13 +70,13 @@ def key_down(viewer, key, modifier):
         C = igl.eigen.MatrixXd(FQCtri.rows(), 3)
         C.setTopRows(Ct.rows(), Ct)
         C.setBottomRows(Ct.rows(), Ct)
-        viewer.data.set_colors(C)
+        viewer.data().set_colors(C)
 
         # Plot a line for each edge of the quad mesh
-        viewer.data.add_edges(PQC0plan, PQC1plan, igl.eigen.MatrixXd([[0, 0, 0]]))
-        viewer.data.add_edges(PQC1plan, PQC2plan, igl.eigen.MatrixXd([[0, 0, 0]]))
-        viewer.data.add_edges(PQC2plan, PQC3plan, igl.eigen.MatrixXd([[0, 0, 0]]))
-        viewer.data.add_edges(PQC3plan, PQC0plan, igl.eigen.MatrixXd([[0, 0, 0]]))
+        viewer.data().add_edges(PQC0plan, PQC1plan, igl.eigen.MatrixXd([[0, 0, 0]]))
+        viewer.data().add_edges(PQC1plan, PQC2plan, igl.eigen.MatrixXd([[0, 0, 0]]))
+        viewer.data().add_edges(PQC2plan, PQC3plan, igl.eigen.MatrixXd([[0, 0, 0]]))
+        viewer.data().add_edges(PQC3plan, PQC0plan, igl.eigen.MatrixXd([[0, 0, 0]]))
 
     else:
         return False
@@ -119,7 +119,7 @@ igl.slice(VQCplan, FQC.col(3), 1, PQC3plan)
 
 # Launch the viewer
 key_down(viewer, ord('2'), 0)
-viewer.core.invert_normals = True
-viewer.core.show_lines = False
+viewer.data().invert_normals = True
+viewer.data().show_lines = False
 viewer.callback_key_down = key_down
 viewer.launch()

+ 4 - 4
python/tutorial/604_Triangle.py

@@ -13,13 +13,13 @@ import pyigl as igl
 
 from shared import check_dependencies
 
-dependencies = ["triangle", "viewer"]
+dependencies = ["triangle", "glfw"]
 check_dependencies(dependencies)
 
 
 # Input polygon
 V = igl.eigen.MatrixXd([[-1, -1], [1, -1], [1, 1], [-1, 1], [-2, -2], [2, -2], [2, 2], [-2, 2]])
-E = igl.eigen.MatrixXi([[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6], [6,7], [7,4]])
+E = igl.eigen.MatrixXd([[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6], [6,7], [7,4]]).castint()
 H = igl.eigen.MatrixXd([[0, 0]])
 
 # Triangulated Interior
@@ -29,6 +29,6 @@ F2 = igl.eigen.MatrixXi()
 igl.triangle.triangulate(V, E, H, "a0.005q", V2, F2)
 
 # Plot the mesh
-viewer = igl.viewer.Viewer()
-viewer.data.set_mesh(V2, F2)
+viewer = igl.glfw.Viewer()
+viewer.data().set_mesh(V2, F2)
 viewer.launch()

+ 10 - 10
python/tutorial/605_Tetgen.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["tetgen", "viewer"]
+dependencies = ["tetgen", "glfw"]
 check_dependencies(dependencies)
 
 
@@ -27,7 +27,7 @@ TV = igl.eigen.MatrixXd()
 TT = igl.eigen.MatrixXi()
 TF = igl.eigen.MatrixXi()
 
-viewer = igl.viewer.Viewer()
+viewer = igl.glfw.Viewer()
 
 
 def key_down(viewer, key, modifier):
@@ -43,7 +43,7 @@ def key_down(viewer, key, modifier):
                 s.append(i)
 
         V_temp = igl.eigen.MatrixXd(len(s) * 4, 3)
-        F_temp = igl.eigen.MatrixXi(len(s) * 4, 3)
+        F_temp = igl.eigen.MatrixXd(len(s) * 4, 3).castint()
 
         for i in range(len(s)):
             V_temp.setRow(i * 4 + 0, TV.row(TT[s[i], 0]))
@@ -51,14 +51,14 @@ def key_down(viewer, key, modifier):
             V_temp.setRow(i * 4 + 2, TV.row(TT[s[i], 2]))
             V_temp.setRow(i * 4 + 3, TV.row(TT[s[i], 3]))
 
-            F_temp.setRow(i * 4 + 0, igl.eigen.MatrixXi([[(i*4)+0, (i*4)+1, (i*4)+3]]))
-            F_temp.setRow(i * 4 + 1, igl.eigen.MatrixXi([[(i*4)+0, (i*4)+2, (i*4)+1]]))
-            F_temp.setRow(i * 4 + 2, igl.eigen.MatrixXi([[(i*4)+3, (i*4)+2, (i*4)+0]]))
-            F_temp.setRow(i * 4 + 3, igl.eigen.MatrixXi([[(i*4)+1, (i*4)+2, (i*4)+3]]))
+            F_temp.setRow(i * 4 + 0, igl.eigen.MatrixXd([[(i*4)+0, (i*4)+1, (i*4)+3]]).castint())
+            F_temp.setRow(i * 4 + 1, igl.eigen.MatrixXd([[(i*4)+0, (i*4)+2, (i*4)+1]]).castint())
+            F_temp.setRow(i * 4 + 2, igl.eigen.MatrixXd([[(i*4)+3, (i*4)+2, (i*4)+0]]).castint())
+            F_temp.setRow(i * 4 + 3, igl.eigen.MatrixXd([[(i*4)+1, (i*4)+2, (i*4)+3]]).castint())
 
-        viewer.data.clear()
-        viewer.data.set_mesh(V_temp, F_temp)
-        viewer.data.set_face_based(True)
+        viewer.data().clear()
+        viewer.data().set_mesh(V_temp, F_temp)
+        viewer.data().set_face_based(True)
 
     else:
         return False

+ 6 - 6
python/tutorial/606_AmbientOcclusion.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["embree", "viewer"]
+dependencies = ["embree", "glfw"]
 check_dependencies(dependencies)
 
 
@@ -24,7 +24,7 @@ AO = igl.eigen.MatrixXd()
 N = igl.eigen.MatrixXd()
 
 
-viewer = igl.viewer.Viewer()
+viewer = igl.glfw.Viewer()
 
 
 def key_down(viewer, key, modifier):
@@ -33,13 +33,13 @@ def key_down(viewer, key, modifier):
 
     if key == ord('1'):
         # Show the mesh without the ambient occlusion factor
-        viewer.data.set_colors(color)
+        viewer.data().set_colors(color)
     elif key == ord('2'):
         # Show the mesh with the ambient occlusion factor
         C = color.replicate(V.rows(), 1)
         for i in range(C.rows()):
             C.setRow(i, C.row(i) * AO[i, 0])
-        viewer.data.set_colors(C)
+        viewer.data().set_colors(C)
     elif key == ord('.'):
         viewer.core.lighting_factor += 0.1
     elif key == ord(','):
@@ -64,9 +64,9 @@ igl.embree.ambient_occlusion(V, F, V, N, 500, AO)
 AO = 1.0 - AO
 
 # Plot the generated mesh
-viewer.data.set_mesh(V, F)
+viewer.data().set_mesh(V, F)
 key_down(viewer, ord('2'), 0)
 viewer.callback_key_down = key_down
-viewer.core.show_lines = False
+viewer.data().show_lines = False
 viewer.core.lighting_factor = 0.0
 viewer.launch()

+ 10 - 10
python/tutorial/607_ScreenCapture.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["png", "viewer"]
+dependencies = ["png", "glfw"]
 check_dependencies(dependencies)
 
 temp_png = os.path.join(os.getcwd(),"out.png")
@@ -27,7 +27,7 @@ def key_down(viewer, key, modifier):
         A = igl.eigen.MatrixXuc(1280, 800)
 
         # Draw the scene in the buffers
-        viewer.core.draw_buffer(viewer.data, viewer.opengl, False, R, G, B, A)
+        viewer.core.draw_buffer(viewer.data(), False, R, G, B, A)
 
         # Save it to a PNG
         igl.png.writePNG(R, G, B, A, temp_png)
@@ -47,18 +47,18 @@ def key_down(viewer, key, modifier):
                                 [0.5, 0.5, 0],
                                 [-0.5, 0.5, 0]])
 
-        F = igl.eigen.MatrixXi([[0, 1, 2], [2, 3, 0]])
+        F = igl.eigen.MatrixXd([[0, 1, 2], [2, 3, 0]]).castint()
 
         UV = igl.eigen.MatrixXd([[0, 0], [1, 0], [1, 1], [0, 1]])
 
-        viewer.data.clear()
-        viewer.data.set_mesh(V, F)
-        viewer.data.set_uv(UV)
+        viewer.data().clear()
+        viewer.data().set_mesh(V, F)
+        viewer.data().set_uv(UV)
         viewer.core.align_camera_center(V)
-        viewer.core.show_texture = True
+        viewer.data().show_texture = True
 
         # Use the image as a texture
-        viewer.data.set_texture(R, G, B)
+        viewer.data().set_texture(R, G, B)
 
     else:
         return False
@@ -73,13 +73,13 @@ if __name__ == "__main__":
     # Load meshes in OFF format
     igl.readOFF(TUTORIAL_SHARED_PATH + "bunny.off", V, F)
 
-    viewer = igl.viewer.Viewer()
+    viewer = igl.glfw.Viewer()
 
     print(
         "Usage: Press 1 to render the scene and save it in a png. \nPress 2 to load the saved png and use it as a texture.")
 
     viewer.callback_key_down = key_down
-    viewer.data.set_mesh(V, F)
+    viewer.data().set_mesh(V, F)
     viewer.launch()
 
     os.remove(temp_png)

+ 6 - 6
python/tutorial/609_Boolean.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["cgal", "viewer"]
+dependencies = ["cgal", "glfw"]
 check_dependencies(dependencies)
 
 boolean_type_names = {igl.MESH_BOOLEAN_TYPE_UNION: "Union", igl.MESH_BOOLEAN_TYPE_INTERSECT: "Intersect", igl.MESH_BOOLEAN_TYPE_MINUS: "Minus", igl.MESH_BOOLEAN_TYPE_XOR: "XOR", igl.MESH_BOOLEAN_TYPE_RESOLVE: "Resolve"}
@@ -34,9 +34,9 @@ def update(viewer):
         else:
             C.setRow(f, Green)
 
-    viewer.data.clear()
-    viewer.data.set_mesh(VC, FC)
-    viewer.data.set_colors(C)
+    viewer.data().clear()
+    viewer.data().set_mesh(VC, FC)
+    viewer.data().set_colors(C)
     print("Done.")
 
 
@@ -78,13 +78,13 @@ if __name__ == "__main__":
 
     boolean_type = igl.MESH_BOOLEAN_TYPE_UNION
 
-    viewer = igl.viewer.Viewer()
+    viewer = igl.glfw.Viewer()
     update(viewer)
 
     print(
         "Usage: Press '.' to switch to next boolean operation type. \nPress ',' to switch to previous boolean operation type. \nPress ']' to push near cutting plane away from camera. \nPress '[' to pull near cutting plane closer to camera. \nHint: investigate _inside_ the model to see orientation changes. \n")
 
-    viewer.core.show_lines = True
+    viewer.data().show_lines = True
     viewer.callback_key_down = key_down
     viewer.core.camera_dnear = 3.9
     viewer.launch()

+ 1 - 1
python/tutorial/702_WindingNumber.py

@@ -13,7 +13,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies, print_usage
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 

+ 1 - 1
python/tutorial/704_SignedDistance.py

@@ -14,7 +14,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 

+ 1 - 1
python/tutorial/708_Picking.py

@@ -14,7 +14,7 @@ import pyigl as igl
 
 from shared import TUTORIAL_SHARED_PATH, check_dependencies, print_usage
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 

+ 1 - 1
python/tutorial/709_VectorFieldVisualizer.py

@@ -13,7 +13,7 @@ sys.path.insert(0, os.getcwd() + "/../")
 import pyigl as igl
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
-dependencies = ["viewer"]
+dependencies = ["glfw"]
 check_dependencies(dependencies)
 
 # Input mesh

+ 0 - 534
shared/cmake/CMakeLists.txt

@@ -1,534 +0,0 @@
-cmake_minimum_required(VERSION 2.8.12)
-project(libigl)
-
-message(DEPRECATION "shared/cmake/CMakeLists.txt is deprecated. Use libigl.cmake instead.")
-
-### Available options ###
-option(LIBIGL_USE_STATIC_LIBRARY    "Use libigl as static library" OFF)
-option(LIBIGL_WITH_ANTTWEAKBAR      "Use AntTweakBar"    OFF)
-option(LIBIGL_WITH_CGAL             "Use CGAL"           OFF)
-option(LIBIGL_WITH_COMISO           "Use CoMiso"         OFF)
-option(LIBIGL_WITH_CORK             "Use Cork"           OFF)
-option(LIBIGL_WITH_EMBREE           "Use Embree"         OFF)
-option(LIBIGL_WITH_LIM              "Use LIM"            OFF)
-option(LIBIGL_WITH_MATLAB           "Use Matlab"         OFF)
-option(LIBIGL_WITH_MOSEK            "Use MOSEK"          OFF)
-option(LIBIGL_WITH_NANOGUI          "Use Nanogui menu"   OFF)
-option(LIBIGL_WITH_OPENGL           "Use OpenGL"         OFF)
-option(LIBIGL_WITH_OPENGL_GLFW      "Use GLFW"           OFF)
-option(LIBIGL_WITH_PNG              "Use PNG"            OFF)
-option(LIBIGL_WITH_TETGEN           "Use Tetgen"         OFF)
-option(LIBIGL_WITH_TRIANGLE         "Use Triangle"       OFF)
-option(LIBIGL_WITH_VIEWER           "Use OpenGL viewer"  OFF)
-option(LIBIGL_WITH_XML              "Use XML"            OFF)
-option(LIBIGL_WITH_PYTHON           "Use Python"         OFF)
-
-if(LIBIGL_WITH_VIEWER AND (NOT LIBIGL_WITH_OPENGL_GLFW OR NOT LIBIGL_WITH_OPENGL) )
-  message(FATAL_ERROR "LIBIGL_WITH_VIEWER=ON requires LIBIGL_WITH_OPENGL_GLFW=ON and LIBIGL_WITH_OPENGL=ON")
-endif()
-
-### Compilation configuration ###
-if(MSVC)
-  ### Enable parallel compilation for Visual Studio
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /bigobj")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /w") # disable all warnings (not ideal but...)
-else()
-  #### Libigl requires a modern C++ compiler that supports c++11
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w") # disable all warnings (not ideal but...)
-endif()
-set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
-
-### OpenMP ### (OpenMP is disable for now)
-#find_package(OpenMP)
-#if(OPENMP_FOUND AND NOT WIN32)
-#  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
-#  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
-#  list(APPEND LIBIGL_DEFINITIONS "${OpenMP_CXX_FLAGS}")
-#endif()
-
-
-### Compiling libraries based on chosen options ###
-set(LIBIGL_INCLUDE_DIRS "")
-set(LIBIGL_LIBRARIES "")
-set(LIBIGL_EXTRA_LIBRARIES "")
-set(LIBIGL_DEFINITIONS "")
-
-if(LIBIGL_USE_STATIC_LIBRARY)
-  list(APPEND LIBIGL_DEFINITIONS "-DIGL_STATIC_LIBRARY")
-endif()
-
-### macro definition ###
-set(LIBIGL_ROOT "${PROJECT_SOURCE_DIR}/../..")
-set(LIBIGL_SOURCE_DIR "${LIBIGL_ROOT}/include")
-set(LIBIGL_EXTERNAL "${LIBIGL_ROOT}/external")
-
-### Multiple dependencies are buried in Nanogui
-set(NANOGUI_DIR "${LIBIGL_EXTERNAL}/nanogui")
-
-### Eigen ###
-if(NOT EIGEN_INCLUDE_DIR)
-  set(EIGEN_INCLUDE_DIR "${NANOGUI_DIR}/ext/eigen")
-endif()
-list(APPEND LIBIGL_INCLUDE_DIRS "${EIGEN_INCLUDE_DIR}")
-
-macro(CompileIGL_Module module_dir )
-  string(REPLACE "/" "_" module_name "${module_dir}")
-  file(GLOB SOURCES_IGL_${module_name}
-  "${LIBIGL_SOURCE_DIR}/igl/${module_dir}/*.cpp"
-  "${LIBIGL_SOURCE_DIR}/igl/copyleft/${module_dir}/*.cpp"
-  )
-  set(module_lib_name igl_${module_name})
-  add_library(${module_lib_name} STATIC ${SOURCES_IGL_${module_name}})
-  target_include_directories(${module_lib_name} PRIVATE ${EIGEN_INCLUDE_DIR})
-  target_include_directories(${module_lib_name} PRIVATE ${LIBIGL_SOURCE_DIR})
-  target_compile_definitions(${module_lib_name} PRIVATE -DIGL_STATIC_LIBRARY)
-  list(APPEND LIBIGL_LIBRARIES "${module_lib_name}")
-endmacro()
-
-### IGL Common ###
-list(APPEND LIBIGL_INCLUDE_DIRS "${LIBIGL_SOURCE_DIR}")
-if(LIBIGL_USE_STATIC_LIBRARY)
-  file(GLOB SOURCES_IGL
-  "${LIBIGL_SOURCE_DIR}/igl/*.cpp"
-  "${LIBIGL_SOURCE_DIR}/igl/copyleft/*.cpp")
-  add_library(igl STATIC ${SOURCES_IGL})
-  target_include_directories(igl PRIVATE ${EIGEN_INCLUDE_DIR})
-  target_include_directories(igl PRIVATE ${LIBIGL_SOURCE_DIR})
-  target_compile_definitions(igl PRIVATE -DIGL_STATIC_LIBRARY)
-  list(APPEND LIBIGL_LIBRARIES "igl")
-endif()
-
-
-### Compile the AntTweakBar part ###
-if(LIBIGL_WITH_ANTTWEAKBAR)
-  set(ANTTWEAKBAR_DIR "${LIBIGL_EXTERNAL}/AntTweakBar")
-  set(ANTTWEAKBAR_INCLUDE_DIR "${ANTTWEAKBAR_DIR}/include")
-  set(ANTTWEAKBAR_C_SRC_FILES
-    "${ANTTWEAKBAR_DIR}/src/TwEventGLFW.c"
-    "${ANTTWEAKBAR_DIR}/src/TwEventGLUT.c"
-    "${ANTTWEAKBAR_DIR}/src/TwEventSDL.c"
-    "${ANTTWEAKBAR_DIR}/src/TwEventSDL12.c"
-    "${ANTTWEAKBAR_DIR}/src/TwEventSDL13.c"
-    )
-  set(ANTTWEAKBAR_CPP_SRC_FILES
-    "${ANTTWEAKBAR_DIR}/src/LoadOGL.cpp"
-    "${ANTTWEAKBAR_DIR}/src/LoadOGLCore.cpp"
-    "${ANTTWEAKBAR_DIR}/src/TwBar.cpp"
-    "${ANTTWEAKBAR_DIR}/src/TwColors.cpp"
-    "${ANTTWEAKBAR_DIR}/src/TwEventSFML.cpp"
-    "${ANTTWEAKBAR_DIR}/src/TwFonts.cpp"
-    "${ANTTWEAKBAR_DIR}/src/TwMgr.cpp"
-    "${ANTTWEAKBAR_DIR}/src/TwOpenGL.cpp"
-    "${ANTTWEAKBAR_DIR}/src/TwOpenGLCore.cpp"
-    "${ANTTWEAKBAR_DIR}/src/TwPrecomp.cpp"
-    )
-    # These are probably needed for windows/Linux, should append if
-    # windows/Linux
-    #"${ANTTWEAKBAR_DIR}/src/TwEventWin.c"
-    #"${ANTTWEAKBAR_DIR}/src/TwEventX11.c"
-    #"${ANTTWEAKBAR_DIR}/src/TwDirect3D10.cpp"
-    #"${ANTTWEAKBAR_DIR}/src/TwDirect3D11.cpp"
-    #"${ANTTWEAKBAR_DIR}/src/TwDirect3D9.cpp"
-  list(
-    APPEND
-    ANTTWEAKBAR_SRC_FILES
-    "${ANTTWEAKBAR_C_SRC_FILES}"
-    "${ANTTWEAKBAR_CPP_SRC_FILES}")
-  add_library(AntTweakBar STATIC "${ANTTWEAKBAR_SRC_FILES}")
-  target_include_directories(AntTweakBar PUBLIC "${ANTTWEAKBAR_INCLUDE_DIR}")
-  if(APPLE)
-    set_target_properties(
-      AntTweakBar
-      PROPERTIES
-      COMPILE_FLAGS
-      "-fPIC -fno-strict-aliasing -x objective-c++")
-    target_compile_definitions(
-      AntTweakBar PUBLIC _MACOSX __PLACEMENT_NEW_INLINE)
-  endif()
-  list(APPEND LIBIGL_INCLUDE_DIRS "${ANTTWEAKBAR_INCLUDE_DIR}")
-  set(LIBIGL_ANTTWEAKBAR_EXTRA_LIBRARIES "AntTweakBar")
-  list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_ANTTWEAKBAR_EXTRA_LIBRARIES})
-  if(LIBIGL_USE_STATIC_LIBRARY)
-    CompileIGL_Module("anttweakbar" "")
-    target_include_directories(igl_anttweakbar PRIVATE ${ANTTWEAKBAR_INCLUDE_DIR})
-  endif()
-endif()
-
-### Compile the cgal parts ###
-if(LIBIGL_WITH_CGAL) # to be cleaned
-  # Core is needed for
-  # `Exact_predicates_exact_constructions_kernel_with_sqrt`
-  find_package(CGAL REQUIRED COMPONENTS Core)
-  # set(Boost_USE_MULTITHREADED      ON)
-  # set(Boost_USE_STATIC_LIBS      ON)
-  #
-  # find_package(BOOST REQUIRED)
-  set(CGAL_DONT_OVERRIDE_CMAKE_FLAGS TRUE CACHE BOOL "CGAL's CMAKE Setup is super annoying ")
-  include(${CGAL_USE_FILE})
-  list(APPEND LIBIGL_INCLUDE_DIRS ${CGAL_3RD_PARTY_INCLUDE_DIRS})
-  list(APPEND LIBIGL_INCLUDE_DIRS ${CGAL_INCLUDE_DIRS})
-  list(APPEND LIBIGL_CGAL_EXTRA_LIBRARIES ${CGAL_3RD_PARTY_LIBRARIES})
-  list(APPEND LIBIGL_CGAL_EXTRA_LIBRARIES ${CGAL_LIBRARIES})
-  list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_CGAL_EXTRA_LIBRARIES})
-  if(LIBIGL_USE_STATIC_LIBRARY)
-    CompileIGL_Module("cgal")
-    target_include_directories(igl_cgal PRIVATE
-      ${CGAL_3RD_PARTY_INCLUDE_DIRS}
-      ${CGAL_INCLUDE_DIRS})
-  endif()
-endif()
-
-#Compile CoMISo
-# NOTE: this cmakefile works only with the
-# comiso available here: https://github.com/libigl/CoMISo
-if(LIBIGL_WITH_COMISO)
-  set(COMISO_DIR "${LIBIGL_EXTERNAL}/CoMISo")
-  set(COMISO_INCLUDE_DIRS
-    "${COMISO_DIR}/ext/gmm-4.2/include"
-    "${COMISO_DIR}/../")
-  list(APPEND LIBIGL_INCLUDE_DIRS ${COMISO_INCLUDE_DIRS})
-  #add_definitions(-DINCLUDE_TEMPLATES) (what need this?)
-  list(APPEND LIBIGL_DEFINITIONS "-DINCLUDE_TEMPLATES")
-  if(APPLE)
-    find_library(accelerate_library Accelerate)
-    list(APPEND LIBIGL_COMISO_EXTRA_LIBRARIES "CoMISo" ${accelerate_library})
-  elseif(UNIX)
-    find_package(BLAS REQUIRED)
-    list(APPEND LIBIGL_COMISO_EXTRA_LIBRARIES "CoMISo" ${BLAS_LIBRARIES})
-  endif(APPLE)
-  if(MSVC)
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D_SCL_SECURE_NO_DEPRECATE")
-    #link_directories("${COMISO_ROOT}/CoMISo/ext/OpenBLAS-v0.2.14-Win64-int64/lib/")
-    list(APPEND LIBIGL_COMISO_EXTRA_LIBRARIES "CoMISo" "${COMISO_DIR}/ext/OpenBLAS-v0.2.14-Win64-int64/lib/libopenblas.dll.a.lib")
-  endif()
-  list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_COMISO_EXTRA_LIBRARIES})
-  add_subdirectory("${COMISO_DIR}" "CoMISo")
-  if(MSVC)
-    # Copy the dll
-    add_custom_target(Copy-CoMISo-DLL ALL       # Adds a post-build event to MyTest
-    COMMAND ${CMAKE_COMMAND} -E copy_if_different
-        "${COMISO_DIR}/ext/OpenBLAS-v0.2.14-Win64-int64/bin/libopenblas.dll"
-        "${CMAKE_CURRENT_BINARY_DIR}/../libopenblas.dll"
-    COMMAND ${CMAKE_COMMAND} -E copy_if_different
-        "${COMISO_DIR}/ext/OpenBLAS-v0.2.14-Win64-int64/bin/libgcc_s_seh-1.dll"
-        "${CMAKE_CURRENT_BINARY_DIR}/../libgcc_s_seh-1.dll"
-    COMMAND ${CMAKE_COMMAND} -E copy_if_different
-        "${COMISO_DIR}/ext/OpenBLAS-v0.2.14-Win64-int64/bin/libgfortran-3.dll"
-        "${CMAKE_CURRENT_BINARY_DIR}/../libgfortran-3.dll"
-    COMMAND ${CMAKE_COMMAND} -E copy_if_different
-        "${COMISO_DIR}/ext/OpenBLAS-v0.2.14-Win64-int64/bin/libquadmath-0.dll"
-        "${CMAKE_CURRENT_BINARY_DIR}/../libquadmath-0.dll")
-  endif()
-  if(LIBIGL_USE_STATIC_LIBRARY)
-    CompileIGL_Module("comiso")
-    target_include_directories(igl_comiso PRIVATE ${COMISO_INCLUDE_DIRS})
-    target_compile_definitions(igl_comiso PRIVATE -DINCLUDE_TEMPLATES)
-  endif()
-endif()
-
-### Compile the cork parts ###
-if(LIBIGL_WITH_CORK)
-  set(CORK_DIR "${LIBIGL_EXTERNAL}/cork")
-  set(CORK_INCLUDE_DIR "${CORK_DIR}/src")
-  # call this "lib-cork" instead of "cork", otherwise cmake gets confused about
-  # "cork" executable
-  add_subdirectory("${CORK_DIR}" "lib-cork")
-  list(APPEND LIBIGL_INCLUDE_DIRS "${CORK_INCLUDE_DIR}")
-  list(APPEND LIBIGL_CORK_EXTRA_LIBRARIES "cork")
-  list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_CORK_EXTRA_LIBRARIES})
-  if(LIBIGL_USE_STATIC_LIBRARY)
-    CompileIGL_Module("cork")
-    target_include_directories(igl_cork PRIVATE ${CORK_INCLUDE_DIR})
-  endif()
-endif()
-
-### Compile the embree part ###
-if(LIBIGL_WITH_EMBREE)
-  set(EMBREE_DIR "${LIBIGL_EXTERNAL}/embree")
-
-  set(EMBREE_ISPC_SUPPORT OFF CACHE BOOL " " FORCE)
-  set(EMBREE_TASKING_SYSTEM "INTERNAL" CACHE BOOL " " FORCE)
-  set(EMBREE_TUTORIALS OFF CACHE BOOL " " FORCE)
-  set(EMBREE_MAX_ISA NONE CACHE STRINGS " " FORCE)
-
-  # set(ENABLE_INSTALLER OFF CACHE BOOL " " FORCE)
-  if(MSVC)
-    # set(EMBREE_STATIC_RUNTIME OFF CACHE BOOL " " FORCE)
-    set(EMBREE_STATIC_LIB OFF CACHE BOOL " " FORCE)
-  else()
-    set(EMBREE_STATIC_LIB ON CACHE BOOL " " FORCE)
-  endif()
-
-  add_subdirectory("${EMBREE_DIR}" "embree")
-  list(APPEND LIBIGL_INCLUDE_DIRS "${EMBREE_DIR}/include")
-  list(APPEND LIBIGL_EMBREE_EXTRA_LIBRARIES "embree")
-  list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_EMBREE_EXTRA_LIBRARIES})
-
-  if(NOT MSVC)
-		list(APPEND LIBIGL_DEFINITIONS "-DENABLE_STATIC_LIB")
-	endif()
-
-  if(MSVC)
-    add_custom_target(Copy-Embree-DLL ALL        # Adds a post-build event to MyTest
-        COMMAND ${CMAKE_COMMAND} -E copy_if_different  # which executes "cmake - E copy_if_different..."
-            "${CMAKE_BINARY_DIR}/libigl/embree/$<CONFIGURATION>/embree.dll"      # <--this is in-file
-          "${CMAKE_BINARY_DIR}/embree.dll")                 # <--this is out-file path	endif()
-  endif()
-
-  if(LIBIGL_USE_STATIC_LIBRARY)
-    CompileIGL_Module("embree" "")
-    target_include_directories(igl_embree PRIVATE ${EMBREE_DIR}/include)
-	if(NOT MSVC)
-		target_compile_definitions(igl_embree PRIVATE -DENABLE_STATIC_LIB)
-	endif()
-  endif()
-endif()
-
-### Compile the lim part ###
-if(LIBIGL_WITH_LIM)
-  set(LIM_DIR "${LIBIGL_EXTERNAL}/lim")
-  add_subdirectory("${LIM_DIR}" "lim")
-  list(APPEND LIBIGL_INCLUDE_DIRS ${LIM_DIR})
-  ## it depends on ligigl, so placing it here solve linking problems
-  #list(APPEND LIBIGL_LIBRARIES "lim")
-  # ^--- Alec: I don't understand this comment. Does lim need to come before
-  # libigl libraries? Why can't lim be placed where it belongs in
-  # LIBIGL_EXTRA_LIBRARIES?
-  set(LIBIGL_LIM_EXTRA_LIBRARIES "lim")
-  list(APPEND LIBIGL_EXTRA_LIBRARIES "${LIBIGL_LIM_EXTRA_LIBRARIES}")
-
-  if(LIBIGL_USE_STATIC_LIBRARY)
-    CompileIGL_Module("lim" "")
-    target_include_directories(igl_lim PRIVATE ${LIM_DIR})
-  endif()
-endif()
-
-### Compile the matlab part ###
-if(LIBIGL_WITH_MATLAB)
-  find_package(Matlab REQUIRED)
-  list(APPEND LIBIGL_INCLUDE_DIRS ${Matlab_INCLUDE_DIRS})
-  list(APPEND LIBIGL_MATLAB_EXTRA_LIBRARIES 
-    ${Matlab_MEX_LIBRARY}
-    ${Matlab_MX_LIBRARY}
-    ${Matlab_MAT_LIBRARY}
-    ${Matlab_ENG_LIBRARY}
-    )
-  list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_MATLAB_EXTRA_LIBRARIES})
-
-  if(LIBIGL_USE_STATIC_LIBRARY)
-    CompileIGL_Module("matlab" "")
-    target_include_directories(igl_matlab PRIVATE ${Matlab_INCLUDE_DIRS})
-  endif()
-endif()
-
-### Compile the mosek part ###
-if(LIBIGL_WITH_MOSEK)
-  find_package(MOSEK REQUIRED)
-  list(APPEND LIBIGL_INCLUDE_DIRS ${MOSEK_INCLUDE_DIR})
-  list(APPEND LIBIGL_MOSEK_EXTRA_LIBRARIES ${MOSEK_LIBRARIES})
-  list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_MOSEK_EXTRA_LIBRARIES})
-  if(LIBIGL_USE_STATIC_LIBRARY)
-    CompileIGL_Module("mosek" "")
-    target_include_directories(igl_mosek PRIVATE ${MOSEK_INCLUDE_DIR})
-  endif()
-else()
-  list(APPEND LIBIGL_DEFINITIONS "-DIGL_NO_MOSEK")
-endif()
-
-### Compile the opengl parts ###
-set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL " " FORCE)
-set(GLFW_BUILD_TESTS OFF CACHE BOOL " " FORCE)
-set(GLFW_BUILD_DOCS OFF CACHE BOOL " " FORCE)
-set(GLFW_BUILD_INSTALL OFF CACHE BOOL " " FORCE)
-if(LIBIGL_WITH_OPENGL)
-  find_package(OpenGL REQUIRED)
-
-  if(LIBIGL_USE_STATIC_LIBRARY)
-    CompileIGL_Module("opengl" "")
-    CompileIGL_Module("opengl2" "")
-    if(NOT APPLE)
-      target_include_directories(igl_opengl PRIVATE "${NANOGUI_DIR}/ext/glew/include")
-      target_include_directories(igl_opengl2 PRIVATE "${NANOGUI_DIR}/ext/glew/include")
-    endif()
-  endif()
-  set(LIBIGL_OPENGL_EXTRA_LIBRARIES ${OPENGL_gl_LIBRARY})
-
-  ### GLEW for linux and windows
-  if((UNIX AND NOT APPLE) OR WIN32) ### Compile glew if needed
-    set(GLEW_INSTALL OFF CACHE BOOL " " FORCE)
-    add_subdirectory("${NANOGUI_DIR}/ext/glew" "glew")
-  endif()
-  if(NOT APPLE)
-    list(APPEND LIBIGL_INCLUDE_DIRS "${NANOGUI_DIR}/ext/glew/include")
-    list(APPEND LIBIGL_OPENGL_EXTRA_LIBRARIES "glew")
-  endif()
-  list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_OPENGL_EXTRA_LIBRARIES})
-
-  list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_OPENGL_EXTRA_LIBRARIES})
-
-  if(LIBIGL_WITH_OPENGL_GLFW)
-    set(GLFW_INCLUDE_DIRS "${NANOGUI_DIR}/ext/glfw/include")
-    if(NOT APPLE)
-      list(APPEND GLFW_INCLUDE_DIRS "${NANOGUI_DIR}/ext/glew/include")
-    endif()
-
-    # Note: if add_subdirectory("${NANOGUI_DIR}" "nanogui") runs below it will
-    # add GLFW as a side-effect; in this case, CMake will complain about
-    # duplicates if we add them here.
-    if (NOT (LIBIGL_WITH_VIEWER AND LIBIGL_WITH_NANOGUI))
-        add_subdirectory("${NANOGUI_DIR}/ext/glfw" "glfw")
-    endif()
-    set(LIBIGL_OPENGL_GLFW_EXTRA_LIBRARIES "glfw" ${GLFW_LIBRARIES})
-    if(LIBIGL_USE_STATIC_LIBRARY)
-      CompileIGL_Module("opengl/glfw" "")
-      target_include_directories(igl_opengl_glfw PRIVATE ${GLFW_INCLUDE_DIRS})
-      target_include_directories(igl_opengl_glfw PRIVATE ${OPENGL_INCLUDE_DIR})
-      if(NOT APPLE)
-        target_include_directories(igl_opengl PRIVATE "${NANOGUI_DIR}/ext/glew/include")
-      endif()
-    endif()
-    list(APPEND LIBIGL_INCLUDE_DIRS ${GLFW_INCLUDE_DIRS})
-    list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_OPENGL_GLFW_EXTRA_LIBRARIES})
-
-    ### Compile the viewer ###
-    if(LIBIGL_WITH_VIEWER)
-      if(LIBIGL_WITH_NANOGUI)
-        list(APPEND LIBIGL_DEFINITIONS "-DIGL_VIEWER_WITH_NANOGUI")
-        if (LIBIGL_WITH_PYTHON)
-          set(NANOGUI_BUILD_PYTHON ON CACHE BOOL " " FORCE)
-        else()
-          set(NANOGUI_BUILD_PYTHON OFF CACHE BOOL " " FORCE)
-        endif()
-        set(NANOGUI_BUILD_EXAMPLE OFF CACHE BOOL " " FORCE)
-        set(NANOGUI_BUILD_SHARED  OFF CACHE BOOL " " FORCE)
-        add_subdirectory("${NANOGUI_DIR}" "nanogui")
-        set(VIEWER_INCLUDE_DIRS
-          "${NANOGUI_DIR}/include"
-          "${NANOGUI_DIR}/ext/nanovg/src")
-        set(LIBIGL_VIEWER_EXTRA_LIBRARIES "nanogui" ${NANOGUI_EXTRA_LIBS})
-      else()
-        set(VIEWER_INCLUDE_DIRS "${NANOGUI_DIR}/ext/glfw/include")
-      endif()
-      list(APPEND VIEWER_INCLUDE_DIRS ${GLFW_INCLUDE_DIRS})
-      list(APPEND LIBIGL_INCLUDE_DIRS ${VIEWER_INCLUDE_DIRS})
-      list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_VIEWER_EXTRA_LIBRARIES})
-      if(LIBIGL_USE_STATIC_LIBRARY)
-        CompileIGL_Module("viewer" "")
-        if(LIBIGL_WITH_NANOGUI)
-          target_compile_definitions(igl_viewer PRIVATE -DIGL_VIEWER_WITH_NANOGUI)
-        endif()
-        target_include_directories(igl_viewer PRIVATE ${VIEWER_INCLUDE_DIRS})
-        if(NOT APPLE)
-          target_include_directories(igl_viewer PRIVATE "${NANOGUI_DIR}/ext/glew/include")
-        endif()
-      endif()
-    endif()
-  endif()
-
-endif()
-
-### Compile the png parts ###
-if(LIBIGL_WITH_PNG)
-  if(LIBIGL_WITH_NANOGUI)
-    set(STBI_LOAD OFF CACHE BOOL " " FORCE)
-  endif()
-  set(STB_IMAGE_DIR "${LIBIGL_EXTERNAL}/stb_image")
-  add_subdirectory("${STB_IMAGE_DIR}" "stb_image")
-  list(APPEND LIBIGL_INCLUDE_DIRS ${STB_IMAGE_DIR})
-  list(APPEND LIBIGL_PNG_EXTRA_LIBRARIES "igl_stb_image")
-  list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_PNG_EXTRA_LIBRARIES})
-  if(LIBIGL_USE_STATIC_LIBRARY)
-    CompileIGL_Module("png" "")
-    target_link_libraries(igl_png PRIVATE igl_stb_image)
-    target_include_directories(igl_png PRIVATE ${STB_IMAGE_DIR})
-    if(NOT APPLE)
-      target_include_directories(igl_png PRIVATE "${NANOGUI_DIR}/ext/glew/include")
-    endif()
-  endif()
-endif()
-
-### Compile the tetgen part ###
-if(LIBIGL_WITH_TETGEN)
-  set(TETGEN_DIR "${LIBIGL_EXTERNAL}/tetgen")
-  add_subdirectory("${TETGEN_DIR}" "tetgen")
-  list(APPEND LIBIGL_INCLUDE_DIRS ${TETGEN_DIR})
-  list(APPEND LIBIGL_TETGEN_EXTRA_LIBRARIES "tetgen")
-  list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_TETGEN_EXTRA_LIBRARIES})
-
-  if(LIBIGL_USE_STATIC_LIBRARY)
-    CompileIGL_Module("tetgen")
-    target_include_directories(igl_tetgen PRIVATE ${TETGEN_DIR})
-  endif()
-endif()
-
-### Compile the triangle part ###
-if(LIBIGL_WITH_TRIANGLE)
-  set(TRIANGLE_DIR "${LIBIGL_EXTERNAL}/triangle")
-  add_subdirectory("${TRIANGLE_DIR}" "triangle")
-  list(APPEND LIBIGL_INCLUDE_DIRS ${TRIANGLE_DIR})
-  list(APPEND LIBIGL_TRIANGLE_EXTRA_LIBRARIES "triangle")
-  list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_TRIANGLE_EXTRA_LIBRARIES})
-
-  if(LIBIGL_USE_STATIC_LIBRARY)
-    CompileIGL_Module("triangle" "")
-    target_include_directories(igl_triangle PRIVATE ${TRIANGLE_DIR})
-  endif()
-endif()
-
-### Compile the xml part ###
-if(LIBIGL_WITH_XML)
-  set(TINYXML2_DIR "${LIBIGL_EXTERNAL}/tinyxml2")
-  add_library(tinyxml2 STATIC ${TINYXML2_DIR}/tinyxml2.cpp ${TINYXML2_DIR}/tinyxml2.h)
-  set_target_properties(tinyxml2 PROPERTIES
-          COMPILE_DEFINITIONS "TINYXML2_EXPORT"
-          VERSION "3.0.0"
-          SOVERSION "3")
-  list(APPEND LIBIGL_INCLUDE_DIRS ${TINYXML2_DIR})
-  list(APPEND LIBIGL_XML_EXTRA_LIBRARIES "tinyxml2")
-  list(APPEND LIBIGL_EXTRA_LIBRARIES ${LIBIGL_XML_EXTRA_LIBRARIES})
-  if(LIBIGL_USE_STATIC_LIBRARY)
-    CompileIGL_Module("xml" "")
-    target_include_directories(igl_xml PRIVATE ${TINYXML2_DIR})
-  endif()
-endif()
-
-# Function to print list nicely
-function(print_list title list)
-  message("-- ${title}:")
-  foreach(elt ${list})
-    message("\t ${elt}")
-  endforeach()
-endfunction()
-
-# Pass the list of compiled libraries to the parent if there is one
-if(NOT ${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME})
-  list(REVERSE LIBIGL_LIBRARIES)
-
-  set(LIBIGL_INCLUDE_DIRS ${LIBIGL_INCLUDE_DIRS} PARENT_SCOPE)
-  set(LIBIGL_LIBRARIES ${LIBIGL_LIBRARIES} PARENT_SCOPE)
-  set(LIBIGL_ANTTWEAKBAR_EXTRA_LIBRARIES ${LIBIGL_ANTTWEAKBAR_EXTRA_LIBRARIES} PARENT_SCOPE)
-  set(LIBIGL_CGAL_EXTRA_LIBRARIES        ${LIBIGL_CGAL_EXTRA_LIBRARIES}        PARENT_SCOPE)
-  set(LIBIGL_COMISO_EXTRA_LIBRARIES      ${LIBIGL_COMISO_EXTRA_LIBRARIES}      PARENT_SCOPE)
-  set(LIBIGL_CORK_EXTRA_LIBRARIES        ${LIBIGL_CORK_EXTRA_LIBRARIES}        PARENT_SCOPE)
-  set(LIBIGL_EMBREE_EXTRA_LIBRARIES      ${LIBIGL_EMBREE_EXTRA_LIBRARIES}      PARENT_SCOPE)
-  set(LIBIGL_LIM_EXTRA_LIBRARIES         ${LIBIGL_LIM_EXTRA_LIBRARIES}         PARENT_SCOPE)
-  set(LIBIGL_MATLAB_EXTRA_LIBRARIES      ${LIBIGL_MATLAB_EXTRA_LIBRARIES}      PARENT_SCOPE)
-  set(LIBIGL_MOSEK_EXTRA_LIBRARIES       ${LIBIGL_MOSEK_EXTRA_LIBRARIES}       PARENT_SCOPE)
-  set(LIBIGL_NANOGUI_EXTRA_LIBRARIES     ${LIBIGL_NANOGUI_EXTRA_LIBRARIES}     PARENT_SCOPE)
-  set(LIBIGL_OPENGL_EXTRA_LIBRARIES      ${LIBIGL_OPENGL_EXTRA_LIBRARIES}     PARENT_SCOPE)
-  set(LIBIGL_OPENGL_GLFW_EXTRA_LIBRARIES ${LIBIGL_OPENGL_GLFW_EXTRA_LIBRARIES} PARENT_SCOPE)
-  set(LIBIGL_PNG_EXTRA_LIBRARIES         ${LIBIGL_PNG_EXTRA_LIBRARIES}         PARENT_SCOPE)
-  set(LIBIGL_TETGEN_EXTRA_LIBRARIES      ${LIBIGL_TETGEN_EXTRA_LIBRARIES}      PARENT_SCOPE)
-  set(LIBIGL_TRIANGLE_EXTRA_LIBRARIES    ${LIBIGL_TRIANGLE_EXTRA_LIBRARIES}    PARENT_SCOPE)
-  set(LIBIGL_VIEWER_EXTRA_LIBRARIES      ${LIBIGL_VIEWER_EXTRA_LIBRARIES}      PARENT_SCOPE)
-  set(LIBIGL_XML_EXTRA_LIBRARIES         ${LIBIGL_XML_EXTRA_LIBRARIES}         PARENT_SCOPE)
-  set(LIBIGL_EXTRA_LIBRARIES ${LIBIGL_EXTRA_LIBRARIES} PARENT_SCOPE)
-  set(LIBIGL_DEFINITIONS ${LIBIGL_DEFINITIONS} PARENT_SCOPE)
-
-  ### ligIGL information ###
-  print_list("libigl includes" "${LIBIGL_INCLUDE_DIRS}")
-  print_list("libigl libraries" "${LIBIGL_LIBRARIES}")
-  print_list("libigl extra libraries" "${LIBIGL_EXTRA_LIBRARIES}")
-  print_list("libigl definitions" "${LIBIGL_DEFINITIONS}")
-endif()

+ 32 - 44
shared/cmake/libigl.cmake

@@ -43,9 +43,6 @@ set(LIBIGL_ROOT "${CMAKE_CURRENT_LIST_DIR}/../..")
 set(LIBIGL_SOURCE_DIR "${LIBIGL_ROOT}/include")
 set(LIBIGL_EXTERNAL "${LIBIGL_ROOT}/external")
 
-### Multiple dependencies are buried in Nanogui
-set(NANOGUI_DIR "${LIBIGL_EXTERNAL}/nanogui")
-
 # Dependencies are linked as INTERFACE targets unless libigl is compiled as a static library
 if(LIBIGL_USE_STATIC_LIBRARY)
   set(IGL_SCOPE PUBLIC)
@@ -86,7 +83,7 @@ if(TARGET Eigen3::Eigen)
   # If an imported target already exists, use it
   target_link_libraries(igl_common INTERFACE Eigen3::Eigen)
 else()
-  target_include_directories(igl_common SYSTEM INTERFACE ${NANOGUI_DIR}/ext/eigen)
+  target_include_directories(igl_common SYSTEM INTERFACE ${LIBIGL_EXTERNAL}/eigen)
 endif()
 
 # C++11 Thread library
@@ -99,7 +96,7 @@ function(compile_igl_module module_dir)
   string(REPLACE "/" "_" module_name "${module_dir}")
   if(LIBIGL_USE_STATIC_LIBRARY)
     file(GLOB SOURCES_IGL_${module_name}
-      "${LIBIGL_SOURCE_DIR}/igl/${module_dir}/*.cpp" 
+      "${LIBIGL_SOURCE_DIR}/igl/${module_dir}/*.cpp"
       "${LIBIGL_SOURCE_DIR}/igl/copyleft/${module_dir}/*.cpp")
     add_library(igl_${module_name} STATIC ${SOURCES_IGL_${module_name}} ${ARGN})
     if(MSVC)
@@ -277,68 +274,59 @@ endif()
 ### Compile the opengl parts ###
 
 if(LIBIGL_WITH_OPENGL)
-  # OpenGL modules
+  # OpenGL module
   find_package(OpenGL REQUIRED)
   compile_igl_module("opengl")
-  compile_igl_module("opengl2")
   target_link_libraries(igl_opengl ${IGL_SCOPE} ${OPENGL_gl_LIBRARY})
-  target_link_libraries(igl_opengl2 ${IGL_SCOPE} ${OPENGL_gl_LIBRARY})
   target_include_directories(igl_opengl SYSTEM ${IGL_SCOPE} ${OPENGL_INCLUDE_DIR})
-  target_include_directories(igl_opengl2 SYSTEM ${IGL_SCOPE} ${OPENGL_INCLUDE_DIR})
 
-  # GLEW for linux and windows
-  if(NOT TARGET glew)
-    add_library(glew STATIC ${NANOGUI_DIR}/ext/glew/src/glew.c)
-    target_include_directories(glew SYSTEM PUBLIC ${NANOGUI_DIR}/ext/glew/include)
-    target_compile_definitions(glew PUBLIC -DGLEW_BUILD -DGLEW_NO_GLU)
+  # glad module
+  if(NOT TARGET glad)
+    add_subdirectory(${LIBIGL_EXTERNAL}/glad glad)
   endif()
-  target_link_libraries(igl_opengl ${IGL_SCOPE} glew)
-  target_link_libraries(igl_opengl2 ${IGL_SCOPE} glew)
+  target_link_libraries(igl_opengl ${IGL_SCOPE} glad)
+endif()
 
-  # Nanogui
-  if(LIBIGL_WITH_NANOGUI)
-    if(LIBIGL_WITH_PYTHON)
-      set(NANOGUI_BUILD_PYTHON ON CACHE BOOL " " FORCE)
-    else()
-      set(NANOGUI_BUILD_PYTHON OFF CACHE BOOL " " FORCE)
-    endif()
-    set(NANOGUI_BUILD_EXAMPLE OFF CACHE BOOL " " FORCE)
-    set(NANOGUI_BUILD_SHARED  OFF CACHE BOOL " " FORCE)
-    add_subdirectory(${NANOGUI_DIR} nanogui)
-    target_include_directories(nanogui PUBLIC
-      "${NANOGUI_DIR}/include"
-      "${NANOGUI_DIR}/ext/nanovg/src")
-  endif()
+################################################################################
+### Compile the GLFW part ###
 
-  # GLFW module
-  if(LIBIGL_WITH_OPENGL_GLFW)
+if(LIBIGL_WITH_OPENGL_GLFW)
+  if(TARGET igl::opengl)
+    # GLFW module
     compile_igl_module("opengl/glfw")
     if(NOT TARGET glfw)
       set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL " " FORCE)
       set(GLFW_BUILD_TESTS OFF CACHE BOOL " " FORCE)
       set(GLFW_BUILD_DOCS OFF CACHE BOOL " " FORCE)
       set(GLFW_INSTALL OFF CACHE BOOL " " FORCE)
-      add_subdirectory(${NANOGUI_DIR}/ext/glfw glfw)
+      add_subdirectory(${LIBIGL_EXTERNAL}/glfw glfw)
     endif()
-    target_include_directories(glfw ${IGL_SCOPE} ${NANOGUI_DIR}/ext/glfw/include)
     target_link_libraries(igl_opengl_glfw ${IGL_SCOPE} igl_opengl glfw)
+  else()
+    message(WARNING "GLFW module could not be compiled")
+    set(LIBIGL_WITH_OPENGL_GLFW OFF CACHE BOOL "" FORCE)
   endif()
+endif()
 
-  # Viewer module
-  if(LIBIGL_WITH_VIEWER)
-    compile_igl_module("viewer")
-    target_link_libraries(igl_viewer ${IGL_SCOPE} glfw glew ${OPENGL_gl_LIBRARY})
-    target_include_directories(igl_viewer SYSTEM ${IGL_SCOPE} ${OPENGL_INCLUDE_DIR})
-    if(TARGET nanogui)
-      target_link_libraries(igl_viewer ${IGL_SCOPE} nanogui)
-      target_compile_definitions(igl_viewer ${IGL_SCOPE} -DIGL_VIEWER_WITH_NANOGUI)
+################################################################################
+### Compile the ImGui part ###
+
+if(LIBIGL_WITH_OPENGL_GLFW_IMGUI)
+  if(TARGET igl::opengl_glfw)
+    # ImGui module
+    compile_igl_module("opengl/glfw/imgui")
+    if(NOT TARGET imgui)
+      add_subdirectory(${LIBIGL_EXTERNAL}/imgui imgui)
     endif()
+    target_link_libraries(igl_opengl_glfw_imgui ${IGL_SCOPE} igl_opengl_glfw imgui)
+  else()
+    message(WARNING "ImGui module could not be compiled")
+    set(LIBIGL_WITH_OPENGL_GLFW_IMGUI OFF CACHE BOOL "" FORCE)
   endif()
-
 endif()
 
 ################################################################################
-### Compile the png parts ###
+### Compile the png part ###
 if(LIBIGL_WITH_PNG)
   # png/ module is anomalous because it also depends on opengl it really should
   # be moved into the opengl/ directory and namespace ...

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

@@ -2,4 +2,4 @@ cmake_minimum_required(VERSION 2.8.12)
 project(102_DrawMesh)
 
 add_executable(${PROJECT_NAME}_bin main.cpp)
-target_link_libraries(${PROJECT_NAME}_bin igl::core igl::viewer tutorials)
+target_link_libraries(${PROJECT_NAME}_bin igl::core igl::opengl igl::opengl_glfw tutorials)

+ 3 - 3
tutorial/102_DrawMesh/main.cpp

@@ -1,5 +1,5 @@
 #include <igl/readOFF.h>
-#include <igl/viewer/Viewer.h>
+#include <igl/opengl/glfw/Viewer.h>
 #include "tutorial_shared_path.h"
 
 Eigen::MatrixXd V;
@@ -11,7 +11,7 @@ int main(int argc, char *argv[])
   igl::readOFF(TUTORIAL_SHARED_PATH "/bunny.off", V, F);
 
   // Plot the mesh
-  igl::viewer::Viewer viewer;
-  viewer.data.set_mesh(V, F);
+  igl::opengl::glfw::Viewer viewer;
+  viewer.data().set_mesh(V, F);
   viewer.launch();
 }

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

@@ -2,4 +2,4 @@ cmake_minimum_required(VERSION 2.8.12)
 project(103_Events)
 
 add_executable(${PROJECT_NAME}_bin main.cpp)
-target_link_libraries(${PROJECT_NAME}_bin igl::core igl::viewer tutorials)
+target_link_libraries(${PROJECT_NAME}_bin igl::core igl::opengl igl::opengl_glfw tutorials)

+ 8 - 8
tutorial/103_Events/main.cpp

@@ -1,5 +1,5 @@
 #include <igl/readOFF.h>
-#include <igl/viewer/Viewer.h>
+#include <igl/opengl/glfw/Viewer.h>
 #include <iostream>
 #include "tutorial_shared_path.h"
 
@@ -7,23 +7,23 @@ Eigen::MatrixXd V1,V2;
 Eigen::MatrixXi F1,F2;
 
 // This function is called every time a keyboard button is pressed
-bool key_down(igl::viewer::Viewer& viewer, unsigned char key, int modifier)
+bool key_down(igl::opengl::glfw::Viewer& viewer, unsigned char key, int modifier)
 {
   std::cout<<"Key: "<<key<<" "<<(unsigned int)key<<std::endl;
   if (key == '1')
   {
     // Clear should be called before drawing the mesh
-    viewer.data.clear();
+    viewer.data().clear();
     // Draw_mesh creates or updates the vertices and faces of the displayed mesh.
     // If a mesh is already displayed, draw_mesh returns an error if the given V and
     // F have size different than the current ones
-    viewer.data.set_mesh(V1, F1);
+    viewer.data().set_mesh(V1, F1);
     viewer.core.align_camera_center(V1,F1);
   }
   else if (key == '2')
   {
-    viewer.data.clear();
-    viewer.data.set_mesh(V2, F2);
+    viewer.data().clear();
+    viewer.data().set_mesh(V2, F2);
     viewer.core.align_camera_center(V2,F2);
   }
 
@@ -41,10 +41,10 @@ int main(int argc, char *argv[])
 2 Switch to fertility mesh
     )";
 
-  igl::viewer::Viewer viewer;
+  igl::opengl::glfw::Viewer viewer;
   // Register a keyboard callback that allows to switch between
   // the two loaded meshes
   viewer.callback_key_down = &key_down;
-  viewer.data.set_mesh(V1, F1);
+  viewer.data().set_mesh(V1, F1);
   viewer.launch();
 }

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

@@ -2,4 +2,4 @@ cmake_minimum_required(VERSION 2.8.12)
 project(104_Colors)
 
 add_executable(${PROJECT_NAME}_bin main.cpp)
-target_link_libraries(${PROJECT_NAME}_bin igl::core igl::viewer tutorials)
+target_link_libraries(${PROJECT_NAME}_bin igl::core igl::opengl igl::opengl_glfw tutorials)

+ 4 - 4
tutorial/104_Colors/main.cpp

@@ -1,5 +1,5 @@
 #include <igl/readOFF.h>
-#include <igl/viewer/Viewer.h>
+#include <igl/opengl/glfw/Viewer.h>
 #include <igl/jet.h>
 #include "tutorial_shared_path.h"
 
@@ -13,8 +13,8 @@ int main(int argc, char *argv[])
   igl::readOFF(TUTORIAL_SHARED_PATH "/screwdriver.off", V, F);
 
   // Plot the mesh
-  igl::viewer::Viewer viewer;
-  viewer.data.set_mesh(V, F);
+  igl::opengl::glfw::Viewer viewer;
+  viewer.data().set_mesh(V, F);
 
   // Use the z coordinate as a scalar field over the surface
   Eigen::VectorXd Z = V.col(2);
@@ -23,7 +23,7 @@ int main(int argc, char *argv[])
   igl::jet(Z,true,C);
 
   // Add per-vertex colors
-  viewer.data.set_colors(C);
+  viewer.data().set_colors(C);
 
   // Launch the viewer
   viewer.launch();

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

@@ -2,4 +2,4 @@ cmake_minimum_required(VERSION 2.8.12)
 project(105_Overlays)
 
 add_executable(${PROJECT_NAME}_bin main.cpp)
-target_link_libraries(${PROJECT_NAME}_bin igl::core igl::viewer tutorials)
+target_link_libraries(${PROJECT_NAME}_bin igl::core igl::opengl igl::opengl_glfw tutorials)

+ 7 - 7
tutorial/105_Overlays/main.cpp

@@ -1,5 +1,5 @@
 #include <igl/readOFF.h>
-#include <igl/viewer/Viewer.h>
+#include <igl/opengl/glfw/Viewer.h>
 #include <sstream>
 #include "tutorial_shared_path.h"
 
@@ -44,15 +44,15 @@ int main(int argc, char *argv[])
   7 ,3;
 
   // Plot the mesh
-  igl::viewer::Viewer viewer;
-  viewer.data.set_mesh(V, F);
+  igl::opengl::glfw::Viewer viewer;
+  viewer.data().set_mesh(V, F);
 
   // Plot the corners of the bounding box as points
-  viewer.data.add_points(V_box,Eigen::RowVector3d(1,0,0));
+  viewer.data().add_points(V_box,Eigen::RowVector3d(1,0,0));
 
   // Plot the edges of the bounding box
   for (unsigned i=0;i<E_box.rows(); ++i)
-    viewer.data.add_edges
+    viewer.data().add_edges
     (
       V_box.row(E_box(i,0)),
       V_box.row(E_box(i,1)),
@@ -62,10 +62,10 @@ int main(int argc, char *argv[])
   // Plot labels with the coordinates of bounding box vertices
   std::stringstream l1;
   l1 << m(0) << ", " << m(1) << ", " << m(2);
-  viewer.data.add_label(m,l1.str());
+  viewer.data().add_label(m,l1.str());
   std::stringstream l2;
   l2 << M(0) << ", " << M(1) << ", " << M(2);
-  viewer.data.add_label(M,l2.str());
+  viewer.data().add_label(M,l2.str());
 
   // Launch the viewer
   viewer.launch();

+ 1 - 1
tutorial/106_ViewerMenu/CMakeLists.txt

@@ -2,4 +2,4 @@ cmake_minimum_required(VERSION 2.8.12)
 project(106_ViewerMenu)
 
 add_executable(${PROJECT_NAME}_bin main.cpp)
-target_link_libraries(${PROJECT_NAME}_bin igl::core igl::viewer tutorials)
+target_link_libraries(${PROJECT_NAME}_bin igl::core igl::opengl igl::opengl_glfw igl::opengl_glfw_imgui tutorials)

+ 82 - 49
tutorial/106_ViewerMenu/main.cpp

@@ -1,71 +1,104 @@
-#ifndef IGL_VIEWER_WITH_NANOGUI
-#include <iostream>
-int main()
-{
-  std::cerr<<
-    "Error: recompile with LIBIGL_VIEWER_WITH_NANOGUI defined."<<std::endl;
-  return EXIT_FAILURE;
-}
-#else
-
 #include <igl/readOFF.h>
-#include <igl/viewer/Viewer.h>
-#include <nanogui/formhelper.h>
-#include <nanogui/screen.h>
+#include <igl/opengl/glfw/Viewer.h>
+#include <igl/opengl/glfw/imgui/ImGuiMenu.h>
+#include <igl/opengl/glfw/imgui/ImGuiHelpers.h>
+#include <imgui/imgui.h>
 #include <iostream>
 #include "tutorial_shared_path.h"
 
-int main(int argc, char *argv[])
+class CustomMenu : public igl::opengl::glfw::imgui::ImGuiMenu
 {
-  Eigen::MatrixXd V;
-  Eigen::MatrixXi F;
+  float floatVariable = 0.1f; // Shared between two menus
 
-  bool boolVariable = true;
-  float floatVariable = 0.1f;
-  enum Orientation { Up=0,Down,Left,Right } dir = Up;
+  virtual void draw_viewer_menu() override
+  {
+    // Draw parent menu
+    ImGuiMenu::draw_viewer_menu();
 
-  // Load a mesh in OFF format
-  igl::readOFF(TUTORIAL_SHARED_PATH "/bunny.off", V, F);
+    // Add new group
+    if (ImGui::CollapsingHeader("New Group", ImGuiTreeNodeFlags_DefaultOpen))
+    {
+      // Expose variable directly ...
+      ImGui::InputFloat("float", &floatVariable, 0, 0, 3);
 
-  // Init the viewer
-  igl::viewer::Viewer viewer;
+      // ... or using a custom callback
+      static bool boolVariable = true;
+      if (ImGui::Checkbox("bool", &boolVariable))
+      {
+        // do something
+        std::cout << "boolVariable: " << std::boolalpha << boolVariable << std::endl;
+      }
+
+      // Expose an enumeration type
+      enum Orientation { Up=0, Down, Left, Right };
+      static Orientation dir = Up;
+      ImGui::Combo("Direction", (int *)(&dir), "Up\0Down\0Left\0Right\0\0");
 
-  // Extend viewer menu
-  viewer.callback_init = [&](igl::viewer::Viewer& viewer)
+      // We can also use a std::vector<std::string> defined dynamically
+      static int num_choices = 3;
+      static std::vector<std::string> choices;
+      static int idx_choice = 0;
+      if (ImGui::InputInt("Num letters", &num_choices))
+      {
+        num_choices = std::max(1, std::min(26, num_choices));
+      }
+      if (num_choices != (int) choices.size())
+      {
+        choices.resize(num_choices);
+        for (int i = 0; i < num_choices; ++i)
+          choices[i] = std::string(1, 'A' + i);
+        if (idx_choice >= num_choices)
+          idx_choice = num_choices - 1;
+      }
+      ImGui::Combo("Letter", &idx_choice, choices);
+
+      // Add a button
+      if (ImGui::Button("Print Hello", ImVec2(-1,0)))
+      {
+        std::cout << "Hello\n";
+      }
+    }
+  }
+
+  virtual void draw_custom_window() override
   {
-    // Add new group
-    viewer.ngui->addGroup("New Group");
+    // Define next window position + size
+    ImGui::SetNextWindowPos(ImVec2(180.f * menu_scaling(), 10), ImGuiSetCond_FirstUseEver);
+    ImGui::SetNextWindowSize(ImVec2(200, 160), ImGuiSetCond_FirstUseEver);
+    ImGui::Begin(
+        "New Window", nullptr,
+        ImGuiWindowFlags_NoSavedSettings
+    );
 
-    // Expose variable directly ...
-    viewer.ngui->addVariable("float",floatVariable);
+    // Expose the same variable directly ...
+    ImGui::PushItemWidth(-80);
+    ImGui::DragFloat("float", &floatVariable, 0.0, 0.0, 3.0);
+    ImGui::PopItemWidth();
 
-    // ... or using a custom callback
-    viewer.ngui->addVariable<bool>("bool",[&](bool val) {
-      boolVariable = val; // set
-    },[&]() {
-      return boolVariable; // get
-    });
+    static std::string str = "bunny";
+    ImGui::InputText("Name", str);
 
-    // Expose an enumaration type
-    viewer.ngui->addVariable<Orientation>("Direction",dir)->setItems({"Up","Down","Left","Right"});
+    ImGui::End();
+  }
 
-    // Add a button
-    viewer.ngui->addButton("Print Hello",[](){ std::cout << "Hello\n"; });
+};
 
-    // Add an additional menu window
-    viewer.ngui->addWindow(Eigen::Vector2i(220,10),"New Window");
+int main(int argc, char *argv[])
+{
+  Eigen::MatrixXd V;
+  Eigen::MatrixXi F;
 
-    // Expose the same variable directly ...
-    viewer.ngui->addVariable("float",floatVariable);
+  // Load a mesh in OFF format
+  igl::readOFF(TUTORIAL_SHARED_PATH "/bunny.off", V, F);
 
-    // Generate menu
-    viewer.screen->performLayout();
+  // Init the viewer
+  igl::opengl::glfw::Viewer viewer;
 
-    return false;
-  };
+  // Attach a custom menu
+  CustomMenu menu;
+  viewer.plugins.push_back(&menu);
 
   // Plot the mesh
-  viewer.data.set_mesh(V, F);
+  viewer.data().set_mesh(V, F);
   viewer.launch();
 }
-#endif

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