Prechádzať zdrojové kódy

- Viewer: moved all the drawing helpers functions in a generic ViewerData class

Former-commit-id: 6b3970f9abce042fbae5acea1eb845ae52eede20
Daniele Panozzo 11 rokov pred
rodič
commit
75b9f9047f

+ 40 - 40
include/igl/viewer/OpenGL_state.cpp

@@ -28,7 +28,7 @@ IGL_INLINE void igl::OpenGL_state::init_buffers()
   glGenBuffers(1, &vbo_points_V);
   glGenBuffers(1, &vbo_points_V_colors);
 
-  dirty = DIRTY_ALL;
+  dirty = ViewerData::DIRTY_ALL;
 }
 
 IGL_INLINE void igl::OpenGL_state::free_buffers()
@@ -54,23 +54,23 @@ IGL_INLINE void igl::OpenGL_state::free_buffers()
   glDeleteTextures(1, &vbo_tex);
 }
 
-IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool face_based, bool invert_normals)
+IGL_INLINE void igl::OpenGL_state::set_data(const igl::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 (!face_based)
+  if (!data.face_based)
   {
     if (!per_corner_uv)
     {
       // Vertex positions
-      if (dirty & DIRTY_POSITION)
+      if (dirty & ViewerData::DIRTY_POSITION)
         V_vbo = (data.V.transpose()).cast<float>();
 
       // Vertex normals
-      if (dirty & DIRTY_NORMAL)
+      if (dirty & ViewerData::DIRTY_NORMAL)
       {
         V_normals_vbo = (data.V_normals.transpose()).cast<float>();
         if (invert_normals)
@@ -78,25 +78,25 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
       }
 
       // Per-vertex material settings
-      if (dirty & DIRTY_AMBIENT)
+      if (dirty & ViewerData::DIRTY_AMBIENT)
         V_ambient_vbo = (data.V_material_ambient.transpose()).cast<float>();
-      if (dirty & DIRTY_DIFFUSE)
+      if (dirty & ViewerData::DIRTY_DIFFUSE)
         V_diffuse_vbo = (data.V_material_diffuse.transpose()).cast<float>();
-      if (dirty & DIRTY_SPECULAR)
+      if (dirty & ViewerData::DIRTY_SPECULAR)
         V_specular_vbo = (data.V_material_specular.transpose()).cast<float>();
 
       // Face indices
-      if (dirty & DIRTY_FACE)
+      if (dirty & ViewerData::DIRTY_FACE)
         F_vbo = (data.F.transpose()).cast<unsigned>();
 
       // Texture coordinates
-      if (dirty & DIRTY_UV)
+      if (dirty & ViewerData::DIRTY_UV)
         V_uv_vbo = (data.V_uv.transpose()).cast<float>();
     }
     else
     {
       // Per vertex properties with per corner UVs
-      if (dirty & DIRTY_POSITION)
+      if (dirty & ViewerData::DIRTY_POSITION)
       {
         V_vbo.resize(3,data.F.rows()*3);
         for (unsigned i=0; i<data.F.rows();++i)
@@ -104,7 +104,7 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
             V_vbo.col(i*3+j) = data.V.row(data.F(i,j)).transpose().cast<float>();
       }
 
-      if (dirty & DIRTY_AMBIENT)
+      if (dirty & ViewerData::DIRTY_AMBIENT)
       {
         V_ambient_vbo.resize(3,data.F.rows()*3);
         for (unsigned i=0; i<data.F.rows();++i)
@@ -112,7 +112,7 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
             V_ambient_vbo.col (i*3+j) = data.V_material_ambient.row(data.F(i,j)).transpose().cast<float>();
       }
 
-      if (dirty & DIRTY_DIFFUSE)
+      if (dirty & ViewerData::DIRTY_DIFFUSE)
       {
         V_diffuse_vbo.resize(3,data.F.rows()*3);
         for (unsigned i=0; i<data.F.rows();++i)
@@ -120,7 +120,7 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
             V_diffuse_vbo.col (i*3+j) = data.V_material_diffuse.row(data.F(i,j)).transpose().cast<float>();
       }
 
-      if (dirty & DIRTY_SPECULAR)
+      if (dirty & ViewerData::DIRTY_SPECULAR)
       {
         V_specular_vbo.resize(3,data.F.rows()*3);
         for (unsigned i=0; i<data.F.rows();++i)
@@ -128,7 +128,7 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
             V_specular_vbo.col(i*3+j) = data.V_material_specular.row(data.F(i,j)).transpose().cast<float>();
       }
 
-      if (dirty & DIRTY_NORMAL)
+      if (dirty & ViewerData::DIRTY_NORMAL)
       {
         V_normals_vbo.resize(3,data.F.rows()*3);
         for (unsigned i=0; i<data.F.rows();++i)
@@ -139,14 +139,14 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
           V_normals_vbo = -V_normals_vbo;
       }
 
-      if (dirty & DIRTY_FACE)
+      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 & DIRTY_UV)
+      if (dirty & ViewerData::DIRTY_UV)
       {
         V_uv_vbo.resize(2,data.F.rows()*3);
         for (unsigned i=0; i<data.F.rows();++i)
@@ -157,7 +157,7 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
   }
   else
   {
-    if (dirty & DIRTY_POSITION)
+    if (dirty & ViewerData::DIRTY_POSITION)
     {
       V_vbo.resize(3,data.F.rows()*3);
       for (unsigned i=0; i<data.F.rows();++i)
@@ -165,7 +165,7 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
           V_vbo.col(i*3+j) = data.V.row(data.F(i,j)).transpose().cast<float>();
     }
 
-    if (dirty & DIRTY_AMBIENT)
+    if (dirty & ViewerData::DIRTY_AMBIENT)
     {
       V_ambient_vbo.resize(3,data.F.rows()*3);
       for (unsigned i=0; i<data.F.rows();++i)
@@ -173,7 +173,7 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
           V_ambient_vbo.col (i*3+j) = data.F_material_ambient.row(i).transpose().cast<float>();
     }
 
-    if (dirty & DIRTY_DIFFUSE)
+    if (dirty & ViewerData::DIRTY_DIFFUSE)
     {
       V_diffuse_vbo.resize(3,data.F.rows()*3);
       for (unsigned i=0; i<data.F.rows();++i)
@@ -181,7 +181,7 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
           V_diffuse_vbo.col (i*3+j) = data.F_material_diffuse.row(i).transpose().cast<float>();
     }
 
-    if (dirty & DIRTY_SPECULAR)
+    if (dirty & ViewerData::DIRTY_SPECULAR)
     {
       V_specular_vbo.resize(3,data.F.rows()*3);
       for (unsigned i=0; i<data.F.rows();++i)
@@ -189,7 +189,7 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
           V_specular_vbo.col(i*3+j) = data.F_material_specular.row(i).transpose().cast<float>();
     }
 
-    if (dirty & DIRTY_NORMAL)
+    if (dirty & ViewerData::DIRTY_NORMAL)
     {
       V_normals_vbo.resize(3,data.F.rows()*3);
       for (unsigned i=0; i<data.F.rows();++i)
@@ -203,14 +203,14 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
         V_normals_vbo = -V_normals_vbo;
     }
 
-    if (dirty & DIRTY_FACE)
+    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 & DIRTY_UV)
+    if (dirty & ViewerData::DIRTY_UV)
     {
         V_uv_vbo.resize(2,data.F.rows()*3);
         for (unsigned i=0; i<data.F.rows();++i)
@@ -219,7 +219,7 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
     }
   }
 
-  if (dirty & DIRTY_TEXTURE)
+  if (dirty & ViewerData::DIRTY_TEXTURE)
   {
     tex_u = data.texture_R.rows();
     tex_v = data.texture_R.cols();
@@ -232,7 +232,7 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
     }
   }
 
-  if (dirty & DIRTY_OVERLAY_LINES)
+  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);
@@ -248,7 +248,7 @@ IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool fa
     }
   }
 
-  if (dirty & DIRTY_OVERLAY_POINTS)
+  if (dirty & ViewerData::DIRTY_OVERLAY_POINTS)
   {
     points_V_vbo.resize(3, data.points.rows());
     points_V_colors_vbo.resize(3, data.points.rows());
@@ -266,20 +266,20 @@ IGL_INLINE void igl::OpenGL_state::bind_mesh()
 {
   glBindVertexArray(vao_mesh);
   shader_mesh.bind();
-  shader_mesh.bindVertexAttribArray("position", vbo_V, V_vbo, dirty & DIRTY_POSITION);
-  shader_mesh.bindVertexAttribArray("normal", vbo_V_normals, V_normals_vbo, dirty & DIRTY_NORMAL);
-  shader_mesh.bindVertexAttribArray("Ka", vbo_V_ambient, V_ambient_vbo, dirty & DIRTY_AMBIENT);
-  shader_mesh.bindVertexAttribArray("Kd", vbo_V_diffuse, V_diffuse_vbo, dirty & DIRTY_DIFFUSE);
-  shader_mesh.bindVertexAttribArray("Ks", vbo_V_specular, V_specular_vbo, dirty & DIRTY_SPECULAR);
-  shader_mesh.bindVertexAttribArray("texcoord", vbo_V_uv, V_uv_vbo, dirty & DIRTY_UV);
+  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 & DIRTY_FACE)
+  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 & DIRTY_TEXTURE)
+  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);
@@ -288,12 +288,12 @@ IGL_INLINE void igl::OpenGL_state::bind_mesh()
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_u, tex_v, 0, GL_RGB, GL_UNSIGNED_BYTE, tex.data());
   }
   glUniform1i(shader_mesh.uniform("tex"), 0);
-  dirty &= ~DIRTY_MESH;
+  dirty &= ~ViewerData::DIRTY_MESH;
 }
 
 IGL_INLINE void igl::OpenGL_state::bind_overlay_lines()
 {
-  bool is_dirty = dirty & DIRTY_OVERLAY_LINES;
+  bool is_dirty = dirty & ViewerData::DIRTY_OVERLAY_LINES;
 
   glBindVertexArray(vao_overlay_lines);
   shader_overlay_lines.bind();
@@ -304,12 +304,12 @@ IGL_INLINE void igl::OpenGL_state::bind_overlay_lines()
   if (is_dirty)
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*lines_F_vbo.size(), lines_F_vbo.data(), GL_DYNAMIC_DRAW);
 
-  dirty &= ~DIRTY_OVERLAY_LINES;
+  dirty &= ~ViewerData::DIRTY_OVERLAY_LINES;
 }
 
 IGL_INLINE void igl::OpenGL_state::bind_overlay_points()
 {
-  bool is_dirty = dirty & DIRTY_OVERLAY_POINTS;
+  bool is_dirty = dirty & ViewerData::DIRTY_OVERLAY_POINTS;
 
   glBindVertexArray(vao_overlay_points);
   shader_overlay_points.bind();
@@ -320,7 +320,7 @@ IGL_INLINE void igl::OpenGL_state::bind_overlay_points()
   if (is_dirty)
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*points_F_vbo.size(), points_F_vbo.data(), GL_DYNAMIC_DRAW);
 
-  dirty &= ~DIRTY_OVERLAY_POINTS;
+  dirty &= ~ViewerData::DIRTY_OVERLAY_POINTS;
 }
 
 IGL_INLINE void igl::OpenGL_state::draw_mesh(bool solid)

+ 1 - 18
include/igl/viewer/OpenGL_state.h

@@ -73,7 +73,7 @@ public:
   IGL_INLINE void init_buffers();
 
   // Update contents from a 'Data' instance
-  IGL_INLINE void set_data(const igl::ViewerData &data, bool face_based, bool invert_normals);
+  IGL_INLINE void set_data(const igl::ViewerData &data, bool invert_normals);
 
   // Bind the underlying OpenGL buffer objects for subsequent mesh draw calls
   IGL_INLINE void bind_mesh();
@@ -96,23 +96,6 @@ public:
   // Release the OpenGL buffer objects
   IGL_INLINE void free_buffers();
 
-  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
-  };
-
 };
 
 }

+ 29 - 294
include/igl/viewer/Viewer.cpp

@@ -133,9 +133,6 @@ Eigen::Matrix4f translate(
 
 #include <igl/readOBJ.h>
 #include <igl/readOFF.h>
-#include <igl/per_face_normals.h>
-#include <igl/per_vertex_normals.h>
-#include <igl/per_corner_normals.h>
 #include <igl/adjacency_list.h>
 #include <igl/writeOBJ.h>
 #include <igl/writeOFF.h>
@@ -532,7 +529,7 @@ namespace igl
     // Default point size / line width
     options.point_size = 15;
     options.line_width = 0.5f;
-    options.face_based = false;
+    data.face_based = false;
     options.is_animating = false;
     options.animation_max_fps = 30.;
 
@@ -590,7 +587,7 @@ namespace igl
       if (plugins[i]->load(mesh_file_name_string))
         return true;
 
-    clear_mesh();
+    data.clear();
 
     size_t last_dot = mesh_file_name_string.rfind('.');
     if (last_dot == std::string::npos)
@@ -624,12 +621,12 @@ namespace igl
       return false;
     }
 
-    compute_normals();
-    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)
-      grid_texture();
+      data.grid_texture();
 
     align_camera_center();
 
@@ -640,70 +637,6 @@ namespace igl
     return true;
   }
 
-  void Viewer::compute_normals()
-  {
-    igl::per_face_normals(data.V, data.F, data.F_normals);
-    igl::per_vertex_normals(data.V, data.F, data.F_normals, data.V_normals);
-    data.dirty |= OpenGL_state::DIRTY_NORMAL;
-  }
-
-  void Viewer::uniform_colors(Eigen::Vector3d ambient, Eigen::Vector3d diffuse, Eigen::Vector3d specular)
-  {
-    data.V_material_ambient.resize(data.V.rows(),3);
-    data.V_material_diffuse.resize(data.V.rows(),3);
-    data.V_material_specular.resize(data.V.rows(),3);
-
-    for (unsigned i=0; i<data.V.rows();++i)
-    {
-      data.V_material_ambient.row(i) = ambient;
-      data.V_material_diffuse.row(i) = diffuse;
-      data.V_material_specular.row(i) = specular;
-    }
-
-    data.F_material_ambient.resize(data.F.rows(),3);
-    data.F_material_diffuse.resize(data.F.rows(),3);
-    data.F_material_specular.resize(data.F.rows(),3);
-
-    for (unsigned i=0; i<data.F.rows();++i)
-    {
-      data.F_material_ambient.row(i) = ambient;
-      data.F_material_diffuse.row(i) = diffuse;
-      data.F_material_specular.row(i) = specular;
-    }
-    data.dirty |= OpenGL_state::DIRTY_SPECULAR | OpenGL_state::DIRTY_DIFFUSE | OpenGL_state::DIRTY_AMBIENT;
-  }
-
-  void Viewer::grid_texture()
-  {
-    if (data.V_uv.rows() == 0)
-    {
-      data.V_uv = data.V.block(0, 0, data.V.rows(), 2);
-      data.V_uv.col(0) = data.V_uv.col(0).array() - data.V_uv.col(0).minCoeff();
-      data.V_uv.col(0) = data.V_uv.col(0).array() / data.V_uv.col(0).maxCoeff();
-      data.V_uv.col(1) = data.V_uv.col(1).array() - data.V_uv.col(1).minCoeff();
-      data.V_uv.col(1) = data.V_uv.col(1).array() / data.V_uv.col(1).maxCoeff();
-      data.V_uv = data.V_uv.array() * 10;
-      data.dirty |= OpenGL_state::DIRTY_TEXTURE;
-    }
-
-    unsigned size = 128;
-    unsigned size2 = size/2;
-    data.texture_R.resize(size, size);
-    for (unsigned i=0; i<size; ++i)
-    {
-      for (unsigned j=0; j<size; ++j)
-      {
-        data.texture_R(i,j) = 0;
-        if ((i<size2 && j<size2) || (i>=size2 && j>=size2))
-          data.texture_R(i,j) = 255;
-      }
-    }
-
-    data.texture_G = data.texture_R;
-    data.texture_B = data.texture_R;
-    data.dirty |= OpenGL_state::DIRTY_TEXTURE;
-  }
-
   bool Viewer::save_mesh_to_file(const char* mesh_file_name)
   {
     std::string mesh_file_name_string(mesh_file_name);
@@ -745,29 +678,9 @@ namespace igl
     return true;
   }
 
-  void Viewer::clear_mesh()
+  void Viewer::clear()
   {
-    data.V                       = Eigen::MatrixXd (0,3);
-    data.F                       = Eigen::MatrixXi (0,3);
-
-    data.F_material_ambient      = Eigen::MatrixXd (0,3);
-    data.F_material_diffuse      = Eigen::MatrixXd (0,3);
-    data.F_material_specular     = Eigen::MatrixXd (0,3);
-
-    data.V_material_ambient      = Eigen::MatrixXd (0,3);
-    data.V_material_diffuse      = Eigen::MatrixXd (0,3);
-    data.V_material_specular     = Eigen::MatrixXd (0,3);
-
-    data.F_normals               = Eigen::MatrixXd (0,3);
-    data.V_normals               = Eigen::MatrixXd (0,3);
-
-    data.V_uv                    = Eigen::MatrixXd (0,2);
-    data.F_uv                    = Eigen::MatrixXi (0,3);
-
-    data.lines                   = Eigen::MatrixXd (0,9);
-    data.points                  = Eigen::MatrixXd (0,6);
-    data.labels_positions        = Eigen::MatrixXd (0,3);
-    data.labels_strings.clear();
+    data.clear();
   }
 
   bool Viewer::key_down(unsigned char key, int modifiers)
@@ -990,8 +903,8 @@ namespace igl
     /* Bind and potentially refresh mesh/line/point data */
     if (data.dirty)
     {
-      opengl.set_data(data, options.face_based, options.invert_normals);
-      data.dirty = OpenGL_state::DIRTY_NONE;
+      opengl.set_data(data, options.invert_normals);
+      data.dirty = ViewerData::DIRTY_NONE;
     }
     opengl.bind_mesh();
 
@@ -1264,7 +1177,7 @@ namespace igl
   void TW_CALL Viewer::set_invert_normals_cb(const void *param, void *clientData)
   {
     Viewer *viewer = static_cast<Viewer *>(clientData);
-    viewer->data.dirty |= OpenGL_state::DIRTY_NORMAL;
+    viewer->data.dirty |= ViewerData::DIRTY_NORMAL;
     viewer->options.invert_normals = *((bool *) param);
   }
 
@@ -1281,7 +1194,7 @@ namespace igl
 
   void TW_CALL Viewer::get_face_based_cb(void *param, void *clientData)
   {
-    *((bool *) param) = static_cast<Viewer *>(clientData)->options.face_based;
+    *((bool *) param) = static_cast<Viewer *>(clientData)->data.face_based;
   }
 
   void TW_CALL Viewer::open_dialog_mesh(void *clientData)
@@ -1332,153 +1245,44 @@ namespace igl
 
   void Viewer::set_face_based(bool newvalue)
   {
-    if (options.face_based != newvalue)
-    {
-      options.face_based = newvalue;
-      data.dirty = OpenGL_state::DIRTY_ALL;
-    }
+    data.set_face_based(newvalue);
   }
 
-  // Helpers that draws the most common meshes
-  void Viewer::set_mesh(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F)
+  void Viewer::compute_normals()
   {
-    using namespace std;
-
-    Eigen::MatrixXd V_temp;
-
-    // If V only has two columns, pad with a column of zeros
-    if (V.cols() == 2)
-    {
-      V_temp = Eigen::MatrixXd::Zero(V.rows(),3);
-      V_temp.block(0,0,V.rows(),2) = V;
-    }
-    else
-      V_temp = V;
-
-    if (data.V.rows() == 0 && data.F.rows() == 0)
-    {
-      clear_mesh();
-      data.V = V_temp;
-      data.F = F;
+    data.compute_normals();
+  }
 
-      compute_normals();
-      uniform_colors(Eigen::Vector3d(51.0/255.0,43.0/255.0,33.3/255.0),
-                     Eigen::Vector3d(255.0/255.0,228.0/255.0,58.0/255.0),
-                     Eigen::Vector3d(255.0/255.0,235.0/255.0,80.0/255.0));
 
-      grid_texture();
-      align_camera_center();
-    }
-    else
-    {
-      if (data.V.rows() == V.rows() && data.F.rows() == F.rows())
-      {
-        data.V = V_temp;
-        data.F = F;
-        align_camera_center();
-      }
-      else
-        cerr << "ERROR (set_mesh): The new mesh has a different number of vertices/faces. Please clear the mesh before plotting.";
-    }
-    data.dirty |= OpenGL_state::DIRTY_FACE | OpenGL_state::DIRTY_POSITION;
+  void Viewer::set_mesh(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F)
+  {
+    data.set_mesh(V,F);
+    align_camera_center();
   }
 
   void Viewer::set_vertices(const Eigen::MatrixXd& V)
   {
-    data.V = V;
-    assert(data.F.size() == 0 || data.F.maxCoeff() < data.V.rows());
-    data.dirty |= OpenGL_state::DIRTY_POSITION;
+    data.set_vertices(V);
   }
 
   void Viewer::set_normals(const Eigen::MatrixXd& N)
   {
-    using namespace std;
-    if (N.rows() == data.V.rows())
-    {
-      set_face_based(false);
-      data.V_normals = N;
-    }
-    else if (N.rows() == data.F.rows() || N.rows() == data.F.rows()*3)
-    {
-      set_face_based(true);
-      data.F_normals = N;
-    }
-    else
-      cerr << "ERROR (set_normals): Please provide a normal per face, per corner or per vertex.";
-    data.dirty |= OpenGL_state::DIRTY_NORMAL;
+    data.set_normals(N);
   }
 
   void Viewer::set_colors(const Eigen::MatrixXd &C)
   {
-    using namespace std;
-    using namespace Eigen;
-    // Ambient color should be darker color
-    const auto ambient = [](const MatrixXd & C)->MatrixXd
-    {
-      return 0.1*C;
-    };
-    // Specular color should be a less saturated and darker color: dampened
-    // highlights
-    const auto specular = [](const MatrixXd & C)->MatrixXd
-    {
-      const double grey = 0.3;
-      return grey+0.1*(C.array()-grey);
-    };
-    if (C.rows() == 1)
-    {
-      for (unsigned i=0;i<data.V_material_diffuse.rows();++i)
-      {
-        data.V_material_diffuse.row(i) = C.row(0);
-      }
-      data.V_material_ambient = ambient(data.V_material_diffuse);
-      data.V_material_specular = specular(data.V_material_diffuse);
-
-      for (unsigned i=0;i<data.F_material_diffuse.rows();++i)
-      {
-        data.F_material_diffuse.row(i) = C.row(0);
-      }
-      data.F_material_ambient = ambient(data.F_material_diffuse);
-      data.F_material_specular = specular(data.F_material_diffuse);
-    }
-    else if (C.rows() == data.V.rows())
-    {
-      set_face_based(false);
-      data.V_material_diffuse = C;
-      data.V_material_ambient = ambient(data.V_material_diffuse);
-      data.V_material_specular = specular(data.V_material_diffuse);
-    }
-    else if (C.rows() == data.F.rows())
-    {
-      set_face_based(true);
-      data.F_material_diffuse = C;
-      data.F_material_ambient = ambient(data.F_material_diffuse);
-      data.F_material_specular = specular(data.F_material_diffuse);
-    }
-    else
-      cerr << "ERROR (set_colors): Please provide a single color, or a color per face or per vertex.";
-    data.dirty |= OpenGL_state::DIRTY_DIFFUSE;
-
+    data.set_colors(C);
   }
 
   void Viewer::set_uv(const Eigen::MatrixXd& UV)
   {
-    using namespace std;
-    if (UV.rows() == data.V.rows())
-    {
-      set_face_based(false);
-      data.V_uv = UV;
-    }
-    else
-      cerr << "ERROR (set_UV): Please provide uv per vertex.";
-    data.dirty |= OpenGL_state::DIRTY_UV;
+    data.set_uv(UV);
   }
 
   void Viewer::set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F)
   {
-    set_face_based(true);
-    data.V_uv = UV_V;
-    data.F_uv = UV_F;
-    data.dirty |= OpenGL_state::DIRTY_UV;
+    data.set_uv(UV_V,UV_F);
   }
 
 
@@ -1487,31 +1291,12 @@ namespace igl
     const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& G,
     const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& B)
   {
-    data.texture_R = R;
-    data.texture_G = G;
-    data.texture_B = B;
-    data.dirty |= OpenGL_state::DIRTY_TEXTURE;
+    data.set_texture(R,G,B);
   }
 
   void Viewer::add_points(const Eigen::MatrixXd& P,  const Eigen::MatrixXd& C)
   {
-    Eigen::MatrixXd P_temp;
-
-    // If P only has two columns, pad with a column of zeros
-    if (P.cols() == 2)
-    {
-      P_temp = Eigen::MatrixXd::Zero(P.rows(),3);
-      P_temp.block(0,0,P.rows(),2) = P;
-    }
-    else
-      P_temp = P;
-
-    int lastid = data.points.rows();
-    data.points.conservativeResize(data.points.rows() + P_temp.rows(),6);
-    for (unsigned i=0; i<P_temp.rows(); ++i)
-      data.points.row(lastid+i) << P_temp.row(i), i<C.rows() ? C.row(i) : C.row(C.rows()-1);
-
-    data.dirty |= OpenGL_state::DIRTY_OVERLAY_POINTS;
+    data.add_points(P,C);
   }
 
   void Viewer::set_edges(
@@ -1519,67 +1304,17 @@ namespace igl
     const Eigen::MatrixXi& E,
     const Eigen::MatrixXd& C)
   {
-    using namespace Eigen;
-    data.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);
-      }
-      data.lines.row(e)<< P.row(E(e,0)), P.row(E(e,1)), color;
-    }
-    data.dirty |= OpenGL_state::DIRTY_OVERLAY_LINES;
+    data.set_edges(P,E,C);
   }
 
   void Viewer::add_edges(const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C)
   {
-    Eigen::MatrixXd P1_temp,P2_temp;
-
-    // If P1 only has two columns, pad with a column of zeros
-    if (P1.cols() == 2)
-    {
-      P1_temp = Eigen::MatrixXd::Zero(P1.rows(),3);
-      P1_temp.block(0,0,P1.rows(),2) = P1;
-      P2_temp = Eigen::MatrixXd::Zero(P2.rows(),3);
-      P2_temp.block(0,0,P2.rows(),2) = P2;
-    }
-    else
-    {
-      P1_temp = P1;
-      P2_temp = P2;
-    }
-
-    int lastid = data.lines.rows();
-    data.lines.conservativeResize(data.lines.rows() + P1_temp.rows(),9);
-    for (unsigned i=0; i<P1_temp.rows(); ++i)
-      data.lines.row(lastid+i) << P1_temp.row(i), P2_temp.row(i), i<C.rows() ? C.row(i) : C.row(C.rows()-1);
-
-    data.dirty |= OpenGL_state::DIRTY_OVERLAY_LINES;
+    data.add_edges(P1,P2,C);
   }
 
   void Viewer::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, 0;
-    }
-    else
-      P_temp = P;
-
-    int lastid = data.labels_positions.rows();
-    data.labels_positions.conservativeResize(lastid+1, 3);
-    data.labels_positions.row(lastid) = P_temp;
-    data.labels_strings.push_back(str);
+    data.add_label(P,str);
   }
 
   int Viewer::launch(std::string filename)

+ 4 - 9
include/igl/viewer/Viewer.h

@@ -94,9 +94,6 @@ namespace igl
       float point_size;
       float line_width;
 
-      // Enable per-face colors and normals
-      bool face_based;
-
       // Animation
       bool is_animating;
       double animation_max_fps;
@@ -137,13 +134,11 @@ namespace igl
     // Keep track of the global position of the scrollwheel
     float scroll_position;
 
-    // Useful functions
-    void compute_normals(); // Computes the normals of the mesh
-    void uniform_colors(Eigen::Vector3d ambient, Eigen::Vector3d diffuse, Eigen::Vector3d specular); // assign uniform colors to all faces/vertices
-    void grid_texture(); // Generate a default grid texture
-
-    void clear_mesh();      // Clear the mesh data
     void align_camera_center(); // Adjust the view to see the entire model
+    void compute_normals();
+
+
+    void clear();      // Clear the mesh data
 
     // Change the visualization mode, invalidating the cache if necessary
     void set_face_based(bool newvalue);

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

@@ -1,5 +1,9 @@
 #include "ViewerData.h"
 
+#include <igl/per_face_normals.h>
+#include <igl/per_vertex_normals.h>
+#include <iostream>
+
 IGL_INLINE void igl::ViewerData::InitSerialization()
 {
   #ifdef ENABLE_XML_SERIALIZATION
@@ -26,5 +30,349 @@ IGL_INLINE void igl::ViewerData::InitSerialization()
 
   xmlSerializer->Add(labels_positions,"labels_positions");
   xmlSerializer->Add(labels_strings,"labels_strings");
+
+  xmlSerializer->Add(face_based,"face_based");
+
   #endif
 }
+
+IGL_INLINE void igl::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::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)
+  {
+    clear();
+    V = V_temp;
+    F = _F;
+
+    compute_normals();
+    uniform_colors(Eigen::Vector3d(51.0/255.0,43.0/255.0,33.3/255.0),
+                   Eigen::Vector3d(255.0/255.0,228.0/255.0,58.0/255.0),
+                   Eigen::Vector3d(255.0/255.0,235.0/255.0,80.0/255.0));
+
+    grid_texture();
+  }
+  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.";
+  }
+  dirty |= DIRTY_FACE | DIRTY_POSITION;
+}
+
+IGL_INLINE void igl::ViewerData::set_vertices(const Eigen::MatrixXd& _V)
+{
+  V = _V;
+  assert(F.size() == 0 || F.maxCoeff() < V.rows());
+  dirty |= DIRTY_POSITION;
+}
+
+IGL_INLINE void igl::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.";
+  dirty |= DIRTY_NORMAL;
+}
+
+IGL_INLINE void igl::ViewerData::set_colors(const Eigen::MatrixXd &C)
+{
+  using namespace std;
+  using namespace Eigen;
+  // Ambient color should be darker color
+  const auto ambient = [](const MatrixXd & C)->MatrixXd
+  {
+    return 0.1*C;
+  };
+  // Specular color should be a less saturated and darker color: dampened
+  // highlights
+  const auto specular = [](const MatrixXd & C)->MatrixXd
+  {
+    const double grey = 0.3;
+    return grey+0.1*(C.array()-grey);
+  };
+  if (C.rows() == 1)
+  {
+    for (unsigned i=0;i<V_material_diffuse.rows();++i)
+    {
+      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)
+    {
+      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);
+    V_material_diffuse = C;
+    V_material_ambient = ambient(V_material_diffuse);
+    V_material_specular = specular(V_material_diffuse);
+  }
+  else if (C.rows() == F.rows())
+  {
+    set_face_based(true);
+    F_material_diffuse = C;
+    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.";
+  dirty |= DIRTY_DIFFUSE;
+
+}
+
+IGL_INLINE void igl::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.";
+  dirty |= DIRTY_UV;
+}
+
+IGL_INLINE void igl::ViewerData::set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F)
+{
+  set_face_based(true);
+  V_uv = UV_V;
+  F_uv = UV_F;
+  dirty |= DIRTY_UV;
+}
+
+
+IGL_INLINE void igl::ViewerData::set_texture(
+  const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& R,
+  const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& G,
+  const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& B)
+{
+  texture_R = R;
+  texture_G = G;
+  texture_B = B;
+  dirty |= DIRTY_TEXTURE;
+}
+
+IGL_INLINE void igl::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::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::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::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, 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::ViewerData::clear()
+{
+  V                       = Eigen::MatrixXd (0,3);
+  F                       = Eigen::MatrixXi (0,3);
+
+  F_material_ambient      = Eigen::MatrixXd (0,3);
+  F_material_diffuse      = Eigen::MatrixXd (0,3);
+  F_material_specular     = Eigen::MatrixXd (0,3);
+
+  V_material_ambient      = Eigen::MatrixXd (0,3);
+  V_material_diffuse      = Eigen::MatrixXd (0,3);
+  V_material_specular     = Eigen::MatrixXd (0,3);
+
+  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::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::ViewerData::uniform_colors(Eigen::Vector3d ambient, Eigen::Vector3d diffuse, Eigen::Vector3d specular)
+{
+  V_material_ambient.resize(V.rows(),3);
+  V_material_diffuse.resize(V.rows(),3);
+  V_material_specular.resize(V.rows(),3);
+
+  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(),3);
+  F_material_diffuse.resize(F.rows(),3);
+  F_material_specular.resize(F.rows(),3);
+
+  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::ViewerData::grid_texture()
+{
+  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;
+  dirty |= DIRTY_TEXTURE;
+}

+ 64 - 0
include/igl/viewer/ViewerData.h

@@ -19,6 +19,67 @@ public:
   #endif
   {};
 
+  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
+  };
+
+  // Helpers functions to fill the fields
+
+  // Empy all fields
+  IGL_INLINE void clear();
+
+  // Change the visualization mode, invalidating the cache if necessary
+  IGL_INLINE void set_face_based(bool newvalue);
+
+  // Helpers that can draw the most common meshes
+  IGL_INLINE void set_mesh(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F);
+  IGL_INLINE void set_vertices(const Eigen::MatrixXd& V);
+  IGL_INLINE void set_normals(const Eigen::MatrixXd& N);
+  // Set the color of the mesh
+  //
+  // Inputs:
+  //   C  #V|#F|1 by 3 list of colors
+  IGL_INLINE void set_colors(const Eigen::MatrixXd &C);
+  IGL_INLINE void set_uv(const Eigen::MatrixXd& UV);
+  IGL_INLINE void set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F);
+  IGL_INLINE void set_texture(
+                    const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& R,
+                    const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& G,
+                    const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& B);
+
+  IGL_INLINE void add_points(const Eigen::MatrixXd& P,  const Eigen::MatrixXd& C);
+  // Sets edges given a list of edge vertices and edge indices. In constrast
+  // to `add_edges` this will (purposefully) clober existing edges.
+  //
+  // Inputs:
+  //   P  #P by 3 list of vertex positions
+  //   E  #E by 2 list of edge indices into P
+  //   C  #E|1 by 3 color(s)
+  IGL_INLINE void set_edges (const Eigen::MatrixXd& P, const Eigen::MatrixXi& E, const Eigen::MatrixXd& C);
+  IGL_INLINE void add_edges (const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C);
+  IGL_INLINE void add_label (const Eigen::VectorXd& P,  const std::string& str);
+
+  // More helpers
+
+  IGL_INLINE void compute_normals(); // Computes the normals of the mesh
+  IGL_INLINE void uniform_colors(Eigen::Vector3d ambient, Eigen::Vector3d diffuse, Eigen::Vector3d specular); // assign uniform colors to all faces/vertices
+  IGL_INLINE void grid_texture(); // Generate a default grid texture
+
+
+
   IGL_INLINE void InitSerialization();
 
   Eigen::MatrixXd V; // Vertices of the current mesh (#V x 3)
@@ -70,6 +131,9 @@ public:
 
   // Caches the two-norm between the min/max point of the bounding box
   float object_scale;
+
+  // Enable per-face or per-vertex properties
+  bool face_based;
   /*********************************/
 };
 

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

@@ -9,8 +9,8 @@ bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
 {
   if (key == '1')
   {
-    // Clear mesh should be called before drawing the mesh
-    viewer.clear_mesh();
+    // Clear should be called before drawing the mesh
+    viewer.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
@@ -18,7 +18,7 @@ bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
   }
   else if (key == '2')
   {
-    viewer.clear_mesh();
+    viewer.clear();
     viewer.set_mesh(V2, F2);
   }
 

+ 13 - 13
tutorial/504_NRosyDesign/main.cpp

@@ -26,16 +26,16 @@ int N = 4;
 void representative_to_nrosy(const MatrixXd& V, const MatrixXi& F, const MatrixXd& R, const int N, MatrixXd& Y)
 {
   MatrixXd B1, B2, B3;
-  
+
   igl::local_basis(V,F,B1,B2,B3);
-  
+
   Y.resize(F.rows()*N,3);
   for (unsigned i=0;i<F.rows();++i)
   {
     double x = R.row(i) * B1.row(i).transpose();
     double y = R.row(i) * B2.row(i).transpose();
     double angle = atan2(y,x);
-    
+
     for (unsigned j=0; j<N;++j)
     {
       double anglej = angle + 2*M_PI*double(j)/double(N);
@@ -51,24 +51,24 @@ void representative_to_nrosy(const MatrixXd& V, const MatrixXi& F, const MatrixX
 void plot_mesh_nrosy(igl::Viewer& viewer, MatrixXd& V, MatrixXi& F, int N, MatrixXd& PD1, VectorXd& S, VectorXi& b)
 {
   // Clear the mesh
-  viewer.clear_mesh();
+  viewer.clear();
   viewer.set_mesh(V,F);
-  
+
   // Expand the representative vectors in the full vector set and plot them as lines
   double avg = igl::avg_edge_length(V, F);
   MatrixXd Y;
   representative_to_nrosy(V, F, PD1, N, Y);
-  
+
   MatrixXd B;
   igl::barycenter(V,F,B);
-  
+
   MatrixXd Be(B.rows()*N,3);
   for(unsigned i=0; i<B.rows();++i)
     for(unsigned j=0; j<N; ++j)
       Be.row(i*N+j) = B.row(i);
-  
+
   viewer.add_edges(Be,Be+Y*(avg/2),RowVector3d(0,0,1));
-  
+
   // Plot the singularities as colored dots (red for negative, blue for positive)
   for (unsigned i=0; i<S.size();++i)
   {
@@ -77,7 +77,7 @@ void plot_mesh_nrosy(igl::Viewer& viewer, MatrixXd& V, MatrixXi& F, int N, Matri
     else if (S(i) > 0.001)
       viewer.add_points(V.row(i),RowVector3d(0,1,0));
   }
-  
+
   // Highlight in red the constrained faces
   MatrixXd C = MatrixXd::Constant(F.rows(),3,1);
   for (unsigned i=0; i<b.size();++i)
@@ -93,10 +93,10 @@ bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
 
   MatrixXd R;
   VectorXd S;
-  
+
   igl::nrosy(V,F,b,bc,VectorXi(),VectorXd(),MatrixXd(),N,0.5,R,S);
   plot_mesh_nrosy(viewer,V,F,N,R,S,b);
-  
+
   return false;
 }
 
@@ -118,7 +118,7 @@ int main(int argc, char *argv[])
 
   // Interpolate the field and plot
   key_down(viewer, '4', 0);
-  
+
   // Plot the mesh
   viewer.set_mesh(V, F);
   viewer.callback_key_down = &key_down;

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

@@ -73,7 +73,7 @@ bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
   if (key <'1' || key >'8')
     return false;
 
-  viewer.clear_mesh();
+  viewer.clear();
   viewer.options.show_lines = false;
   viewer.options.show_texture = false;
 

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

@@ -72,7 +72,7 @@ bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
   if (key <'1' || key >'6')
     return false;
 
-  viewer.clear_mesh();
+  viewer.clear();
   viewer.options.show_lines = false;
   viewer.options.show_texture = false;
 

+ 2 - 2
tutorial/605_Tetgen/main.cpp

@@ -47,9 +47,9 @@ bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
       F_temp.row(i*4+3) << (i*4)+1, (i*4)+2, (i*4)+3;
     }
 
-    viewer.clear_mesh();
+    viewer.clear();
     viewer.set_mesh(V_temp,F_temp);
-    viewer.options.face_based = true;
+    viewer.set_face_based(true);
   }
 
 

+ 3 - 3
tutorial/tutorial.md

@@ -194,12 +194,12 @@ bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
 {
   if (key == '1')
   {
-    viewer.clear_mesh();
+    viewer.clear();
     viewer.set_mesh(V1, F1);
   }
   else if (key == '2')
   {
-    viewer.clear_mesh();
+    viewer.clear();
     viewer.set_mesh(V2, F2);
   }
   return false;
@@ -1155,7 +1155,7 @@ as a constrained optimization problem [#jacobson_2011][]. The weights enforce
 smoothness by minimizing a smoothness energy: the familiar Laplacian energy:
 
  $\sum\limits_{i = 1}^m \int_S (\Delta w_i)^2 dA$
-  
+
 subject to constraints which enforce interpolation of handle constraints:
 
  $w_i(\mathbf{x}) = \begin{cases} 1 & \text{ if } \mathbf{x} \in H_i\\ 0 & \text{ otherwise }