Browse Source

Viewer: moved all the camera and rendering options code in a reusable class

Former-commit-id: e4eb2c7cecf506abd1cc38d0bbed59d4d2703cd0
Daniele Panozzo 11 years ago
parent
commit
54d08046c9

+ 14 - 380
include/igl/viewer/Viewer.cpp

@@ -40,90 +40,6 @@
 #include <algorithm>
 #include <igl/project.h>
 
-Eigen::Matrix4f lookAt (
-                        const Eigen::Vector3f& eye,
-                        const Eigen::Vector3f& center,
-                        const Eigen::Vector3f& up)
-{
-  Eigen::Vector3f f = (center - eye).normalized();
-  Eigen::Vector3f s = f.cross(up).normalized();
-  Eigen::Vector3f u = s.cross(f);
-
-  Eigen::Matrix4f Result = Eigen::Matrix4f::Identity();
-  Result(0,0) = s(0);
-  Result(0,1) = s(1);
-  Result(0,2) = s(2);
-  Result(1,0) = u(0);
-  Result(1,1) = u(1);
-  Result(1,2) = u(2);
-  Result(2,0) =-f(0);
-  Result(2,1) =-f(1);
-  Result(2,2) =-f(2);
-  Result(0,3) =-s.transpose() * eye;
-  Result(1,3) =-u.transpose() * eye;
-  Result(2,3) = f.transpose() * eye;
-  return Result;
-}
-
-Eigen::Matrix4f ortho (
-                       const float left,
-                       const float right,
-                       const float bottom,
-                       const float top,
-                       const float zNear,
-                       const float zFar
-                       )
-{
-  Eigen::Matrix4f Result = Eigen::Matrix4f::Identity();
-  Result(0,0) = 2.0f / (right - left);
-  Result(1,1) = 2.0f / (top - bottom);
-  Result(2,2) = - 2.0f / (zFar - zNear);
-  Result(0,3) = - (right + left) / (right - left);
-  Result(1,3) = - (top + bottom) / (top - bottom);
-  Result(2,3) = - (zFar + zNear) / (zFar - zNear);
-  return Result;
-}
-
-Eigen::Matrix4f frustum (
-                         const float left,
-                         const float right,
-                         const float bottom,
-                         const float top,
-                         const float nearVal,
-                         const float farVal)
-{
-  Eigen::Matrix4f Result = Eigen::Matrix4f::Zero();
-  Result(0,0) = (2.0f * nearVal) / (right - left);
-  Result(1,1) = (2.0f * nearVal) / (top - bottom);
-  Result(0,2) = (right + left) / (right - left);
-  Result(1,2) = (top + bottom) / (top - bottom);
-  Result(2,2) = -(farVal + nearVal) / (farVal - nearVal);
-  Result(3,2) = -1.0f;
-  Result(2,3) = -(2.0f * farVal * nearVal) / (farVal - nearVal);
-  return Result;
-}
-
-Eigen::Matrix4f scale (const Eigen::Matrix4f& m,
-                       const Eigen::Vector3f& v)
-{
-  Eigen::Matrix4f Result;
-  Result.col(0) = m.col(0).array() * v(0);
-  Result.col(1) = m.col(1).array() * v(1);
-  Result.col(2) = m.col(2).array() * v(2);
-  Result.col(3) = m.col(3);
-  return Result;
-}
-
-Eigen::Matrix4f translate(
-                          const Eigen::Matrix4f& m,
-                          const Eigen::Vector3f& v)
-{
-  Eigen::Matrix4f Result = m;
-  Result.col(3) = m.col(0).array() * v(0) + m.col(1).array() * v(1) + m.col(2).array() * v(2) + m.col(3).array();
-  return Result;
-}
-
-
 #include <limits>
 #include <cassert>
 
@@ -139,7 +55,6 @@ Eigen::Matrix4f translate(
 #include <igl/massmatrix.h>
 #include <igl/file_dialog_open.h>
 #include <igl/file_dialog_save.h>
-#include <igl/quat_to_mat.h>
 #include <igl/quat_mult.h>
 #include <igl/axis_angle_to_quat.h>
 #include <igl/trackball.h>
@@ -153,8 +68,6 @@ static double highdpi = 1;
 static double scroll_x = 0;
 static double scroll_y = 0;
 
-static igl::TextRenderer __font_renderer;
-
 static void glfw_mouse_press(GLFWwindow* window, int button, int action, int modifier)
 {
   bool tw_used = TwEventMouseButtonGLFW(button, action);
@@ -481,57 +394,12 @@ namespace igl
                " label='Show Faces Labels' key='CTRL+;' help='Toggle face"
                " indices'");
 
-    __font_renderer.Init();
-
+    options.init();
     init_plugins();
   }
 
   Viewer::Viewer()
   {
-    // Default shininess
-    options.shininess = 35.0f;
-
-    // Default colors
-    options.background_color << 0.3f, 0.3f, 0.5f;
-    options.line_color << 0.0f, 0.0f, 0.0f;
-
-    // Default lights settings
-    options.light_position << 0.0f, -0.30f, -5.0f;
-    options.lighting_factor = 1.0f; //on
-
-    // Default trackball
-    options.trackball_angle << 0.0f, 0.0f, 0.0f, 1.0f;
-
-    // Defalut model viewing parameters
-    options.model_zoom = 1.0f;
-    options.model_translation << 0,0,0;
-
-    // Camera parameters
-    options.camera_zoom = 1.0f;
-    options.orthographic = false;
-    options.camera_view_angle = 45.0;
-    options.camera_dnear = 1.0;
-    options.camera_dfar = 100.0;
-    options.camera_eye << 0, 0, 5;
-    options.camera_center << 0, 0, 0;
-    options.camera_up << 0, 1, 0;
-
-    // Default visualization options
-    options.show_faces = true;
-    options.show_lines = true;
-    options.invert_normals = false;
-    options.show_overlay = true;
-    options.show_overlay_depth = true;
-    options.show_vertid = false;
-    options.show_faceid = false;
-    options.show_texture = false;
-
-    // Default point size / line width
-    options.point_size = 15;
-    options.line_width = 0.5f;
-    data.face_based = false;
-    options.is_animating = false;
-    options.animation_max_fps = 30.;
 
     // Temporary variables initialization
     down = false;
@@ -559,6 +427,7 @@ namespace igl
     callback_mouse_scroll  = 0;
     callback_key_down      = 0;
     callback_key_up        = 0;
+
   }
 
   void Viewer::init_plugins()
@@ -628,7 +497,7 @@ namespace igl
     if (data.V_uv.rows() == 0)
       data.grid_texture();
 
-    align_camera_center();
+    options.align_camera_center(data.V);
 
     for (unsigned int i = 0; i<plugins.size(); ++i)
       if (plugins[i]->post_load())
@@ -750,7 +619,7 @@ namespace igl
     else
       center = data.V.colwise().sum()/data.V.rows();
 
-    Eigen::Vector3f coord = igl::project(Eigen::Vector3f(center(0),center(1),center(2)), view * model, proj, viewport);
+    Eigen::Vector3f coord = igl::project(Eigen::Vector3f(center(0),center(1),center(2)), options.view * options.model, options.proj, options.viewport);
     down_mouse_z = coord[2];
     down_rotation = options.trackball_angle;
 
@@ -816,8 +685,8 @@ namespace igl
       {
         case ROTATION :
         {
-          igl::trackball(width,
-                         height,
+          igl::trackball(options.viewport(2),
+                         options.viewport(3),
                          2.0f,
                          down_rotation.data(),
                          down_mouse_x,
@@ -833,8 +702,8 @@ namespace igl
         case TRANSLATE:
         {
           //translation
-          Eigen::Vector3f pos1 = igl::unproject(Eigen::Vector3f(mouse_x, viewport[3] - mouse_y, down_mouse_z), view * model, proj, viewport);
-          Eigen::Vector3f pos0 = igl::unproject(Eigen::Vector3f(down_mouse_x, viewport[3] - down_mouse_y, down_mouse_z), view * model, proj, viewport);
+          Eigen::Vector3f pos1 = igl::unproject(Eigen::Vector3f(mouse_x, options.viewport[3] - mouse_y, down_mouse_z), options.view * options.model, options.proj, options.viewport);
+          Eigen::Vector3f pos0 = igl::unproject(Eigen::Vector3f(down_mouse_x, options.viewport[3] - down_mouse_y, down_mouse_z), options.view * options.model, options.proj, options.viewport);
 
           Eigen::Vector3f diff = pos1 - pos0;
           options.model_translation = down_translation + Eigen::Vector3f(diff[0],diff[1],diff[2]);
@@ -884,13 +753,8 @@ namespace igl
   {
     using namespace std;
     using namespace Eigen;
-    glClearColor(options.background_color[0],
-                 options.background_color[1],
-                 options.background_color[2],
-                 1.0f);
-    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-    glEnable(GL_DEPTH_TEST);
+    options.clear_framebuffers();
 
     if (callback_pre_draw)
       if (callback_pre_draw(*this))
@@ -900,170 +764,7 @@ namespace igl
       if (plugins[i]->pre_draw())
         return;
 
-    /* Bind and potentially refresh mesh/line/point data */
-    if (data.dirty)
-    {
-      opengl.set_data(data, options.invert_normals);
-      data.dirty = ViewerData::DIRTY_NONE;
-    }
-    opengl.bind_mesh();
-
-    // Initialize uniform
-    glViewport(0, 0, width, height);
-
-    model = Eigen::Matrix4f::Identity();
-    view  = Eigen::Matrix4f::Identity();
-    proj  = Eigen::Matrix4f::Identity();
-
-    // Set view
-    view = lookAt(Eigen::Vector3f(options.camera_eye[0], options.camera_eye[1], options.camera_eye[2]),
-                  Eigen::Vector3f(options.camera_center[0], options.camera_center[1], options.camera_center[2]),
-                  Eigen::Vector3f(options.camera_up[0], options.camera_up[1], options.camera_up[2]));
-
-    // Set projection
-    if (options.orthographic)
-    {
-      float length = (options.camera_eye - options.camera_center).norm();
-      float h = tan(options.camera_view_angle/360.0 * M_PI) * (length);
-      proj = ortho(-h*width/height, h*width/height, -h, h, options.camera_dnear, options.camera_dfar);
-    }
-    else
-    {
-      float fH = tan(options.camera_view_angle / 360.0 * M_PI) * options.camera_dnear;
-      float fW = fH * (double)width/(double)height;
-      proj = frustum(-fW, fW, -fH, fH, options.camera_dnear, options.camera_dfar);
-    }
-    // end projection
-
-    // Set model transformation
-    float mat[16];
-    igl::quat_to_mat(options.trackball_angle.data(), mat);
-
-    for (unsigned i=0;i<4;++i)
-      for (unsigned j=0;j<4;++j)
-        model(i,j) = mat[i+4*j];
-
-    model = scale(model, Eigen::Vector3f(options.camera_zoom,options.camera_zoom,options.camera_zoom));
-    model = scale(model, Eigen::Vector3f(options.model_zoom,options.model_zoom,options.model_zoom));
-    model = translate(model, Eigen::Vector3f(options.model_translation[0],options.model_translation[1],options.model_translation[2]));
-
-    // Send transformations to the GPU
-    GLint modeli = opengl.shader_mesh.uniform("model");
-    GLint viewi  = opengl.shader_mesh.uniform("view");
-    GLint proji  = opengl.shader_mesh.uniform("proj");
-    glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
-    glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
-    glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
-
-    // Light parameters
-    GLint specular_exponenti    = opengl.shader_mesh.uniform("specular_exponent");
-    GLint light_position_worldi = opengl.shader_mesh.uniform("light_position_world");
-    GLint lighting_factori      = opengl.shader_mesh.uniform("lighting_factor");
-    GLint fixed_colori          = opengl.shader_mesh.uniform("fixed_color");
-    GLint texture_factori       = opengl.shader_mesh.uniform("texture_factor");
-
-    glUniform1f(specular_exponenti, options.shininess);
-    Vector3f rev_light = -1.*options.light_position;
-    glUniform3fv(light_position_worldi, 1, rev_light.data());
-    glUniform1f(lighting_factori, options.lighting_factor); // enables lighting
-    glUniform4f(fixed_colori, 0.0, 0.0, 0.0, 0.0);
-
-    if (data.V.rows()>0)
-    {
-      // Render fill
-      if (options.show_faces)
-      {
-        // Texture
-        glUniform1f(texture_factori, options.show_texture ? 1.0f : 0.0f);
-        opengl.draw_mesh(true);
-        glUniform1f(texture_factori, 0.0f);
-      }
-
-      // Render wireframe
-      if (options.show_lines)
-      {
-        glLineWidth(options.line_width);
-        glUniform4f(fixed_colori, options.line_color[0], options.line_color[1],
-          options.line_color[2], 1.0f);
-        opengl.draw_mesh(false);
-        glUniform4f(fixed_colori, 0.0f, 0.0f, 0.0f, 0.0f);
-      }
-
-      if (options.show_vertid)
-      {
-        __font_renderer.BeginDraw(view*model, proj, viewport, data.object_scale);
-        for (int i=0; i<data.V.rows(); ++i)
-          __font_renderer.DrawText(data.V.row(i), data.V_normals.row(i), to_string(i));
-        __font_renderer.EndDraw();
-      }
-
-      if (options.show_faceid)
-      {
-        __font_renderer.BeginDraw(view*model, proj, viewport, data.object_scale);
-
-        for (int i=0; i<data.F.rows(); ++i)
-        {
-          Eigen::RowVector3d p = Eigen::RowVector3d::Zero();
-          for (int j=0;j<data.F.cols();++j)
-            p += data.V.row(data.F(i,j));
-          p /= data.F.cols();
-
-          __font_renderer.DrawText(p, data.F_normals.row(i), to_string(i));
-        }
-        __font_renderer.EndDraw();
-      }
-    }
-
-    if (options.show_overlay)
-    {
-      if (options.show_overlay_depth)
-        glEnable(GL_DEPTH_TEST);
-      else
-        glDisable(GL_DEPTH_TEST);
-
-      if (data.lines.rows() > 0)
-      {
-        opengl.bind_overlay_lines();
-        modeli = opengl.shader_overlay_lines.uniform("model");
-        viewi  = opengl.shader_overlay_lines.uniform("view");
-        proji  = opengl.shader_overlay_lines.uniform("proj");
-
-        glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
-        glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
-        glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
-        // This must be enabled, otherwise glLineWidth has no effect
-        glEnable(GL_LINE_SMOOTH);
-        glLineWidth(options.line_width);
-
-        opengl.draw_overlay_lines();
-      }
-
-      if (data.points.rows() > 0)
-      {
-        opengl.bind_overlay_points();
-        modeli = opengl.shader_overlay_points.uniform("model");
-        viewi  = opengl.shader_overlay_points.uniform("view");
-        proji  = opengl.shader_overlay_points.uniform("proj");
-
-        glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
-        glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
-        glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
-        glPointSize(options.point_size);
-
-        opengl.draw_overlay_points();
-      }
-
-      if (data.labels_positions.rows() > 0)
-      {
-        __font_renderer.BeginDraw(view*model, proj, viewport, data.object_scale);
-        for (int i=0; i<data.labels_positions.rows(); ++i)
-          __font_renderer.DrawText(data.labels_positions.row(i), Eigen::Vector3d(0.0,0.0,0.0),
-              data.labels_strings[i]);
-        __font_renderer.EndDraw();
-      }
-
-      glEnable(GL_DEPTH_TEST);
-    }
+    options.draw(data,opengl);
 
     if (callback_post_draw)
       if (callback_post_draw(*this))
@@ -1118,40 +819,9 @@ namespace igl
     return true;
   }
 
-  void Viewer::align_camera_center()
-  {
-    get_scale_and_shift_to_fit_mesh(data.V,data.F,options.model_zoom,options.model_translation);
-    data.object_scale = (data.V.colwise().maxCoeff() - data.V.colwise().minCoeff()).norm();
-  }
-
   void Viewer::resize(int w, int h)
   {
-    width = w;
-    height = h;
-    viewport = Eigen::Vector4f(0,0,width,height);
-  }
-
-  void Viewer::get_scale_and_shift_to_fit_mesh(
-    const Eigen::MatrixXd& V,
-    const Eigen::MatrixXi& F,
-    float& zoom,
-    Eigen::Vector3f& shift)
-  {
-    if (V.rows() == 0)
-      return;
-    //Compute mesh centroid
-    Eigen::SparseMatrix<double> M;
-    igl::massmatrix(V,F,igl::MASSMATRIX_TYPE_VORONOI,M);
-    const auto & MV = M*V;
-    Eigen::RowVector3d centroid  = MV.colwise().sum()/M.diagonal().sum();
-    Eigen::RowVector3d min_point = V.colwise().minCoeff();
-    Eigen::RowVector3d max_point = V.colwise().maxCoeff();
-
-    shift = -centroid.cast<float>();
-    double x_scale = fabs(max_point[0] - min_point[0]);
-    double y_scale = fabs(max_point[1] - min_point[1]);
-    double z_scale = fabs(max_point[2] - min_point[2]);
-    zoom = 2.0/ std::max(z_scale,std::max(x_scale,y_scale));
+    options.viewport = Eigen::Vector4f(0,0,w,h);
   }
 
   void TW_CALL Viewer::snap_to_canonical_quaternion_cb(void *clientData)
@@ -1161,7 +831,7 @@ namespace igl
   }
   void TW_CALL Viewer::align_camera_center_cb(void *clientData)
   {
-    static_cast<Viewer *>(clientData)->align_camera_center();
+    static_cast<Viewer *>(clientData)->options.align_camera_center(static_cast<Viewer *>(clientData)->data.V);
   }
 
   void TW_CALL Viewer::save_scene_cb(void *clientData)
@@ -1207,42 +877,6 @@ namespace igl
     static_cast<Viewer *>(clientData)->load_mesh_from_file(fname.c_str());
   }
 
-  // Serialization
-  void Viewer::Options::InitSerialization()
-  {
-    #ifdef ENABLE_XML_SERIALIZATION
-    xmlSerializer->Add(shininess, "shininess");
-    xmlSerializer->Add(background_color, "background_color");
-    xmlSerializer->Add(line_color, "line_color");
-    xmlSerializer->Add(light_position, "light_position");
-    xmlSerializer->Add(lighting_factor, "lighting_factor");
-    xmlSerializer->Add(trackball_angle, "trackball_angle");
-    xmlSerializer->Add(model_zoom, "model_zoom");
-    xmlSerializer->Add(model_translation, "model_translation");
-    xmlSerializer->Add(model_zoom_uv, "model_zoom_uv");
-    xmlSerializer->Add(model_translation_uv, "model_translation_uv");
-    xmlSerializer->Add(camera_zoom, "camera_zoom");
-    xmlSerializer->Add(orthographic, "orthographic");
-    xmlSerializer->Add(camera_eye, "camera_eye");
-    xmlSerializer->Add(camera_up, "camera_up");
-    xmlSerializer->Add(camera_center, "camera_center");
-    xmlSerializer->Add(camera_view_angle, "camera_view_angle");
-    xmlSerializer->Add(camera_dnear, "camera_dnear");
-    xmlSerializer->Add(camera_dfar, "camera_dfar");
-    xmlSerializer->Add(show_overlay, "show_overlay");
-    xmlSerializer->Add(show_overlay_depth, "show_overlay_depth");
-    xmlSerializer->Add(show_texture, "show_texture");
-    xmlSerializer->Add(show_faces, "show_faces");
-    xmlSerializer->Add(show_lines, "show_lines");
-    xmlSerializer->Add(show_vertid, "show_vertid");
-    xmlSerializer->Add(show_faceid, "show_faceid");
-    xmlSerializer->Add(point_size, "point_size");
-    xmlSerializer->Add(line_width, "line_width");
-    xmlSerializer->Add(invert_normals, "invert_normals");
-    xmlSerializer->Add(face_based, "face_based");
-    #endif
-  }
-
   void Viewer::set_face_based(bool newvalue)
   {
     data.set_face_based(newvalue);
@@ -1257,7 +891,7 @@ namespace igl
   void Viewer::set_mesh(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F)
   {
     data.set_mesh(V,F);
-    align_camera_center();
+    options.align_camera_center(V);
   }
 
   void Viewer::set_vertices(const Eigen::MatrixXd& V)
@@ -1417,7 +1051,7 @@ namespace igl
     }
 
     opengl.free();
-    __font_renderer.Shut();
+    options.shut();
 
     shutdown_plugins();
 

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

@@ -24,6 +24,7 @@
 #include <igl/viewer/ViewerData.h>
 #include <igl/viewer/OpenGL_state.h>
 #include <igl/viewer/ViewerPlugin.h>
+#include <igl/viewer/ViewerCore.h>
 
 namespace igl
 {
@@ -35,72 +36,8 @@ namespace igl
     int launch(std::string filename = "");
     void init();
 
-    class Options
-    #ifdef ENABLE_XML_SERIALIZATION
-    : public ::igl::XMLSerialization
-    #endif
-    {
-    public:
-      Options()
-      #ifdef ENABLE_XML_SERIALIZATION
-      : XMLSerialization("Options")
-      #endif
-      {};
-      void InitSerialization();
-
-      // Shape material
-      float shininess;
-
-      // Colors
-      Eigen::Vector3f background_color;
-      Eigen::Vector3f line_color;
-
-      // Lighting
-      Eigen::Vector3f light_position;
-      float lighting_factor;
-
-      // Trackball angle (quaternion)
-      Eigen::Vector4f trackball_angle;
-
-      // Model viewing parameters
-      float model_zoom;
-      Eigen::Vector3f model_translation;
-
-      // Model viewing paramters (uv coordinates)
-      float model_zoom_uv;
-      Eigen::Vector3f model_translation_uv;
-
-      // Camera parameters
-      float camera_zoom;
-      bool orthographic;
-      Eigen::Vector3f camera_eye;
-      Eigen::Vector3f camera_up;
-      Eigen::Vector3f camera_center;
-      float camera_view_angle;
-      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;
-
-      // Point size / line width
-      float point_size;
-      float line_width;
-
-      // Animation
-      bool is_animating;
-      double animation_max_fps;
-    };
-
     // Stores all the viewing options
-    Options options;
+    igl::ViewerCore options;
 
     // Stores all the data that should be visualized
     igl::ViewerData data;
@@ -127,17 +64,12 @@ namespace igl
     // Anttweak bar
     TwBar* bar;
 
-    // Window size
-    int width;
-    int height;
-
     // Keep track of the global position of the scrollwheel
     float scroll_position;
 
-    void align_camera_center(); // Adjust the view to see the entire model
+    // Wrapper for ViewerData::compute_normals()
     void compute_normals();
 
-
     void clear();      // Clear the mesh data
 
     // Change the visualization mode, invalidating the cache if necessary
@@ -147,10 +79,6 @@ namespace igl
     void set_mesh(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F);
     void set_vertices(const Eigen::MatrixXd& V);
     void set_normals(const Eigen::MatrixXd& N);
-    // Set the color of the mesh
-    //
-    // Inputs:
-    //   C  #V|#F|1 by 3 list of colors
     void set_colors(const Eigen::MatrixXd &C);
     void set_uv(const Eigen::MatrixXd& UV);
     void set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F);
@@ -160,23 +88,12 @@ namespace igl
                       const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& B);
 
     void add_points(const Eigen::MatrixXd& P,  const Eigen::MatrixXd& C);
-    // Sets edges given a list of edge vertices and edge indices. In constrast
-    // to `add_edges` this will (purposefully) clober existing edges.
-    //
-    // Inputs:
-    //   P  #P by 3 list of vertex positions
-    //   E  #E by 2 list of edge indices into P
-    //   C  #E|1 by 3 color(s)
     void set_edges (const Eigen::MatrixXd& P, const Eigen::MatrixXi& E, const Eigen::MatrixXd& C);
     void add_edges (const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C);
     void add_label (const Eigen::VectorXd& P,  const std::string& str);
 
-    // Save the OpenGL transformation matrices used for the previous rendering pass
-    Eigen::Matrix4f view;
-    Eigen::Matrix4f model;
-    Eigen::Matrix4f proj;
 
-    Eigen::Vector4f viewport;
+//    Eigen::Vector4f viewport;
 
     // UI Enumerations
     enum MouseButton {IGL_LEFT, IGL_MIDDLE, IGL_RIGHT};
@@ -204,14 +121,6 @@ namespace igl
     bool load_scene();
     bool save_scene();
 
-    // Determines how much to zoom and shift such that the mesh fills the unit
-    // box (centered at the origin)
-    static void get_scale_and_shift_to_fit_mesh(
-      const Eigen::MatrixXd& V,
-      const Eigen::MatrixXi& F,
-      float & zoom,
-      Eigen::Vector3f& shift);
-
     // Draw everything
     void draw();
 

+ 400 - 0
include/igl/viewer/ViewerCore.cpp

@@ -0,0 +1,400 @@
+#include "ViewerCore.h"
+#include <igl/quat_to_mat.h>
+
+
+Eigen::Matrix4f lookAt (
+                        const Eigen::Vector3f& eye,
+                        const Eigen::Vector3f& center,
+                        const Eigen::Vector3f& up)
+{
+  Eigen::Vector3f f = (center - eye).normalized();
+  Eigen::Vector3f s = f.cross(up).normalized();
+  Eigen::Vector3f u = s.cross(f);
+
+  Eigen::Matrix4f Result = Eigen::Matrix4f::Identity();
+  Result(0,0) = s(0);
+  Result(0,1) = s(1);
+  Result(0,2) = s(2);
+  Result(1,0) = u(0);
+  Result(1,1) = u(1);
+  Result(1,2) = u(2);
+  Result(2,0) =-f(0);
+  Result(2,1) =-f(1);
+  Result(2,2) =-f(2);
+  Result(0,3) =-s.transpose() * eye;
+  Result(1,3) =-u.transpose() * eye;
+  Result(2,3) = f.transpose() * eye;
+  return Result;
+}
+
+Eigen::Matrix4f ortho (
+                       const float left,
+                       const float right,
+                       const float bottom,
+                       const float top,
+                       const float zNear,
+                       const float zFar
+                       )
+{
+  Eigen::Matrix4f Result = Eigen::Matrix4f::Identity();
+  Result(0,0) = 2.0f / (right - left);
+  Result(1,1) = 2.0f / (top - bottom);
+  Result(2,2) = - 2.0f / (zFar - zNear);
+  Result(0,3) = - (right + left) / (right - left);
+  Result(1,3) = - (top + bottom) / (top - bottom);
+  Result(2,3) = - (zFar + zNear) / (zFar - zNear);
+  return Result;
+}
+
+Eigen::Matrix4f frustum (
+                         const float left,
+                         const float right,
+                         const float bottom,
+                         const float top,
+                         const float nearVal,
+                         const float farVal)
+{
+  Eigen::Matrix4f Result = Eigen::Matrix4f::Zero();
+  Result(0,0) = (2.0f * nearVal) / (right - left);
+  Result(1,1) = (2.0f * nearVal) / (top - bottom);
+  Result(0,2) = (right + left) / (right - left);
+  Result(1,2) = (top + bottom) / (top - bottom);
+  Result(2,2) = -(farVal + nearVal) / (farVal - nearVal);
+  Result(3,2) = -1.0f;
+  Result(2,3) = -(2.0f * farVal * nearVal) / (farVal - nearVal);
+  return Result;
+}
+
+Eigen::Matrix4f scale (const Eigen::Matrix4f& m,
+                       const Eigen::Vector3f& v)
+{
+  Eigen::Matrix4f Result;
+  Result.col(0) = m.col(0).array() * v(0);
+  Result.col(1) = m.col(1).array() * v(1);
+  Result.col(2) = m.col(2).array() * v(2);
+  Result.col(3) = m.col(3);
+  return Result;
+}
+
+Eigen::Matrix4f translate(
+                          const Eigen::Matrix4f& m,
+                          const Eigen::Vector3f& v)
+{
+  Eigen::Matrix4f Result = m;
+  Result.col(3) = m.col(0).array() * v(0) + m.col(1).array() * v(1) + m.col(2).array() * v(2) + m.col(3).array();
+  return Result;
+}
+
+
+
+void igl::ViewerCore::InitSerialization()
+{
+  #ifdef ENABLE_XML_SERIALIZATION
+  xmlSerializer->Add(shininess, "shininess");
+  xmlSerializer->Add(background_color, "background_color");
+  xmlSerializer->Add(line_color, "line_color");
+  xmlSerializer->Add(light_position, "light_position");
+  xmlSerializer->Add(lighting_factor, "lighting_factor");
+  xmlSerializer->Add(trackball_angle, "trackball_angle");
+  xmlSerializer->Add(model_zoom, "model_zoom");
+  xmlSerializer->Add(model_translation, "model_translation");
+  xmlSerializer->Add(model_zoom_uv, "model_zoom_uv");
+  xmlSerializer->Add(model_translation_uv, "model_translation_uv");
+  xmlSerializer->Add(camera_zoom, "camera_zoom");
+  xmlSerializer->Add(orthographic, "orthographic");
+  xmlSerializer->Add(camera_eye, "camera_eye");
+  xmlSerializer->Add(camera_up, "camera_up");
+  xmlSerializer->Add(camera_center, "camera_center");
+  xmlSerializer->Add(camera_view_angle, "camera_view_angle");
+  xmlSerializer->Add(camera_dnear, "camera_dnear");
+  xmlSerializer->Add(camera_dfar, "camera_dfar");
+  xmlSerializer->Add(show_overlay, "show_overlay");
+  xmlSerializer->Add(show_overlay_depth, "show_overlay_depth");
+  xmlSerializer->Add(show_texture, "show_texture");
+  xmlSerializer->Add(show_faces, "show_faces");
+  xmlSerializer->Add(show_lines, "show_lines");
+  xmlSerializer->Add(show_vertid, "show_vertid");
+  xmlSerializer->Add(show_faceid, "show_faceid");
+  xmlSerializer->Add(point_size, "point_size");
+  xmlSerializer->Add(line_width, "line_width");
+  xmlSerializer->Add(invert_normals, "invert_normals");
+  xmlSerializer->Add(face_based, "face_based");
+  xmlSerializer->Add(face_based, "object_scale");
+  xmlSerializer->Add(viewport, "viewport");
+  xmlSerializer->Add(view, "view");
+  xmlSerializer->Add(model, "model");
+  xmlSerializer->Add(proj, "proj");
+
+  #endif
+}
+
+IGL_INLINE void igl::ViewerCore::align_camera_center(const Eigen::MatrixXd& V)
+{
+  get_scale_and_shift_to_fit_mesh(V,model_zoom,model_translation);
+  object_scale = (V.colwise().maxCoeff() - V.colwise().minCoeff()).norm();
+}
+
+IGL_INLINE void igl::ViewerCore::get_scale_and_shift_to_fit_mesh(
+  const Eigen::MatrixXd& V,
+  float& zoom,
+  Eigen::Vector3f& shift)
+{
+  if (V.rows() == 0)
+    return;
+
+  Eigen::RowVector3d min_point = V.colwise().minCoeff();
+  Eigen::RowVector3d max_point = V.colwise().maxCoeff();
+  Eigen::RowVector3d centroid  = (max_point.array() + min_point.array())/2;
+
+  shift = -centroid.cast<float>();
+  double x_scale = fabs(max_point[0] - min_point[0]);
+  double y_scale = fabs(max_point[1] - min_point[1]);
+  double z_scale = fabs(max_point[2] - min_point[2]);
+  zoom = 2.0/ std::max(z_scale,std::max(x_scale,y_scale));
+}
+
+IGL_INLINE void igl::ViewerCore::clear_framebuffers()
+{
+  glClearColor(background_color[0],
+               background_color[1],
+               background_color[2],
+               1.0f);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+IGL_INLINE void igl::ViewerCore::draw(ViewerData& data, OpenGL_state& opengl)
+{
+  using namespace std;
+  using namespace Eigen;
+
+  glEnable(GL_DEPTH_TEST);
+
+  /* Bind and potentially refresh mesh/line/point data */
+  if (data.dirty)
+  {
+    opengl.set_data(data, invert_normals);
+    data.dirty = ViewerData::DIRTY_NONE;
+  }
+  opengl.bind_mesh();
+
+  // Initialize uniform
+  glViewport(viewport(0), viewport(1), viewport(2), viewport(3));
+
+  model = Eigen::Matrix4f::Identity();
+  view  = Eigen::Matrix4f::Identity();
+  proj  = Eigen::Matrix4f::Identity();
+
+  // Set view
+  view = lookAt(Eigen::Vector3f(camera_eye[0], camera_eye[1], camera_eye[2]),
+                Eigen::Vector3f(camera_center[0], camera_center[1], camera_center[2]),
+                Eigen::Vector3f(camera_up[0], camera_up[1], camera_up[2]));
+
+  float width  = viewport(2);
+  float height = viewport(3);
+
+  // Set projection
+  if (orthographic)
+  {
+    float length = (camera_eye - camera_center).norm();
+    float h = tan(camera_view_angle/360.0 * M_PI) * (length);
+    proj = ortho(-h*width/height, h*width/height, -h, h, camera_dnear, camera_dfar);
+  }
+  else
+  {
+    float fH = tan(camera_view_angle / 360.0 * M_PI) * camera_dnear;
+    float fW = fH * (double)width/(double)height;
+    proj = frustum(-fW, fW, -fH, fH, camera_dnear, camera_dfar);
+  }
+  // end projection
+
+  // Set model transformation
+  float mat[16];
+  igl::quat_to_mat(trackball_angle.data(), mat);
+
+  for (unsigned i=0;i<4;++i)
+    for (unsigned j=0;j<4;++j)
+      model(i,j) = mat[i+4*j];
+
+  model = scale(model, Eigen::Vector3f(camera_zoom,camera_zoom,camera_zoom));
+  model = scale(model, Eigen::Vector3f(model_zoom,model_zoom,model_zoom));
+  model = translate(model, Eigen::Vector3f(model_translation[0],model_translation[1],model_translation[2]));
+
+  // Send transformations to the GPU
+  GLint modeli = opengl.shader_mesh.uniform("model");
+  GLint viewi  = opengl.shader_mesh.uniform("view");
+  GLint proji  = opengl.shader_mesh.uniform("proj");
+  glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
+  glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
+  glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
+
+  // Light parameters
+  GLint specular_exponenti    = opengl.shader_mesh.uniform("specular_exponent");
+  GLint light_position_worldi = opengl.shader_mesh.uniform("light_position_world");
+  GLint lighting_factori      = opengl.shader_mesh.uniform("lighting_factor");
+  GLint fixed_colori          = opengl.shader_mesh.uniform("fixed_color");
+  GLint texture_factori       = opengl.shader_mesh.uniform("texture_factor");
+
+  glUniform1f(specular_exponenti, shininess);
+  Vector3f rev_light = -1.*light_position;
+  glUniform3fv(light_position_worldi, 1, rev_light.data());
+  glUniform1f(lighting_factori, lighting_factor); // enables lighting
+  glUniform4f(fixed_colori, 0.0, 0.0, 0.0, 0.0);
+
+  if (data.V.rows()>0)
+  {
+    // Render fill
+    if (show_faces)
+    {
+      // Texture
+      glUniform1f(texture_factori, show_texture ? 1.0f : 0.0f);
+      opengl.draw_mesh(true);
+      glUniform1f(texture_factori, 0.0f);
+    }
+
+    // Render wireframe
+    if (show_lines)
+    {
+      glLineWidth(line_width);
+      glUniform4f(fixed_colori, line_color[0], line_color[1],
+        line_color[2], 1.0f);
+      opengl.draw_mesh(false);
+      glUniform4f(fixed_colori, 0.0f, 0.0f, 0.0f, 0.0f);
+    }
+
+    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();
+    }
+  }
+
+  if (show_overlay)
+  {
+    if (show_overlay_depth)
+      glEnable(GL_DEPTH_TEST);
+    else
+      glDisable(GL_DEPTH_TEST);
+
+    if (data.lines.rows() > 0)
+    {
+      opengl.bind_overlay_lines();
+      modeli = opengl.shader_overlay_lines.uniform("model");
+      viewi  = opengl.shader_overlay_lines.uniform("view");
+      proji  = opengl.shader_overlay_lines.uniform("proj");
+
+      glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
+      glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
+      glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
+      // This must be enabled, otherwise glLineWidth has no effect
+      glEnable(GL_LINE_SMOOTH);
+      glLineWidth(line_width);
+
+      opengl.draw_overlay_lines();
+    }
+
+    if (data.points.rows() > 0)
+    {
+      opengl.bind_overlay_points();
+      modeli = opengl.shader_overlay_points.uniform("model");
+      viewi  = opengl.shader_overlay_points.uniform("view");
+      proji  = opengl.shader_overlay_points.uniform("proj");
+
+      glUniformMatrix4fv(modeli, 1, GL_FALSE, model.data());
+      glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
+      glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
+      glPointSize(point_size);
+
+      opengl.draw_overlay_points();
+    }
+
+    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();
+    }
+
+    glEnable(GL_DEPTH_TEST);
+  }
+
+}
+
+IGL_INLINE igl::ViewerCore::ViewerCore()
+#ifdef ENABLE_XML_SERIALIZATION
+: XMLSerialization("Core")
+#endif
+{
+  // Default shininess
+  shininess = 35.0f;
+
+  // Default colors
+  background_color << 0.3f, 0.3f, 0.5f;
+  line_color << 0.0f, 0.0f, 0.0f;
+
+  // Default lights settings
+  light_position << 0.0f, -0.30f, -5.0f;
+  lighting_factor = 1.0f; //on
+
+  // Default trackball
+  trackball_angle << 0.0f, 0.0f, 0.0f, 1.0f;
+
+  // Defalut model viewing parameters
+  model_zoom = 1.0f;
+  model_translation << 0,0,0;
+
+  // Camera parameters
+  camera_zoom = 1.0f;
+  orthographic = false;
+  camera_view_angle = 45.0;
+  camera_dnear = 1.0;
+  camera_dfar = 100.0;
+  camera_eye << 0, 0, 5;
+  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;
+
+  // Default point size / line width
+  point_size = 15;
+  line_width = 0.5f;
+  is_animating = false;
+  animation_max_fps = 30.;
+}
+
+IGL_INLINE void igl::ViewerCore::init()
+{
+  textrenderer.Init();
+}
+
+IGL_INLINE void igl::ViewerCore::shut()
+{
+  textrenderer.Shut();
+}

+ 108 - 0
include/igl/viewer/ViewerCore.h

@@ -0,0 +1,108 @@
+#ifndef IGL_VIEWER_CORE_H
+#define IGL_VIEWER_CORE_H
+
+#include <igl/igl_inline.h>
+#include <igl/viewer/TextRenderer.h>
+
+namespace igl
+{
+
+class ViewerCore
+#ifdef ENABLE_XML_SERIALIZATION
+: public ::igl::XMLSerialization
+#endif
+{
+public:
+  IGL_INLINE ViewerCore();
+
+  IGL_INLINE void init();
+  IGL_INLINE void shut();
+
+
+  IGL_INLINE void InitSerialization();
+
+  IGL_INLINE void align_camera_center(const Eigen::MatrixXd& V); // Adjust the view to see the entire model
+
+  // Determines how much to zoom and shift such that the mesh fills the unit
+  // box (centered at the origin)
+  IGL_INLINE void get_scale_and_shift_to_fit_mesh(
+    const Eigen::MatrixXd& V,
+    float & zoom,
+    Eigen::Vector3f& shift);
+
+  IGL_INLINE void clear_framebuffers();
+
+  // Draw everything
+  IGL_INLINE void draw(ViewerData& data, OpenGL_state& opengl);
+
+  TextRenderer textrenderer;
+
+  // Shape material
+  float shininess;
+
+  // Colors
+  Eigen::Vector3f background_color;
+  Eigen::Vector3f line_color;
+
+  // Lighting
+  Eigen::Vector3f light_position;
+  float lighting_factor;
+
+  // Trackball angle (quaternion)
+  Eigen::Vector4f trackball_angle;
+
+  // Model viewing parameters
+  float model_zoom;
+  Eigen::Vector3f model_translation;
+
+  // Model viewing paramters (uv coordinates)
+  float model_zoom_uv;
+  Eigen::Vector3f model_translation_uv;
+
+  // Camera parameters
+  float camera_zoom;
+  bool orthographic;
+  Eigen::Vector3f camera_eye;
+  Eigen::Vector3f camera_up;
+  Eigen::Vector3f camera_center;
+  float camera_view_angle;
+  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;
+
+  // Point size / line width
+  float point_size;
+  float line_width;
+
+  // Animation
+  bool is_animating;
+  double animation_max_fps;
+
+  // Caches the two-norm between the min/max point of the bounding box
+  float object_scale;
+
+  // Window size
+  Eigen::Vector4f viewport;
+
+  // Save the OpenGL transformation matrices used for the previous rendering pass
+  Eigen::Matrix4f view;
+  Eigen::Matrix4f model;
+  Eigen::Matrix4f proj;
+};
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "ViewerCore.cpp"
+#endif
+
+#endif

+ 1 - 4
include/igl/viewer/ViewerData.h

@@ -17,7 +17,7 @@ public:
   #ifdef ENABLE_XML_SERIALIZATION
   : XMLSerialization("Data"), dirty(DIRTY_ALL)
   #endif
-  {};
+  {clear();};
 
   enum DirtyFlags
   {
@@ -129,9 +129,6 @@ public:
   // Marks dirty buffers that need to be uploaded to OpenGL
   uint32_t dirty;
 
-  // 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;
   /*********************************/