Browse Source

rudimentary support for multiple meshes

Former-commit-id: d5908f8cae2e07f5cc1c44ed554bc1607b0cf59d
Alec Jacobson 8 years ago
parent
commit
d2e89ec1fc

+ 6 - 1
include/igl/opengl/State.cpp

@@ -86,7 +86,7 @@ IGL_INLINE void igl::opengl::State::set_data(
     X_vbo.resize(data.F.rows()*3,3);
     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>();
+        X_vbo.row(i*3+j) = X.row(i).cast<float>().head(3);
   };
 
   // Input:
@@ -366,6 +366,11 @@ IGL_INLINE void igl::opengl::State::draw_overlay_points()
 
 IGL_INLINE void igl::opengl::State::init()
 {
+  if(is_initialized)
+  {
+    return;
+  }
+  is_initialized = true;
   std::string mesh_vertex_shader_string =
   "#version 150\n"
   "uniform mat4 model;"

+ 1 - 0
include/igl/opengl/State.h

@@ -29,6 +29,7 @@ class State
 public:
   typedef unsigned int GLuint;
 
+  bool is_initialized = false;
   GLuint vao_mesh;
   GLuint vao_overlay_lines;
   GLuint vao_overlay_points;

+ 6 - 4
include/igl/opengl/ViewerCore.h

@@ -5,12 +5,12 @@
 // 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>
+#include <igl/opengl/State.h>
 #ifdef IGL_VIEWER_WITH_NANOGUI
-#include <igl/viewer/TextRenderer.h>
+#include <igl/opengl/glfw/TextRenderer.h>
 #endif
 #include <igl/ViewerData.h>
 #include <igl/opengl/State.h>
@@ -74,6 +74,8 @@ public:
   IGL_INLINE void clear_framebuffers();
 
   // Draw everything
+  //
+  // data cannot be const because it is being set to "clean"
   IGL_INLINE void draw(ViewerData& data, State& opengl, bool update_matrices = true);
   IGL_INLINE void draw_buffer(
     ViewerData& data,

+ 276 - 241
include/igl/opengl/glfw/Viewer.cpp

@@ -198,6 +198,145 @@ namespace opengl
 {
 namespace glfw
 {
+
+  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;
+  }
+
+  IGL_INLINE int  Viewer::launch_init(bool resizable,bool fullscreen)
+  {
+    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
+    {
+      window = glfwCreateWindow(1280,800,"libigl viewer",nullptr,nullptr);
+    }
+    if (!window)
+    {
+      glfwTerminate();
+      return EXIT_FAILURE;
+    }
+    glfwMakeContextCurrent(window);
+    #ifndef __APPLE__
+      glewExperimental = true;
+      GLenum err = glewInit();
+      if(GLEW_OK != err)
+      {
+        /* Problem: glewInit failed, something is seriously wrong. */
+       fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
+      }
+      glGetError(); // pull and savely ignonre unhandled errors like GL_INVALID_ENUM
+      fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
+    #endif
+    #if defined(DEBUG) || defined(_DEBUG)
+      int major, minor, rev;
+      major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
+      minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
+      rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);
+      printf("OpenGL version recieved: %d.%d.%d\n", major, minor, rev);
+      printf("Supported OpenGL is %s\n", (const char*)glGetString(GL_VERSION));
+      printf("Supported GLSL is %s\n", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
+    #endif
+    glfwSetInputMode(window,GLFW_CURSOR,GLFW_CURSOR_NORMAL);
+    // Initialize FormScreen
+#ifdef IGL_VIEWER_WITH_NANOGUI
+    screen = new nanogui::Screen();
+    screen->initialize(window, false);
+    ngui = new nanogui::FormHelper(screen);
+#endif
+    __viewer = this;
+    // Register callbacks
+    glfwSetKeyCallback(window, glfw_key_callback);
+    glfwSetCursorPosCallback(window,glfw_mouse_move);
+    glfwSetWindowSizeCallback(window,glfw_window_size);
+    glfwSetMouseButtonCallback(window,glfw_mouse_press);
+    glfwSetScrollCallback(window,glfw_mouse_scroll);
+    glfwSetCharModsCallback(window,glfw_char_mods_callback);
+    glfwSetDropCallback(window,glfw_drop_callback);
+    // Handle retina displays (windows and mac)
+    int width, height;
+    glfwGetFramebufferSize(window, &width, &height);
+    int width_window, height_window;
+    glfwGetWindowSize(window, &width_window, &height_window);
+    highdpi = width/width_window;
+    glfw_window_size(window,width_window,height_window);
+    //opengl.init();
+    core.align_camera_center(selected_data().V,selected_data().F);
+    // Initialize IGL viewer
+    init();
+    return EXIT_SUCCESS;
+  }
+
+  IGL_INLINE bool Viewer::launch_rendering(bool loop)
+  {
+    // glfwMakeContextCurrent(window);
+    // Rendering loop
+    while (!glfwWindowShouldClose(window))
+    {
+      double tic = get_seconds();
+      draw();
+      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;
+  }
+
+  IGL_INLINE void Viewer::launch_shut()
+  {
+    for(auto & opengl : opengl_list)
+    {
+      opengl.free();
+    }
+    core.shut();
+    shutdown_plugins();
+#ifdef IGL_VIEWER_WITH_NANOGUI
+    delete ngui;
+    //delete screen;
+    screen = nullptr;
+    ngui = nullptr;
+#endif
+    glfwDestroyWindow(window);
+    glfwTerminate();
+    return;
+  }
+
   IGL_INLINE void Viewer::init()
   {
 #ifdef IGL_VIEWER_WITH_NANOGUI
@@ -223,7 +362,8 @@ namespace glfw
   #endif
 
     ngui->addGroup("Viewing Options");
-    ngui->addButton("Center object",[&](){this->core.align_camera_center(this->data.V,this->data.F);});
+    ngui->addButton("Center object",[&](){this->core.align_camera_center(
+      this->selected_data().V,this->selected_data().F);});
     ngui->addButton("Snap canonical view",[&]()
     {
       this->snap_to_canonical_quaternion();
@@ -235,17 +375,17 @@ namespace glfw
 
     ngui->addVariable<bool>("Face-based", [&](bool checked)
     {
-      this->data.set_face_based(checked);
+      this->selected_data().set_face_based(checked);
     },[&]()
     {
-      return this->data.face_based;
+      return this->selected_data().face_based;
     });
 
     ngui->addVariable("Show texture",core.show_texture);
 
     ngui->addVariable<bool>("Invert normals",[&](bool checked)
     {
-      this->data.dirty |= ViewerData::DIRTY_NORMAL;
+      this->selected_data().dirty |= ViewerData::DIRTY_NORMAL;
       this->core.invert_normals = checked;
     },[&]()
     {
@@ -277,7 +417,27 @@ namespace glfw
     init_plugins();
   }
 
-  IGL_INLINE Viewer::Viewer()
+  IGL_INLINE void Viewer::init_plugins()
+  {
+    // Init all plugins
+    for (unsigned int i = 0; i<plugins.size(); ++i)
+    {
+      plugins[i]->init(this);
+    }
+  }
+
+  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),
+    opengl_list(1),
+    selected_data_index(0)
   {
 #ifdef IGL_VIEWER_WITH_NANOGUI
     ngui = nullptr;
@@ -290,7 +450,7 @@ namespace glfw
     scroll_position = 0.0f;
 
     // Per face
-    data.set_face_based(false);
+    selected_data().set_face_based(false);
 
     // C-style callbacks
     callback_init         = nullptr;
@@ -324,7 +484,8 @@ namespace glfw
   T,t     Toggle filled faces
   Z       Snap to canonical view
   [,]     Toggle between rotation control types (e.g. trackball, two-axis
-          valuator with fixed up))"
+          valuator with fixed up)
+  <,>     Toggle between models.)"
 #ifdef IGL_VIEWER_WITH_NANOGUI
 		R"(
   ;       Toggle vertex labels
@@ -335,27 +496,10 @@ namespace glfw
 #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()
-  {
-    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);
@@ -369,7 +513,14 @@ namespace glfw
       }
     }
 
-    data.clear();
+    // Create new data slot and set to selected
+    if(!(selected_data().F.rows() == 0  && selected_data().V.rows() == 0))
+    {
+      data_list.emplace_back();
+      opengl_list.emplace_back();
+      selected_data_index = data_list.size()-1;
+    }
+    selected_data().clear();
 
     size_t last_dot = mesh_file_name_string.rfind('.');
     if (last_dot == std::string::npos)
@@ -386,7 +537,7 @@ namespace glfw
       Eigen::MatrixXi F;
       if (!igl::readOFF(mesh_file_name_string, V, F))
         return false;
-      data.set_mesh(V,F);
+      selected_data().set_mesh(V,F);
     }
     else if (extension == "obj" || extension =="OBJ")
     {
@@ -406,8 +557,8 @@ namespace glfw
         return false;
       }
 
-      data.set_mesh(V,F);
-      data.set_uv(UV_V,UV_F);
+      selected_data().set_mesh(V,F);
+      selected_data().set_uv(UV_V,UV_F);
 
     }
     else
@@ -417,16 +568,16 @@ namespace glfw
       return false;
     }
 
-    data.compute_normals();
-    data.uniform_colors(Eigen::Vector3d(51.0/255.0,43.0/255.0,33.3/255.0),
+    selected_data().compute_normals();
+    selected_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 (selected_data().V_uv.rows() == 0)
     {
-      data.grid_texture();
+      selected_data().grid_texture();
     }
 
-    core.align_camera_center(data.V,data.F);
+    core.align_camera_center(selected_data().V,selected_data().F);
 
     for (unsigned int i = 0; i<plugins.size(); ++i)
       if (plugins[i]->post_load())
@@ -454,7 +605,8 @@ namespace glfw
     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,selected_data().V,selected_data().F);
     }
     else if (extension == "obj" || extension =="OBJ")
     {
@@ -464,8 +616,10 @@ namespace glfw
       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, 
+          selected_data().V,
+          selected_data().F, 
+          corner_normals, fNormIndices, UV_V, UV_F);
     }
     else
     {
@@ -501,13 +655,13 @@ namespace glfw
       case 'F':
       case 'f':
       {
-        data.set_face_based(!data.face_based);
+        selected_data().set_face_based(!selected_data().face_based);
         return true;
       }
       case 'I':
       case 'i':
       {
-        data.dirty |= ViewerData::DIRTY_NORMAL;
+        selected_data().dirty |= ViewerData::DIRTY_NORMAL;
         core.invert_normals = !core.invert_normals;
         return true;
       }
@@ -547,6 +701,13 @@ namespace glfw
         }
         return true;
       }
+      case '<':
+      case '>':
+      {
+        selected_data_index = 
+          (selected_data_index + data_list.size() + (unicode_key=='>'?1:-1))%data_list.size();
+        return true;
+      }
 #ifdef IGL_VIEWER_WITH_NANOGUI
       case ';':
         core.show_vertid = !core.show_vertid;
@@ -605,12 +766,12 @@ namespace glfw
 
     // Initialization code for the trackball
     Eigen::RowVector3d center;
-    if (data.V.rows() == 0)
+    if (selected_data().V.rows() == 0)
     {
       center << 0,0,0;
     }else
     {
-      center = data.V.colwise().sum()/data.V.rows();
+      center = selected_data().V.colwise().sum()/selected_data().V.rows();
     }
 
     Eigen::Vector3f coord =
@@ -763,35 +924,29 @@ namespace glfw
     return true;
   }
 
-  IGL_INLINE void Viewer::draw()
+  IGL_INLINE bool Viewer::load_scene()
   {
-    using namespace std;
-    using namespace Eigen;
-
-    core.clear_framebuffers();
-
-    if (callback_pre_draw)
-      if (callback_pre_draw(*this))
-        return;
-
-    for (unsigned int i = 0; i<plugins.size(); ++i)
-      if (plugins[i]->pre_draw())
-        return;
-
-    core.draw(data,opengl);
-
-    if (callback_post_draw)
-      if (callback_post_draw(*this))
-        return;
-
-    for (unsigned int i = 0; i<plugins.size(); ++i)
-      if (plugins[i]->post_draw())
-        break;
+    std::string fname = igl::file_dialog_open();
+    if(fname.length() == 0)
+    {
+      return false;
+    }
+    return load_scene(fname);
+  }
 
-#ifdef IGL_VIEWER_WITH_NANOGUI
-	screen->drawContents();
-	screen->drawWidgets();
+  IGL_INLINE bool Viewer::load_scene(std::string fname)
+  {
+#ifdef ENABLE_SERIALIZATION
+    igl::deserialize(core,"Core",fname.c_str());
+#ifndef ENABLE_SERIALIZATION_CORE_ONLY
+    igl::deserialize(selected_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
 #endif
+    return true;
   }
 
   IGL_INLINE bool Viewer::save_scene()
@@ -805,7 +960,7 @@ namespace glfw
     igl::serialize(core,"Core",fname.c_str(),true);
 
 #ifndef ENABLE_SERIALIZATION_CORE_ONLY
-    igl::serialize(data,"Data",fname.c_str());
+    igl::serialize(selected_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
@@ -815,30 +970,49 @@ namespace glfw
     return true;
   }
 
-  IGL_INLINE bool Viewer::load_scene()
-  {
-    std::string fname = igl::file_dialog_open();
-    if(fname.length() == 0)
-      return false;
-
-    return load_scene(fname);
-  }
-
-  IGL_INLINE bool Viewer::load_scene(std::string fname)
+  IGL_INLINE void Viewer::draw()
   {
-#ifdef ENABLE_SERIALIZATION
-
-    igl::deserialize(core,"Core",fname.c_str());
-
-#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
-
+    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;
+      }
+    }
+    assert(data_list.size() == opengl_list.size());
+    for(int i = 0;i<data_list.size();i++)
+    {
+      opengl_list[i].init();
+      core.draw(data_list[i],opengl_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;
+      }
+    }
+#ifdef IGL_VIEWER_WITH_NANOGUI
+	screen->drawContents();
+	screen->drawWidgets();
 #endif
-
-    return true;
   }
 
   IGL_INLINE void Viewer::resize(int w,int h)
@@ -872,161 +1046,22 @@ namespace glfw
     this->save_mesh_to_file(fname.c_str());
   }
 
-
-  IGL_INLINE int  Viewer::launch_init(bool resizable,bool fullscreen)
-  {
-    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
-    {
-      window = glfwCreateWindow(1280,800,"libigl viewer",nullptr,nullptr);
-    }
-
-    if (!window)
-    {
-      glfwTerminate();
-      return EXIT_FAILURE;
-    }
-
-    glfwMakeContextCurrent(window);
-
-    #ifndef __APPLE__
-      glewExperimental = true;
-      GLenum err = glewInit();
-      if(GLEW_OK != err)
-      {
-        /* Problem: glewInit failed, something is seriously wrong. */
-       fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
-      }
-      glGetError(); // pull and savely ignonre unhandled errors like GL_INVALID_ENUM
-      fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
-    #endif
-
-    #if defined(DEBUG) || defined(_DEBUG)
-      int major, minor, rev;
-      major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
-      minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
-      rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);
-      printf("OpenGL version recieved: %d.%d.%d\n", major, minor, rev);
-      printf("Supported OpenGL is %s\n", (const char*)glGetString(GL_VERSION));
-      printf("Supported GLSL is %s\n", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
-    #endif
-
-    glfwSetInputMode(window,GLFW_CURSOR,GLFW_CURSOR_NORMAL);
-
-    // Initialize FormScreen
-#ifdef IGL_VIEWER_WITH_NANOGUI
-    screen = new nanogui::Screen();
-    screen->initialize(window, false);
-    ngui = new nanogui::FormHelper(screen);
-#endif
-
-    __viewer = this;
-
-    // Register callbacks
-    glfwSetKeyCallback(window, glfw_key_callback);
-    glfwSetCursorPosCallback(window,glfw_mouse_move);
-    glfwSetWindowSizeCallback(window,glfw_window_size);
-    glfwSetMouseButtonCallback(window,glfw_mouse_press);
-    glfwSetScrollCallback(window,glfw_mouse_scroll);
-    glfwSetCharModsCallback(window,glfw_char_mods_callback);
-    glfwSetDropCallback(window,glfw_drop_callback);
-
-    // Handle retina displays (windows and mac)
-    int width, height;
-    glfwGetFramebufferSize(window, &width, &height);
-
-    int width_window, height_window;
-    glfwGetWindowSize(window, &width_window, &height_window);
-
-    highdpi = width/width_window;
-
-    glfw_window_size(window,width_window,height_window);
-
-    opengl.init();
-
-    core.align_camera_center(data.V,data.F);
-
-    // Initialize IGL viewer
-    init();
-    return EXIT_SUCCESS;
-  }
-
-  IGL_INLINE bool Viewer::launch_rendering(bool loop)
-  {
-    // glfwMakeContextCurrent(window);
-
-    // Rendering loop
-    while (!glfwWindowShouldClose(window))
-    {
-      double tic = get_seconds();
-      draw();
-
-      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;
-  }
-
-  IGL_INLINE void Viewer::launch_shut()
+  IGL_INLINE ViewerData& Viewer::selected_data()
   {
-    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(!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 int Viewer::launch(bool resizable,bool fullscreen)
+  IGL_INLINE State& Viewer::selected_opengl()
   {
-    // TODO return values are being ignored...
-    launch_init(resizable,fullscreen);
-    launch_rendering(true);
-    launch_shut();
-    return EXIT_SUCCESS;
+    assert(!opengl_list.empty() && "opengl_list should never be empty");
+    assert(opengl_list.size() == data_list.size());
+    assert(
+      (selected_data_index >= 0 && selected_data_index < opengl_list.size()) && 
+      "selected_data_index should be in bounds");
+    return opengl_list[selected_data_index];
   }
 } // end namespace
 } // end namespace

+ 44 - 57
include/igl/opengl/glfw/Viewer.h

@@ -12,20 +12,20 @@
 #define IGL_OPENGL_4
 #endif
 
-#include <vector>
-#include <string>
-#include <cstdint>
-
-#include <Eigen/Core>
-#include <Eigen/Geometry>
-
-#include <igl/igl_inline.h>
 
+#include "../../igl_inline.h"
 #include "../State.h"
 #include "../ViewerCore.h"
 #include "../../ViewerData.h"
 #include "ViewerPlugin.h"
 
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+#include <vector>
+#include <string>
+#include <cstdint>
+
 #define IGL_MOD_SHIFT           0x0001
 #define IGL_MOD_CONTROL         0x0002
 #define IGL_MOD_ALT             0x0004
@@ -47,86 +47,74 @@ namespace glfw
   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
-    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);
-
     // 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();
-
     // Draw everything
     IGL_INLINE void draw();
-
     // OpenGL context resize
     IGL_INLINE void resize(int w,int h);
-
     // 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& selected_data();
+    //IGL_INLINE const ViewerData& const_selected_data() const;
+    IGL_INLINE State& selected_opengl();
+  private:
+    // 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;
+    // Stores the vbos indices and opengl related settings
+    std::vector<State> opengl_list;
+  public:
+    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;
+#ifdef IGL_VIEWER_WITH_NANOGUI
+    nanogui::FormHelper* ngui;
+    nanogui::Screen* screen;
+#endif
+    // Keep track of the global position of the scrollwheel
+    float scroll_position;
     // C++-style functions
     //
     // Returns **true** if action should be cancelled.
@@ -141,7 +129,6 @@ namespace glfw
     // 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;