Răsfoiți Sursa

Merge branch 'master' of https://github.com/libigl/libigl

Alec Jacobson 5 ani în urmă
părinte
comite
dde868d297

+ 1 - 2
include/igl/direct_delta_mush.cpp

@@ -264,6 +264,5 @@ IGL_INLINE void igl::direct_delta_mush_precomputation(
 #ifdef IGL_STATIC_LIBRARY
 
 // Explicit template instantiation
-template void igl::direct_delta_mush<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::__1::vector<Eigen::Transform<double, 3, 2, 0>, Eigen::aligned_allocator<Eigen::Transform<double, 3, 2, 0> > > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
-template void igl::direct_delta_mush_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::direct_delta_mush<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<Eigen::Transform<double, 3, 2, 0>, Eigen::aligned_allocator<Eigen::Transform<double, 3, 2, 0> > > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&); template void igl::direct_delta_mush_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 1 - 1
include/igl/flip_avoiding_line_search.cpp

@@ -303,7 +303,7 @@ namespace igl
 IGL_INLINE double igl::flip_avoiding_line_search(
   const Eigen::MatrixXi F,
   Eigen::MatrixXd& cur_v,
-  Eigen::MatrixXd& dst_v,
+  const Eigen::MatrixXd& dst_v,
   std::function<double(Eigen::MatrixXd&)> energy,
   double cur_energy)
 {

+ 1 - 1
include/igl/flip_avoiding_line_search.h

@@ -36,7 +36,7 @@ namespace igl
   IGL_INLINE double flip_avoiding_line_search(
     const Eigen::MatrixXi F,
     Eigen::MatrixXd& cur_v,
-    Eigen::MatrixXd& dst_v,
+    const Eigen::MatrixXd& dst_v,
     std::function<double(Eigen::MatrixXd&)> energy,
     double cur_energy = -1);
 

+ 159 - 0
include/igl/opengl/MeshGL.cpp

@@ -10,6 +10,7 @@
 #include "bind_vertex_attrib_array.h"
 #include "create_shader_program.h"
 #include "destroy_shader_program.h"
+#include "verasansmono_compressed.h"
 #include <iostream>
 
 IGL_INLINE igl::opengl::MeshGL::MeshGL():
@@ -31,6 +32,7 @@ IGL_INLINE void igl::opengl::MeshGL::init_buffers()
   glGenBuffers(1, &vbo_V_uv);
   glGenBuffers(1, &vbo_F);
   glGenTextures(1, &vbo_tex);
+  glGenTextures(1, &font_atlas);
 
   // Line overlay
   glGenVertexArrays(1, &vao_overlay_lines);
@@ -46,6 +48,11 @@ IGL_INLINE void igl::opengl::MeshGL::init_buffers()
   glGenBuffers(1, &vbo_points_V);
   glGenBuffers(1, &vbo_points_V_colors);
 
+  // Text Labels
+  vertex_labels.init_buffers();
+  face_labels.init_buffers();
+  custom_labels.init_buffers();
+
   dirty = MeshGL::DIRTY_ALL;
 }
 
@@ -71,10 +78,34 @@ IGL_INLINE void igl::opengl::MeshGL::free_buffers()
     glDeleteBuffers(1, &vbo_points_V);
     glDeleteBuffers(1, &vbo_points_V_colors);
 
+    // Text Labels
+    vertex_labels.free_buffers();
+    face_labels.free_buffers();
+    custom_labels.free_buffers();
+
     glDeleteTextures(1, &vbo_tex);
+    glDeleteTextures(1, &font_atlas);
   }
 }
 
+IGL_INLINE void igl::opengl::MeshGL::TextGL::init_buffers()
+{
+  glGenVertexArrays(1, &vao_labels);
+  glBindVertexArray(vao_labels);
+  glGenBuffers(1, &vbo_labels_pos);
+  glGenBuffers(1, &vbo_labels_characters);
+  glGenBuffers(1, &vbo_labels_offset);
+  glGenBuffers(1, &vbo_labels_indices);
+}
+
+IGL_INLINE void igl::opengl::MeshGL::TextGL::free_buffers()
+{
+  glDeleteBuffers(1, &vbo_labels_pos);
+  glDeleteBuffers(1, &vbo_labels_characters);
+  glDeleteBuffers(1, &vbo_labels_offset);
+  glDeleteBuffers(1, &vbo_labels_indices);
+}
+
 IGL_INLINE void igl::opengl::MeshGL::bind_mesh()
 {
   glBindVertexArray(vao_mesh);
@@ -116,7 +147,9 @@ IGL_INLINE void igl::opengl::MeshGL::bind_overlay_lines()
 
   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_lines_F);
   if (is_dirty)
+  {
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*lines_F_vbo.size(), lines_F_vbo.data(), GL_DYNAMIC_DRAW);
+  }
 
   dirty &= ~MeshGL::DIRTY_OVERLAY_LINES;
 }
@@ -132,11 +165,50 @@ IGL_INLINE void igl::opengl::MeshGL::bind_overlay_points()
 
   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_points_F);
   if (is_dirty)
+  {
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*points_F_vbo.size(), points_F_vbo.data(), GL_DYNAMIC_DRAW);
+  }
 
   dirty &= ~MeshGL::DIRTY_OVERLAY_POINTS;
 }
 
+IGL_INLINE void igl::opengl::MeshGL::init_text_rendering()
+{
+  // Decompress the png of the font atlas
+  unsigned char verasansmono_font_atlas[256*256];
+  decompress_verasansmono_atlas(verasansmono_font_atlas);
+
+  // Bind atlas
+  glBindTexture(GL_TEXTURE_2D, font_atlas);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 256, 256, 0, GL_RED, GL_UNSIGNED_BYTE, verasansmono_font_atlas);
+
+  // TextGL initialization
+  vertex_labels.dirty_flag = MeshGL::DIRTY_VERTEX_LABELS;
+  face_labels.dirty_flag = MeshGL::DIRTY_FACE_LABELS;
+  custom_labels.dirty_flag = MeshGL::DIRTY_CUSTOM_LABELS;
+}
+
+IGL_INLINE void igl::opengl::MeshGL::bind_labels(const TextGL& labels)
+{
+  bool is_dirty = dirty & labels.dirty_flag;
+  glBindTexture(GL_TEXTURE_2D, font_atlas);
+  glBindVertexArray(labels.vao_labels);
+  glUseProgram(shader_text);
+  bind_vertex_attrib_array(shader_text, "position" , labels.vbo_labels_pos       , labels.label_pos_vbo   , is_dirty);
+  bind_vertex_attrib_array(shader_text, "character", labels.vbo_labels_characters, labels.label_char_vbo  , is_dirty);
+  bind_vertex_attrib_array(shader_text, "offset"   , labels.vbo_labels_offset    , labels.label_offset_vbo, is_dirty);
+  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, labels.vbo_labels_indices);
+  if (is_dirty)
+  {
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*labels.label_indices_vbo.size(), labels.label_indices_vbo.data(), GL_DYNAMIC_DRAW);
+  }
+  dirty &= ~labels.dirty_flag;
+}
+
 IGL_INLINE void igl::opengl::MeshGL::draw_mesh(bool solid)
 {
   glPolygonMode(GL_FRONT_AND_BACK, solid ? GL_FILL : GL_LINE);
@@ -163,6 +235,11 @@ IGL_INLINE void igl::opengl::MeshGL::draw_overlay_points()
   glDrawElements(GL_POINTS, points_F_vbo.rows(), GL_UNSIGNED_INT, 0);
 }
 
+IGL_INLINE void igl::opengl::MeshGL::draw_labels(const TextGL& labels)
+{
+  glDrawElements(GL_POINTS, labels.label_indices_vbo.rows(), GL_UNSIGNED_INT, 0);
+}
+
 IGL_INLINE void igl::opengl::MeshGL::init()
 {
   if(is_initialized)
@@ -289,7 +366,82 @@ R"(#version 150
   }
 )";
 
+  std::string text_vert_shader =
+R"(#version 330
+    in vec3 position;
+    in float character;
+    in float offset;
+    uniform mat4 view;
+    uniform mat4 proj;
+    out int vPosition;
+    out int vCharacter;
+    out float vOffset;
+    void main()
+    {
+      vCharacter = int(character);
+      vOffset = offset;
+      vPosition = gl_VertexID;
+      gl_Position = proj * view * vec4(position, 1.0);
+    }
+)";
+
+  std::string text_geom_shader =
+R"(#version 150 core
+    layout(points) in;
+    layout(triangle_strip, max_vertices = 4) out;
+    out vec2 gTexCoord;
+    uniform mat4 view;
+    uniform mat4 proj;
+    uniform vec2 CellSize;
+    uniform vec2 CellOffset;
+    uniform vec2 RenderSize;
+    uniform vec2 RenderOrigin;
+    uniform float TextShiftFactor;
+    in int vPosition[1];
+    in int vCharacter[1];
+    in float vOffset[1];
+    void main()
+    {
+      // Code taken from https://prideout.net/strings-inside-vertex-buffers
+      // Determine the final quad's position and size:
+      vec4 P = gl_in[0].gl_Position + vec4( vOffset[0]*TextShiftFactor, 0.0, 0.0, 0.0 ); // 0.04
+      vec4 U = vec4(1, 0, 0, 0) * RenderSize.x; // 1.0
+      vec4 V = vec4(0, 1, 0, 0) * RenderSize.y; // 1.0
+
+      // Determine the texture coordinates:
+      int letter = vCharacter[0]; // used to be the character
+      letter = clamp(letter - 32, 0, 96);
+      int row = letter / 16 + 1;
+      int col = letter % 16;
+      float S0 = CellOffset.x + CellSize.x * col;
+      float T0 = CellOffset.y + 1 - CellSize.y * row;
+      float S1 = S0 + CellSize.x - CellOffset.x;
+      float T1 = T0 + CellSize.y;
+
+      // Output the quad's vertices:
+      gTexCoord = vec2(S0, T1); gl_Position = P - U - V; EmitVertex();
+      gTexCoord = vec2(S1, T1); gl_Position = P + U - V; EmitVertex();
+      gTexCoord = vec2(S0, T0); gl_Position = P - U + V; EmitVertex();
+      gTexCoord = vec2(S1, T0); gl_Position = P + U + V; EmitVertex();
+      EndPrimitive();
+    }
+)";
+
+  std::string text_frag_shader =
+R"(#version 330
+    out vec4 outColor;
+    in vec2 gTexCoord;
+    uniform sampler2D font_atlas;
+    uniform vec3 TextColor;
+    void main()
+    {
+      float A = texture(font_atlas, gTexCoord).r;
+      outColor = vec4(TextColor, A);
+    }
+)";
+
   init_buffers();
+  init_text_rendering();
   create_shader_program(
     mesh_vertex_shader_string,
     mesh_fragment_shader_string,
@@ -305,6 +457,12 @@ R"(#version 150
     overlay_point_fragment_shader_string,
     {},
     shader_overlay_points);
+  create_shader_program(
+    text_geom_shader,
+    text_vert_shader,
+    text_frag_shader,
+    {},
+    shader_text);
 }
 
 IGL_INLINE void igl::opengl::MeshGL::free()
@@ -323,6 +481,7 @@ IGL_INLINE void igl::opengl::MeshGL::free()
     free(shader_mesh);
     free(shader_overlay_lines);
     free(shader_overlay_points);
+    free(shader_text);
     free_buffers();
   }
 }

+ 31 - 1
include/igl/opengl/MeshGL.h

@@ -40,7 +40,10 @@ public:
     DIRTY_MESH           = 0x00FF,
     DIRTY_OVERLAY_LINES  = 0x0100,
     DIRTY_OVERLAY_POINTS = 0x0200,
-    DIRTY_ALL            = 0x03FF
+    DIRTY_VERTEX_LABELS  = 0x0400,
+    DIRTY_FACE_LABELS    = 0x0800,
+    DIRTY_CUSTOM_LABELS  = 0x1000,
+    DIRTY_ALL            = 0xFFFF
   };
 
   bool is_initialized = false;
@@ -50,6 +53,7 @@ public:
   GLuint shader_mesh;
   GLuint shader_overlay_lines;
   GLuint shader_overlay_points;
+  GLuint shader_text;
 
   GLuint vbo_V; // Vertices of the current mesh (#V x 3)
   GLuint vbo_V_uv; // UV coordinates for the current mesh (#V x 2)
@@ -81,6 +85,27 @@ public:
   RowMatrixXf points_V_vbo;
   RowMatrixXf points_V_colors_vbo;
 
+  // Text Rendering
+  struct TextGL
+  { 
+    uint32_t dirty_flag;
+    GLuint vao_labels;
+    GLuint vbo_labels_pos;
+    GLuint vbo_labels_characters;
+    GLuint vbo_labels_offset; 
+    GLuint vbo_labels_indices;
+    RowMatrixXf label_pos_vbo;
+    RowMatrixXf label_char_vbo;
+    RowMatrixXf label_offset_vbo;
+    Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> label_indices_vbo;
+    void init_buffers();
+    void free_buffers();
+  };
+  TextGL vertex_labels;
+  TextGL face_labels;  
+  TextGL custom_labels;
+  GLuint font_atlas;
+
   int tex_u;
   int tex_v;
   GLint tex_filter;
@@ -123,6 +148,11 @@ public:
   /// Draw the currently buffered point overlay
   IGL_INLINE void draw_overlay_points();
 
+  // Text Binding and Draw functions
+  IGL_INLINE void init_text_rendering();
+  IGL_INLINE void bind_labels(const TextGL& labels);
+  IGL_INLINE void draw_labels(const TextGL& labels);
+
   // Release the OpenGL buffer objects
   IGL_INLINE void free_buffers();
 

+ 34 - 2
include/igl/opengl/ViewerCore.cpp

@@ -238,13 +238,17 @@ IGL_INLINE void igl::opengl::ViewerCore::draw(
       glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
       glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
       glPointSize(data.point_size);
-
       data.meshgl.draw_overlay_points();
     }
-
     glEnable(GL_DEPTH_TEST);
   }
 
+  if(is_set(data.show_vertex_labels)&&data.vertex_labels_positions.rows()>0) 
+    draw_labels(data, data.meshgl.vertex_labels);
+  if(is_set(data.show_face_labels)&&data.face_labels_positions.rows()>0) 
+    draw_labels(data, data.meshgl.face_labels);
+  if(is_set(data.show_custom_labels)&&data.labels_positions.rows()>0) 
+    draw_labels(data, data.meshgl.custom_labels);
 }
 
 IGL_INLINE void igl::opengl::ViewerCore::draw_buffer(ViewerData& data,
@@ -344,6 +348,34 @@ IGL_INLINE void igl::opengl::ViewerCore::draw_buffer(ViewerData& data,
   free(pixels);
 }
 
+// Define uniforms for text labels
+IGL_INLINE void igl::opengl::ViewerCore::draw_labels(
+  ViewerData& data,
+  const igl::opengl::MeshGL::TextGL& labels
+){
+  glDisable(GL_LINE_SMOOTH); // Clear settings if overlay is activated
+  data.meshgl.bind_labels(labels);
+  GLint viewi = glGetUniformLocation(data.meshgl.shader_text,"view");
+  GLint proji = glGetUniformLocation(data.meshgl.shader_text,"proj");
+  glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
+  glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
+  // Parameters for mapping characters from font atlass
+  float width  = viewport(2);
+  float height = viewport(3);
+  float text_shift_scale_factor = orthographic ? 0.01 : 0.03;
+  float render_scale = orthographic ? 0.6 : 1.7;
+  glUniform1f(glGetUniformLocation(data.meshgl.shader_text, "TextShiftFactor"), text_shift_scale_factor);
+  glUniform3f(glGetUniformLocation(data.meshgl.shader_text, "TextColor"), 0, 0, 0);
+  glUniform2f(glGetUniformLocation(data.meshgl.shader_text, "CellSize"), 1.0f / 16, (300.0f / 384) / 6);
+  glUniform2f(glGetUniformLocation(data.meshgl.shader_text, "CellOffset"), 0.5 / 256.0, 0.5 / 256.0);
+  glUniform2f(glGetUniformLocation(data.meshgl.shader_text, "RenderSize"), 
+                                    render_scale * 0.75 * 16 / (width), 
+                                    render_scale * 0.75 * 33.33 / (height));
+  glUniform2f(glGetUniformLocation(data.meshgl.shader_text, "RenderOrigin"), -2, 2);
+  data.meshgl.draw_labels(labels);
+  glEnable(GL_DEPTH_TEST);
+}
+
 IGL_INLINE void igl::opengl::ViewerCore::set_rotation_type(
   const igl::opengl::ViewerCore::RotationType & value)
 {

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

@@ -80,6 +80,10 @@ public:
     Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
     Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
     Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A);
+  IGL_INLINE void draw_labels(
+    ViewerData& data,
+    const igl::opengl::MeshGL::TextGL& labels
+  );
 
   // Trackball angle (quaternion)
   enum RotationType

+ 103 - 5
include/igl/opengl/ViewerData.cpp

@@ -28,9 +28,9 @@ IGL_INLINE igl::opengl::ViewerData::ViewerData()
   invert_normals    (false),
   show_overlay      (~unsigned(0)),
   show_overlay_depth(~unsigned(0)),
-  show_vertid       (false),
-  show_faceid       (false),
-  show_labels       (false),
+  show_vertex_labels(0),
+  show_face_labels  (0),
+  show_custom_labels(0),
   show_texture      (false),
   use_matcap        (false),
   point_size(30),
@@ -191,7 +191,7 @@ IGL_INLINE void igl::opengl::ViewerData::set_colors(const Eigen::MatrixXd &C)
   }
   else if(C.rows() == V.rows() || C.rows() == F.rows())
   {
-    // face based colors? 
+    // face based colors?
     if((C.rows()==F.rows()) && (C.rows() != V.rows() || face_based))
     {
       set_face_based(true);
@@ -417,6 +417,8 @@ IGL_INLINE void igl::opengl::ViewerData::add_label(const Eigen::VectorXd& P,  co
   labels_positions.conservativeResize(lastid+1, 3);
   labels_positions.row(lastid) = P_temp;
   labels_strings.push_back(str);
+
+  dirty |= MeshGL::DIRTY_CUSTOM_LABELS;
 }
 
 IGL_INLINE void igl::opengl::ViewerData::set_labels(const Eigen::MatrixXd& P, const std::vector<std::string>& str)
@@ -454,7 +456,12 @@ IGL_INLINE void igl::opengl::ViewerData::clear()
 
   lines                   = Eigen::MatrixXd (0,9);
   points                  = Eigen::MatrixXd (0,6);
+
+  vertex_labels_positions = Eigen::MatrixXd (0,3);
+  face_labels_positions   = Eigen::MatrixXd (0,3);
   labels_positions        = Eigen::MatrixXd (0,3);
+  vertex_labels_strings.clear();
+  face_labels_strings.clear();
   labels_strings.clear();
 
   face_based = false;
@@ -562,6 +569,41 @@ IGL_INLINE void igl::opengl::ViewerData::grid_texture()
   dirty |= MeshGL::DIRTY_TEXTURE;
 }
 
+// Populate VBOs of a particular label stype (Vert, Face, Custom)
+IGL_INLINE void igl::opengl::ViewerData::update_labels(
+  igl::opengl::MeshGL& meshgl,
+  igl::opengl::MeshGL::TextGL& GL_labels,
+  const Eigen::MatrixXd& positions,
+  const std::vector<std::string>& strings
+){
+  if (positions.rows()>0)
+  {
+    int numCharsToRender = 0;
+    for(size_t p=0; p<positions.rows(); p++)
+    {
+      numCharsToRender += strings.at(p).length();
+    }
+    GL_labels.label_pos_vbo.resize(numCharsToRender, 3);
+    GL_labels.label_char_vbo.resize(numCharsToRender, 1);
+    GL_labels.label_offset_vbo.resize(numCharsToRender, 1);
+    GL_labels.label_indices_vbo.resize(numCharsToRender, 1);
+    int idx=0;
+    assert(strings.size() == positions.rows());
+    for(size_t s=0; s<strings.size(); s++)
+    {
+      const auto & label = strings.at(s);
+      for(size_t c=0; c<label.length(); c++)
+      {
+        GL_labels.label_pos_vbo.row(idx) = positions.row(s).cast<float>();
+        GL_labels.label_char_vbo(idx) = (float)(label.at(c));
+        GL_labels.label_offset_vbo(idx) = c;
+        GL_labels.label_indices_vbo(idx) = idx;
+        idx++;
+      }
+    }
+  }
+}
+
 IGL_INLINE void igl::opengl::ViewerData::updateGL(
   const igl::opengl::ViewerData& data,
   const bool invert_normals,
@@ -694,7 +736,7 @@ IGL_INLINE void igl::opengl::ViewerData::updateGL(
           meshgl.F_vbo.row(i) << i*3+0, i*3+1, i*3+2;
       }
 
-      if (meshgl.dirty & MeshGL::DIRTY_UV)
+      if ( (meshgl.dirty & MeshGL::DIRTY_UV) && data.V_uv.rows()>0)
       {
         meshgl.V_uv_vbo.resize(data.F.rows()*3,2);
         for (unsigned i=0; i<data.F.rows();++i)
@@ -795,4 +837,60 @@ IGL_INLINE void igl::opengl::ViewerData::updateGL(
       meshgl.points_F_vbo(i) = i;
     }
   }
+
+  if (meshgl.dirty & MeshGL::DIRTY_FACE_LABELS)
+  {
+    if(face_labels_positions.rows()==0)
+    {
+      face_labels_positions.conservativeResize(F.rows(), 3);
+      Eigen::MatrixXd faceNormals = F_normals.normalized();
+      for (int f=0; f<F.rows();++f)
+      {
+        std::string faceName = std::to_string(f);
+        face_labels_positions.row(f) = V.row(F.row(f)(0));
+        face_labels_positions.row(f) += V.row(F.row(f)(1));
+        face_labels_positions.row(f) += V.row(F.row(f)(2));
+        face_labels_positions.row(f) /= 3.;
+        face_labels_positions.row(f) = (faceNormals*0.05).row(f) + face_labels_positions.row(f);
+        face_labels_strings.push_back(faceName);
+      }
+    }
+    update_labels(
+      meshgl,
+      meshgl.face_labels,
+      face_labels_positions,
+      face_labels_strings
+    );
+  }
+
+  if (meshgl.dirty & MeshGL::DIRTY_VERTEX_LABELS)
+  {
+    if(vertex_labels_positions.rows()==0)
+    {
+      vertex_labels_positions.conservativeResize(V.rows(), 3);
+      Eigen::MatrixXd normalized = V_normals.normalized();
+      for (int v=0; v<V.rows();++v)
+      {
+        std::string vertName = std::to_string(v);
+        vertex_labels_positions.row(v) = (normalized*0.1).row(v) + V.row(v);
+        vertex_labels_strings.push_back(vertName);
+      }
+    }
+    update_labels(
+      meshgl,
+      meshgl.vertex_labels,
+      vertex_labels_positions,
+      vertex_labels_strings
+    );
+  }
+
+  if (meshgl.dirty & MeshGL::DIRTY_CUSTOM_LABELS)
+  {
+    update_labels(
+      meshgl,
+      meshgl.custom_labels,
+      labels_positions,
+      labels_strings
+    );
+  }
 }

+ 17 - 7
include/igl/opengl/ViewerData.h

@@ -234,7 +234,11 @@ public:
   // Text labels plotted over the scene
   // Textp contains, in the i-th row, the position in global coordinates where the i-th label should be anchored
   // Texts contains in the i-th position the text of the i-th label
+  Eigen::MatrixXd           vertex_labels_positions;
+  Eigen::MatrixXd           face_labels_positions;
   Eigen::MatrixXd           labels_positions;
+  std::vector<std::string>  vertex_labels_strings;
+  std::vector<std::string>  face_labels_strings;
   std::vector<std::string>  labels_strings;
 
   // Marks dirty buffers that need to be uploaded to OpenGL
@@ -259,9 +263,9 @@ public:
   unsigned int use_matcap;
   unsigned int show_faces;
   unsigned int show_lines;
-  bool show_vertid; // shared across viewports for now
-  bool show_faceid; // shared across viewports for now
-  bool show_labels; // shared across viewports for now
+  unsigned int show_vertex_labels;
+  unsigned int show_face_labels;
+  unsigned int show_custom_labels;
 
   // Point size / line width
   float point_size;
@@ -279,11 +283,17 @@ public:
   igl::opengl::MeshGL meshgl;
 
   // Update contents from a 'Data' instance
+  IGL_INLINE void update_labels(
+    igl::opengl::MeshGL& meshgl,
+    igl::opengl::MeshGL::TextGL& GL_labels,
+    const Eigen::MatrixXd& positions,
+    const std::vector<std::string>& strings
+  );
   IGL_INLINE void updateGL(
     const igl::opengl::ViewerData& data,
     const bool invert_normals,
     igl::opengl::MeshGL& meshgl);
-};
+  };
 
 } // namespace opengl
 } // namespace igl
@@ -324,9 +334,9 @@ namespace igl
       SERIALIZE_MEMBER(invert_normals);
       SERIALIZE_MEMBER(show_overlay);
       SERIALIZE_MEMBER(show_overlay_depth);
-      SERIALIZE_MEMBER(show_vertid);
-      SERIALIZE_MEMBER(show_faceid);
-      SERIALIZE_MEMBER(show_labels);
+      SERIALIZE_MEMBER(show_vertex_labels);
+      SERIALIZE_MEMBER(show_face_labels);
+      SERIALIZE_MEMBER(show_custom_labels);
       SERIALIZE_MEMBER(show_texture);
       SERIALIZE_MEMBER(double_sided);
       SERIALIZE_MEMBER(point_size);

+ 2 - 2
include/igl/opengl/glfw/Viewer.cpp

@@ -592,10 +592,10 @@ namespace glfw
         return true;
       }
       case ';':
-        data().show_vertid = !data().show_vertid;
+        data().show_vertex_labels = !data().show_vertex_labels;
         return true;
       case ':':
-        data().show_faceid = !data().show_faceid;
+        data().show_face_labels = !data().show_face_labels;
         return true;
       default: break;//do nothing
     }

+ 3 - 101
include/igl/opengl/glfw/imgui/ImGuiMenu.cpp

@@ -152,9 +152,6 @@ IGL_INLINE bool ImGuiMenu::key_up(int key, int modifiers)
 // Draw menu
 IGL_INLINE void ImGuiMenu::draw_menu()
 {
-  // Text labels
-  draw_labels_window();
-
   // Viewer settings
   if (callback_draw_viewer_window) { callback_draw_viewer_window(); }
   else { draw_viewer_window(); }
@@ -301,105 +298,10 @@ IGL_INLINE void ImGuiMenu::draw_viewer_menu()
   {
     make_checkbox("Wireframe", viewer->data().show_lines);
     make_checkbox("Fill", viewer->data().show_faces);
-    ImGui::Checkbox("Show vertex labels", &(viewer->data().show_vertid));
-    ImGui::Checkbox("Show faces labels", &(viewer->data().show_faceid));
-    ImGui::Checkbox("Show extra labels", &(viewer->data().show_labels));
-  }
-}
-
-IGL_INLINE void ImGuiMenu::draw_labels_window()
-{
-  // Text labels
-  ImGui::SetNextWindowPos(ImVec2(0,0), ImGuiCond_Always);
-  ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize, ImGuiCond_Always);
-  bool visible = true;
-  ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0,0,0,0));
-  ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0);
-  ImGui::Begin("ViewerLabels", &visible,
-      ImGuiWindowFlags_NoTitleBar
-      | ImGuiWindowFlags_NoResize
-      | ImGuiWindowFlags_NoMove
-      | ImGuiWindowFlags_NoScrollbar
-      | ImGuiWindowFlags_NoScrollWithMouse
-      | ImGuiWindowFlags_NoCollapse
-      | ImGuiWindowFlags_NoSavedSettings
-      | ImGuiWindowFlags_NoInputs);
-  for (const auto & data : viewer->data_list)
-  {
-    draw_labels(data);
-  }
-  ImGui::End();
-  ImGui::PopStyleColor();
-  ImGui::PopStyleVar();
-}
-
-IGL_INLINE void ImGuiMenu::draw_labels(const igl::opengl::ViewerData &data)
-{
-  // Alec: How can we get these to respect (optionally) the depth of the scene?
-  if (data.show_vertid)
-  {
-    for (int i = 0; i < data.V.rows(); ++i)
-    {
-      draw_text(
-        data.V.row(i), 
-        data.V_normals.row(i), 
-        std::to_string(i),
-        data.label_color);
-    }
+    make_checkbox("Show vertex labels", viewer->data().show_vertex_labels);
+    make_checkbox("Show faces labels", viewer->data().show_face_labels);
+    make_checkbox("Show extra labels", viewer->data().show_custom_labels);
   }
-
-  if (data.show_faceid)
-  {
-    for (int i = 0; i < data.F.rows(); ++i)
-    {
-      Eigen::RowVector3d p = Eigen::RowVector3d::Zero();
-      for (int j = 0; j < data.F.cols(); ++j)
-      {
-        p += data.V.row(data.F(i,j));
-      }
-      p /= (double) data.F.cols();
-
-      draw_text(
-        p, 
-        data.F_normals.row(i), 
-        std::to_string(i),
-        data.label_color);
-    }
-  }
-
-  if (data.show_labels)
-  {
-    for (int i = 0; i < data.labels_positions.rows(); ++i)
-    {
-      draw_text(
-        data.labels_positions.row(i), 
-        Eigen::Vector3d(0.0,0.0,0.0),
-        data.labels_strings[i],
-        data.label_color);
-    }
-  }
-}
-
-IGL_INLINE void ImGuiMenu::draw_text(
-  Eigen::Vector3d pos, 
-  Eigen::Vector3d normal, 
-  const std::string &text,
-  const Eigen::Vector4f color)
-{
-  pos += normal * 0.005f * viewer->core().object_scale;
-  Eigen::Vector3f coord = igl::project(Eigen::Vector3f(pos.cast<float>()),
-    viewer->core().view, viewer->core().proj, viewer->core().viewport);
-
-  // Draw text labels slightly bigger than normal text
-  ImDrawList* drawList = ImGui::GetWindowDrawList();
-  drawList->AddText(ImGui::GetFont(), ImGui::GetFontSize() * 1.2,
-      ImVec2(coord[0]/pixel_ratio_, (viewer->core().viewport[3] - coord[1])/pixel_ratio_),
-      ImGui::GetColorU32(ImVec4(
-        color(0),
-        color(1),
-        color(2),
-        color(3))),
-      &text[0], &text[0] + text.size());
 }
 
 IGL_INLINE float ImGuiMenu::pixel_ratio()

+ 2 - 6
include/igl/opengl/glfw/imgui/ImGuiMenu.h

@@ -86,13 +86,9 @@ public:
   std::function<void(void)> callback_draw_viewer_menu;
   std::function<void(void)> callback_draw_custom_window;
 
-  IGL_INLINE void draw_labels_window();
-
-  IGL_INLINE void draw_labels(const igl::opengl::ViewerData &data);
-
   IGL_INLINE void draw_text(
-    Eigen::Vector3d pos, 
-    Eigen::Vector3d normal, 
+    Eigen::Vector3d pos,
+    Eigen::Vector3d normal,
     const std::string &text,
     const Eigen::Vector4f color = Eigen::Vector4f(0,0,0.04,1)); // old default color
 

Fișier diff suprimat deoarece este prea mare
+ 17 - 0
include/igl/opengl/verasansmono_compressed.cpp


+ 21 - 0
include/igl/opengl/verasansmono_compressed.h

@@ -0,0 +1,21 @@
+#ifndef IGL_OPENGL_VERASANSMONO_COMPRESSED_H
+#define IGL_OPENGL_VERASANSMONO_COMPRESSED_H
+
+#include <igl/opengl/../igl_inline.h>
+
+namespace igl
+{
+namespace opengl
+{
+
+IGL_INLINE void decompress_verasansmono_atlas(unsigned char* _fontatlas);
+
+}
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "verasansmono_compressed.cpp"
+#endif
+
+#endif

+ 18 - 17
include/igl/readPLY.cpp

@@ -8,17 +8,17 @@
 #include "tinyply.h"
 
 
-namespace igl 
+namespace igl
 {
 
 template <typename T, typename Derived>
 IGL_INLINE bool _tinyply_buffer_to_matrix(
-  tinyply::PlyData & D, 
+  tinyply::PlyData & D,
   Eigen::PlainObjectBase<Derived> & M,
   size_t rows,
   size_t cols )
 {
-  Eigen::Map< Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> > 
+  Eigen::Map< Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> >
     _map( reinterpret_cast<T *>( D.buffer.get()), rows, cols );
 
   M = _map.template cast<typename Derived::Scalar>();
@@ -27,9 +27,9 @@ IGL_INLINE bool _tinyply_buffer_to_matrix(
 
 
 
-template <typename Derived> 
+template <typename Derived>
 IGL_INLINE bool tinyply_buffer_to_matrix(
-  tinyply::PlyData & D, 
+  tinyply::PlyData & D,
   Eigen::PlainObjectBase<Derived> & M,
   size_t rows,
   size_t cols )
@@ -60,13 +60,13 @@ IGL_INLINE bool tinyply_buffer_to_matrix(
 
 template <typename T, typename Derived>
 IGL_INLINE bool _tinyply_tristrips_to_trifaces(
-  tinyply::PlyData & D, 
+  tinyply::PlyData & D,
   Eigen::PlainObjectBase<Derived> & M,
   size_t el,
   size_t el_len )
 {
 
-  Eigen::Map< Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> > 
+  Eigen::Map< Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> >
      _map( reinterpret_cast<T *>( D.buffer.get()), el, el_len );
 
   // to make it more interesting, triangles in triangle strip can be separated by negative index elements
@@ -77,7 +77,7 @@ IGL_INLINE bool _tinyply_tristrips_to_trifaces(
   for(size_t i=0; i<el; i++)
     for(size_t j=0; j<(el_len-2); j++)
     {
-      if(_map(i,j)>=0 && _map(i,j+1)>=0 && _map(i,j+2)>=0) 
+      if(_map(i,j)>=0 && _map(i,j+1)>=0 && _map(i,j+2)>=0)
         triangles++;
     }
 
@@ -107,9 +107,9 @@ IGL_INLINE bool _tinyply_tristrips_to_trifaces(
   return true;
 }
 
-template <typename Derived> 
+template <typename Derived>
 IGL_INLINE bool tinyply_tristrips_to_faces(
-  tinyply::PlyData & D, 
+  tinyply::PlyData & D,
   Eigen::PlainObjectBase<Derived> & M,
   size_t el,
   size_t el_len )
@@ -212,7 +212,7 @@ IGL_INLINE bool readPLY(
   std::vector<std::string> & comments
   )
 {
-  // buffer the whole file in memory 
+  // buffer the whole file in memory
   // then read from memory buffer
   try
   {
@@ -299,7 +299,7 @@ IGL_INLINE bool readPLY(
   std::set<std::string> edge_std  { "vertex1", "vertex2"}; //non-standard edge indexes
 
   // Tinyply treats parsed data as untyped byte buffers.
-  std::shared_ptr<tinyply::PlyData> vertices, normals, faces, texcoords, edges; 
+  std::shared_ptr<tinyply::PlyData> vertices, normals, faces, texcoords, edges;
 
   // Some ply files contain tristrips instead of faces
   std::shared_ptr<tinyply::PlyData> tristrips;
@@ -315,7 +315,7 @@ IGL_INLINE bool readPLY(
 
   for (auto c : file.get_comments())
       comments.push_back(c);
-  
+
   for (auto e : file.get_elements())
   {
       if(e.name == "vertex" ) // found a vertex
@@ -353,7 +353,7 @@ IGL_INLINE bool readPLY(
 
   // The header information can be used to programmatically extract properties on elements
   // known to exist in the header prior to reading the data. For brevity of this sample, properties
-  // like vertex position are hard-coded:  
+  // like vertex position are hard-coded:
   try {
     vertices = file.request_properties_from_element("vertex", { "x", "y", "z" });
   }
@@ -423,12 +423,12 @@ IGL_INLINE bool readPLY(
       }
   }
 
-  
+
   try {
     edges = file.request_properties_from_element("edge", { "vertex1", "vertex2" });
   }
   catch (const std::exception & ) { }
-  
+
   if(! _vertex_header.empty())
     _vertex_data = file.request_properties_from_element( "vertex", _vertex_header);
   if(! _face_header.empty())
@@ -484,7 +484,7 @@ IGL_INLINE bool readPLY(
     VD.resize(vertices->count,_vertex_header.size());
     tinyply_buffer_to_matrix(*_vertex_data, VD, vertices->count, _vertex_header.size());
   }
-  
+
   /// convert face data:
   Fheader=_face_header;
   if(_face_header.empty())
@@ -682,5 +682,6 @@ template bool igl::readPLY<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<
 template bool igl::readPLY<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 
 template bool igl::readPLY<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&);
+template bool igl::readPLY<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&);
 #endif
 

+ 46 - 22
include/igl/scaf.cpp

@@ -332,7 +332,7 @@ IGL_INLINE double compute_soft_constraint_energy(const SCAFData &s)
   return e;
 }
 
-IGL_INLINE double compute_energy(SCAFData &s, Eigen::MatrixXd &w_uv, bool whole)
+IGL_INLINE double compute_energy(SCAFData &s, const Eigen::MatrixXd &w_uv, bool whole)
 {
   if (w_uv.rows() != s.v_num)
     assert(!whole);
@@ -529,6 +529,30 @@ IGL_INLINE void build_scaffold_linear_system(const SCAFData &s, Eigen::SparseMat
   rhs = Aut * (frhs - Ae * known_pos);
 }
 
+IGL_INLINE void build_weighted_arap_system(SCAFData &s, Eigen::SparseMatrix<double> &L, Eigen::VectorXd &rhs)
+{
+  // fixed frame solving:
+  // x_e as the fixed frame, x_u for unknowns (mesh + unknown scaffold)
+  // min ||(A_u*x_u + A_e*x_e) - b||^2
+  // => A_u'*A_u*x_u  = Au'* (b - A_e*x_e) := Au'* b_u
+  //
+  // separate matrix build:
+  // min ||A_m x_m - b_m||^2 + ||A_s x_all - b_s||^2 + soft + proximal
+  // First change dimension of A_m to fit for x_all
+  // (Not just at the end, since x_all is flattened along dimensions)
+  // L = A_m'*A_m + A_s'*A_s + soft + proximal
+  // rhs = A_m'* b_m + A_s' * b_s + soft + proximal
+  //
+  Eigen::SparseMatrix<double> L_m, L_s;
+  Eigen::VectorXd rhs_m, rhs_s;
+  build_surface_linear_system(s, L_m, rhs_m);  // complete Am, with soft
+  build_scaffold_linear_system(s, L_s, rhs_s); // complete As, without proximal
+
+  L = L_m + L_s;
+  rhs = rhs_m + rhs_s;
+  L.makeCompressed();
+}
+
 IGL_INLINE void solve_weighted_arap(SCAFData &s, Eigen::MatrixXd &uv)
 {
   using namespace Eigen;
@@ -562,27 +586,7 @@ IGL_INLINE void solve_weighted_arap(SCAFData &s, Eigen::MatrixXd &uv)
 
   Eigen::SparseMatrix<double> L;
   Eigen::VectorXd rhs;
-
-  // fixed frame solving:
-  // x_e as the fixed frame, x_u for unknowns (mesh + unknown scaffold)
-  // min ||(A_u*x_u + A_e*x_e) - b||^2
-  // => A_u'*A_u*x_u  = Au'* (b - A_e*x_e) := Au'* b_u
-  //
-  // separate matrix build:
-  // min ||A_m x_m - b_m||^2 + ||A_s x_all - b_s||^2 + soft + proximal
-  // First change dimension of A_m to fit for x_all
-  // (Not just at the end, since x_all is flattened along dimensions)
-  // L = A_m'*A_m + A_s'*A_s + soft + proximal
-  // rhs = A_m'* b_m + A_s' * b_s + soft + proximal
-  //
-  Eigen::SparseMatrix<double> L_m, L_s;
-  Eigen::VectorXd rhs_m, rhs_s;
-  build_surface_linear_system(s, L_m, rhs_m);  // complete Am, with soft
-  build_scaffold_linear_system(s, L_s, rhs_s); // complete As, without proximal
-
-  L = L_m + L_s;
-  rhs = rhs_m + rhs_s;
-  L.makeCompressed();
+  build_weighted_arap_system(s, L, rhs);
 
   Eigen::VectorXd unknown_Uc((v_n - s.frame_ids.size() - s.fixed_ids.size()) * dim), Uc(dim * v_n);
 
@@ -612,6 +616,7 @@ IGL_INLINE double perform_iteration(SCAFData &s)
                                         whole_E, -1) /
          s.mesh_measure;
 }
+
 }
 }
 
@@ -702,5 +707,24 @@ IGL_INLINE Eigen::MatrixXd igl::scaf_solve(SCAFData &s, int iter_num)
   return s.w_uv.topRows(s.mv_num);
 }
 
+IGL_INLINE void igl::scaf_system(SCAFData &s, Eigen::SparseMatrix<double> &L, Eigen::VectorXd &rhs)
+{
+    s.energy = igl::scaf::compute_energy(s, s.w_uv, false) / s.mesh_measure;
+
+    s.total_energy = igl::scaf::compute_energy(s, s.w_uv, true) / s.mesh_measure;
+    s.rect_frame_V = Eigen::MatrixXd();
+    igl::scaf::mesh_improve(s);
+
+    double new_weight = s.mesh_measure * s.energy / (s.sf_num * 100);
+    s.scaffold_factor = new_weight;
+    igl::scaf::update_scaffold(s);
+
+    igl::scaf::compute_jacobians(s, s.w_uv, true);
+    igl::slim_update_weights_and_closest_rotations_with_jacobians(s.Ji_m, s.slim_energy, 0, s.W_m, s.Ri_m);
+    igl::slim_update_weights_and_closest_rotations_with_jacobians(s.Ji_s, s.scaf_energy, 0, s.W_s, s.Ri_s);
+
+    igl::scaf::build_weighted_arap_system(s, L, rhs);
+}
+
 #ifdef IGL_STATIC_LIBRARY
 #endif

+ 32 - 14
include/igl/scaf.h

@@ -68,15 +68,15 @@ namespace igl
     };
 
 
-// Compute necessary information to start using SCAF
-// Inputs:
-//		V           #V by 3 list of mesh vertex positions
-//		F           #F by 3/3 list of mesh faces (triangles/tets)
-//    data          igl::SCAFData
-//    slim_energy Energy type to minimize
-//    b           list of boundary indices into V (soft constraint)
-//    bc          #b by dim list of boundary conditions (soft constraint)
-//    soft_p      Soft penalty factor (can be zero)
+    // Compute necessary information to start using SCAF
+    // Inputs:
+    //		V           #V by 3 list of mesh vertex positions
+    //		F           #F by 3/3 list of mesh faces (triangles/tets)
+    //    data          igl::SCAFData
+    //    slim_energy Energy type to minimize
+    //    b           list of boundary indices into V (soft constraint)
+    //    bc          #b by dim list of boundary conditions (soft constraint)
+    //    soft_p      Soft penalty factor (can be zero)
     IGL_INLINE void scaf_precompute(
         const Eigen::MatrixXd &V,
         const Eigen::MatrixXi &F,
@@ -87,12 +87,30 @@ namespace igl
         Eigen::MatrixXd& bc,
         double soft_p);
 
+    // Run iter_num iterations of SCAF, with precomputed data
+    // Outputs:
+    //    V_o (in SLIMData): #V by dim list of mesh vertex positions
+    IGL_INLINE Eigen::MatrixXd scaf_solve(SCAFData &data, int iter_num);
 
-// Run iter_num iterations of SCAF, with precomputed data
-// Outputs:
-//    V_o (in SLIMData): #V by dim list of mesh vertex positions
-  IGL_INLINE Eigen::MatrixXd scaf_solve(SCAFData &data, int iter_num);
-  }
+    // Set up the SCAF system L * uv = rhs, without solving it.
+    // Inputs:
+    //    s:   igl::SCAFData. Will be modified by energy and Jacobian computation.
+    // Outputs:
+    //    L:   m by m matrix
+    //    rhs: m by 1 vector
+    //         with m = dim * (#V_mesh + #V_scaf - #V_frame)
+    IGL_INLINE void scaf_system(SCAFData &s, Eigen::SparseMatrix<double> &L, Eigen::VectorXd &rhs);
+
+    namespace scaf
+    {
+        // Compute SCAF energy
+        // Inputs:
+        //    s:     igl::SCAFData
+        //    w_uv:  (#V_mesh + #V_scaf) by dim matrix
+        //    whole: Include scaffold if true
+        IGL_INLINE double compute_energy(SCAFData &s, const Eigen::MatrixXd &w_uv, bool whole);
+    }
+}
 
 #ifndef IGL_STATIC_LIBRARY
 #  include "scaf.cpp"

+ 4 - 4
include/igl/slim.cpp

@@ -51,11 +51,11 @@ namespace igl
     // Definitions of internal functions
     IGL_INLINE void buildRhs(igl::SLIMData& s, const Eigen::SparseMatrix<double> &A);
     IGL_INLINE void add_soft_constraints(igl::SLIMData& s, Eigen::SparseMatrix<double> &L);
-    IGL_INLINE double compute_energy(igl::SLIMData& s, Eigen::MatrixXd &V_new);
+    IGL_INLINE double compute_energy(igl::SLIMData& s, const Eigen::MatrixXd &V_new);
     IGL_INLINE double compute_soft_const_energy(igl::SLIMData& s,
                                                 const Eigen::MatrixXd &V,
                                                 const Eigen::MatrixXi &F,
-                                                Eigen::MatrixXd &V_o);
+                                                const Eigen::MatrixXd &V_o);
 
     IGL_INLINE void solve_weighted_arap(igl::SLIMData& s,
                                         const Eigen::MatrixXd &V,
@@ -287,7 +287,7 @@ namespace igl
       }
     }
 
-    IGL_INLINE double compute_energy(igl::SLIMData& s, Eigen::MatrixXd &V_new)
+    IGL_INLINE double compute_energy(igl::SLIMData& s, const Eigen::MatrixXd &V_new)
     {
       compute_jacobians(s,V_new);
       return mapping_energy_with_jacobians(s.Ji, s.M, s.slim_energy, s.exp_factor) +
@@ -297,7 +297,7 @@ namespace igl
     IGL_INLINE double compute_soft_const_energy(igl::SLIMData& s,
                                                 const Eigen::MatrixXd &V,
                                                 const Eigen::MatrixXi &F,
-                                                Eigen::MatrixXd &V_o)
+                                                const Eigen::MatrixXd &V_o)
     {
       double e = 0;
       for (int i = 0; i < s.b.rows(); i++)

+ 18 - 17
include/igl/writePLY.cpp

@@ -57,9 +57,9 @@ bool writePLY(
     typedef typename DerivedVD::Scalar VDScalar;
     typedef typename DerivedFD::Scalar FDScalar;
     typedef typename DerivedED::Scalar EDScalar;
-    
+
     // temporary storage for data to be passed to tinyply internals
-    std::vector<NScalar> _v;
+    std::vector<VScalar> _v;
     std::vector<NScalar> _n;
     std::vector<UVScalar> _uv;
     std::vector<VDScalar> _vd;
@@ -78,10 +78,10 @@ bool writePLY(
     _v.resize(V.size());
     Eigen::Map< Eigen::Matrix<VScalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > >( &_v[0], V.rows(), V.cols() ) = V;
 
-    file.add_properties_to_element("vertex", { "x", "y", "z" }, 
+    file.add_properties_to_element("vertex", { "x", "y", "z" },
         tynyply_type<VScalar>(), V.rows(), reinterpret_cast<uint8_t*>( &_v[0] ), tinyply::Type::INVALID, 0);
 
-    if(N.rows()>0) 
+    if(N.rows()>0)
     {
         _n.resize(N.size());
         Eigen::Map<Eigen::Matrix<NScalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > >( &_n[0], N.rows(), N.cols() ) = N;
@@ -89,7 +89,7 @@ bool writePLY(
             tynyply_type<NScalar>(), N.rows(), reinterpret_cast<uint8_t*>( &_n[0] ),tinyply::Type::INVALID, 0);
     }
 
-    if(UV.rows()>0) 
+    if(UV.rows()>0)
     {
         _uv.resize(UV.size());
         Eigen::Map<Eigen::Matrix<UVScalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > >( &_uv[0], UV.rows(), UV.cols() ) = UV;
@@ -129,7 +129,7 @@ bool writePLY(
             tynyply_type<FDScalar>(), FD.rows(), reinterpret_cast<uint8_t*>( &_fd[0] ), tinyply::Type::INVALID, 0);
     }
 
-    if(E.rows()>0) 
+    if(E.rows()>0)
     {
         assert(E.cols()==2);
         _ev.resize(E.size());
@@ -233,7 +233,7 @@ bool writePLY(
 {
   Eigen::MatrixXd _dummy;
   std::vector<std::string> _dummy_header;
-  
+
   return writePLY(filename,V,F,_dummy, _dummy, _dummy, _dummy, _dummy_header, _dummy, _dummy_header, _dummy, _dummy_header, _dummy_header, true);
 }
 
@@ -251,7 +251,7 @@ bool writePLY(
 {
   Eigen::MatrixXd _dummy;
   std::vector<std::string> _dummy_header;
-  
+
   return writePLY(filename,V,F,E, _dummy, _dummy, _dummy, _dummy_header, _dummy, _dummy_header, _dummy, _dummy_header, _dummy_header, true);
 }
 
@@ -272,7 +272,7 @@ bool writePLY(
 {
   Eigen::MatrixXd _dummy;
   std::vector<std::string> _dummy_header;
-  
+
   return writePLY(filename,V,F,_dummy, N,UV, _dummy, _dummy_header, _dummy, _dummy_header, _dummy, _dummy_header, _dummy_header, true);
 }
 
@@ -294,7 +294,7 @@ bool writePLY(
 {
   Eigen::MatrixXd _dummy;
   std::vector<std::string> _dummy_header;
-  
+
   return writePLY(filename,V,F,E, N,UV, _dummy, _dummy_header, _dummy, _dummy_header, _dummy, _dummy_header, _dummy_header, true);
 }
 
@@ -311,8 +311,8 @@ bool writePLY(
 {
   Eigen::MatrixXd _dummy(0,0);
   std::vector<std::string> _dummy_header;
-  
-  return writePLY(filename,V,F,_dummy, _dummy,_dummy, _dummy, _dummy_header, 
+
+  return writePLY(filename,V,F,_dummy, _dummy,_dummy, _dummy, _dummy_header,
                          _dummy, _dummy_header, _dummy, _dummy_header, _dummy_header, force_ascii);
 }
 
@@ -331,7 +331,7 @@ bool writePLY(
 {
   Eigen::MatrixXd _dummy(0,0);
   std::vector<std::string> _dummy_header;
-  
+
   return writePLY(filename,V,F,E, _dummy,_dummy, _dummy, _dummy_header,
                          _dummy, _dummy_header, _dummy, _dummy_header, _dummy_header, force_ascii);
 }
@@ -359,8 +359,8 @@ bool writePLY(
 {
   Eigen::MatrixXd _dummy(0,0);
   std::vector<std::string> _dummy_header;
-  
-  return writePLY(filename,V,F,_dummy, N, UV, VD, VDheader, 
+
+  return writePLY(filename,V,F,_dummy, N, UV, VD, VDheader,
                          _dummy, _dummy_header, _dummy, _dummy_header, comments, true);
 }
 
@@ -389,8 +389,8 @@ bool writePLY(
 {
   Eigen::MatrixXd _dummy(0,0);
   std::vector<std::string> _dummy_header;
-  
-  return writePLY(filename,V,F,E, N, UV, VD, VDheader, 
+
+  return writePLY(filename,V,F,E, N, UV, VD, VDheader,
                          _dummy, _dummy_header, _dummy, _dummy_header, comments, true);
 
 }
@@ -405,4 +405,5 @@ bool writePLY(
 // Explicit template instantiation
 template bool igl::writePLY<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
 template bool igl::writePLY<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, bool);
+template bool igl::writePLY<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, bool);
 #endif

+ 80 - 0
tests/include/igl/scaf.cpp

@@ -0,0 +1,80 @@
+#include <test_common.h>
+#include <igl/cat.h>
+#include <igl/scaf.h>
+#include <igl/slice.h>
+#include <igl/harmonic.h>
+#include <igl/boundary_loop.h>
+#include <igl/map_vertices_to_circle.h>
+#include <igl/flip_avoiding_line_search.h>
+
+// Assert that building the SCAF equation system via scaf_system() and
+// solving it manually yields the same result as calling scaf_solve() directly.
+TEST_CASE("scaf_system: Test scaf_system() vs scaf_solve()", "[igl]")
+{
+  // Read cube mesh
+  Eigen::MatrixXd V;
+  Eigen::MatrixXi F;
+  igl::read_triangle_mesh(test_common::data_path("cube.obj"), V, F);
+
+  // Cut to disk
+  F = F.topRows(F.rows() - 1).eval();
+
+  // Compute Tutte's embedding
+  Eigen::MatrixXd uv_init;
+  {
+      Eigen::MatrixXd bnd_uv;
+      std::vector<int> boundary;
+      igl::boundary_loop(F, boundary);
+      Eigen::VectorXi bnd = Eigen::Map<Eigen::VectorXi>(boundary.data(), boundary.size());
+      igl::map_vertices_to_circle(V, bnd, bnd_uv);
+      igl::harmonic(F, bnd, bnd_uv ,1, uv_init);
+      uv_init.conservativeResize(V.rows(), 2);
+  }
+
+  // Init empty constraint vectors
+  Eigen::VectorXi b;
+  Eigen::MatrixXd bc;
+
+  // Run one scaf iteration as reference
+  igl::SCAFData s_ref;
+  {
+      igl::scaf_precompute(V, F, uv_init, s_ref, igl::MappingEnergyType::SYMMETRIC_DIRICHLET, b, bc, 0);
+      igl::scaf_solve(s_ref, 1);
+  }
+
+  // Obtain SCAF linear system perform iteration manually
+  igl::SCAFData s_test;
+  {
+      // Set up system
+      igl::scaf_precompute(V, F, uv_init, s_test, igl::MappingEnergyType::SYMMETRIC_DIRICHLET, b, bc, 0);
+      Eigen::SparseMatrix<double> L;
+      Eigen::VectorXd rhs;
+      igl::scaf_system(s_test, L, rhs);
+
+      // Solve
+      Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> solver;
+      auto x = solver.compute(L).solve(rhs);
+
+      // Write result to uv_target
+      Eigen::MatrixXd uv_target = s_test.w_uv;
+      const int n_v_var = s_test.w_uv.rows() - s_test.frame_ids.size();
+      for (int i = 0; i < n_v_var; ++i)
+      {
+          int row = i;
+          if (i >= s_test.v_num)
+              row += s_test.frame_ids.size();
+
+          uv_target(row, 0) = x[i];
+          uv_target(row, 1) = x[i + n_v_var];
+      }
+
+      // Line search
+      auto E = [&s_test](Eigen::MatrixXd &uv) { return igl::scaf::compute_energy(s_test, uv, true); };
+      Eigen::MatrixXi w_T;
+      igl::cat(1, s_test.m_T, s_test.s_T, w_T);
+      igl::flip_avoiding_line_search(w_T, s_test.w_uv, uv_target, E, -1);
+  }
+
+  // Compare both results
+  REQUIRE(s_test.w_uv == s_ref.w_uv);
+}

+ 75 - 0
tests/include/igl/writePLY.cpp

@@ -77,3 +77,78 @@ TEST_CASE("writePLY: bunny.ply", "[igl]")
     // there are comments
     REQUIRE (comments.size() == 2);
 }
+
+
+
+TEST_CASE("writePLY: bunny.ply float", "[igl]")
+{
+    std::ifstream f(test_common::data_path("bunny.ply"));
+    REQUIRE (f.good());
+    f.close();
+    
+    Eigen::MatrixXf V1,N1,UV1,VD1,FD1,ED1;
+    std::vector<std::string> Vheader1,Fheader1,Eheader1,comments1;
+
+    Eigen::MatrixXi F1,E1;
+
+    // load test data first
+    REQUIRE (igl::readPLY(test_common::data_path("bunny.ply"), V1, F1, E1, N1, UV1, VD1,Vheader1, FD1,Fheader1, ED1,Eheader1,comments1));
+
+    // add more data 
+    Vheader1.push_back("dummy_data");
+    Eigen::VectorXf dummy_data(V1.rows());
+    for(size_t i=0;i<V1.rows();++i)
+        dummy_data(i)=(double)i;
+    Eigen::MatrixXf VD2(V1.rows(),VD1.cols()+1);
+    VD2<<VD1,dummy_data;
+
+
+    // test that saving preserves all the data, including new data column
+    REQUIRE (igl::writePLY("test_bunny.ply", V1, F1, E1, N1, UV1, VD2, Vheader1, FD1,Fheader1, ED1, Eheader1, comments1, true));
+
+    Eigen::MatrixXf V,N,UV,VD,FD,ED;
+    Eigen::MatrixXi F,E;
+    std::vector<std::string> Vheader,Fheader,Eheader,comments;
+
+    // test that saving preserves all the data
+    REQUIRE (igl::readPLY("test_bunny.ply", V, F, E, N, UV, VD,Vheader, FD,Fheader, ED,Eheader, comments));
+
+    REQUIRE (V.rows() == 35947);
+    REQUIRE (V.cols() == 3);
+    REQUIRE (F.rows() == 69451);
+    REQUIRE (F.cols() == 3);
+    // no edge data
+    REQUIRE (E.rows() == 0);
+    REQUIRE (E.cols() == 0);
+
+    // no normals or texture coordinates
+    REQUIRE (N.rows() == 0);
+    REQUIRE (N.cols() == 0);
+    REQUIRE (UV.rows() == 0);
+    REQUIRE (UV.cols() == 0);
+
+    // this bunny have additonal data
+    REQUIRE (VD.rows() == 35947);
+    REQUIRE (VD.cols() == 3);
+
+    // the dummy column contents check
+    for(size_t i=0;i<V.rows();++i)
+        REQUIRE (VD(i,2) == (double)i);
+
+    REQUIRE (Vheader.size() == 3);
+    REQUIRE (Vheader[0] == "confidence" );
+    REQUIRE (Vheader[1] == "intensity" );
+    REQUIRE (Vheader[2] == "dummy_data" );
+
+    // no Face data or edge data
+    REQUIRE (FD.rows() == 0);
+    REQUIRE (FD.cols() == 0);
+    REQUIRE (Fheader.size() == 0);
+
+    REQUIRE (ED.rows() == 0);
+    REQUIRE (ED.cols() == 0);
+    REQUIRE (Eheader.size() == 0);
+
+    // there are comments
+    REQUIRE (comments.size() == 2);
+}

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

@@ -63,12 +63,12 @@ int main(int argc, char *argv[])
   // Plot labels with the coordinates of bounding box vertices
   std::stringstream l1;
   l1 << m(0) << ", " << m(1) << ", " << m(2);
-  viewer.data().add_label(m,l1.str());
+  viewer.data().add_label(m+Eigen::Vector3d(-0.007, 0, 0),l1.str());
   std::stringstream l2;
   l2 << M(0) << ", " << M(1) << ", " << M(2);
-  viewer.data().add_label(M,l2.str());
+  viewer.data().add_label(M+Eigen::Vector3d(0.007, 0, 0),l2.str());
   // activate label rendering
-  viewer.data().show_labels = true;
+  viewer.data().show_custom_labels = true;
 
   // Rendering of text labels is handled by ImGui, so we need to enable the ImGui
   // plugin to show text labels.

+ 1 - 0
tutorial/106_ViewerMenu/main.cpp

@@ -99,5 +99,6 @@ int main(int argc, char *argv[])
 
   // Plot the mesh
   viewer.data().set_mesh(V, F);
+  viewer.data().add_label(viewer.data().V.row(0) + viewer.data().V_normals.row(0).normalized()*0.005, "Hello World!");
   viewer.launch();
 }

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff