Browse Source

- moved all the viewer opengl code and shaders in a reusable external class

Former-commit-id: c01a43f6be8416a91ac2ad9e9d1e79f616679e61
Daniele Panozzo 11 years ago
parent
commit
31d7e4ccb3

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

@@ -0,0 +1,477 @@
+#include "OpenGL_state.h"
+
+IGL_INLINE void igl::OpenGL_state::init_buffers()
+{
+  // Mesh: Vertex Array Object & Buffer objects
+  glGenVertexArrays(1, &vao_mesh);
+  glBindVertexArray(vao_mesh);
+  glGenBuffers(1, &vbo_V);
+  glGenBuffers(1, &vbo_V_normals);
+  glGenBuffers(1, &vbo_V_ambient);
+  glGenBuffers(1, &vbo_V_diffuse);
+  glGenBuffers(1, &vbo_V_specular);
+  glGenBuffers(1, &vbo_V_uv);
+  glGenBuffers(1, &vbo_F);
+  glGenTextures(1, &vbo_tex);
+
+  // Line overlay
+  glGenVertexArrays(1, &vao_overlay_lines);
+  glBindVertexArray(vao_overlay_lines);
+  glGenBuffers(1, &vbo_lines_F);
+  glGenBuffers(1, &vbo_lines_V);
+  glGenBuffers(1, &vbo_lines_V_colors);
+
+  // Point overlay
+  glGenVertexArrays(1, &vao_overlay_points);
+  glBindVertexArray(vao_overlay_points);
+  glGenBuffers(1, &vbo_points_F);
+  glGenBuffers(1, &vbo_points_V);
+  glGenBuffers(1, &vbo_points_V_colors);
+
+  dirty = DIRTY_ALL;
+}
+
+IGL_INLINE void igl::OpenGL_state::free_buffers()
+{
+  glDeleteVertexArrays(1, &vao_mesh);
+  glDeleteVertexArrays(1, &vao_overlay_lines);
+  glDeleteVertexArrays(1, &vao_overlay_points);
+
+  glDeleteBuffers(1, &vbo_V);
+  glDeleteBuffers(1, &vbo_V_normals);
+  glDeleteBuffers(1, &vbo_V_ambient);
+  glDeleteBuffers(1, &vbo_V_diffuse);
+  glDeleteBuffers(1, &vbo_V_specular);
+  glDeleteBuffers(1, &vbo_V_uv);
+  glDeleteBuffers(1, &vbo_F);
+  glDeleteBuffers(1, &vbo_lines_F);
+  glDeleteBuffers(1, &vbo_lines_V);
+  glDeleteBuffers(1, &vbo_lines_V_colors);
+  glDeleteBuffers(1, &vbo_points_F);
+  glDeleteBuffers(1, &vbo_points_V);
+  glDeleteBuffers(1, &vbo_points_V_colors);
+
+  glDeleteTextures(1, &vbo_tex);
+}
+
+IGL_INLINE void igl::OpenGL_state::set_data(const igl::ViewerData &data, bool face_based, 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 (!per_corner_uv)
+    {
+      // Vertex positions
+      if (dirty & DIRTY_POSITION)
+        V_vbo = (data.V.transpose()).cast<float>();
+
+      // Vertex normals
+      if (dirty & DIRTY_NORMAL)
+      {
+        V_normals_vbo = (data.V_normals.transpose()).cast<float>();
+        if (invert_normals)
+          V_normals_vbo = -V_normals_vbo;
+      }
+
+      // Per-vertex material settings
+      if (dirty & DIRTY_AMBIENT)
+        V_ambient_vbo = (data.V_material_ambient.transpose()).cast<float>();
+      if (dirty & DIRTY_DIFFUSE)
+        V_diffuse_vbo = (data.V_material_diffuse.transpose()).cast<float>();
+      if (dirty & DIRTY_SPECULAR)
+        V_specular_vbo = (data.V_material_specular.transpose()).cast<float>();
+
+      // Face indices
+      if (dirty & DIRTY_FACE)
+        F_vbo = (data.F.transpose()).cast<unsigned>();
+
+      // Texture coordinates
+      if (dirty & DIRTY_UV)
+        V_uv_vbo = (data.V_uv.transpose()).cast<float>();
+    }
+    else
+    {
+      // Per vertex properties with per corner UVs
+      if (dirty & DIRTY_POSITION)
+      {
+        V_vbo.resize(3,data.F.rows()*3);
+        for (unsigned i=0; i<data.F.rows();++i)
+          for (unsigned j=0;j<3;++j)
+            V_vbo.col(i*3+j) = data.V.row(data.F(i,j)).transpose().cast<float>();
+      }
+
+      if (dirty & DIRTY_AMBIENT)
+      {
+        V_ambient_vbo.resize(3,data.F.rows()*3);
+        for (unsigned i=0; i<data.F.rows();++i)
+          for (unsigned j=0;j<3;++j)
+            V_ambient_vbo.col (i*3+j) = data.V_material_ambient.row(data.F(i,j)).transpose().cast<float>();
+      }
+
+      if (dirty & DIRTY_DIFFUSE)
+      {
+        V_diffuse_vbo.resize(3,data.F.rows()*3);
+        for (unsigned i=0; i<data.F.rows();++i)
+          for (unsigned j=0;j<3;++j)
+            V_diffuse_vbo.col (i*3+j) = data.V_material_diffuse.row(data.F(i,j)).transpose().cast<float>();
+      }
+
+      if (dirty & DIRTY_SPECULAR)
+      {
+        V_specular_vbo.resize(3,data.F.rows()*3);
+        for (unsigned i=0; i<data.F.rows();++i)
+          for (unsigned j=0;j<3;++j)
+            V_specular_vbo.col(i*3+j) = data.V_material_specular.row(data.F(i,j)).transpose().cast<float>();
+      }
+
+      if (dirty & DIRTY_NORMAL)
+      {
+        V_normals_vbo.resize(3,data.F.rows()*3);
+        for (unsigned i=0; i<data.F.rows();++i)
+          for (unsigned j=0;j<3;++j)
+            V_normals_vbo.col (i*3+j) = data.V_normals.row(data.F(i,j)).transpose().cast<float>();
+
+        if (invert_normals)
+          V_normals_vbo = -V_normals_vbo;
+      }
+
+      if (dirty & 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)
+      {
+        V_uv_vbo.resize(2,data.F.rows()*3);
+        for (unsigned i=0; i<data.F.rows();++i)
+          for (unsigned j=0;j<3;++j)
+            V_uv_vbo.col(i*3+j) = data.V_uv.row(data.F(i,j)).transpose().cast<float>();
+      }
+    }
+  }
+  else
+  {
+    if (dirty & DIRTY_POSITION)
+    {
+      V_vbo.resize(3,data.F.rows()*3);
+      for (unsigned i=0; i<data.F.rows();++i)
+        for (unsigned j=0;j<3;++j)
+          V_vbo.col(i*3+j) = data.V.row(data.F(i,j)).transpose().cast<float>();
+    }
+
+    if (dirty & DIRTY_AMBIENT)
+    {
+      V_ambient_vbo.resize(3,data.F.rows()*3);
+      for (unsigned i=0; i<data.F.rows();++i)
+        for (unsigned j=0;j<3;++j)
+          V_ambient_vbo.col (i*3+j) = data.F_material_ambient.row(i).transpose().cast<float>();
+    }
+
+    if (dirty & DIRTY_DIFFUSE)
+    {
+      V_diffuse_vbo.resize(3,data.F.rows()*3);
+      for (unsigned i=0; i<data.F.rows();++i)
+        for (unsigned j=0;j<3;++j)
+          V_diffuse_vbo.col (i*3+j) = data.F_material_diffuse.row(i).transpose().cast<float>();
+    }
+
+    if (dirty & DIRTY_SPECULAR)
+    {
+      V_specular_vbo.resize(3,data.F.rows()*3);
+      for (unsigned i=0; i<data.F.rows();++i)
+        for (unsigned j=0;j<3;++j)
+          V_specular_vbo.col(i*3+j) = data.F_material_specular.row(i).transpose().cast<float>();
+    }
+
+    if (dirty & DIRTY_NORMAL)
+    {
+      V_normals_vbo.resize(3,data.F.rows()*3);
+      for (unsigned i=0; i<data.F.rows();++i)
+        for (unsigned j=0;j<3;++j)
+          V_normals_vbo.col (i*3+j) =
+             per_corner_normals ?
+               data.F_normals.row(i*3+j).transpose().cast<float>() :
+               data.F_normals.row(i).transpose().cast<float>();
+
+      if (invert_normals)
+        V_normals_vbo = -V_normals_vbo;
+    }
+
+    if (dirty & 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)
+    {
+        V_uv_vbo.resize(2,data.F.rows()*3);
+        for (unsigned i=0; i<data.F.rows();++i)
+          for (unsigned j=0;j<3;++j)
+            V_uv_vbo.col(i*3+j) = data.V_uv.row(per_corner_uv ? data.F_uv(i,j) : data.F(i,j)).transpose().cast<float>();
+    }
+  }
+
+  if (dirty & DIRTY_TEXTURE)
+  {
+    tex_u = data.texture_R.rows();
+    tex_v = data.texture_R.cols();
+    tex.resize(data.texture_R.size()*3);
+    for (unsigned i=0;i<data.texture_R.size();++i)
+    {
+      tex(i*3+0) = data.texture_R(i);
+      tex(i*3+1) = data.texture_G(i);
+      tex(i*3+2) = data.texture_B(i);
+    }
+  }
+
+  if (dirty & DIRTY_OVERLAY_LINES)
+  {
+    lines_V_vbo.resize(3, data.lines.rows()*2);
+    lines_V_colors_vbo.resize(3, data.lines.rows()*2);
+    lines_F_vbo.resize(1, data.lines.rows()*2);
+    for (unsigned i=0; i<data.lines.rows();++i)
+    {
+      lines_V_vbo.col(2*i+0) = data.lines.block<1, 3>(i, 0).transpose().cast<float>();
+      lines_V_vbo.col(2*i+1) = data.lines.block<1, 3>(i, 3).transpose().cast<float>();
+      lines_V_colors_vbo.col(2*i+0) = data.lines.block<1, 3>(i, 6).transpose().cast<float>();
+      lines_V_colors_vbo.col(2*i+1) = data.lines.block<1, 3>(i, 6).transpose().cast<float>();
+      lines_F_vbo(2*i+0) = 2*i+0;
+      lines_F_vbo(2*i+1) = 2*i+1;
+    }
+  }
+
+  if (dirty & DIRTY_OVERLAY_POINTS)
+  {
+    points_V_vbo.resize(3, data.points.rows());
+    points_V_colors_vbo.resize(3, data.points.rows());
+    points_F_vbo.resize(1, data.points.rows());
+    for (unsigned i=0; i<data.points.rows();++i)
+    {
+      points_V_vbo.col(i) = data.points.block<1, 3>(i, 0).transpose().cast<float>();
+      points_V_colors_vbo.col(i) = data.points.block<1, 3>(i, 3).transpose().cast<float>();
+      points_F_vbo(i) = i;
+    }
+  }
+}
+
+IGL_INLINE void igl::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);
+
+  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_F);
+  if (dirty & 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)
+  {
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    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;
+}
+
+IGL_INLINE void igl::OpenGL_state::bind_overlay_lines()
+{
+  bool is_dirty = dirty & DIRTY_OVERLAY_LINES;
+
+  glBindVertexArray(vao_overlay_lines);
+  shader_overlay_lines.bind();
+  shader_overlay_lines.bindVertexAttribArray("position", vbo_lines_V, lines_V_vbo, is_dirty);
+  shader_overlay_lines.bindVertexAttribArray("color", vbo_lines_V_colors, lines_V_colors_vbo, is_dirty);
+
+  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_lines_F);
+  if (is_dirty)
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*lines_F_vbo.size(), lines_F_vbo.data(), GL_DYNAMIC_DRAW);
+
+  dirty &= ~DIRTY_OVERLAY_LINES;
+}
+
+IGL_INLINE void igl::OpenGL_state::bind_overlay_points()
+{
+  bool is_dirty = dirty & DIRTY_OVERLAY_POINTS;
+
+  glBindVertexArray(vao_overlay_points);
+  shader_overlay_points.bind();
+  shader_overlay_points.bindVertexAttribArray("position", vbo_points_V, points_V_vbo, is_dirty);
+  shader_overlay_points.bindVertexAttribArray("color", vbo_points_V_colors, points_V_colors_vbo, is_dirty);
+
+  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_points_F);
+  if (is_dirty)
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*points_F_vbo.size(), points_F_vbo.data(), GL_DYNAMIC_DRAW);
+
+  dirty &= ~DIRTY_OVERLAY_POINTS;
+}
+
+IGL_INLINE void igl::OpenGL_state::draw_mesh(bool solid)
+{
+  glPolygonMode(GL_FRONT_AND_BACK, solid ? GL_FILL : GL_LINE);
+
+  /* Avoid Z-buffer fighting between filled triangles & wireframe lines */
+  if (solid)
+  {
+    glEnable(GL_POLYGON_OFFSET_FILL);
+    glPolygonOffset(1.0, 1.0);
+  }
+  glDrawElements(GL_TRIANGLES, 3*F_vbo.cols(), GL_UNSIGNED_INT, 0);
+
+  glDisable(GL_POLYGON_OFFSET_FILL);
+  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
+
+IGL_INLINE void igl::OpenGL_state::draw_overlay_lines()
+{
+  glDrawElements(GL_LINES, lines_F_vbo.cols(), GL_UNSIGNED_INT, 0);
+}
+
+IGL_INLINE void igl::OpenGL_state::draw_overlay_points()
+{
+  glDrawElements(GL_POINTS, points_F_vbo.cols(), GL_UNSIGNED_INT, 0);
+}
+
+IGL_INLINE void igl::OpenGL_state::init()
+{
+  std::string mesh_vertex_shader_string =
+  "#version 150\n"
+  "uniform mat4 model;"
+  "uniform mat4 view;"
+  "uniform mat4 proj;"
+  "in vec3 position;"
+  "in vec3 normal;"
+  "out vec3 position_eye;"
+  "out vec3 normal_eye;"
+  "in vec3 Ka;"
+  "in vec3 Kd;"
+  "in vec3 Ks;"
+  "in vec2 texcoord;"
+  "out vec2 texcoordi;"
+  "out vec3 Kai;"
+  "out vec3 Kdi;"
+  "out vec3 Ksi;"
+
+  "void main()"
+  "{"
+  "  position_eye = vec3 (view * model * vec4 (position, 1.0));"
+  "  normal_eye = vec3 (view * model * vec4 (normal, 0.0));"
+  "  normal_eye = normalize(normal_eye);"
+  "  gl_Position = proj * vec4 (position_eye, 1.0);" //proj * view * model * vec4(position, 1.0);"
+  "  Kai = Ka;"
+  "  Kdi = Kd;"
+  "  Ksi = Ks;"
+  "  texcoordi = texcoord;"
+  "}";
+
+  std::string mesh_fragment_shader_string =
+  "#version 150\n"
+  "uniform mat4 model;"
+  "uniform mat4 view;"
+  "uniform mat4 proj;"
+  "uniform vec4 fixed_color;"
+  "in vec3 position_eye;"
+  "in vec3 normal_eye;"
+  "uniform vec3 light_position_world;"
+  "vec3 Ls = vec3 (1, 1, 1);"
+  "vec3 Ld = vec3 (1, 1, 1);"
+  "vec3 La = vec3 (1, 1, 1);"
+  "in vec3 Ksi;"
+  "in vec3 Kdi;"
+  "in vec3 Kai;"
+  "in vec2 texcoordi;"
+  "uniform sampler2D tex;"
+  "uniform float specular_exponent;"
+  "uniform float lighting_factor;"
+  "uniform float texture_factor;"
+  "out vec4 outColor;"
+  "void main()"
+  "{"
+  "vec3 Ia = La * Kai;"    // ambient intensity
+
+  "vec3 light_position_eye = vec3 (view * vec4 (light_position_world, 1.0));"
+  "vec3 distance_to_light_eye = light_position_eye - position_eye;"
+  "vec3 direction_to_light_eye = normalize (distance_to_light_eye);"
+  "float dot_prod = dot (direction_to_light_eye, normal_eye);"
+  "dot_prod = max (dot_prod, 0.0);"
+  "vec3 Id = Ld * Kdi * dot_prod;"    // Diffuse intensity
+
+  "vec3 reflection_eye = reflect (-direction_to_light_eye, normal_eye);"
+  "vec3 surface_to_viewer_eye = normalize (-position_eye);"
+  "float dot_prod_specular = dot (reflection_eye, surface_to_viewer_eye);"
+  "dot_prod_specular = max (dot_prod_specular, 0.0);"
+  "float specular_factor = pow (dot_prod_specular, specular_exponent);"
+  "vec3 Is = Ls * Ksi * specular_factor;"    // specular intensity
+  "vec4 color = vec4(lighting_factor * (Is + Id) + Ia, 1.0) + vec4((1.0-lighting_factor) * Kdi,1.0);"
+  "outColor = mix(vec4(1,1,1,1), texture(tex, texcoordi), texture_factor) * color;"
+  "if (fixed_color != vec4(0.0)) outColor = fixed_color;"
+  "}";
+
+  std::string overlay_vertex_shader_string =
+  "#version 150\n"
+  "uniform mat4 model;"
+  "uniform mat4 view;"
+  "uniform mat4 proj;"
+  "in vec3 position;"
+  "in vec3 color;"
+  "out vec3 color_frag;"
+
+  "void main()"
+  "{"
+  "  gl_Position = proj * view * model * vec4 (position, 1.0);"
+  "  color_frag = color;"
+  "}";
+
+  std::string overlay_fragment_shader_string =
+  "#version 150\n"
+  "in vec3 color_frag;"
+  "out vec4 outColor;"
+  "void main()"
+  "{"
+  "  outColor = vec4(color_frag, 1.0);"
+  "}";
+
+  std::string overlay_point_fragment_shader_string =
+  "#version 150\n"
+  "in vec3 color_frag;"
+  "out vec4 outColor;"
+  "void main()"
+  "{"
+  "  if (length(gl_PointCoord - vec2(0.5)) > 0.5)"
+  "    discard;"
+  "  outColor = vec4(color_frag, 1.0);"
+  "}";
+
+  init_buffers();
+  shader_mesh.init(mesh_vertex_shader_string,
+      mesh_fragment_shader_string, "outColor");
+  shader_overlay_lines.init(overlay_vertex_shader_string,
+      overlay_fragment_shader_string, "outColor");
+  shader_overlay_points.init(overlay_vertex_shader_string,
+      overlay_point_fragment_shader_string, "outColor");
+}
+
+IGL_INLINE void igl::OpenGL_state::free()
+{
+  shader_mesh.free();
+  shader_overlay_lines.free();
+  shader_overlay_points.free();
+  free_buffers();
+}

+ 123 - 0
include/igl/viewer/OpenGL_state.h

@@ -0,0 +1,123 @@
+#ifndef IGL_OPENGL_STATE_H
+#define IGL_OPENGL_STATE_H
+
+// Coverts mesh data inside a igl::ViewerData class in an OpenGL compatible format
+// The class includes a shader and the opengl calls to plot the data
+
+#include <igl/igl_inline.h>
+#include <igl/viewer/OpenGL_shader.h>
+
+namespace igl
+{
+
+class OpenGL_state
+{
+public:
+  typedef unsigned int GLuint;
+
+  GLuint vao_mesh;
+  GLuint vao_overlay_lines;
+  GLuint vao_overlay_points;
+  OpenGL_shader shader_mesh;
+  OpenGL_shader shader_overlay_lines;
+  OpenGL_shader shader_overlay_points;
+
+  GLuint vbo_V; // Vertices of the current mesh (#V x 3)
+  GLuint vbo_V_uv; // UV coordinates for the current mesh (#V x 2)
+  GLuint vbo_V_normals; // Vertices of the current mesh (#V x 3)
+  GLuint vbo_V_ambient; // Ambient material  (#V x 3)
+  GLuint vbo_V_diffuse; // Diffuse material  (#V x 3)
+  GLuint vbo_V_specular; // Specular material  (#V x 3)
+
+  GLuint vbo_F; // Faces of the mesh (#F x 3)
+  GLuint vbo_tex; // Texture
+
+  GLuint vbo_lines_F;         // Indices of the line overlay
+  GLuint vbo_lines_V;         // Vertices of the line overlay
+  GLuint vbo_lines_V_colors;  // Color values of the line overlay
+  GLuint vbo_points_F;        // Indices of the point overlay
+  GLuint vbo_points_V;        // Vertices of the point overlay
+  GLuint vbo_points_V_colors; // Color values of the point overlay
+
+  // Temporary copy of the content of each VBO
+  Eigen::MatrixXf V_vbo;
+  Eigen::MatrixXf V_normals_vbo;
+  Eigen::MatrixXf V_ambient_vbo;
+  Eigen::MatrixXf V_diffuse_vbo;
+  Eigen::MatrixXf V_specular_vbo;
+  Eigen::MatrixXf V_uv_vbo;
+  Eigen::MatrixXf lines_V_vbo;
+  Eigen::MatrixXf lines_V_colors_vbo;
+  Eigen::MatrixXf points_V_vbo;
+  Eigen::MatrixXf points_V_colors_vbo;
+
+  int tex_u;
+  int tex_v;
+  Eigen::Matrix<char,Eigen::Dynamic,1> tex;
+
+  Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic> F_vbo;
+  Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic> lines_F_vbo;
+  Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic> points_F_vbo;
+
+  // Marks dirty buffers that need to be uploaded to OpenGL
+  uint32_t dirty;
+
+  // Initialize shaders and buffers
+  IGL_INLINE void init();
+
+  // Release all resources
+  IGL_INLINE void free();
+
+  // Create a new set of OpenGL buffer objects
+  IGL_INLINE void init_buffers();
+
+  // Update contents from a 'Data' instance
+  IGL_INLINE void set_data(const igl::ViewerData &data, bool face_based, bool invert_normals);
+
+  // Bind the underlying OpenGL buffer objects for subsequent mesh draw calls
+  IGL_INLINE void bind_mesh();
+
+  /// Draw the currently buffered mesh (either solid or wireframe)
+  IGL_INLINE void draw_mesh(bool solid);
+
+  // Bind the underlying OpenGL buffer objects for subsequent line overlay draw calls
+  IGL_INLINE void bind_overlay_lines();
+
+  /// Draw the currently buffered line overlay
+  IGL_INLINE void draw_overlay_lines();
+
+  // Bind the underlying OpenGL buffer objects for subsequent point overlay draw calls
+  IGL_INLINE void bind_overlay_points();
+
+  /// Draw the currently buffered point overlay
+  IGL_INLINE void draw_overlay_points();
+
+  // 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
+  };
+
+};
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "OpenGL_state.cpp"
+#endif
+
+#endif

+ 21 - 496
include/igl/viewer/Viewer.cpp

@@ -665,7 +665,7 @@ namespace igl
   {
   {
     igl::per_face_normals(data.V, data.F, data.F_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);
     igl::per_vertex_normals(data.V, data.F, data.F_normals, data.V_normals);
-    data.dirty |= DIRTY_NORMAL;
+    data.dirty |= OpenGL_state::DIRTY_NORMAL;
   }
   }
 
 
   void Viewer::uniform_colors(Eigen::Vector3d ambient, Eigen::Vector3d diffuse, Eigen::Vector3d specular)
   void Viewer::uniform_colors(Eigen::Vector3d ambient, Eigen::Vector3d diffuse, Eigen::Vector3d specular)
@@ -691,7 +691,7 @@ namespace igl
       data.F_material_diffuse.row(i) = diffuse;
       data.F_material_diffuse.row(i) = diffuse;
       data.F_material_specular.row(i) = specular;
       data.F_material_specular.row(i) = specular;
     }
     }
-    data.dirty |= DIRTY_SPECULAR | DIRTY_DIFFUSE | DIRTY_AMBIENT;
+    data.dirty |= OpenGL_state::DIRTY_SPECULAR | OpenGL_state::DIRTY_DIFFUSE | OpenGL_state::DIRTY_AMBIENT;
   }
   }
 
 
   void Viewer::grid_texture()
   void Viewer::grid_texture()
@@ -704,7 +704,7 @@ namespace igl
       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).minCoeff();
       data.V_uv.col(1) = data.V_uv.col(1).array() / data.V_uv.col(1).maxCoeff();
       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.V_uv = data.V_uv.array() * 10;
-      data.dirty |= DIRTY_TEXTURE;
+      data.dirty |= OpenGL_state::DIRTY_TEXTURE;
     }
     }
 
 
     unsigned size = 128;
     unsigned size = 128;
@@ -722,7 +722,7 @@ namespace igl
 
 
     data.texture_G = data.texture_R;
     data.texture_G = data.texture_R;
     data.texture_B = data.texture_R;
     data.texture_B = data.texture_R;
-    data.dirty |= DIRTY_TEXTURE;
+    data.dirty |= OpenGL_state::DIRTY_TEXTURE;
   }
   }
 
 
   bool Viewer::save_mesh_to_file(const char* mesh_file_name)
   bool Viewer::save_mesh_to_file(const char* mesh_file_name)
@@ -988,483 +988,6 @@ namespace igl
     return true;
     return true;
   }
   }
 
 
-  void Viewer::OpenGL_state::init()
-  {
-    // Mesh: Vertex Array Object & Buffer objects
-    glGenVertexArrays(1, &vao_mesh);
-    glBindVertexArray(vao_mesh);
-    glGenBuffers(1, &vbo_V);
-    glGenBuffers(1, &vbo_V_normals);
-    glGenBuffers(1, &vbo_V_ambient);
-    glGenBuffers(1, &vbo_V_diffuse);
-    glGenBuffers(1, &vbo_V_specular);
-    glGenBuffers(1, &vbo_V_uv);
-    glGenBuffers(1, &vbo_F);
-    glGenTextures(1, &vbo_tex);
-
-    // Line overlay
-    glGenVertexArrays(1, &vao_overlay_lines);
-    glBindVertexArray(vao_overlay_lines);
-    glGenBuffers(1, &vbo_lines_F);
-    glGenBuffers(1, &vbo_lines_V);
-    glGenBuffers(1, &vbo_lines_V_colors);
-
-    // Point overlay
-    glGenVertexArrays(1, &vao_overlay_points);
-    glBindVertexArray(vao_overlay_points);
-    glGenBuffers(1, &vbo_points_F);
-    glGenBuffers(1, &vbo_points_V);
-    glGenBuffers(1, &vbo_points_V_colors);
-
-    dirty = DIRTY_ALL;
-  }
-
-  void Viewer::OpenGL_state::free()
-  {
-    glDeleteVertexArrays(1, &vao_mesh);
-    glDeleteVertexArrays(1, &vao_overlay_lines);
-    glDeleteVertexArrays(1, &vao_overlay_points);
-
-    glDeleteBuffers(1, &vbo_V);
-    glDeleteBuffers(1, &vbo_V_normals);
-    glDeleteBuffers(1, &vbo_V_ambient);
-    glDeleteBuffers(1, &vbo_V_diffuse);
-    glDeleteBuffers(1, &vbo_V_specular);
-    glDeleteBuffers(1, &vbo_V_uv);
-    glDeleteBuffers(1, &vbo_F);
-    glDeleteBuffers(1, &vbo_lines_F);
-    glDeleteBuffers(1, &vbo_lines_V);
-    glDeleteBuffers(1, &vbo_lines_V_colors);
-    glDeleteBuffers(1, &vbo_points_F);
-    glDeleteBuffers(1, &vbo_points_V);
-    glDeleteBuffers(1, &vbo_points_V_colors);
-
-    glDeleteTextures(1, &vbo_tex);
-  }
-
-  void Viewer::OpenGL_state::set_data(const igl::ViewerData &data, bool face_based, 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 (!per_corner_uv)
-      {
-        // Vertex positions
-        if (dirty & DIRTY_POSITION)
-          V_vbo = (data.V.transpose()).cast<float>();
-
-        // Vertex normals
-        if (dirty & DIRTY_NORMAL)
-        {
-          V_normals_vbo = (data.V_normals.transpose()).cast<float>();
-          if (invert_normals)
-            V_normals_vbo = -V_normals_vbo;
-        }
-
-        // Per-vertex material settings
-        if (dirty & DIRTY_AMBIENT)
-          V_ambient_vbo = (data.V_material_ambient.transpose()).cast<float>();
-        if (dirty & DIRTY_DIFFUSE)
-          V_diffuse_vbo = (data.V_material_diffuse.transpose()).cast<float>();
-        if (dirty & DIRTY_SPECULAR)
-          V_specular_vbo = (data.V_material_specular.transpose()).cast<float>();
-
-        // Face indices
-        if (dirty & DIRTY_FACE)
-          F_vbo = (data.F.transpose()).cast<unsigned>();
-
-        // Texture coordinates
-        if (dirty & DIRTY_UV)
-          V_uv_vbo = (data.V_uv.transpose()).cast<float>();
-      }
-      else
-      {
-        // Per vertex properties with per corner UVs
-        if (dirty & DIRTY_POSITION)
-        {
-          V_vbo.resize(3,data.F.rows()*3);
-          for (unsigned i=0; i<data.F.rows();++i)
-            for (unsigned j=0;j<3;++j)
-              V_vbo.col(i*3+j) = data.V.row(data.F(i,j)).transpose().cast<float>();
-        }
-
-        if (dirty & DIRTY_AMBIENT)
-        {
-          V_ambient_vbo.resize(3,data.F.rows()*3);
-          for (unsigned i=0; i<data.F.rows();++i)
-            for (unsigned j=0;j<3;++j)
-              V_ambient_vbo.col (i*3+j) = data.V_material_ambient.row(data.F(i,j)).transpose().cast<float>();
-        }
-
-        if (dirty & DIRTY_DIFFUSE)
-        {
-          V_diffuse_vbo.resize(3,data.F.rows()*3);
-          for (unsigned i=0; i<data.F.rows();++i)
-            for (unsigned j=0;j<3;++j)
-              V_diffuse_vbo.col (i*3+j) = data.V_material_diffuse.row(data.F(i,j)).transpose().cast<float>();
-        }
-
-        if (dirty & DIRTY_SPECULAR)
-        {
-          V_specular_vbo.resize(3,data.F.rows()*3);
-          for (unsigned i=0; i<data.F.rows();++i)
-            for (unsigned j=0;j<3;++j)
-              V_specular_vbo.col(i*3+j) = data.V_material_specular.row(data.F(i,j)).transpose().cast<float>();
-        }
-
-        if (dirty & DIRTY_NORMAL)
-        {
-          V_normals_vbo.resize(3,data.F.rows()*3);
-          for (unsigned i=0; i<data.F.rows();++i)
-            for (unsigned j=0;j<3;++j)
-              V_normals_vbo.col (i*3+j) = data.V_normals.row(data.F(i,j)).transpose().cast<float>();
-
-          if (invert_normals)
-            V_normals_vbo = -V_normals_vbo;
-        }
-
-        if (dirty & 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)
-        {
-          V_uv_vbo.resize(2,data.F.rows()*3);
-          for (unsigned i=0; i<data.F.rows();++i)
-            for (unsigned j=0;j<3;++j)
-              V_uv_vbo.col(i*3+j) = data.V_uv.row(data.F(i,j)).transpose().cast<float>();
-        }
-      }
-    }
-    else
-    {
-      if (dirty & DIRTY_POSITION)
-      {
-        V_vbo.resize(3,data.F.rows()*3);
-        for (unsigned i=0; i<data.F.rows();++i)
-          for (unsigned j=0;j<3;++j)
-            V_vbo.col(i*3+j) = data.V.row(data.F(i,j)).transpose().cast<float>();
-      }
-
-      if (dirty & DIRTY_AMBIENT)
-      {
-        V_ambient_vbo.resize(3,data.F.rows()*3);
-        for (unsigned i=0; i<data.F.rows();++i)
-          for (unsigned j=0;j<3;++j)
-            V_ambient_vbo.col (i*3+j) = data.F_material_ambient.row(i).transpose().cast<float>();
-      }
-
-      if (dirty & DIRTY_DIFFUSE)
-      {
-        V_diffuse_vbo.resize(3,data.F.rows()*3);
-        for (unsigned i=0; i<data.F.rows();++i)
-          for (unsigned j=0;j<3;++j)
-            V_diffuse_vbo.col (i*3+j) = data.F_material_diffuse.row(i).transpose().cast<float>();
-      }
-
-      if (dirty & DIRTY_SPECULAR)
-      {
-        V_specular_vbo.resize(3,data.F.rows()*3);
-        for (unsigned i=0; i<data.F.rows();++i)
-          for (unsigned j=0;j<3;++j)
-            V_specular_vbo.col(i*3+j) = data.F_material_specular.row(i).transpose().cast<float>();
-      }
-
-      if (dirty & DIRTY_NORMAL)
-      {
-        V_normals_vbo.resize(3,data.F.rows()*3);
-        for (unsigned i=0; i<data.F.rows();++i)
-          for (unsigned j=0;j<3;++j)
-            V_normals_vbo.col (i*3+j) =
-               per_corner_normals ?
-                 data.F_normals.row(i*3+j).transpose().cast<float>() :
-                 data.F_normals.row(i).transpose().cast<float>();
-
-        if (invert_normals)
-          V_normals_vbo = -V_normals_vbo;
-      }
-
-      if (dirty & 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)
-      {
-          V_uv_vbo.resize(2,data.F.rows()*3);
-          for (unsigned i=0; i<data.F.rows();++i)
-            for (unsigned j=0;j<3;++j)
-              V_uv_vbo.col(i*3+j) = data.V_uv.row(per_corner_uv ? data.F_uv(i,j) : data.F(i,j)).transpose().cast<float>();
-      }
-    }
-
-    if (dirty & DIRTY_TEXTURE)
-    {
-      tex_u = data.texture_R.rows();
-      tex_v = data.texture_R.cols();
-      tex.resize(data.texture_R.size()*3);
-      for (unsigned i=0;i<data.texture_R.size();++i)
-      {
-        tex(i*3+0) = data.texture_R(i);
-        tex(i*3+1) = data.texture_G(i);
-        tex(i*3+2) = data.texture_B(i);
-      }
-    }
-
-    if (dirty & DIRTY_OVERLAY_LINES)
-    {
-      lines_V_vbo.resize(3, data.lines.rows()*2);
-      lines_V_colors_vbo.resize(3, data.lines.rows()*2);
-      lines_F_vbo.resize(1, data.lines.rows()*2);
-      for (unsigned i=0; i<data.lines.rows();++i)
-      {
-        lines_V_vbo.col(2*i+0) = data.lines.block<1, 3>(i, 0).transpose().cast<float>();
-        lines_V_vbo.col(2*i+1) = data.lines.block<1, 3>(i, 3).transpose().cast<float>();
-        lines_V_colors_vbo.col(2*i+0) = data.lines.block<1, 3>(i, 6).transpose().cast<float>();
-        lines_V_colors_vbo.col(2*i+1) = data.lines.block<1, 3>(i, 6).transpose().cast<float>();
-        lines_F_vbo(2*i+0) = 2*i+0;
-        lines_F_vbo(2*i+1) = 2*i+1;
-      }
-    }
-
-    if (dirty & DIRTY_OVERLAY_POINTS)
-    {
-      points_V_vbo.resize(3, data.points.rows());
-      points_V_colors_vbo.resize(3, data.points.rows());
-      points_F_vbo.resize(1, data.points.rows());
-      for (unsigned i=0; i<data.points.rows();++i)
-      {
-        points_V_vbo.col(i) = data.points.block<1, 3>(i, 0).transpose().cast<float>();
-        points_V_colors_vbo.col(i) = data.points.block<1, 3>(i, 3).transpose().cast<float>();
-        points_F_vbo(i) = i;
-      }
-    }
-  }
-
-  void Viewer::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);
-
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_F);
-    if (dirty & 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)
-    {
-      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-      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;
-  }
-
-  void Viewer::OpenGL_state::bind_overlay_lines()
-  {
-    bool is_dirty = dirty & DIRTY_OVERLAY_LINES;
-
-    glBindVertexArray(vao_overlay_lines);
-    shader_overlay_lines.bind();
-    shader_overlay_lines.bindVertexAttribArray("position", vbo_lines_V, lines_V_vbo, is_dirty);
-    shader_overlay_lines.bindVertexAttribArray("color", vbo_lines_V_colors, lines_V_colors_vbo, is_dirty);
-
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_lines_F);
-    if (is_dirty)
-      glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*lines_F_vbo.size(), lines_F_vbo.data(), GL_DYNAMIC_DRAW);
-
-    dirty &= ~DIRTY_OVERLAY_LINES;
-  }
-
-  void Viewer::OpenGL_state::bind_overlay_points()
-  {
-    bool is_dirty = dirty & DIRTY_OVERLAY_POINTS;
-
-    glBindVertexArray(vao_overlay_points);
-    shader_overlay_points.bind();
-    shader_overlay_points.bindVertexAttribArray("position", vbo_points_V, points_V_vbo, is_dirty);
-    shader_overlay_points.bindVertexAttribArray("color", vbo_points_V_colors, points_V_colors_vbo, is_dirty);
-
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_points_F);
-    if (is_dirty)
-      glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*points_F_vbo.size(), points_F_vbo.data(), GL_DYNAMIC_DRAW);
-
-    dirty &= ~DIRTY_OVERLAY_POINTS;
-  }
-
-  void Viewer::OpenGL_state::draw_mesh(bool solid)
-  {
-    glPolygonMode(GL_FRONT_AND_BACK, solid ? GL_FILL : GL_LINE);
-
-    /* Avoid Z-buffer fighting between filled triangles & wireframe lines */
-    if (solid)
-    {
-      glEnable(GL_POLYGON_OFFSET_FILL);
-      glPolygonOffset(1.0, 1.0);
-    }
-    glDrawElements(GL_TRIANGLES, 3*F_vbo.cols(), GL_UNSIGNED_INT, 0);
-
-    glDisable(GL_POLYGON_OFFSET_FILL);
-    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-  }
-
-  void Viewer::OpenGL_state::draw_overlay_lines()
-  {
-    glDrawElements(GL_LINES, lines_F_vbo.cols(), GL_UNSIGNED_INT, 0);
-  }
-
-  void Viewer::OpenGL_state::draw_overlay_points()
-  {
-    glDrawElements(GL_POINTS, points_F_vbo.cols(), GL_UNSIGNED_INT, 0);
-  }
-
-  void Viewer::init_opengl()
-  {
-    std::string mesh_vertex_shader_string =
-    "#version 150\n"
-    "uniform mat4 model;"
-    "uniform mat4 view;"
-    "uniform mat4 proj;"
-    "in vec3 position;"
-    "in vec3 normal;"
-    "out vec3 position_eye;"
-    "out vec3 normal_eye;"
-    "in vec3 Ka;"
-    "in vec3 Kd;"
-    "in vec3 Ks;"
-    "in vec2 texcoord;"
-    "out vec2 texcoordi;"
-    "out vec3 Kai;"
-    "out vec3 Kdi;"
-    "out vec3 Ksi;"
-
-    "void main()"
-    "{"
-    "  position_eye = vec3 (view * model * vec4 (position, 1.0));"
-    "  normal_eye = vec3 (view * model * vec4 (normal, 0.0));"
-    "  normal_eye = normalize(normal_eye);"
-    "  gl_Position = proj * vec4 (position_eye, 1.0);" //proj * view * model * vec4(position, 1.0);"
-    "  Kai = Ka;"
-    "  Kdi = Kd;"
-    "  Ksi = Ks;"
-    "  texcoordi = texcoord;"
-    "}";
-
-    std::string mesh_fragment_shader_string =
-    "#version 150\n"
-    "uniform mat4 model;"
-    "uniform mat4 view;"
-    "uniform mat4 proj;"
-    "uniform vec4 fixed_color;"
-    "in vec3 position_eye;"
-    "in vec3 normal_eye;"
-    "uniform vec3 light_position_world;"
-    "vec3 Ls = vec3 (1, 1, 1);"
-    "vec3 Ld = vec3 (1, 1, 1);"
-    "vec3 La = vec3 (1, 1, 1);"
-    "in vec3 Ksi;"
-    "in vec3 Kdi;"
-    "in vec3 Kai;"
-    "in vec2 texcoordi;"
-    "uniform sampler2D tex;"
-    "uniform float specular_exponent;"
-    "uniform float lighting_factor;"
-    "uniform float texture_factor;"
-    "out vec4 outColor;"
-    "void main()"
-    "{"
-    "vec3 Ia = La * Kai;"    // ambient intensity
-
-    "vec3 light_position_eye = vec3 (view * vec4 (light_position_world, 1.0));"
-    "vec3 distance_to_light_eye = light_position_eye - position_eye;"
-    "vec3 direction_to_light_eye = normalize (distance_to_light_eye);"
-    "float dot_prod = dot (direction_to_light_eye, normal_eye);"
-    "dot_prod = max (dot_prod, 0.0);"
-    "vec3 Id = Ld * Kdi * dot_prod;"    // Diffuse intensity
-
-    "vec3 reflection_eye = reflect (-direction_to_light_eye, normal_eye);"
-    "vec3 surface_to_viewer_eye = normalize (-position_eye);"
-    "float dot_prod_specular = dot (reflection_eye, surface_to_viewer_eye);"
-    "dot_prod_specular = max (dot_prod_specular, 0.0);"
-    "float specular_factor = pow (dot_prod_specular, specular_exponent);"
-    "vec3 Is = Ls * Ksi * specular_factor;"    // specular intensity
-    "vec4 color = vec4(lighting_factor * (Is + Id) + Ia, 1.0) + vec4((1.0-lighting_factor) * Kdi,1.0);"
-    "outColor = mix(vec4(1,1,1,1), texture(tex, texcoordi), texture_factor) * color;"
-    "if (fixed_color != vec4(0.0)) outColor = fixed_color;"
-    "}";
-
-    std::string overlay_vertex_shader_string =
-    "#version 150\n"
-    "uniform mat4 model;"
-    "uniform mat4 view;"
-    "uniform mat4 proj;"
-    "in vec3 position;"
-    "in vec3 color;"
-    "out vec3 color_frag;"
-
-    "void main()"
-    "{"
-    "  gl_Position = proj * view * model * vec4 (position, 1.0);"
-    "  color_frag = color;"
-    "}";
-
-    std::string overlay_fragment_shader_string =
-    "#version 150\n"
-    "in vec3 color_frag;"
-    "out vec4 outColor;"
-    "void main()"
-    "{"
-    "  outColor = vec4(color_frag, 1.0);"
-    "}";
-
-    std::string overlay_point_fragment_shader_string =
-    "#version 150\n"
-    "in vec3 color_frag;"
-    "out vec4 outColor;"
-    "void main()"
-    "{"
-    "  if (length(gl_PointCoord - vec2(0.5)) > 0.5)"
-    "    discard;"
-    "  outColor = vec4(color_frag, 1.0);"
-    "}";
-
-    opengl.init();
-    opengl.shader_mesh.init(mesh_vertex_shader_string,
-        mesh_fragment_shader_string, "outColor");
-    opengl.shader_overlay_lines.init(overlay_vertex_shader_string,
-        overlay_fragment_shader_string, "outColor");
-    opengl.shader_overlay_points.init(overlay_vertex_shader_string,
-        overlay_point_fragment_shader_string, "outColor");
-  }
-
-  void Viewer::free_opengl()
-  {
-    opengl.shader_mesh.free();
-    opengl.shader_overlay_lines.free();
-    opengl.shader_overlay_points.free();
-    opengl.free();
-    __font_renderer.Shut();
-  }
-
   void Viewer::draw()
   void Viewer::draw()
   {
   {
     using namespace std;
     using namespace std;
@@ -1489,7 +1012,7 @@ namespace igl
     if (data.dirty)
     if (data.dirty)
     {
     {
       opengl.set_data(data, options.face_based, options.invert_normals);
       opengl.set_data(data, options.face_based, options.invert_normals);
-      data.dirty = DIRTY_NONE;
+      data.dirty = OpenGL_state::DIRTY_NONE;
     }
     }
     opengl.bind_mesh();
     opengl.bind_mesh();
 
 
@@ -1762,7 +1285,7 @@ namespace igl
   void TW_CALL Viewer::set_invert_normals_cb(const void *param, void *clientData)
   void TW_CALL Viewer::set_invert_normals_cb(const void *param, void *clientData)
   {
   {
     Viewer *viewer = static_cast<Viewer *>(clientData);
     Viewer *viewer = static_cast<Viewer *>(clientData);
-    viewer->data.dirty |= Viewer::DIRTY_NORMAL;
+    viewer->data.dirty |= OpenGL_state::DIRTY_NORMAL;
     viewer->options.invert_normals = *((bool *) param);
     viewer->options.invert_normals = *((bool *) param);
   }
   }
 
 
@@ -1833,7 +1356,7 @@ namespace igl
     if (options.face_based != newvalue)
     if (options.face_based != newvalue)
     {
     {
       options.face_based = newvalue;
       options.face_based = newvalue;
-      data.dirty = DIRTY_ALL;
+      data.dirty = OpenGL_state::DIRTY_ALL;
     }
     }
   }
   }
 
 
@@ -1878,14 +1401,14 @@ namespace igl
       else
       else
         cerr << "ERROR (set_mesh): The new mesh has a different number of vertices/faces. Please clear the mesh before plotting.";
         cerr << "ERROR (set_mesh): The new mesh has a different number of vertices/faces. Please clear the mesh before plotting.";
     }
     }
-    data.dirty |= DIRTY_FACE | DIRTY_POSITION;
+    data.dirty |= OpenGL_state::DIRTY_FACE | OpenGL_state::DIRTY_POSITION;
   }
   }
 
 
   void Viewer::set_vertices(const Eigen::MatrixXd& V)
   void Viewer::set_vertices(const Eigen::MatrixXd& V)
   {
   {
     data.V = V;
     data.V = V;
     assert(data.F.size() == 0 || data.F.maxCoeff() < data.V.rows());
     assert(data.F.size() == 0 || data.F.maxCoeff() < data.V.rows());
-    data.dirty |= DIRTY_POSITION;
+    data.dirty |= OpenGL_state::DIRTY_POSITION;
   }
   }
 
 
   void Viewer::set_normals(const Eigen::MatrixXd& N)
   void Viewer::set_normals(const Eigen::MatrixXd& N)
@@ -1903,7 +1426,7 @@ namespace igl
     }
     }
     else
     else
       cerr << "ERROR (set_normals): Please provide a normal per face, per corner or per vertex.";
       cerr << "ERROR (set_normals): Please provide a normal per face, per corner or per vertex.";
-    data.dirty |= DIRTY_NORMAL;
+    data.dirty |= OpenGL_state::DIRTY_NORMAL;
   }
   }
 
 
   void Viewer::set_colors(const Eigen::MatrixXd &C)
   void Viewer::set_colors(const Eigen::MatrixXd &C)
@@ -1954,7 +1477,7 @@ namespace igl
     }
     }
     else
     else
       cerr << "ERROR (set_colors): Please provide a single color, or a color per face or per vertex.";
       cerr << "ERROR (set_colors): Please provide a single color, or a color per face or per vertex.";
-    data.dirty |= DIRTY_DIFFUSE;
+    data.dirty |= OpenGL_state::DIRTY_DIFFUSE;
 
 
   }
   }
 
 
@@ -1968,7 +1491,7 @@ namespace igl
     }
     }
     else
     else
       cerr << "ERROR (set_UV): Please provide uv per vertex.";
       cerr << "ERROR (set_UV): Please provide uv per vertex.";
-    data.dirty |= DIRTY_UV;
+    data.dirty |= OpenGL_state::DIRTY_UV;
   }
   }
 
 
   void Viewer::set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F)
   void Viewer::set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F)
@@ -1976,7 +1499,7 @@ namespace igl
     set_face_based(true);
     set_face_based(true);
     data.V_uv = UV_V;
     data.V_uv = UV_V;
     data.F_uv = UV_F;
     data.F_uv = UV_F;
-    data.dirty |= DIRTY_UV;
+    data.dirty |= OpenGL_state::DIRTY_UV;
   }
   }
 
 
 
 
@@ -1988,7 +1511,7 @@ namespace igl
     data.texture_R = R;
     data.texture_R = R;
     data.texture_G = G;
     data.texture_G = G;
     data.texture_B = B;
     data.texture_B = B;
-    data.dirty |= DIRTY_TEXTURE;
+    data.dirty |= OpenGL_state::DIRTY_TEXTURE;
   }
   }
 
 
   void Viewer::add_points(const Eigen::MatrixXd& P,  const Eigen::MatrixXd& C)
   void Viewer::add_points(const Eigen::MatrixXd& P,  const Eigen::MatrixXd& C)
@@ -2009,7 +1532,7 @@ namespace igl
     for (unsigned i=0; i<P_temp.rows(); ++i)
     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.points.row(lastid+i) << P_temp.row(i), i<C.rows() ? C.row(i) : C.row(C.rows()-1);
 
 
-    data.dirty |= DIRTY_OVERLAY_POINTS;
+    data.dirty |= OpenGL_state::DIRTY_OVERLAY_POINTS;
   }
   }
 
 
   void Viewer::set_edges(
   void Viewer::set_edges(
@@ -2032,7 +1555,7 @@ namespace igl
       }
       }
       data.lines.row(e)<< P.row(E(e,0)), P.row(E(e,1)), color;
       data.lines.row(e)<< P.row(E(e,0)), P.row(E(e,1)), color;
     }
     }
-    data.dirty |= DIRTY_OVERLAY_LINES;
+    data.dirty |= OpenGL_state::DIRTY_OVERLAY_LINES;
   }
   }
 
 
   void Viewer::add_edges(const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C)
   void Viewer::add_edges(const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C)
@@ -2058,7 +1581,7 @@ namespace igl
     for (unsigned i=0; i<P1_temp.rows(); ++i)
     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.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 |= DIRTY_OVERLAY_LINES;
+    data.dirty |= OpenGL_state::DIRTY_OVERLAY_LINES;
   }
   }
 
 
   void Viewer::add_label(const Eigen::VectorXd& P,  const std::string& str)
   void Viewer::add_label(const Eigen::VectorXd& P,  const std::string& str)
@@ -2148,7 +1671,7 @@ namespace igl
 
 
     glfw_window_size(window,width_window,height_window);
     glfw_window_size(window,width_window,height_window);
 
 
-    init_opengl();
+    opengl.init();
 
 
     // Load the mesh passed as input
     // Load the mesh passed as input
     if (filename.size() > 0)
     if (filename.size() > 0)
@@ -2179,7 +1702,9 @@ namespace igl
       }
       }
     }
     }
 
 
-    free_opengl();
+    opengl.free();
+    __font_renderer.Shut();
+    
     shutdown_plugins();
     shutdown_plugins();
 
 
     glfwDestroyWindow(window);
     glfwDestroyWindow(window);

+ 2 - 103
include/igl/viewer/Viewer.h

@@ -22,6 +22,7 @@
 #include <Eigen/Core>
 #include <Eigen/Core>
 #include <igl/viewer/OpenGL_shader.h>
 #include <igl/viewer/OpenGL_shader.h>
 #include <igl/viewer/ViewerData.h>
 #include <igl/viewer/ViewerData.h>
+#include <igl/viewer/OpenGL_state.h>
 
 
 namespace igl
 namespace igl
 {
 {
@@ -102,103 +103,6 @@ namespace igl
       double animation_max_fps;
       double animation_max_fps;
     };
     };
 
 
-    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
-    };
-
-    class OpenGL_state
-    {
-    public:
-      typedef unsigned int GLuint;
-
-      GLuint vao_mesh;
-      GLuint vao_overlay_lines;
-      GLuint vao_overlay_points;
-      OpenGL_shader shader_mesh;
-      OpenGL_shader shader_overlay_lines;
-      OpenGL_shader shader_overlay_points;
-
-      GLuint vbo_V; // Vertices of the current mesh (#V x 3)
-      GLuint vbo_V_uv; // UV coordinates for the current mesh (#V x 2)
-      GLuint vbo_V_normals; // Vertices of the current mesh (#V x 3)
-      GLuint vbo_V_ambient; // Ambient material  (#V x 3)
-      GLuint vbo_V_diffuse; // Diffuse material  (#V x 3)
-      GLuint vbo_V_specular; // Specular material  (#V x 3)
-
-      GLuint vbo_F; // Faces of the mesh (#F x 3)
-      GLuint vbo_tex; // Texture
-
-      GLuint vbo_lines_F;         // Indices of the line overlay
-      GLuint vbo_lines_V;         // Vertices of the line overlay
-      GLuint vbo_lines_V_colors;  // Color values of the line overlay
-      GLuint vbo_points_F;        // Indices of the point overlay
-      GLuint vbo_points_V;        // Vertices of the point overlay
-      GLuint vbo_points_V_colors; // Color values of the point overlay
-
-      // Temporary copy of the content of each VBO
-      Eigen::MatrixXf V_vbo;
-      Eigen::MatrixXf V_normals_vbo;
-      Eigen::MatrixXf V_ambient_vbo;
-      Eigen::MatrixXf V_diffuse_vbo;
-      Eigen::MatrixXf V_specular_vbo;
-      Eigen::MatrixXf V_uv_vbo;
-      Eigen::MatrixXf lines_V_vbo;
-      Eigen::MatrixXf lines_V_colors_vbo;
-      Eigen::MatrixXf points_V_vbo;
-      Eigen::MatrixXf points_V_colors_vbo;
-
-      int tex_u;
-      int tex_v;
-      Eigen::Matrix<char,Eigen::Dynamic,1> tex;
-
-      Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic> F_vbo;
-      Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic> lines_F_vbo;
-      Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic> points_F_vbo;
-
-      // Marks dirty buffers that need to be uploaded to OpenGL
-      uint32_t dirty;
-
-      // Create a new set of OpenGL buffer objects
-      void init();
-
-      // Update contents from a 'Data' instance
-      void set_data(const igl::ViewerData &data, bool face_based, bool invert_normals);
-
-      // Bind the underlying OpenGL buffer objects for subsequent mesh draw calls
-      void bind_mesh();
-
-      /// Draw the currently buffered mesh (either solid or wireframe)
-      void draw_mesh(bool solid);
-
-      // Bind the underlying OpenGL buffer objects for subsequent line overlay draw calls
-      void bind_overlay_lines();
-
-      /// Draw the currently buffered line overlay
-      void draw_overlay_lines();
-
-      // Bind the underlying OpenGL buffer objects for subsequent point overlay draw calls
-      void bind_overlay_points();
-
-      /// Draw the currently buffered point overlay
-      void draw_overlay_points();
-
-      // Release the OpenGL buffer objects
-      void free();
-    };
-
     // Stores all the viewing options
     // Stores all the viewing options
     Options options;
     Options options;
 
 
@@ -206,7 +110,7 @@ namespace igl
     igl::ViewerData data;
     igl::ViewerData data;
 
 
     // Stores the vbos indices and opengl related settings
     // Stores the vbos indices and opengl related settings
-    OpenGL_state opengl;
+    igl::OpenGL_state opengl;
 
 
     // List of registered plugins
     // List of registered plugins
     std::vector<Viewer_plugin*> plugins;
     std::vector<Viewer_plugin*> plugins;
@@ -314,11 +218,6 @@ namespace igl
       float & zoom,
       float & zoom,
       Eigen::Vector3f& shift);
       Eigen::Vector3f& shift);
 
 
-
-    // Init opengl shaders and VBOs
-    void init_opengl();
-    void free_opengl();
-
     // Draw everything
     // Draw everything
     void draw();
     void draw();
 
 

+ 1 - 1
include/igl/viewer/ViewerData.cpp

@@ -1,6 +1,6 @@
 #include "ViewerData.h"
 #include "ViewerData.h"
 
 
-void igl::ViewerData::InitSerialization()
+IGL_INLINE void igl::ViewerData::InitSerialization()
 {
 {
   #ifdef ENABLE_XML_SERIALIZATION
   #ifdef ENABLE_XML_SERIALIZATION
   xmlSerializer->Add(V,"V");
   xmlSerializer->Add(V,"V");

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

@@ -18,7 +18,7 @@ public:
   #endif
   #endif
   {};
   {};
 
 
-  void InitSerialization();
+  IGL_INLINE void InitSerialization();
 
 
   Eigen::MatrixXd V; // Vertices of the current mesh (#V x 3)
   Eigen::MatrixXd V; // Vertices of the current mesh (#V x 3)
   Eigen::MatrixXi F; // Faces of the mesh (#F x 3)
   Eigen::MatrixXi F; // Faces of the mesh (#F x 3)