mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-21 20:25:20 +00:00
Update eigen to v5.0.1 and libigl to v2.6.0. (#11311)
* Update eigen from v3.3.7 to v5.0.1. This updates eigen from v3.3.7 released on December 11, 2018-12-11 to v5.0.1 released on 2025-11-11. There have be a large number of bug-fixes, optimizations, and improvements between these releases. See the details at; https://gitlab.com/libeigen/eigen/-/releases It retains the previous custom minimal `CMakeLists.txt`, and adds a README-OrcaSlicer.md that explains what version and parts of the upstream eigen release have been included, and where the full release can be found. * Update libigl from v2.0.0 (or older) to v2.6.0. This updates libigl from what was probably v2.0.0 released on 2018-10-16 to v2.6.0 released on 2025-05-15. It's possible the old version was even older than that but there is no version indicators in the code and I ran out of patience identifying missing changes and only went back as far as v2.0.0. There have been a large number of bug-fixes, optimizations, and improvements between these versions. See the following for details; https://github.com/libigl/libigl/releases I retained the minimal custom `CMakeLists.txt`, added `README.md` from the libigl distribution which identifies the version, and added a README-OrcaSlicer.md that details the version and parts that have been included. * Update libslic3r for libigl v2.6.0 changes. This updates libslic3r for all changes moving to eigen v5.0.1 and libigl v2.6.0. Despite the large number of updates to both dependencies, no changes were required for the eigen update, and only one change was required for the libigl update. For libigl, `igl::Hit` was changed to a template taking the Scalar type to use. Previously it was hard-coded to `float`, so to minimize possible impact I've updated all places it is used from `igl::Hit` to `igl::Hit<float>`. * Add compiler option `-DNOMINMAX` for libigl with MSVC. MSVC by default defines `min(()` and `max()` macros that break `std::numeric_limits<>::max()`. The upstream cmake that we don't include adds `-DNOMINMAX` for the libigl module when compiling with MSVC, so we need to add the same thing here. * Fix src/libslic3r/TriangleMeshDeal.cpp for the unmodified upstream libigl. This fixes `TriangleMeshDeal.cpp` to work with the unmodified upstream libigl v2.6.0. loop.{h,cpp} implementation. This file and feature was added in PR "BBS Port: Mesh Subdivision" (#12150) which included changes to `loop.{h,cpp}` in the old version of libigl. This PR avoids modifying the included dependencies, and uses the updated upstream versions of those files without any modifications, which requires fixing TriangleMeshDeal.cpp to work with them. In particular, the modifications made to `loop.{h,cpp}` included changing the return type from void to bool, adding additional validation checking of the input meshes, and returning false if they failed validation. These added checks looked unnecessary and would only have caught problems if the input mesh was very corrupt. To make `TriangleMeshDeal.cpp` work without this built-in checking functionality, I removed checking/handling of any `false` return value. There was also a hell of a lot of redundant copying and casting back and forth between float and double, so I cleaned that up. The input and output meshs use floats for the vertexes, and there would be no accuracy benefits from casting to and from doubles for the simple weighted average operations done by igl::loop(). So this just uses `Eigen:Map` to use the original input mesh vertex data directly without requiring any copy or casting. * Move eigen from included `deps_src` to externaly fetched `deps`. This copys what PrusaSlicer did and moved it from an included dependency under `deps_src` to an externaly fetched dependency under `deps`. This requires updating some `CMakeList.txt` configs and removing the old and obsolete `cmake/modules/FindEigen3.cmake`. The details of when this was done in PrusaSlicer and the followup fixes are at; *21116995d7* https://github.com/prusa3d/PrusaSlicer/issues/13608 * https://github.com/prusa3d/PrusaSlicer/pull/13609 *e3c277b9eeFor some reason I don't fully understand this also required fixing `src/slic3r/GUI/GUI_App.cpp` by adding `#include <boost/nowide/cstdio.hpp>` to fix an `error: ‘remove’ is not a member of ‘boost::nowide'`. The main thing I don't understand is how it worked before. Note that this include is in the PrusaSlicer version of this file, but it also significantly deviates from what is currently in OrcaSlicer in many other ways. * Whups... I missed adding the deps/Eigen/Eigen.cmake file... * Tidy some whitespace indenting in CMakeLists.txt. * Ugh... tabs indenting needing fixes. * Change the include order of deps/Eigen. It turns out that although Boost includes some references to Eigen, Eigen also includes some references to Boost for supporting some of it's additional numeric types. I don't think it matters much since we are not using these features, but I think technically its more correct to say Eigen depends on Boost than the other way around, so I've re-ordered them. * Add source for Eigen 5.0.1 download to flatpak yml config. * Add explicit `DEPENDS dep_Boost to deps/Eigen. I missed this before. This ensures we don't rely on include orders to make sure Boost is installed before we configure Eigen. * Add `DEPENDS dep_Boost dep_GMP dep_MPFR` to deps/Eigen. It turns out Eigen can also use GMP and MPFR for multi-precision and multi-precision-rounded numeric types if they are available. Again, I don't think we are using these so it doesn't really matter, but it is technically correct and ensures they are there if we ever do need them. * Fix deps DEPENDENCY ordering for GMP, MPFR, Eigen, and CGAL. I think this is finally correct. Apparently CGAL also optionally depends on Eigen, so the correct dependency order from lowest to highest is GMP, MPFR, Eigen, and CGAL. --------- Co-authored-by: Donovan Baarda <dbaarda@google.com> Co-authored-by: Noisyfox <timemanager.rick@gmail.com>
This commit is contained in:
@@ -10,8 +10,15 @@
|
||||
#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():
|
||||
tex_filter(GL_LINEAR),
|
||||
tex_wrap(GL_REPEAT)
|
||||
{
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::MeshGL::init_buffers()
|
||||
{
|
||||
// Mesh: Vertex Array Object & Buffer objects
|
||||
@@ -25,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);
|
||||
@@ -40,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;
|
||||
}
|
||||
|
||||
@@ -65,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);
|
||||
@@ -88,10 +125,10 @@ IGL_INLINE void igl::opengl::MeshGL::bind_mesh()
|
||||
glBindTexture(GL_TEXTURE_2D, vbo_tex);
|
||||
if (dirty & MeshGL::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);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tex_wrap);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tex_wrap);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex_filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex_filter);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_u, tex_v, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.data());
|
||||
}
|
||||
@@ -110,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;
|
||||
}
|
||||
@@ -126,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);
|
||||
@@ -157,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)
|
||||
@@ -181,17 +264,29 @@ R"(#version 150
|
||||
out vec4 Kai;
|
||||
out vec4 Kdi;
|
||||
out vec4 Ksi;
|
||||
uniform mat4 shadow_view;
|
||||
uniform mat4 shadow_proj;
|
||||
uniform bool shadow_pass;
|
||||
uniform bool is_shadow_mapping;
|
||||
out vec4 position_shadow;
|
||||
|
||||
void main()
|
||||
{
|
||||
position_eye = vec3 (view * vec4 (position, 1.0));
|
||||
normal_eye = vec3 (normal_matrix * vec4 (normal, 0.0));
|
||||
normal_eye = normalize(normal_eye);
|
||||
gl_Position = proj * vec4 (position_eye, 1.0); //proj * view * vec4(position, 1.0);"
|
||||
Kai = Ka;
|
||||
Kdi = Kd;
|
||||
Ksi = Ks;
|
||||
texcoordi = texcoord;
|
||||
if(!shadow_pass)
|
||||
{
|
||||
if(is_shadow_mapping)
|
||||
{
|
||||
position_shadow = shadow_proj * shadow_view * vec4(position, 1.0);
|
||||
}
|
||||
normal_eye = vec3 (normal_matrix * vec4 (normal, 0.0));
|
||||
normal_eye = normalize(normal_eye);
|
||||
Kai = Ka;
|
||||
Kdi = Kd;
|
||||
Ksi = Ks;
|
||||
texcoordi = texcoord;
|
||||
}
|
||||
gl_Position = proj * vec4 (position_eye, 1.0); //proj * view * vec4(position, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
@@ -202,6 +297,9 @@ R"(#version 150
|
||||
uniform vec4 fixed_color;
|
||||
in vec3 position_eye;
|
||||
in vec3 normal_eye;
|
||||
uniform bool is_directional_light;
|
||||
uniform bool is_shadow_mapping;
|
||||
uniform bool shadow_pass;
|
||||
uniform vec3 light_position_eye;
|
||||
vec3 Ls = vec3 (1, 1, 1);
|
||||
vec3 Ld = vec3 (1, 1, 1);
|
||||
@@ -214,26 +312,76 @@ R"(#version 150
|
||||
uniform float specular_exponent;
|
||||
uniform float lighting_factor;
|
||||
uniform float texture_factor;
|
||||
uniform float matcap_factor;
|
||||
uniform float double_sided;
|
||||
|
||||
uniform sampler2D shadow_tex;
|
||||
in vec4 position_shadow;
|
||||
|
||||
out vec4 outColor;
|
||||
void main()
|
||||
{
|
||||
vec3 Ia = La * vec3(Kai); // ambient intensity
|
||||
if(shadow_pass)
|
||||
{
|
||||
// Would it be better to have a separate no-op frag shader?
|
||||
outColor = vec4(0.56,0.85,0.77,1.);
|
||||
return;
|
||||
}
|
||||
// If is_directional_light then assume normalized
|
||||
vec3 direction_to_light_eye = light_position_eye;
|
||||
if(! is_directional_light)
|
||||
{
|
||||
vec3 vector_to_light_eye = light_position_eye - position_eye;
|
||||
direction_to_light_eye = normalize(vector_to_light_eye);
|
||||
}
|
||||
float shadow = 1.0;
|
||||
if(is_shadow_mapping)
|
||||
{
|
||||
vec3 shadow_pos = (position_shadow.xyz / position_shadow.w) * 0.5 + 0.5;
|
||||
float currentDepth = shadow_pos.z;
|
||||
//float bias = 0.005;
|
||||
float ddd = max(dot(normalize(normal_eye), direction_to_light_eye),0);
|
||||
float bias = max(0.02 * (1.0 - ddd), 0.005);
|
||||
// 5-point stencil
|
||||
if(shadow_pos.z < 1.0)
|
||||
{
|
||||
float closestDepth = texture( shadow_tex , shadow_pos.xy).r;
|
||||
shadow = currentDepth - bias >= closestDepth ? 0.0 : 1.0;
|
||||
vec2 texelSize = 1.0 / textureSize(shadow_tex, 0);
|
||||
for(int x = -1; x <= 1; x+=2)
|
||||
{
|
||||
for(int y = -1; y <= 1; y+=2)
|
||||
{
|
||||
float pcfDepth = texture(shadow_tex, shadow_pos.xy + vec2(x, y) * texelSize).r;
|
||||
shadow += currentDepth - bias >= pcfDepth ? 0.0 : 1.0;
|
||||
}
|
||||
}
|
||||
shadow /= 5.0;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 vector_to_light_eye = light_position_eye - position_eye;
|
||||
vec3 direction_to_light_eye = normalize (vector_to_light_eye);
|
||||
float dot_prod = dot (direction_to_light_eye, normalize(normal_eye));
|
||||
float clamped_dot_prod = max (dot_prod, 0.0);
|
||||
vec3 Id = Ld * vec3(Kdi) * clamped_dot_prod; // Diffuse intensity
|
||||
if(matcap_factor == 1.0f)
|
||||
{
|
||||
vec2 uv = normalize(normal_eye).xy * 0.5 + 0.5;
|
||||
outColor = mix(Kai,texture(tex, uv),shadow);
|
||||
}else
|
||||
{
|
||||
vec3 Ia = La * vec3(Kai); // ambient intensity
|
||||
|
||||
vec3 reflection_eye = reflect (-direction_to_light_eye, normalize(normal_eye));
|
||||
vec3 surface_to_viewer_eye = normalize (-position_eye);
|
||||
float dot_prod_specular = dot (reflection_eye, surface_to_viewer_eye);
|
||||
dot_prod_specular = float(abs(dot_prod)==dot_prod) * max (dot_prod_specular, 0.0);
|
||||
float specular_factor = pow (dot_prod_specular, specular_exponent);
|
||||
vec3 Is = Ls * vec3(Ksi) * specular_factor; // specular intensity
|
||||
vec4 color = vec4(lighting_factor * (Is + Id) + Ia + (1.0-lighting_factor) * vec3(Kdi),(Kai.a+Ksi.a+Kdi.a)/3);
|
||||
outColor = mix(vec4(1,1,1,1), texture(tex, texcoordi), texture_factor) * color;
|
||||
if (fixed_color != vec4(0.0)) outColor = fixed_color;
|
||||
float dot_prod = dot (direction_to_light_eye, normalize(normal_eye));
|
||||
float clamped_dot_prod = abs(max (dot_prod, -double_sided));
|
||||
vec3 Id = Ld * vec3(Kdi) * clamped_dot_prod; // Diffuse intensity
|
||||
|
||||
vec3 reflection_eye = reflect (-direction_to_light_eye, normalize(normal_eye));
|
||||
vec3 surface_to_viewer_eye = normalize (-position_eye);
|
||||
float dot_prod_specular = dot (reflection_eye, surface_to_viewer_eye);
|
||||
dot_prod_specular = float(abs(dot_prod)==dot_prod) * abs(max (dot_prod_specular, -double_sided));
|
||||
float specular_factor = pow (dot_prod_specular, specular_exponent);
|
||||
vec3 Is = Ls * vec3(Ksi) * specular_factor; // specular intensity
|
||||
vec4 color = vec4(Ia + shadow*(lighting_factor * (Is + Id) + (1.0-lighting_factor) * vec3(Kdi)),(Kai.a+Ksi.a+Kdi.a)/3);
|
||||
outColor = mix(vec4(1,1,1,1), texture(tex, texcoordi), texture_factor) * color;
|
||||
if (fixed_color != vec4(0.0)) outColor = fixed_color;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
@@ -274,7 +422,79 @@ 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 vCharacter;
|
||||
out float vOffset;
|
||||
void main()
|
||||
{
|
||||
vCharacter = int(character);
|
||||
vOffset = offset;
|
||||
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 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,
|
||||
@@ -290,6 +510,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()
|
||||
@@ -308,6 +534,7 @@ IGL_INLINE void igl::opengl::MeshGL::free()
|
||||
free(shader_mesh);
|
||||
free(shader_overlay_lines);
|
||||
free(shader_overlay_points);
|
||||
free(shader_text);
|
||||
free_buffers();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,23 +8,26 @@
|
||||
#ifndef IGL_OPENGL_MESHGL_H
|
||||
#define IGL_OPENGL_MESHGL_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_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <cstdint>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
/// 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
|
||||
class MeshGL
|
||||
{
|
||||
public:
|
||||
typedef unsigned int GLuint;
|
||||
typedef unsigned int GLint;
|
||||
|
||||
/// Bitmask flags for keeping track of what needs to be (re)-uploaded to the
|
||||
/// GPU
|
||||
enum DirtyFlags
|
||||
{
|
||||
DIRTY_NONE = 0x0000,
|
||||
@@ -39,7 +42,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;
|
||||
@@ -49,23 +55,38 @@ 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)
|
||||
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)
|
||||
/// Vertices of the current mesh (#V x 3)
|
||||
GLuint vbo_V;
|
||||
/// UV coordinates for the current mesh (#V x 2)
|
||||
GLuint vbo_V_uv;
|
||||
/// Vertices of the current mesh (#V x 3)
|
||||
GLuint vbo_V_normals;
|
||||
/// Ambient material (#V x 3)
|
||||
GLuint vbo_V_ambient;
|
||||
/// Diffuse material (#V x 3)
|
||||
GLuint vbo_V_diffuse;
|
||||
/// Specular material (#V x 3)
|
||||
GLuint vbo_V_specular;
|
||||
|
||||
GLuint vbo_F; // Faces of the mesh (#F x 3)
|
||||
GLuint vbo_tex; // Texture
|
||||
/// Faces of the mesh (#F x 3)
|
||||
GLuint vbo_F;
|
||||
/// Texture
|
||||
GLuint vbo_tex;
|
||||
|
||||
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
|
||||
/// Indices of the line overlay
|
||||
GLuint vbo_lines_F;
|
||||
/// Vertices of the line overlay
|
||||
GLuint vbo_lines_V;
|
||||
/// Color values of the line overlay
|
||||
GLuint vbo_lines_V_colors;
|
||||
/// Indices of the point overlay
|
||||
GLuint vbo_points_F;
|
||||
/// Vertices of the point overlay
|
||||
GLuint vbo_points_V;
|
||||
/// Color values of the point overlay
|
||||
GLuint vbo_points_V_colors;
|
||||
|
||||
// Temporary copy of the content of each VBO
|
||||
typedef Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> RowMatrixXf;
|
||||
@@ -80,45 +101,79 @@ public:
|
||||
RowMatrixXf points_V_vbo;
|
||||
RowMatrixXf points_V_colors_vbo;
|
||||
|
||||
// Text Rendering
|
||||
struct TextGL
|
||||
{
|
||||
std::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;
|
||||
GLint tex_wrap;
|
||||
Eigen::Matrix<char,Eigen::Dynamic,1> tex;
|
||||
|
||||
Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> F_vbo;
|
||||
Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> lines_F_vbo;
|
||||
Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> points_F_vbo;
|
||||
|
||||
// Marks dirty buffers that need to be uploaded to OpenGL
|
||||
uint32_t dirty;
|
||||
/// Marks dirty buffers that need to be uploaded to OpenGL
|
||||
std::uint32_t dirty;
|
||||
|
||||
// Initialize shaders and buffers
|
||||
IGL_INLINE MeshGL();
|
||||
|
||||
/// Initialize shaders and buffers
|
||||
IGL_INLINE void init();
|
||||
|
||||
// Release all resources
|
||||
/// Release all resources
|
||||
IGL_INLINE void free();
|
||||
|
||||
// Create a new set of OpenGL buffer objects
|
||||
/// Create a new set of OpenGL buffer objects
|
||||
IGL_INLINE void init_buffers();
|
||||
|
||||
// Bind the underlying OpenGL buffer objects for subsequent mesh draw calls
|
||||
/// 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)
|
||||
///
|
||||
/// @param[in] solid Whether to draw the mesh as a solid or wireframe
|
||||
IGL_INLINE void draw_mesh(bool solid);
|
||||
|
||||
// Bind the underlying OpenGL buffer objects for subsequent line overlay draw calls
|
||||
/// 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
|
||||
/// 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
|
||||
/// Text Binding and Draw functions
|
||||
IGL_INLINE void init_text_rendering();
|
||||
/// Bind the underlying OpenGL buffer objects for subsequent text draw calls
|
||||
IGL_INLINE void bind_labels(const TextGL& labels);
|
||||
/// Draw the currently buffered text
|
||||
IGL_INLINE void draw_labels(const TextGL& labels);
|
||||
|
||||
/// Release the OpenGL buffer objects
|
||||
IGL_INLINE void free_buffers();
|
||||
|
||||
};
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "ViewerCore.h"
|
||||
#include "ViewerData.h"
|
||||
#include "gl.h"
|
||||
#include "../quat_to_mat.h"
|
||||
#include "../null.h"
|
||||
#include "../snap_to_fixed_up.h"
|
||||
#include "../look_at.h"
|
||||
#include "../frustum.h"
|
||||
@@ -16,6 +18,8 @@
|
||||
#include "../massmatrix.h"
|
||||
#include "../barycenter.h"
|
||||
#include "../PI.h"
|
||||
#include "report_gl_error.h"
|
||||
#include "read_pixels.h"
|
||||
#include <Eigen/Geometry>
|
||||
#include <iostream>
|
||||
|
||||
@@ -87,11 +91,16 @@ IGL_INLINE void igl::opengl::ViewerCore::get_scale_and_shift_to_fit_mesh(
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::clear_framebuffers()
|
||||
{
|
||||
// The glScissor call ensures we only clear this core's buffers,
|
||||
// (in case the user wants different background colors in each viewport.)
|
||||
glScissor(viewport(0), viewport(1), viewport(2), viewport(3));
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glClearColor(background_color[0],
|
||||
background_color[1],
|
||||
background_color[2],
|
||||
background_color[3]);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::draw(
|
||||
@@ -112,7 +121,7 @@ IGL_INLINE void igl::opengl::ViewerCore::draw(
|
||||
/* Bind and potentially refresh mesh/line/point data */
|
||||
if (data.dirty)
|
||||
{
|
||||
data.updateGL(data, data.invert_normals,data.meshgl);
|
||||
data.updateGL(data, data.invert_normals, data.meshgl);
|
||||
data.dirty = MeshGL::DIRTY_NONE;
|
||||
}
|
||||
data.meshgl.bind_mesh();
|
||||
@@ -166,39 +175,67 @@ IGL_INLINE void igl::opengl::ViewerCore::draw(
|
||||
GLint lighting_factori = glGetUniformLocation(data.meshgl.shader_mesh,"lighting_factor");
|
||||
GLint fixed_colori = glGetUniformLocation(data.meshgl.shader_mesh,"fixed_color");
|
||||
GLint texture_factori = glGetUniformLocation(data.meshgl.shader_mesh,"texture_factor");
|
||||
GLint matcap_factori = glGetUniformLocation(data.meshgl.shader_mesh,"matcap_factor");
|
||||
GLint double_sidedi = glGetUniformLocation(data.meshgl.shader_mesh,"double_sided");
|
||||
|
||||
const bool eff_is_directional_light = is_directional_light || is_shadow_mapping;
|
||||
glUniform1f(specular_exponenti, data.shininess);
|
||||
glUniform3fv(light_position_eyei, 1, light_position.data());
|
||||
if(eff_is_directional_light)
|
||||
{
|
||||
Eigen::Vector3f light_direction = light_position.normalized();
|
||||
glUniform3fv(light_position_eyei, 1, light_direction.data());
|
||||
}else
|
||||
{
|
||||
glUniform3fv(light_position_eyei, 1, light_position.data());
|
||||
}
|
||||
if(is_shadow_mapping)
|
||||
{
|
||||
glUniformMatrix4fv(glGetUniformLocation(data.meshgl.shader_mesh,"shadow_view"), 1, GL_FALSE, shadow_view.data());
|
||||
glUniformMatrix4fv(glGetUniformLocation(data.meshgl.shader_mesh,"shadow_proj"), 1, GL_FALSE, shadow_proj.data());
|
||||
glActiveTexture(GL_TEXTURE0+1);
|
||||
glBindTexture(GL_TEXTURE_2D, shadow_depth_tex);
|
||||
{
|
||||
glUniform1i(glGetUniformLocation(data.meshgl.shader_mesh,"shadow_tex"), 1);
|
||||
}
|
||||
}
|
||||
glUniform1f(lighting_factori, lighting_factor); // enables lighting
|
||||
glUniform4f(fixed_colori, 0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
glUniform1i(glGetUniformLocation(data.meshgl.shader_mesh,"is_directional_light"),eff_is_directional_light);
|
||||
glUniform1i(glGetUniformLocation(data.meshgl.shader_mesh,"is_shadow_mapping"),is_shadow_mapping);
|
||||
glUniform1i(glGetUniformLocation(data.meshgl.shader_mesh,"shadow_pass"),false);
|
||||
|
||||
if (data.V.rows()>0)
|
||||
{
|
||||
// Render fill
|
||||
if (data.show_faces)
|
||||
if (is_set(data.show_faces))
|
||||
{
|
||||
// Texture
|
||||
glUniform1f(texture_factori, data.show_texture ? 1.0f : 0.0f);
|
||||
glUniform1f(texture_factori, is_set(data.show_texture) ? 1.0f : 0.0f);
|
||||
glUniform1f(matcap_factori, is_set(data.use_matcap) ? 1.0f : 0.0f);
|
||||
glUniform1f(double_sidedi, data.double_sided ? 1.0f : 0.0f);
|
||||
data.meshgl.draw_mesh(true);
|
||||
glUniform1f(matcap_factori, 0.0f);
|
||||
glUniform1f(texture_factori, 0.0f);
|
||||
}
|
||||
|
||||
// Render wireframe
|
||||
if (data.show_lines)
|
||||
if (is_set(data.show_lines))
|
||||
{
|
||||
glLineWidth(data.line_width);
|
||||
glUniform4f(fixed_colori,
|
||||
data.line_color[0],
|
||||
data.line_color[1],
|
||||
data.line_color[2], 1.0f);
|
||||
data.line_color[2],
|
||||
data.line_color[3]);
|
||||
data.meshgl.draw_mesh(false);
|
||||
glUniform4f(fixed_colori, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.show_overlay)
|
||||
if (is_set(data.show_overlay))
|
||||
{
|
||||
if (data.show_overlay_depth)
|
||||
if (is_set(data.show_overlay_depth))
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
else
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
@@ -227,16 +264,89 @@ 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,
|
||||
IGL_INLINE void igl::opengl::ViewerCore::initialize_shadow_pass()
|
||||
{
|
||||
// attach buffers
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, shadow_depth_fbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, shadow_color_rbo);
|
||||
// clear buffer
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
// In the libigl viewer setup, each mesh has its own shader program. This is
|
||||
// kind of funny because they should all be the same, just different uniform
|
||||
// values.
|
||||
glViewport(0,0,shadow_width,shadow_height);
|
||||
// Assumes light is directional
|
||||
assert(is_directional_light);
|
||||
Eigen::Vector3f camera_eye = light_position.normalized()*5;
|
||||
Eigen::Vector3f camera_up = [&camera_eye]()
|
||||
{
|
||||
Eigen::Matrix<float,3,2> T;
|
||||
igl::null(camera_eye.transpose().eval(),T);
|
||||
return T.col(0);
|
||||
}();
|
||||
Eigen::Vector3f camera_center = this->camera_center;
|
||||
// Same camera parameters except 2× field of view and reduced far plane
|
||||
float camera_view_angle = 2*this->camera_view_angle;
|
||||
float camera_dnear = this->camera_dnear;
|
||||
float camera_dfar = this->camera_dfar;
|
||||
Eigen::Quaternionf trackball_angle = this->trackball_angle;
|
||||
float camera_zoom = this->camera_zoom;
|
||||
float camera_base_zoom = this->camera_base_zoom;
|
||||
Eigen::Vector3f camera_translation = this->camera_translation;
|
||||
Eigen::Vector3f camera_base_translation = this->camera_base_translation;
|
||||
camera_dfar = exp2( 0.5 * ( log2(camera_dnear) + log2(camera_dfar)));
|
||||
igl::look_at( camera_eye, camera_center, camera_up, shadow_view);
|
||||
shadow_view = shadow_view
|
||||
* (trackball_angle * Eigen::Scaling(camera_zoom * camera_base_zoom)
|
||||
* Eigen::Translation3f(camera_translation + camera_base_translation)).matrix();
|
||||
|
||||
float length = (camera_eye - camera_center).norm();
|
||||
float h = tan(camera_view_angle/360.0 * igl::PI) * (length);
|
||||
igl::ortho(-h*shadow_width/shadow_height, h*shadow_width/shadow_height, -h, h, camera_dnear, camera_dfar,shadow_proj);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::deinitialize_shadow_pass()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::draw_shadow_pass(
|
||||
ViewerData& data,
|
||||
bool /*update_matrices*/)
|
||||
{
|
||||
if (data.dirty)
|
||||
{
|
||||
data.updateGL(data, data.invert_normals, data.meshgl);
|
||||
data.dirty = igl::opengl::MeshGL::DIRTY_NONE;
|
||||
}
|
||||
data.meshgl.bind_mesh();
|
||||
// Send transformations to the GPU as if rendering from shadow point of view
|
||||
GLint viewi = glGetUniformLocation(data.meshgl.shader_mesh,"view");
|
||||
GLint proji = glGetUniformLocation(data.meshgl.shader_mesh,"proj");
|
||||
glUniformMatrix4fv(viewi, 1, GL_FALSE, shadow_view.data());
|
||||
glUniformMatrix4fv(proji, 1, GL_FALSE, shadow_proj.data());
|
||||
glUniform1i(glGetUniformLocation(data.meshgl.shader_mesh,"shadow_pass"),true);
|
||||
data.meshgl.draw_mesh(true);
|
||||
glUniform1i(glGetUniformLocation(data.meshgl.shader_mesh,"shadow_pass"),false);
|
||||
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::draw_buffer(
|
||||
ViewerData& data,
|
||||
bool update_matrices,
|
||||
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
|
||||
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
|
||||
@@ -248,8 +358,28 @@ IGL_INLINE void igl::opengl::ViewerCore::draw_buffer(ViewerData& data,
|
||||
|
||||
unsigned width = R.rows();
|
||||
unsigned height = R.cols();
|
||||
if(width == 0 && height == 0)
|
||||
{
|
||||
width = viewport(2);
|
||||
height = viewport(3);
|
||||
}
|
||||
R.resize(width,height);
|
||||
G.resize(width,height);
|
||||
B.resize(width,height);
|
||||
A.resize(width,height);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// PREPARE width×height BUFFERS does *not* depend on `data`
|
||||
// framebuffer
|
||||
// textureColorBufferMultiSampled
|
||||
// rbo
|
||||
// intermediateFBO
|
||||
// screenTexture
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing
|
||||
|
||||
// Create an initial multisampled framebuffer
|
||||
unsigned int framebuffer;
|
||||
glGenFramebuffers(1, &framebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
@@ -333,6 +463,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) * data.label_size;
|
||||
glUniform1f(glGetUniformLocation(data.meshgl.shader_text, "TextShiftFactor"), text_shift_scale_factor);
|
||||
glUniform3f(glGetUniformLocation(data.meshgl.shader_text, "TextColor"), data.label_color(0), data.label_color(1), data.label_color(2));
|
||||
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)
|
||||
{
|
||||
@@ -347,6 +505,28 @@ IGL_INLINE void igl::opengl::ViewerCore::set_rotation_type(
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::set(unsigned int &property_mask, bool value) const
|
||||
{
|
||||
if (!value)
|
||||
unset(property_mask);
|
||||
else
|
||||
property_mask |= id;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::unset(unsigned int &property_mask) const
|
||||
{
|
||||
property_mask &= ~id;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::toggle(unsigned int &property_mask) const
|
||||
{
|
||||
property_mask ^= id;
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::opengl::ViewerCore::is_set(unsigned int property_mask) const
|
||||
{
|
||||
return (property_mask & id);
|
||||
}
|
||||
|
||||
IGL_INLINE igl::opengl::ViewerCore::ViewerCore()
|
||||
{
|
||||
@@ -355,10 +535,16 @@ IGL_INLINE igl::opengl::ViewerCore::ViewerCore()
|
||||
|
||||
// Default lights settings
|
||||
light_position << 0.0f, 0.3f, 0.0f;
|
||||
is_directional_light = false;
|
||||
is_shadow_mapping = false;
|
||||
shadow_width = 2056;
|
||||
shadow_height = 2056;
|
||||
|
||||
lighting_factor = 1.0f; //on
|
||||
|
||||
// Default trackball
|
||||
trackball_angle = Eigen::Quaternionf::Identity();
|
||||
rotation_type = ViewerCore::ROTATION_TYPE_TRACKBALL;
|
||||
set_rotation_type(ViewerCore::ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP);
|
||||
|
||||
// Camera parameters
|
||||
@@ -384,8 +570,71 @@ IGL_INLINE igl::opengl::ViewerCore::ViewerCore()
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::init()
|
||||
{
|
||||
delete_shadow_buffers();
|
||||
generate_shadow_buffers();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::shut()
|
||||
{
|
||||
delete_shadow_buffers();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::delete_shadow_buffers()
|
||||
{
|
||||
glDeleteTextures(1,&shadow_depth_tex);
|
||||
glDeleteFramebuffers(1,&shadow_depth_fbo);
|
||||
glDeleteRenderbuffers(1,&shadow_color_rbo);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::generate_shadow_buffers()
|
||||
{
|
||||
// Create a texture for writing the shadow map depth values into
|
||||
{
|
||||
glDeleteTextures(1,&shadow_depth_tex);
|
||||
glGenTextures(1, &shadow_depth_tex);
|
||||
glBindTexture(GL_TEXTURE_2D, shadow_depth_tex);
|
||||
// Should this be using double/float precision?
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
|
||||
shadow_width,
|
||||
shadow_height,
|
||||
0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, Eigen::Vector4f(1,1,1,1).data() );
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
// Generate a framebuffer with depth attached to this texture and color
|
||||
// attached to a render buffer object
|
||||
glGenFramebuffers(1, &shadow_depth_fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, shadow_depth_fbo);
|
||||
// Attach depth texture
|
||||
glFramebufferTexture2D(
|
||||
GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
|
||||
shadow_depth_tex,0);
|
||||
// Generate a render buffer to write colors into. Low precision we don't
|
||||
// care about them. Is there a way to not write/compute them at? Probably
|
||||
// just need to change fragment shader.
|
||||
glGenRenderbuffers(1,&shadow_color_rbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER,shadow_color_rbo);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, shadow_width, shadow_height);
|
||||
// Attach color buffer
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER, shadow_color_rbo);
|
||||
//Does the GPU support current FBO configuration?
|
||||
GLenum status;
|
||||
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
switch(status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_COMPLETE:
|
||||
break;
|
||||
default:
|
||||
printf("[ViewerCore] Error: We failed to set up a good FBO: %d\n",status);
|
||||
assert(false);
|
||||
}
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,9 @@
|
||||
#ifndef IGL_OPENGL_VIEWERCORE_H
|
||||
#define IGL_OPENGL_VIEWERCORE_H
|
||||
|
||||
#include <igl/opengl/MeshGL.h>
|
||||
#include <igl/opengl/ViewerData.h>
|
||||
#include "MeshGL.h"
|
||||
|
||||
#include <igl/igl_inline.h>
|
||||
#include "../igl_inline.h"
|
||||
#include <Eigen/Geometry>
|
||||
#include <Eigen/Core>
|
||||
|
||||
@@ -20,59 +19,83 @@ namespace igl
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
// Basic class of the 3D mesh viewer
|
||||
// TODO: write documentation
|
||||
// Forward declaration
|
||||
class ViewerData;
|
||||
|
||||
/// Basic class of the 3D mesh viewer
|
||||
class ViewerCore
|
||||
{
|
||||
public:
|
||||
using GLuint = MeshGL::GLuint;
|
||||
IGL_INLINE ViewerCore();
|
||||
|
||||
// Initialization
|
||||
/// Initialization
|
||||
IGL_INLINE void init();
|
||||
|
||||
// Shutdown
|
||||
/// Shutdown
|
||||
IGL_INLINE void shut();
|
||||
|
||||
// Serialization code
|
||||
/// Serialization code
|
||||
IGL_INLINE void InitSerialization();
|
||||
|
||||
|
||||
// ------------------- Camera control functions
|
||||
|
||||
// Adjust the view to see the entire model
|
||||
/// Adjust the view to see the entire model
|
||||
/// @param[in] V #V by 3 list of vertex positions
|
||||
/// @param[in] F #F by 3 list of triangle indices into V
|
||||
IGL_INLINE void align_camera_center(
|
||||
const Eigen::MatrixXd& V,
|
||||
const Eigen::MatrixXi& F);
|
||||
/// \overload
|
||||
IGL_INLINE void align_camera_center(
|
||||
const Eigen::MatrixXd& V);
|
||||
|
||||
// Determines how much to zoom and shift such that the mesh fills the unit
|
||||
// box (centered at the origin)
|
||||
/// Determines how much to zoom and shift such that the mesh fills the unit
|
||||
/// box (centered at the origin)
|
||||
/// @param[in] V #V by 3 list of vertex positions
|
||||
/// @param[in] F #F by 3 list of triangle indices into V
|
||||
/// @param[out] zoom zoom factor
|
||||
/// @param[out] shift 3d shift
|
||||
IGL_INLINE void get_scale_and_shift_to_fit_mesh(
|
||||
const Eigen::MatrixXd& V,
|
||||
const Eigen::MatrixXi& F,
|
||||
float & zoom,
|
||||
Eigen::Vector3f& shift);
|
||||
/// \overload
|
||||
IGL_INLINE void get_scale_and_shift_to_fit_mesh(
|
||||
const Eigen::MatrixXd& V,
|
||||
float & zoom,
|
||||
Eigen::Vector3f& shift);
|
||||
|
||||
// Adjust the view to see the entire model
|
||||
IGL_INLINE void align_camera_center(
|
||||
const Eigen::MatrixXd& V);
|
||||
|
||||
// Determines how much to zoom and shift such that the mesh fills the unit
|
||||
// box (centered at the origin)
|
||||
IGL_INLINE void get_scale_and_shift_to_fit_mesh(
|
||||
const Eigen::MatrixXd& V,
|
||||
float & zoom,
|
||||
Eigen::Vector3f& shift);
|
||||
|
||||
// ------------------- Drawing functions
|
||||
|
||||
// Clear the frame buffers
|
||||
/// Clear the frame buffers
|
||||
IGL_INLINE void clear_framebuffers();
|
||||
|
||||
// Draw everything
|
||||
//
|
||||
// data cannot be const because it is being set to "clean"
|
||||
/// Draw everything
|
||||
///
|
||||
/// \note data cannot be const because it is being set to "clean"
|
||||
///
|
||||
/// @param[in] data which ViewerData to draw
|
||||
/// @param[in] update_matrices whether to update view, proj, and norm
|
||||
/// matrices in shaders
|
||||
IGL_INLINE void draw(ViewerData& data, bool update_matrices = true);
|
||||
/// initialize shadow pass
|
||||
IGL_INLINE void initialize_shadow_pass();
|
||||
/// deinitialize shadow pass
|
||||
IGL_INLINE void deinitialize_shadow_pass();
|
||||
/// Draw everything to shadow map
|
||||
/// @param[in] data which ViewerData to draw
|
||||
/// @param[in] update_matrices whether to update view, proj, and norm
|
||||
IGL_INLINE void draw_shadow_pass(ViewerData& data, bool update_matrices = true);
|
||||
/// Render given ViewerData to a buffer. The width and height are determined by
|
||||
/// non-zeros dimensions of R (and G,B,A should match) or – if both are zero —
|
||||
/// are set to this core's viewport sizes.
|
||||
///
|
||||
/// @param[in] data which ViewerData to draw
|
||||
/// @param[in] update_matrices whether to update view, proj, and norm matrices in
|
||||
/// shaders
|
||||
/// @param[out] R width by height red pixel color values
|
||||
/// @param[out] G width by height green pixel color values
|
||||
/// @param[out] B width by height blue pixel color values
|
||||
/// @param[out] A width by height alpha pixel color values
|
||||
///
|
||||
IGL_INLINE void draw_buffer(
|
||||
ViewerData& data,
|
||||
bool update_matrices,
|
||||
@@ -80,58 +103,133 @@ 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);
|
||||
/// Draw the text lables
|
||||
/// @param[in] data which ViewerData to draw
|
||||
/// @param[in] labels text labels to draw
|
||||
IGL_INLINE void draw_labels(
|
||||
ViewerData& data,
|
||||
const igl::opengl::MeshGL::TextGL& labels
|
||||
);
|
||||
|
||||
// Trackball angle (quaternion)
|
||||
/// Type of user interface for changing the view rotation based on the mouse
|
||||
/// draggin.
|
||||
enum RotationType
|
||||
{
|
||||
/// Typical trackball rotation (like Meshlab)
|
||||
ROTATION_TYPE_TRACKBALL = 0,
|
||||
/// Fixed up rotation (like Blender, Maya, etc.)
|
||||
ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1,
|
||||
/// No rotation suitable for 2D
|
||||
ROTATION_TYPE_NO_ROTATION = 2,
|
||||
/// Total number of rotation types
|
||||
NUM_ROTATION_TYPES = 3
|
||||
};
|
||||
/// Set the current rotation type
|
||||
/// @param[in] value the new rotation type
|
||||
IGL_INLINE void set_rotation_type(const RotationType & value);
|
||||
|
||||
/// Set a ViewerData visualization option for this viewport
|
||||
/// @param[in] property_mask a bit mask of visualization option
|
||||
/// @param[in] value whether to set or unset the property
|
||||
IGL_INLINE void set(unsigned int &property_mask, bool value = true) const;
|
||||
|
||||
/// Unset a ViewerData visualization option for this viewport
|
||||
/// @param[in] property_mask a bit mask of visualization option
|
||||
IGL_INLINE void unset(unsigned int &property_mask) const;
|
||||
|
||||
/// Toggle a ViewerData visualization option for this viewport
|
||||
/// @param[in] property_mask a bit mask of visualization option
|
||||
IGL_INLINE void toggle(unsigned int &property_mask) const;
|
||||
|
||||
/// Check whether a ViewerData visualization option is set for this viewport
|
||||
/// @param[in] property_mask a bit mask of visualization option
|
||||
/// @returns whether the property is set
|
||||
IGL_INLINE bool is_set(unsigned int property_mask) const;
|
||||
|
||||
/// delete the shadow buffers
|
||||
IGL_INLINE void delete_shadow_buffers();
|
||||
/// generate the shadow buffers
|
||||
IGL_INLINE void generate_shadow_buffers();
|
||||
|
||||
// ------------------- Properties
|
||||
|
||||
// Colors
|
||||
/// Unique identifier
|
||||
unsigned int id = 1u;
|
||||
|
||||
/// Background color as RGBA
|
||||
Eigen::Vector4f background_color;
|
||||
|
||||
// Lighting
|
||||
/// Light position (or direction to light)
|
||||
Eigen::Vector3f light_position;
|
||||
/// Whether to treat `light_position` as a point or direction
|
||||
bool is_directional_light;
|
||||
/// Whether shadow mapping is on
|
||||
bool is_shadow_mapping;
|
||||
/// Width of the shadow map
|
||||
GLuint shadow_width;
|
||||
/// Height of the shadow map
|
||||
GLuint shadow_height;
|
||||
/// Shadow map depth texture
|
||||
GLuint shadow_depth_tex;
|
||||
/// Shadow map depth framebuffer object
|
||||
GLuint shadow_depth_fbo;
|
||||
/// Shadow map color render buffer object
|
||||
GLuint shadow_color_rbo;
|
||||
/// Factor of lighting (0: no lighting, 1: full lighting)
|
||||
float lighting_factor;
|
||||
|
||||
/// Type of rotation interaction
|
||||
RotationType rotation_type;
|
||||
/// View rotation as quaternion
|
||||
Eigen::Quaternionf trackball_angle;
|
||||
|
||||
// Camera parameters
|
||||
/// Base zoom of camera
|
||||
float camera_base_zoom;
|
||||
/// Current zoom of camera
|
||||
float camera_zoom;
|
||||
/// Whether camera is orthographic (or perspective)
|
||||
bool orthographic;
|
||||
/// Base translation of camera
|
||||
Eigen::Vector3f camera_base_translation;
|
||||
/// Current translation of camera
|
||||
Eigen::Vector3f camera_translation;
|
||||
/// Current "eye" / origin position of camera
|
||||
Eigen::Vector3f camera_eye;
|
||||
/// Current "up" vector of camera
|
||||
Eigen::Vector3f camera_up;
|
||||
/// Current "look at" position of camera
|
||||
Eigen::Vector3f camera_center;
|
||||
/// Current view angle of camera
|
||||
float camera_view_angle;
|
||||
/// Near plane of camera
|
||||
float camera_dnear;
|
||||
/// Far plane of camera
|
||||
float camera_dfar;
|
||||
|
||||
/// Whether testing for depth is enabled
|
||||
bool depth_test;
|
||||
|
||||
// Animation
|
||||
/// Whether "animating" (continuous drawing) is enabled
|
||||
bool is_animating;
|
||||
/// Max fps of animation loop (e.g. 30fps or 60fps)
|
||||
double animation_max_fps;
|
||||
|
||||
// Caches the two-norm between the min/max point of the bounding box
|
||||
/// Caches the two-norm between the min/max point of the bounding box
|
||||
float object_scale;
|
||||
|
||||
// Viewport size
|
||||
/// Viewport size
|
||||
Eigen::Vector4f viewport;
|
||||
|
||||
// Save the OpenGL transformation matrices used for the previous rendering pass
|
||||
/// OpenGL view transformation matrix on last render pass
|
||||
Eigen::Matrix4f view;
|
||||
/// OpenGL proj transformation matrix on last render pass
|
||||
Eigen::Matrix4f proj;
|
||||
/// OpenGL norm transformation matrix on last render pass
|
||||
Eigen::Matrix4f norm;
|
||||
/// OpenGL shadow_view transformation matrix on last render pass
|
||||
Eigen::Matrix4f shadow_view;
|
||||
/// OpenGL shadow_proj transformation matrix on last render pass
|
||||
Eigen::Matrix4f shadow_proj;
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
};
|
||||
@@ -139,7 +237,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
#include <igl/serialize.h>
|
||||
#include "../serialize.h"
|
||||
namespace igl {
|
||||
namespace serialization {
|
||||
|
||||
|
||||
@@ -7,28 +7,39 @@
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "ViewerData.h"
|
||||
#include "ViewerCore.h"
|
||||
|
||||
#include "../per_face_normals.h"
|
||||
#include "../material_colors.h"
|
||||
#include "../parula.h"
|
||||
#include "../per_vertex_normals.h"
|
||||
|
||||
// Really? Just for GL_NEAREST?
|
||||
#include "gl.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
IGL_INLINE igl::opengl::ViewerData::ViewerData()
|
||||
: dirty(MeshGL::DIRTY_ALL),
|
||||
show_faces(true),
|
||||
show_lines(true),
|
||||
invert_normals(false),
|
||||
show_overlay(true),
|
||||
show_overlay_depth(true),
|
||||
show_vertid(false),
|
||||
show_faceid(false),
|
||||
show_texture(false),
|
||||
:
|
||||
dirty(MeshGL::DIRTY_ALL),
|
||||
face_based (false),
|
||||
double_sided (false),
|
||||
invert_normals (false),
|
||||
is_visible (~unsigned(0)),
|
||||
show_custom_labels(0),
|
||||
show_face_labels (0),
|
||||
show_faces (~unsigned(0)),
|
||||
show_lines (~unsigned(0)),
|
||||
show_overlay (~unsigned(0)),
|
||||
show_overlay_depth(~unsigned(0)),
|
||||
show_texture (false),
|
||||
show_vertex_labels(0),
|
||||
use_matcap (false),
|
||||
point_size(30),
|
||||
line_width(0.5f),
|
||||
label_size(1),
|
||||
line_color(0,0,0,1),
|
||||
label_color(0,0,0.04,1),
|
||||
shininess(35.0f),
|
||||
id(-1)
|
||||
{
|
||||
@@ -72,6 +83,7 @@ IGL_INLINE void igl::opengl::ViewerData::set_mesh(
|
||||
Eigen::Vector3d(GOLD_DIFFUSE[0], GOLD_DIFFUSE[1], GOLD_DIFFUSE[2]),
|
||||
Eigen::Vector3d(GOLD_SPECULAR[0], GOLD_SPECULAR[1], GOLD_SPECULAR[2]));
|
||||
|
||||
// Generates a checkerboard texture
|
||||
grid_texture();
|
||||
}
|
||||
else
|
||||
@@ -112,15 +124,34 @@ IGL_INLINE void igl::opengl::ViewerData::set_normals(const Eigen::MatrixXd& N)
|
||||
dirty |= MeshGL::DIRTY_NORMAL;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_visible(bool value, unsigned int core_id /*= 1*/)
|
||||
{
|
||||
if (value)
|
||||
is_visible |= core_id;
|
||||
else
|
||||
is_visible &= ~core_id;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::copy_options(const ViewerCore &from, const ViewerCore &to)
|
||||
{
|
||||
to.set(show_overlay , from.is_set(show_overlay) );
|
||||
to.set(show_overlay_depth, from.is_set(show_overlay_depth));
|
||||
to.set(show_texture , from.is_set(show_texture) );
|
||||
to.set(use_matcap , from.is_set(use_matcap) );
|
||||
to.set(show_faces , from.is_set(show_faces) );
|
||||
to.set(show_lines , from.is_set(show_lines) );
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_colors(const Eigen::MatrixXd &C)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
// This Gouraud coloring should be deprecated in favor of Phong coloring in
|
||||
// set-data
|
||||
if(C.rows()>0 && C.cols() == 1)
|
||||
{
|
||||
Eigen::MatrixXd C3;
|
||||
igl::parula(C,true,C3);
|
||||
return set_colors(C3);
|
||||
assert(false && "deprecated: call set_data directly instead");
|
||||
return set_data(C);
|
||||
}
|
||||
// Ambient color should be darker color
|
||||
const auto ambient = [](const MatrixXd & C)->MatrixXd
|
||||
@@ -160,35 +191,39 @@ IGL_INLINE void igl::opengl::ViewerData::set_colors(const Eigen::MatrixXd &C)
|
||||
F_material_ambient = ambient(F_material_diffuse);
|
||||
F_material_specular = specular(F_material_diffuse);
|
||||
}
|
||||
else if (C.rows() == V.rows())
|
||||
else if(C.rows() == V.rows() || C.rows() == F.rows())
|
||||
{
|
||||
set_face_based(false);
|
||||
for (unsigned i=0;i<V_material_diffuse.rows();++i)
|
||||
// face based colors?
|
||||
if((C.rows()==F.rows()) && (C.rows() != V.rows() || face_based))
|
||||
{
|
||||
if (C.cols() == 3)
|
||||
V_material_diffuse.row(i) << C.row(i), 1;
|
||||
else if (C.cols() == 4)
|
||||
V_material_diffuse.row(i) << C.row(i);
|
||||
set_face_based(true);
|
||||
for (unsigned i=0;i<F_material_diffuse.rows();++i)
|
||||
{
|
||||
if (C.cols() == 3)
|
||||
F_material_diffuse.row(i) << C.row(i), 1;
|
||||
else if (C.cols() == 4)
|
||||
F_material_diffuse.row(i) << C.row(i);
|
||||
}
|
||||
F_material_ambient = ambient(F_material_diffuse);
|
||||
F_material_specular = specular(F_material_diffuse);
|
||||
}
|
||||
V_material_ambient = ambient(V_material_diffuse);
|
||||
V_material_specular = specular(V_material_diffuse);
|
||||
}
|
||||
else if (C.rows() == F.rows())
|
||||
{
|
||||
set_face_based(true);
|
||||
for (unsigned i=0;i<F_material_diffuse.rows();++i)
|
||||
else/*(C.rows() == V.rows())*/
|
||||
{
|
||||
if (C.cols() == 3)
|
||||
F_material_diffuse.row(i) << C.row(i), 1;
|
||||
else if (C.cols() == 4)
|
||||
F_material_diffuse.row(i) << C.row(i);
|
||||
set_face_based(false);
|
||||
for (unsigned i=0;i<V_material_diffuse.rows();++i)
|
||||
{
|
||||
if (C.cols() == 3)
|
||||
V_material_diffuse.row(i) << C.row(i), 1;
|
||||
else if (C.cols() == 4)
|
||||
V_material_diffuse.row(i) << C.row(i);
|
||||
}
|
||||
V_material_ambient = ambient(V_material_diffuse);
|
||||
V_material_specular = specular(V_material_diffuse);
|
||||
}
|
||||
F_material_ambient = ambient(F_material_diffuse);
|
||||
F_material_specular = specular(F_material_diffuse);
|
||||
}
|
||||
else
|
||||
cerr << "ERROR (set_colors): Please provide a single color, or a color per face or per vertex."<<endl;
|
||||
dirty |= MeshGL::DIRTY_DIFFUSE;
|
||||
dirty |= MeshGL::DIRTY_DIFFUSE | MeshGL::DIRTY_SPECULAR | MeshGL::DIRTY_AMBIENT;
|
||||
|
||||
}
|
||||
|
||||
@@ -197,7 +232,6 @@ IGL_INLINE void igl::opengl::ViewerData::set_uv(const Eigen::MatrixXd& UV)
|
||||
using namespace std;
|
||||
if (UV.rows() == V.rows())
|
||||
{
|
||||
set_face_based(false);
|
||||
V_uv = UV;
|
||||
}
|
||||
else
|
||||
@@ -207,13 +241,11 @@ IGL_INLINE void igl::opengl::ViewerData::set_uv(const Eigen::MatrixXd& UV)
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F)
|
||||
{
|
||||
set_face_based(true);
|
||||
V_uv = UV_V.block(0,0,UV_V.rows(),2);
|
||||
F_uv = UV_F;
|
||||
dirty |= MeshGL::DIRTY_UV;
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_texture(
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
|
||||
@@ -239,6 +271,56 @@ IGL_INLINE void igl::opengl::ViewerData::set_texture(
|
||||
dirty |= MeshGL::DIRTY_TEXTURE;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_data(
|
||||
const Eigen::VectorXd & D,
|
||||
double caxis_min,
|
||||
double caxis_max,
|
||||
igl::ColorMapType cmap,
|
||||
int num_steps)
|
||||
{
|
||||
if(!show_texture)
|
||||
{
|
||||
Eigen::MatrixXd CM;
|
||||
igl::colormap(cmap,Eigen::VectorXd::LinSpaced(num_steps,0,1).eval(),0,1,CM);
|
||||
set_colormap(CM);
|
||||
}
|
||||
Eigen::MatrixXd UV = ((D.array()-caxis_min)/(caxis_max-caxis_min)).replicate(1,2);
|
||||
if(D.size() == V.rows())
|
||||
{
|
||||
set_uv(UV);
|
||||
}else
|
||||
{
|
||||
assert(D.size() == F.rows());
|
||||
Eigen::MatrixXi UV_F =
|
||||
Eigen::VectorXi::LinSpaced(F.rows(),0,F.rows()-1).replicate(1,3);
|
||||
set_uv(UV,UV_F);
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_data(const Eigen::VectorXd & D, igl::ColorMapType cmap, int num_steps)
|
||||
{
|
||||
const double caxis_min = D.minCoeff();
|
||||
const double caxis_max = D.maxCoeff();
|
||||
return set_data(D,caxis_min,caxis_max,cmap,num_steps);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_colormap(const Eigen::MatrixXd & CM)
|
||||
{
|
||||
assert(CM.cols() == 3 && "colormap CM should have 3 columns");
|
||||
// Convert to R,G,B textures
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic, Eigen::Dynamic> R =
|
||||
(CM.col(0)*255.0).cast<unsigned char>();
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic, Eigen::Dynamic> G =
|
||||
(CM.col(1)*255.0).cast<unsigned char>();
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic, Eigen::Dynamic> B =
|
||||
(CM.col(2)*255.0).cast<unsigned char>();
|
||||
set_colors(Eigen::RowVector3d(1,1,1));
|
||||
set_texture(R,G,B);
|
||||
show_texture = ~unsigned(0);
|
||||
meshgl.tex_filter = GL_NEAREST;
|
||||
meshgl.tex_wrap = GL_CLAMP_TO_EDGE;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_points(
|
||||
const Eigen::MatrixXd& P,
|
||||
const Eigen::MatrixXd& C)
|
||||
@@ -269,6 +351,11 @@ IGL_INLINE void igl::opengl::ViewerData::add_points(const Eigen::MatrixXd& P, c
|
||||
dirty |= MeshGL::DIRTY_OVERLAY_POINTS;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::clear_points()
|
||||
{
|
||||
points.resize(0, 6);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_edges(
|
||||
const Eigen::MatrixXd& P,
|
||||
const Eigen::MatrixXi& E,
|
||||
@@ -287,11 +374,35 @@ IGL_INLINE void igl::opengl::ViewerData::set_edges(
|
||||
{
|
||||
color<<C.row(e);
|
||||
}
|
||||
lines.row(e)<< P.row(E(e,0)), P.row(E(e,1)), color;
|
||||
if(P.cols() == 2)
|
||||
{
|
||||
lines.row(e)<< P.row(E(e,0)),0, P.row(E(e,1)),0, color;
|
||||
}else
|
||||
{
|
||||
lines.row(e)<< P.row(E(e,0)), P.row(E(e,1)), color;
|
||||
}
|
||||
}
|
||||
dirty |= MeshGL::DIRTY_OVERLAY_LINES;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_edges_from_vector_field(
|
||||
const Eigen::MatrixXd& P,
|
||||
const Eigen::MatrixXd& V,
|
||||
const Eigen::MatrixXd& C)
|
||||
{
|
||||
assert(P.rows() == V.rows());
|
||||
Eigen::MatrixXi E(P.rows(),2);
|
||||
const Eigen::MatrixXd PV =
|
||||
(Eigen::MatrixXd(P.rows()+V.rows(),3)<<P,P+V).finished();
|
||||
for(int i = 0;i<P.rows();i++)
|
||||
{
|
||||
E(i,0) = i;
|
||||
E(i,1) = i+P.rows();
|
||||
}
|
||||
const Eigen::MatrixXd CC = C.replicate<2,1>();
|
||||
set_edges(PV,E, C.rows() == 1?C:C.replicate<2,1>());
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::add_edges(const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C)
|
||||
{
|
||||
Eigen::MatrixXd P1_temp,P2_temp;
|
||||
@@ -318,6 +429,11 @@ IGL_INLINE void igl::opengl::ViewerData::add_edges(const Eigen::MatrixXd& P1, co
|
||||
dirty |= MeshGL::DIRTY_OVERLAY_LINES;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::clear_edges()
|
||||
{
|
||||
lines.resize(0, 9);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::add_label(const Eigen::VectorXd& P, const std::string& str)
|
||||
{
|
||||
Eigen::RowVectorXd P_temp;
|
||||
@@ -335,6 +451,24 @@ 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)
|
||||
{
|
||||
assert(P.rows() == str.size() && "position # and label # do not match!");
|
||||
assert(P.cols() == 3 && "dimension of label positions incorrect!");
|
||||
labels_positions = P;
|
||||
labels_strings = str;
|
||||
|
||||
dirty |= MeshGL::DIRTY_CUSTOM_LABELS;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::clear_labels()
|
||||
{
|
||||
labels_positions.resize(0,3);
|
||||
labels_strings.clear();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::clear()
|
||||
@@ -358,16 +492,33 @@ 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;
|
||||
double_sided = false;
|
||||
invert_normals = false;
|
||||
show_texture = false;
|
||||
use_matcap = false;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::compute_normals()
|
||||
{
|
||||
igl::per_face_normals(V, F, F_normals);
|
||||
igl::per_vertex_normals(V, F, F_normals, V_normals);
|
||||
if(V.cols() == 2)
|
||||
{
|
||||
F_normals = Eigen::RowVector3d(0,0,1).replicate(F.rows(),1);
|
||||
V_normals = Eigen::RowVector3d(0,0,1).replicate(V.rows(),1);
|
||||
}else
|
||||
{
|
||||
assert(V.cols() == 3);
|
||||
igl::per_face_normals(V, F, F_normals);
|
||||
igl::per_vertex_normals(V, F, F_normals, V_normals);
|
||||
}
|
||||
dirty |= MeshGL::DIRTY_NORMAL;
|
||||
}
|
||||
|
||||
@@ -416,25 +567,33 @@ IGL_INLINE void igl::opengl::ViewerData::uniform_colors(
|
||||
dirty |= MeshGL::DIRTY_SPECULAR | MeshGL::DIRTY_DIFFUSE | MeshGL::DIRTY_AMBIENT;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::normal_matcap()
|
||||
{
|
||||
const int size = 512;
|
||||
texture_R.resize(size, size);
|
||||
texture_G.resize(size, size);
|
||||
texture_B.resize(size, size);
|
||||
const Eigen::Vector3d navy(0.3,0.3,0.5);
|
||||
static const auto clamp = [](double t){ return std::max(std::min(t,1.0),0.0);};
|
||||
for(int i = 0;i<size;i++)
|
||||
{
|
||||
const double x = (double(i)/double(size-1)*2.-1.);
|
||||
for(int j = 0;j<size;j++)
|
||||
{
|
||||
const double y = (double(j)/double(size-1)*2.-1.);
|
||||
const double z = sqrt(1.0-std::min(x*x+y*y,1.0));
|
||||
Eigen::Vector3d C = Eigen::Vector3d(x*0.5+0.5,y*0.5+0.5,z);
|
||||
texture_R(i,j) = clamp(C(0))*255;
|
||||
texture_G(i,j) = clamp(C(1))*255;
|
||||
texture_B(i,j) = clamp(C(2))*255;
|
||||
}
|
||||
}
|
||||
texture_A.setConstant(texture_R.rows(),texture_R.cols(),255);
|
||||
dirty |= MeshGL::DIRTY_TEXTURE;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::grid_texture()
|
||||
{
|
||||
// Don't do anything for an empty mesh
|
||||
if(V.rows() == 0)
|
||||
{
|
||||
V_uv.resize(V.rows(),2);
|
||||
return;
|
||||
}
|
||||
if (V_uv.rows() == 0)
|
||||
{
|
||||
V_uv = V.block(0, 0, V.rows(), 2);
|
||||
V_uv.col(0) = V_uv.col(0).array() - V_uv.col(0).minCoeff();
|
||||
V_uv.col(0) = V_uv.col(0).array() / V_uv.col(0).maxCoeff();
|
||||
V_uv.col(1) = V_uv.col(1).array() - V_uv.col(1).minCoeff();
|
||||
V_uv.col(1) = V_uv.col(1).array() / V_uv.col(1).maxCoeff();
|
||||
V_uv = V_uv.array() * 10;
|
||||
dirty |= MeshGL::DIRTY_TEXTURE;
|
||||
}
|
||||
|
||||
unsigned size = 128;
|
||||
unsigned size2 = size/2;
|
||||
texture_R.resize(size, size);
|
||||
@@ -454,6 +613,40 @@ 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::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,
|
||||
@@ -545,35 +738,23 @@ IGL_INLINE void igl::opengl::ViewerData::updateGL(
|
||||
if (meshgl.dirty & MeshGL::DIRTY_AMBIENT)
|
||||
{
|
||||
meshgl.V_ambient_vbo.resize(data.F.rows()*3,4);
|
||||
for (unsigned i=0; i<data.F.rows();++i)
|
||||
for (unsigned j=0;j<3;++j)
|
||||
meshgl.V_ambient_vbo.row(i*3+j) = data.V_material_ambient.row(data.F(i,j)).cast<float>();
|
||||
per_corner(data.V_material_ambient,meshgl.V_ambient_vbo);
|
||||
}
|
||||
if (meshgl.dirty & MeshGL::DIRTY_DIFFUSE)
|
||||
{
|
||||
meshgl.V_diffuse_vbo.resize(data.F.rows()*3,4);
|
||||
for (unsigned i=0; i<data.F.rows();++i)
|
||||
for (unsigned j=0;j<3;++j)
|
||||
meshgl.V_diffuse_vbo.row(i*3+j) = data.V_material_diffuse.row(data.F(i,j)).cast<float>();
|
||||
per_corner(data.V_material_diffuse,meshgl.V_diffuse_vbo);
|
||||
}
|
||||
if (meshgl.dirty & MeshGL::DIRTY_SPECULAR)
|
||||
{
|
||||
meshgl.V_specular_vbo.resize(data.F.rows()*3,4);
|
||||
for (unsigned i=0; i<data.F.rows();++i)
|
||||
for (unsigned j=0;j<3;++j)
|
||||
meshgl.V_specular_vbo.row(i*3+j) = data.V_material_specular.row(data.F(i,j)).cast<float>();
|
||||
per_corner(data.V_material_specular,meshgl.V_specular_vbo);
|
||||
}
|
||||
|
||||
if (meshgl.dirty & MeshGL::DIRTY_NORMAL)
|
||||
{
|
||||
meshgl.V_normals_vbo.resize(data.F.rows()*3,3);
|
||||
for (unsigned i=0; i<data.F.rows();++i)
|
||||
for (unsigned j=0;j<3;++j)
|
||||
meshgl.V_normals_vbo.row(i*3+j) =
|
||||
per_corner_normals ?
|
||||
data.F_normals.row(i*3+j).cast<float>() :
|
||||
data.V_normals.row(data.F(i,j)).cast<float>();
|
||||
|
||||
per_corner(data.V_normals,meshgl.V_normals_vbo);
|
||||
|
||||
if (invert_normals)
|
||||
meshgl.V_normals_vbo = -meshgl.V_normals_vbo;
|
||||
@@ -586,7 +767,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)
|
||||
@@ -596,8 +777,7 @@ IGL_INLINE void igl::opengl::ViewerData::updateGL(
|
||||
data.F_uv(i,j) : data.F(i,j)).cast<float>();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
{
|
||||
if (meshgl.dirty & MeshGL::DIRTY_POSITION)
|
||||
{
|
||||
@@ -637,7 +817,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)
|
||||
@@ -688,4 +868,57 @@ 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.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.vertex_labels,
|
||||
vertex_labels_positions,
|
||||
vertex_labels_strings
|
||||
);
|
||||
}
|
||||
|
||||
if (meshgl.dirty & MeshGL::DIRTY_CUSTOM_LABELS)
|
||||
{
|
||||
update_labels(
|
||||
meshgl.custom_labels,
|
||||
labels_positions,
|
||||
labels_strings
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,211 +8,361 @@
|
||||
#ifndef IGL_VIEWERDATA_H
|
||||
#define IGL_VIEWERDATA_H
|
||||
|
||||
#include "../igl_inline.h"
|
||||
#include "MeshGL.h"
|
||||
#include "../igl_inline.h"
|
||||
#include "../colormap.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <Eigen/Core>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
// Alec: This is a mesh class containing a variety of data types (normals,
|
||||
// overlays, material colors, etc.)
|
||||
//
|
||||
namespace igl
|
||||
{
|
||||
|
||||
// TODO: write documentation
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
class ViewerCore;
|
||||
|
||||
/// Object being drawn (i.e., mesh and its accessories) by the ViewerCore
|
||||
///
|
||||
/// \warning Eigen data members (such as Eigen::Vector4f) should explicitly
|
||||
/// disable alignment (e.g. use `Eigen::Matrix<float, 4, 1, Eigen::DontAlign>`),
|
||||
/// in order to avoid alignment issues further down the line (esp. if the
|
||||
/// structure are stored in a std::vector).
|
||||
///
|
||||
/// See this thread for a more detailed discussion:
|
||||
/// https://github.com/libigl/libigl/pull/1029
|
||||
///
|
||||
class ViewerData
|
||||
{
|
||||
public:
|
||||
ViewerData();
|
||||
|
||||
// Empty all fields
|
||||
/// Empty all fields
|
||||
IGL_INLINE void clear();
|
||||
|
||||
// Change the visualization mode, invalidating the cache if necessary
|
||||
/// Change whether drawing per-vertex or per-face; invalidating cache if
|
||||
/// necessary
|
||||
///
|
||||
/// @param[in] newvalue whether face based
|
||||
IGL_INLINE void set_face_based(bool newvalue);
|
||||
|
||||
// Helpers that can draw the most common meshes
|
||||
/// Set the current mesh. Call this once at the beginning and whenever
|
||||
/// **both** the vertices and faces are changing.
|
||||
///
|
||||
/// @param[in] V #V by 3 list of mesh vertex positions
|
||||
/// @param[in] F #F by 3/4 list of mesh faces (triangles/tets)
|
||||
IGL_INLINE void set_mesh(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F);
|
||||
/// Set just the vertices. Call this if _just_ the vertices are changing. You
|
||||
/// may need to call compute_normals to update the lighting correctly.
|
||||
///
|
||||
/// @param[in] V #V by 3 list of mesh vertex positions
|
||||
IGL_INLINE void set_vertices(const Eigen::MatrixXd& V);
|
||||
/// Set the normals of a mesh.
|
||||
///
|
||||
/// @param[in] N #V|#F|3#F by 3 list of mesh normals
|
||||
///
|
||||
/// \see compute_normals
|
||||
IGL_INLINE void set_normals(const Eigen::MatrixXd& N);
|
||||
/// Set whether this object is visible
|
||||
/// @param[in] value true iff this object is visible
|
||||
/// @param[in] core_id Index of the core to set (default is 0)
|
||||
IGL_INLINE void set_visible(bool value, unsigned int core_id = 1);
|
||||
|
||||
// Set the color of the mesh
|
||||
//
|
||||
// Inputs:
|
||||
// C #V|#F|1 by 3 list of colors
|
||||
/// Set the diffuse color of the mesh. The ambient color will be set to 0.1*C
|
||||
/// and the specular color will be set to 0.3+0.1*(C-0.3).
|
||||
///
|
||||
/// @param[in] C #V|#F|1 by 3 list of diffuse colors
|
||||
IGL_INLINE void set_colors(const Eigen::MatrixXd &C);
|
||||
// Set per-vertex UV coordinates
|
||||
//
|
||||
// Inputs:
|
||||
// UV #V by 2 list of UV coordinates (indexed by F)
|
||||
IGL_INLINE void set_uv(const Eigen::MatrixXd& UV);
|
||||
// Set per-corner UV coordinates
|
||||
//
|
||||
// Inputs:
|
||||
// UV_V #UV by 2 list of UV coordinates
|
||||
// UV_F #F by 3 list of UV indices into UV_V
|
||||
IGL_INLINE void set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F);
|
||||
// Set the texture associated with the mesh.
|
||||
//
|
||||
// Inputs:
|
||||
// R width by height image matrix of red channel
|
||||
// G width by height image matrix of green channel
|
||||
// B width by height image matrix of blue channel
|
||||
//
|
||||
IGL_INLINE void set_texture(
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B);
|
||||
|
||||
// Set the texture associated with the mesh.
|
||||
//
|
||||
// Inputs:
|
||||
// R width by height image matrix of red channel
|
||||
// G width by height image matrix of green channel
|
||||
// B width by height image matrix of blue channel
|
||||
// A width by height image matrix of alpha channel
|
||||
//
|
||||
/// Set per-vertex UV coordinates
|
||||
///
|
||||
/// @param[in] UV #V by 2 list of UV coordinates (indexed by F)
|
||||
IGL_INLINE void set_uv(const Eigen::MatrixXd& UV);
|
||||
|
||||
/// Set per-corner UV coordinates
|
||||
///
|
||||
/// @param[in] UV_V #UV by 2 list of UV coordinates
|
||||
/// @param[in] UV_F #F by 3 list of UV indices into UV_V
|
||||
IGL_INLINE void set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F);
|
||||
|
||||
/// Set the texture associated with the mesh.
|
||||
///
|
||||
/// @param[in] R width by height image matrix of red channel
|
||||
/// @param[in] G width by height image matrix of green channel
|
||||
/// @param[in] B width by height image matrix of blue channel
|
||||
/// @param[in] A width by height image matrix of alpha channel
|
||||
///
|
||||
IGL_INLINE void set_texture(
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A);
|
||||
/// \overload
|
||||
IGL_INLINE void set_texture(
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B);
|
||||
|
||||
// Sets points given a list of point vertices. In constrast to `set_points`
|
||||
// this will (purposefully) clober existing points.
|
||||
//
|
||||
// Inputs:
|
||||
// P #P by 3 list of vertex positions
|
||||
// C #P|1 by 3 color(s)
|
||||
/// Set pseudo-color-able scalar data associated with the mesh.
|
||||
///
|
||||
/// @param[in] caxis_min caxis minimum bound
|
||||
/// @param[in] caxis_max caxis maximum bound
|
||||
/// @param[in] D #V|#F by 1 list of scalar values
|
||||
/// @param[in] cmap colormap type
|
||||
/// @param[in] num_steps number of intervals to discretize the colormap
|
||||
IGL_INLINE void set_data(
|
||||
const Eigen::VectorXd & D,
|
||||
double caxis_min,
|
||||
double caxis_max,
|
||||
igl::ColorMapType cmap = igl::COLOR_MAP_TYPE_VIRIDIS,
|
||||
int num_steps = 21);
|
||||
|
||||
/// \overload
|
||||
/// \brief Use min(D) and max(D) to set caxis.
|
||||
IGL_INLINE void set_data(const Eigen::VectorXd & D,
|
||||
igl::ColorMapType cmap = igl::COLOR_MAP_TYPE_VIRIDIS,
|
||||
int num_steps = 21);
|
||||
|
||||
/// Not to be confused with set_colors, this creates a _texture_ that will be
|
||||
/// referenced to pseudocolor according to the scalar field passed to set_data.
|
||||
///
|
||||
/// @param[in] CM #CM by 3 list of colors
|
||||
IGL_INLINE void set_colormap(const Eigen::MatrixXd & CM);
|
||||
|
||||
/// Sets points given a list of point vertices. In constrast to `add_points`
|
||||
/// this will (purposefully) clober existing points.
|
||||
///
|
||||
/// @param[in] P #P by 3 list of vertex positions
|
||||
/// @param[in] C #P|1 by 3 color(s)
|
||||
IGL_INLINE void set_points(
|
||||
const Eigen::MatrixXd& P,
|
||||
const Eigen::MatrixXd& C);
|
||||
|
||||
/// Add points given a list of point vertices.
|
||||
///
|
||||
/// @param[in] P #P by 3 list of vertex positions
|
||||
/// @param[in] C #P|1 by 3 color(s)
|
||||
IGL_INLINE void add_points(const Eigen::MatrixXd& P, const Eigen::MatrixXd& C);
|
||||
// Sets edges given a list of edge vertices and edge indices. In constrast
|
||||
// to `add_edges` this will (purposefully) clober existing edges.
|
||||
//
|
||||
// Inputs:
|
||||
// P #P by 3 list of vertex positions
|
||||
// E #E by 2 list of edge indices into P
|
||||
// C #E|1 by 3 color(s)
|
||||
|
||||
/// Clear the point data
|
||||
IGL_INLINE void clear_points();
|
||||
|
||||
/// Sets edges given a list of edge vertices and edge indices. In constrast
|
||||
/// to `add_edges` this will (purposefully) clober existing edges.
|
||||
///
|
||||
/// @param[in] P #P by 3 list of vertex positions
|
||||
/// @param[in] E #E by 2 list of edge indices into P
|
||||
/// @param[in] C #E|1 by 3 color(s)
|
||||
IGL_INLINE void set_edges (const Eigen::MatrixXd& P, const Eigen::MatrixXi& E, const Eigen::MatrixXd& C);
|
||||
// Alec: This is very confusing. Why does add_edges have a different API from
|
||||
// set_edges?
|
||||
/// Add edges given a list of edge start and end positions and colors
|
||||
///
|
||||
/// @param[in] P1 #P by 3 list of edge start positions
|
||||
/// @param[in] P2 #P by 3 list of edge end positions
|
||||
/// @param[in] C #P|1 by 3 color(s)
|
||||
/// \note This is very confusing. Why does add_edges have a different API from
|
||||
/// set_edges?
|
||||
IGL_INLINE void add_edges (const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C);
|
||||
/// Sets edges given a list of points and eminating vectors
|
||||
///
|
||||
/// @param[in] P #P by 3 list of vertex positions
|
||||
/// @param[in] V #P by 3 list of eminating vectors
|
||||
/// @param[in] C #P|1 by 3 color(s)
|
||||
IGL_INLINE void set_edges_from_vector_field(
|
||||
const Eigen::MatrixXd& P,
|
||||
const Eigen::MatrixXd& V,
|
||||
const Eigen::MatrixXd& C);
|
||||
|
||||
/// Clear the edge data
|
||||
IGL_INLINE void clear_edges();
|
||||
|
||||
/// Sets / Adds text labels at the given positions in 3D.
|
||||
/// \param[in] P #P by 3 list of vertex positions
|
||||
/// \param[in] str #P list of text labels
|
||||
/// \note This requires the ImGui viewer plugin to display text labels.
|
||||
IGL_INLINE void set_labels (const Eigen::MatrixXd& P, const std::vector<std::string>& str);
|
||||
/// Sets / Adds text labels at the given positions in 3D.
|
||||
/// @param[in] P 3D position of the label
|
||||
/// @param[in] str text label
|
||||
IGL_INLINE void add_label (const Eigen::VectorXd& P, const std::string& str);
|
||||
|
||||
// Computes the normals of the mesh
|
||||
/// Clear the label data
|
||||
IGL_INLINE void clear_labels ();
|
||||
|
||||
/// Computes the normals of the mesh
|
||||
IGL_INLINE void compute_normals();
|
||||
|
||||
// Assigns uniform colors to all faces/vertices
|
||||
/// Assigns uniform colors to all faces/vertices
|
||||
/// \param[in] ambient ambient color
|
||||
/// \param[in] diffuse diffuse color
|
||||
/// \param[in] specular specular color
|
||||
IGL_INLINE void uniform_colors(
|
||||
const Eigen::Vector3d& diffuse,
|
||||
const Eigen::Vector3d& ambient,
|
||||
const Eigen::Vector3d& diffuse,
|
||||
const Eigen::Vector3d& specular);
|
||||
|
||||
// Assigns uniform colors to all faces/vertices
|
||||
/// \overload
|
||||
IGL_INLINE void uniform_colors(
|
||||
const Eigen::Vector4d& ambient,
|
||||
const Eigen::Vector4d& diffuse,
|
||||
const Eigen::Vector4d& specular);
|
||||
|
||||
// Generates a default grid texture
|
||||
/// Generate a normal image matcap
|
||||
IGL_INLINE void normal_matcap();
|
||||
|
||||
/// Generates a default grid texture (without uvs)
|
||||
IGL_INLINE void grid_texture();
|
||||
|
||||
Eigen::MatrixXd V; // Vertices of the current mesh (#V x 3)
|
||||
Eigen::MatrixXi F; // Faces of the mesh (#F x 3)
|
||||
/// Copy visualization options from one viewport to another
|
||||
/// \param[in] from source viewport
|
||||
/// \param[in] to destination viewport
|
||||
IGL_INLINE void copy_options(const ViewerCore &from, const ViewerCore &to);
|
||||
|
||||
/// Vertices of the current mesh (#V x 3)
|
||||
Eigen::MatrixXd V;
|
||||
/// Faces of the mesh (#F x 3)
|
||||
Eigen::MatrixXi F;
|
||||
|
||||
// Per face attributes
|
||||
Eigen::MatrixXd F_normals; // One normal per face
|
||||
/// One normal per face
|
||||
Eigen::MatrixXd F_normals;
|
||||
|
||||
Eigen::MatrixXd F_material_ambient; // Per face ambient color
|
||||
Eigen::MatrixXd F_material_diffuse; // Per face diffuse color
|
||||
Eigen::MatrixXd F_material_specular; // Per face specular color
|
||||
/// Per face ambient color
|
||||
Eigen::MatrixXd F_material_ambient;
|
||||
/// Per face diffuse color
|
||||
Eigen::MatrixXd F_material_diffuse;
|
||||
/// Per face specular color
|
||||
Eigen::MatrixXd F_material_specular;
|
||||
|
||||
// Per vertex attributes
|
||||
Eigen::MatrixXd V_normals; // One normal per vertex
|
||||
/// One normal per vertex
|
||||
Eigen::MatrixXd V_normals;
|
||||
|
||||
Eigen::MatrixXd V_material_ambient; // Per vertex ambient color
|
||||
Eigen::MatrixXd V_material_diffuse; // Per vertex diffuse color
|
||||
Eigen::MatrixXd V_material_specular; // Per vertex specular color
|
||||
/// Per vertex ambient color
|
||||
Eigen::MatrixXd V_material_ambient;
|
||||
/// Per vertex diffuse color
|
||||
Eigen::MatrixXd V_material_diffuse;
|
||||
/// Per vertex specular color
|
||||
Eigen::MatrixXd V_material_specular;
|
||||
|
||||
// UV parametrization
|
||||
Eigen::MatrixXd V_uv; // UV vertices
|
||||
Eigen::MatrixXi F_uv; // optional faces for UVs
|
||||
/// UV vertices
|
||||
Eigen::MatrixXd V_uv;
|
||||
/// optional faces for UVs
|
||||
Eigen::MatrixXi F_uv;
|
||||
|
||||
// Texture
|
||||
/// Texture red colors
|
||||
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_R;
|
||||
/// Texture green colors
|
||||
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_G;
|
||||
/// Texture blue colors
|
||||
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_B;
|
||||
/// Texture alpha values
|
||||
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_A;
|
||||
|
||||
// Overlays
|
||||
|
||||
// Lines plotted over the scene
|
||||
// (Every row contains 9 doubles in the following format S_x, S_y, S_z, T_x, T_y, T_z, C_r, C_g, C_b),
|
||||
/// Lines plotted over the scene
|
||||
/// (Every row contains 9 doubles in the following format S_x, S_y, S_z, T_x, T_y, T_z, C_r, C_g, C_b),
|
||||
// with S and T the coordinates of the two vertices of the line in global coordinates, and C the color in floating point rgb format
|
||||
Eigen::MatrixXd lines;
|
||||
|
||||
// Points plotted over the scene
|
||||
// (Every row contains 6 doubles in the following format P_x, P_y, P_z, C_r, C_g, C_b),
|
||||
// with P the position in global coordinates of the center of the point, and C the color in floating point rgb format
|
||||
/// Points plotted over the scene
|
||||
/// (Every row contains 6 doubles in the following format P_x, P_y, P_z, C_r, C_g, C_b),
|
||||
/// with P the position in global coordinates of the center of the point, and C the color in floating point rgb format
|
||||
Eigen::MatrixXd points;
|
||||
|
||||
// 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
|
||||
/// Text positions of vertices
|
||||
Eigen::MatrixXd vertex_labels_positions;
|
||||
/// Text positions of faces
|
||||
Eigen::MatrixXd face_labels_positions;
|
||||
/// Text positions of labels
|
||||
Eigen::MatrixXd labels_positions;
|
||||
/// Text strings of labels at vertices
|
||||
std::vector<std::string> vertex_labels_strings;
|
||||
/// Text strings of labels at faces
|
||||
std::vector<std::string> face_labels_strings;
|
||||
/// Text strings of labels
|
||||
std::vector<std::string> labels_strings;
|
||||
|
||||
// Marks dirty buffers that need to be uploaded to OpenGL
|
||||
/// Marks dirty buffers that need to be uploaded to OpenGL
|
||||
uint32_t dirty;
|
||||
|
||||
// Enable per-face or per-vertex properties
|
||||
/// Enable per-face or per-vertex properties
|
||||
bool face_based;
|
||||
|
||||
// Visualization options
|
||||
bool show_overlay;
|
||||
bool show_overlay_depth;
|
||||
bool show_texture;
|
||||
bool show_faces;
|
||||
bool show_lines;
|
||||
bool show_vertid;
|
||||
bool show_faceid;
|
||||
/// Enable double-sided lighting on faces
|
||||
bool double_sided;
|
||||
|
||||
/// Invert mesh normals
|
||||
bool invert_normals;
|
||||
|
||||
// Point size / line width
|
||||
float point_size;
|
||||
float line_width;
|
||||
Eigen::Vector4f line_color;
|
||||
/// Visualization options
|
||||
/// Each option is a binary mask specifying on which viewport each option is set.
|
||||
/// When using a single viewport, standard boolean can still be used for simplicity.
|
||||
unsigned int is_visible;
|
||||
unsigned int show_custom_labels;
|
||||
unsigned int show_face_labels;
|
||||
unsigned int show_faces;
|
||||
unsigned int show_lines;
|
||||
unsigned int show_overlay;
|
||||
unsigned int show_overlay_depth;
|
||||
unsigned int show_texture;
|
||||
unsigned int show_vertex_labels;
|
||||
unsigned int use_matcap;
|
||||
|
||||
// Shape material
|
||||
/// Point size / line width
|
||||
float point_size;
|
||||
/// line_width is NOT SUPPORTED on Mac OS and Windows
|
||||
float line_width;
|
||||
/// Size of lables
|
||||
float label_size;
|
||||
/// Color of lines
|
||||
Eigen::Matrix<float, 4, 1, Eigen::DontAlign> line_color;
|
||||
/// Color of labels
|
||||
Eigen::Matrix<float, 4, 1, Eigen::DontAlign> label_color;
|
||||
|
||||
/// Shape material shininess
|
||||
/// \deprecated unused?
|
||||
float shininess;
|
||||
|
||||
// Unique identifier
|
||||
/// Unique identifier
|
||||
int id;
|
||||
|
||||
// OpenGL representation of the mesh
|
||||
/// OpenGL representation of the mesh
|
||||
igl::opengl::MeshGL meshgl;
|
||||
|
||||
// Update contents from a 'Data' instance
|
||||
/// Update contents from a 'Data' instance
|
||||
///
|
||||
/// @param[in,out] GL_labels labels to be updated
|
||||
/// @param[in] positions positions of the labels
|
||||
/// @param[in] strings strings of the labels
|
||||
IGL_INLINE void update_labels(
|
||||
igl::opengl::MeshGL::TextGL& GL_labels,
|
||||
const Eigen::MatrixXd& positions,
|
||||
const std::vector<std::string>& strings
|
||||
);
|
||||
/// Update the meshgl object
|
||||
/// \param[in] data data to be used for the update
|
||||
/// \param[in] invert_normals whether to invert normals
|
||||
/// \param[in,out] meshgl mesh to be updated
|
||||
IGL_INLINE void updateGL(
|
||||
const igl::opengl::ViewerData& data,
|
||||
const bool invert_normals,
|
||||
igl::opengl::MeshGL& meshgl);
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace opengl
|
||||
} // namespace igl
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <igl/serialize.h>
|
||||
#include "../serialize.h"
|
||||
namespace igl
|
||||
{
|
||||
namespace serialization
|
||||
@@ -246,9 +396,11 @@ 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_vertex_labels);
|
||||
SERIALIZE_MEMBER(show_face_labels);
|
||||
SERIALIZE_MEMBER(show_custom_labels);
|
||||
SERIALIZE_MEMBER(show_texture);
|
||||
SERIALIZE_MEMBER(double_sided);
|
||||
SERIALIZE_MEMBER(point_size);
|
||||
SERIALIZE_MEMBER(line_width);
|
||||
SERIALIZE_MEMBER(line_color);
|
||||
|
||||
@@ -1,11 +1,54 @@
|
||||
#include "bind_vertex_attrib_array.h"
|
||||
|
||||
IGL_INLINE GLint igl::opengl::bind_vertex_attrib_array(
|
||||
namespace igl{ namespace opengl{
|
||||
// This would be cleaner with C++17 if constexpr
|
||||
template <typename Scalar>
|
||||
IGL_INLINE void bind_vertex_attrib_array_helper(
|
||||
const GLint id,
|
||||
const int size,
|
||||
const int num_cols,
|
||||
const Scalar * data,
|
||||
const bool refresh);
|
||||
|
||||
template <>
|
||||
IGL_INLINE void bind_vertex_attrib_array_helper<float>(
|
||||
const GLint id,
|
||||
const int size,
|
||||
const int num_cols,
|
||||
const float * data,
|
||||
const bool refresh)
|
||||
{
|
||||
if (refresh)
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*size, data, GL_DYNAMIC_DRAW);
|
||||
glVertexAttribPointer(id, num_cols, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
};
|
||||
|
||||
template <>
|
||||
IGL_INLINE void bind_vertex_attrib_array_helper<double>(
|
||||
const GLint id,
|
||||
const int size,
|
||||
const int num_cols,
|
||||
const double * data,
|
||||
const bool refresh)
|
||||
{
|
||||
// Are you really sure you want to use doubles? Are you going to change the
|
||||
// `in vec3` etc. in your vertex shader to `in dvec3` ?
|
||||
// Are you on a mac, where this will be emulated in software?
|
||||
if (refresh)
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(double)*size, data, GL_DYNAMIC_DRAW);
|
||||
glVertexAttribLPointer(id, num_cols, GL_DOUBLE, 0, 0);
|
||||
};
|
||||
}}
|
||||
|
||||
|
||||
namespace igl{ namespace opengl{
|
||||
template <typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
|
||||
IGL_INLINE GLint bind_vertex_attrib_array(
|
||||
const GLuint program_shader,
|
||||
const std::string &name,
|
||||
GLuint bufferID,
|
||||
const Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> &M,
|
||||
bool refresh)
|
||||
const Eigen::Matrix<Scalar,RowsAtCompileTime,ColsAtCompileTime,Eigen::RowMajor> &M,
|
||||
const bool refresh)
|
||||
{
|
||||
GLint id = glGetAttribLocation(program_shader, name.c_str());
|
||||
if (id < 0)
|
||||
@@ -16,9 +59,19 @@ IGL_INLINE GLint igl::opengl::bind_vertex_attrib_array(
|
||||
return id;
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
|
||||
if (refresh)
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*M.size(), M.data(), GL_DYNAMIC_DRAW);
|
||||
glVertexAttribPointer(id, M.cols(), GL_FLOAT, GL_FALSE, 0, 0);
|
||||
|
||||
bind_vertex_attrib_array_helper<Scalar>(
|
||||
id, M.size(), M.cols(), M.data(), refresh);
|
||||
|
||||
glEnableVertexAttribArray(id);
|
||||
return id;
|
||||
}
|
||||
}}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template int igl::opengl::bind_vertex_attrib_array<float, -1, -1>(unsigned int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int, Eigen::Matrix<float, -1, -1, 1, -1, -1> const&, bool);
|
||||
// generated by autoexplicit.sh
|
||||
template int igl::opengl::bind_vertex_attrib_array<float, -1, 3>(unsigned int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int, Eigen::Matrix<float, -1, 3, 1, -1, 3> const&, bool);
|
||||
#endif
|
||||
|
||||
@@ -8,22 +8,22 @@ namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Bind a per-vertex array attribute and refresh its contents from an Eigen
|
||||
// matrix
|
||||
//
|
||||
// Inputs:
|
||||
// program_shader id of shader program
|
||||
// name name of attribute in vertex shader
|
||||
// bufferID id of buffer to bind to
|
||||
// M #V by dim matrix of per-vertex data
|
||||
// refresh whether to actually call glBufferData or just bind the buffer
|
||||
// Returns id of named attribute in shader
|
||||
/// Bind a per-vertex array attribute and refresh its contents from an Eigen
|
||||
/// matrix
|
||||
///
|
||||
/// @param[in] program_shader id of shader program
|
||||
/// @param[in] name name of attribute in vertex shader
|
||||
/// @param[in] bufferID id of buffer to bind to
|
||||
/// @param[in] M #V by dim matrix of per-vertex data
|
||||
/// @param[in] refresh whether to actually call glBufferData or just bind the buffer
|
||||
/// @return id of named attribute in shader
|
||||
template <typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
|
||||
IGL_INLINE GLint bind_vertex_attrib_array(
|
||||
const GLuint program_shader,
|
||||
const std::string &name,
|
||||
GLuint bufferID,
|
||||
const Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> &M,
|
||||
bool refresh);
|
||||
const Eigen::Matrix<Scalar,RowsAtCompileTime,ColsAtCompileTime,Eigen::RowMajor> &M,
|
||||
const bool refresh);
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
|
||||
@@ -11,17 +11,16 @@
|
||||
#include "gl.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
// Create a VBO (Vertex Buffer Object) for a list of indices:
|
||||
// GL_ELEMENT_ARRAY_BUFFER_ARB for the triangle indices (F)
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Inputs:
|
||||
// F #F by 3 eigen Matrix of face (triangle) indices
|
||||
// Outputs:
|
||||
// F_vbo_id buffer id for face indices
|
||||
//
|
||||
/// Create a VBO (Vertex Buffer Object) for a list of indices:
|
||||
/// GL_ELEMENT_ARRAY_BUFFER_ARB for the triangle indices (F)
|
||||
///
|
||||
/// @param[in] F #F by 3 eigen Matrix of face (triangle) indices
|
||||
/// @param[out] F_vbo_id buffer id for face indices
|
||||
///
|
||||
IGL_INLINE void create_index_vbo(
|
||||
const Eigen::MatrixXi & F,
|
||||
GLuint & F_vbo_id);
|
||||
|
||||
@@ -11,38 +11,32 @@
|
||||
#include "gl.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
// Create a VBO (Vertex Buffer Object) for a mesh. Actually two VBOs: one
|
||||
// GL_ARRAY_BUFFER for the vertex positions (V) and one
|
||||
// GL_ELEMENT_ARRAY_BUFFER for the triangle indices (F)
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
// Inputs:
|
||||
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
||||
// F #F by 3 eigen Matrix of face (triangle) indices
|
||||
// Outputs:
|
||||
// V_vbo_id buffer id for vertex positions
|
||||
// F_vbo_id buffer id for face indices
|
||||
//
|
||||
// NOTE: when using glDrawElements VBOs for V and F using MatrixXd and
|
||||
// MatrixXi will have types GL_DOUBLE and GL_UNSIGNED_INT respectively
|
||||
//
|
||||
/// Create a VBO (Vertex Buffer Object) for a mesh. Actually two VBOs: one
|
||||
/// GL_ARRAY_BUFFER for the vertex positions (V) and one
|
||||
/// GL_ELEMENT_ARRAY_BUFFER for the triangle indices (F)
|
||||
///
|
||||
/// @param[in] V #V by 3 eigen Matrix of mesh vertex 3D positions
|
||||
/// @param[in] F #F by 3 eigen Matrix of face (triangle) indices
|
||||
/// @param[out] V_vbo_id buffer id for vertex positions
|
||||
/// @param[out] F_vbo_id buffer id for face indices
|
||||
///
|
||||
/// \note when using glDrawElements VBOs for V and F using MatrixXd and
|
||||
/// MatrixXi will have types GL_DOUBLE and GL_UNSIGNED_INT respectively
|
||||
///
|
||||
IGL_INLINE void create_mesh_vbo(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
GLuint & V_vbo_id,
|
||||
GLuint & F_vbo_id);
|
||||
|
||||
// Inputs:
|
||||
// V #V by 3 eigen Matrix of mesh vertex 3D positions
|
||||
// F #F by 3 eigen Matrix of face (triangle) indices
|
||||
// N #V by 3 eigen Matrix of mesh vertex 3D normals
|
||||
// Outputs:
|
||||
// V_vbo_id buffer id for vertex positions
|
||||
// F_vbo_id buffer id for face indices
|
||||
// N_vbo_id buffer id for vertex positions
|
||||
/// \overload
|
||||
///
|
||||
/// @param[in] N #V by 3 eigen Matrix of mesh vertex 3D normals
|
||||
/// @param[out] N_vbo_id buffer id for vertex positions
|
||||
IGL_INLINE void create_mesh_vbo(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
|
||||
@@ -16,40 +16,46 @@ namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Create a shader program with a vertex and fragments shader loading from
|
||||
// source strings and vertex attributes assigned from a map before linking the
|
||||
// shaders to the program, making it ready to use with glUseProgram(id)
|
||||
// Inputs:
|
||||
// geom_source string containing source code of geometry shader (can be
|
||||
// "" to mean use default pass-through)
|
||||
// vert_source string containing source code of vertex shader
|
||||
// frag_source string containing source code of fragment shader
|
||||
// attrib map containing table of vertex attribute strings add their
|
||||
// correspondingly ids (generated previously using glBindAttribLocation)
|
||||
// Outputs:
|
||||
// id index id of created shader, set to 0 on error
|
||||
// Returns true on success, false on error
|
||||
//
|
||||
// Note: Caller is responsible for making sure that current value of id is not
|
||||
// leaking a shader (since it will be overwritten)
|
||||
//
|
||||
// See also: destroy_shader_program
|
||||
/// Create a shader program with a vertex and fragments shader loading from
|
||||
/// source strings and vertex attributes assigned from a map before linking the
|
||||
/// shaders to the program, making it ready to use with glUseProgram(id)
|
||||
///
|
||||
/// @param[in] geom_source string containing source code of geometry shader (can be
|
||||
/// "" to mean use default pass-through)
|
||||
/// @param[in] vert_source string containing source code of vertex shader
|
||||
/// @param[in] frag_source string containing source code of fragment shader
|
||||
/// @param[in] attrib map containing table of vertex attribute strings add their
|
||||
/// correspondingly ids (generated previously using glBindAttribLocation)
|
||||
/// @param[out] id index id of created shader, set to 0 on error
|
||||
/// @return true on success, false on error
|
||||
///
|
||||
/// \note Caller is responsible for making sure that current value of id is not
|
||||
/// leaking a shader (since it will be overwritten)
|
||||
///
|
||||
/// \see destroy_shader_program
|
||||
IGL_INLINE bool create_shader_program(
|
||||
const std::string &geom_source,
|
||||
const std::string &vert_source,
|
||||
const std::string &frag_source,
|
||||
const std::map<std::string,GLuint> &attrib,
|
||||
GLuint & id);
|
||||
/// \overload
|
||||
IGL_INLINE bool create_shader_program(
|
||||
const std::string &vert_source,
|
||||
const std::string &frag_source,
|
||||
const std::map<std::string,GLuint> &attrib,
|
||||
GLuint & id);
|
||||
/// \overload
|
||||
///
|
||||
/// @return index id of created shader, set to 0 on error
|
||||
IGL_INLINE GLuint create_shader_program(
|
||||
const std::string & geom_source,
|
||||
const std::string & vert_source,
|
||||
const std::string & frag_source,
|
||||
const std::map<std::string,GLuint> &attrib);
|
||||
/// \overload
|
||||
///
|
||||
/// @return index id of created shader, set to 0 on error
|
||||
IGL_INLINE GLuint create_shader_program(
|
||||
const std::string & vert_source,
|
||||
const std::string & frag_source,
|
||||
|
||||
@@ -11,19 +11,17 @@
|
||||
#include "gl.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
// Create a VBO (Vertex Buffer Object) for a list of vectors:
|
||||
// GL_ARRAY_BUFFER for the vectors (V)
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Templates:
|
||||
// T should be a eigen matrix primitive type like int or double
|
||||
// Inputs:
|
||||
// V m by n eigen Matrix of type T values
|
||||
// Outputs:
|
||||
// V_vbo_id buffer id for vectors
|
||||
//
|
||||
/// Create a VBO (Vertex Buffer Object) for a list of vectors:
|
||||
/// GL_ARRAY_BUFFER for the vectors (V)
|
||||
///
|
||||
/// @tparam T should be a eigen matrix primitive type like int or double
|
||||
/// @param[in] V m by n eigen Matrix of type T values
|
||||
/// @param[out] V_vbo_id buffer id for vectors
|
||||
///
|
||||
template <typename T>
|
||||
IGL_INLINE void create_vector_vbo(
|
||||
const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & V,
|
||||
|
||||
@@ -14,16 +14,16 @@ namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Properly destroy a shader program. Detach and delete each of its shaders
|
||||
// and delete it
|
||||
// Inputs:
|
||||
// id index id of created shader, set to 0 on error
|
||||
// Returns true on success, false on error
|
||||
//
|
||||
// Note: caller is responsible for making sure he doesn't foolishly continue
|
||||
// to use id as if it still contains a program
|
||||
//
|
||||
// See also: create_shader_program
|
||||
/// Properly destroy a shader program. Detach and delete each of its shaders
|
||||
/// and delete it
|
||||
///
|
||||
/// @param[in] id index id of created shader, set to 0 on error
|
||||
/// @return true on success, false on error
|
||||
///
|
||||
/// \note caller is responsible for making sure he doesn't foolishly continue
|
||||
/// to use id as if it still contains a program
|
||||
///
|
||||
/// \see create_shader_program
|
||||
IGL_INLINE bool destroy_shader_program(const GLuint id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,10 @@ namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Return the number of bytes for a given OpenGL type // Inputs:
|
||||
// type enum value of opengl type
|
||||
// Returns size in bytes of type
|
||||
/// Return the number of bytes for a given OpenGL type
|
||||
///
|
||||
/// @param[in] type enum value of opengl type
|
||||
/// @return size in bytes of type
|
||||
IGL_INLINE int gl_type_size(const GLenum type);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,8 +45,8 @@ namespace glfw
|
||||
// UI Enumerations
|
||||
enum class MouseButton {Left, Middle, Right};
|
||||
enum class MouseMode { None, Rotation, Zoom, Pan, Translation} mouse_mode;
|
||||
IGL_INLINE int launch(bool resizable = true,bool fullscreen = false);
|
||||
IGL_INLINE int launch_init(bool resizable = true,bool fullscreen = false);
|
||||
IGL_INLINE int launch (bool fullscreen = false, const std::string &name = "libigl viewer", int width = 0, int height = 0);
|
||||
IGL_INLINE int launch_init(bool fullscreen = false, const std::string &name = "libigl viewer", int width = 0, int height = 0);
|
||||
IGL_INLINE bool launch_rendering(bool loop = true);
|
||||
IGL_INLINE void launch_shut();
|
||||
IGL_INLINE void init();
|
||||
@@ -72,6 +72,34 @@ namespace glfw
|
||||
IGL_INLINE bool save_scene(std::string fname);
|
||||
// Draw everything
|
||||
IGL_INLINE void draw();
|
||||
// Render given ViewerCore to a buffer. The width and height are determined
|
||||
// by non-zeros dimensions of R or – if both are zero — are set to this
|
||||
// core's viewport sizes. Other buffers are resized to fit if needed.
|
||||
//
|
||||
// Template:
|
||||
// T image storage type, e.g., unsigned char (values ∈ [0,255]), double
|
||||
// (values ∈ [0.0,1.0]).
|
||||
// Inputs:
|
||||
// data which ViewerData to draw
|
||||
// update_matrices whether to update view, proj, and norm matrices in
|
||||
// shaders
|
||||
// Outputs:
|
||||
// R width by height red pixel color values
|
||||
// G width by height green pixel color values
|
||||
// B width by height blue pixel color values
|
||||
// A width by height alpha pixel color values
|
||||
// D width by height depth pixel values. Depth values are _not_
|
||||
// anti-aliased like RGBA.
|
||||
//
|
||||
template <typename T>
|
||||
IGL_INLINE void draw_buffer(
|
||||
// can't be const because of writing in and out of `core.viewport`
|
||||
/*const*/ igl::opengl::ViewerCore & core,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & R,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & G,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & B,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & A,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & D);
|
||||
// OpenGL context resize
|
||||
IGL_INLINE void resize(int w,int h); // explicitly set window size
|
||||
IGL_INLINE void post_resize(int w,int h); // external resize due to user interaction
|
||||
@@ -79,17 +107,29 @@ namespace glfw
|
||||
IGL_INLINE void snap_to_canonical_quaternion();
|
||||
IGL_INLINE void open_dialog_load_mesh();
|
||||
IGL_INLINE void open_dialog_save_mesh();
|
||||
IGL_INLINE ViewerData& data();
|
||||
|
||||
// Append a new "slot" for a mesh (i.e., create empty entires at the end of
|
||||
////////////////////////
|
||||
// Multi-mesh methods //
|
||||
////////////////////////
|
||||
|
||||
// Return the current mesh, or the mesh corresponding to a given unique identifier
|
||||
//
|
||||
// Inputs:
|
||||
// mesh_id unique identifier associated to the desired mesh (current mesh if -1)
|
||||
IGL_INLINE ViewerData& data(int mesh_id = -1);
|
||||
IGL_INLINE const ViewerData& data(int mesh_id = -1) const;
|
||||
|
||||
// Append a new "slot" for a mesh (i.e., create empty entries at the end of
|
||||
// the data_list and opengl_state_list.
|
||||
//
|
||||
// Inputs:
|
||||
// visible If true, the new mesh is set to be visible on all existing viewports
|
||||
// Returns the id of the last appended mesh
|
||||
//
|
||||
// Side Effects:
|
||||
// selected_data_index is set this newly created, last entry (i.e.,
|
||||
// #meshes-1)
|
||||
IGL_INLINE int append_mesh();
|
||||
IGL_INLINE int append_mesh(bool visible = true);
|
||||
|
||||
// Erase a mesh (i.e., its corresponding data and state entires in data_list
|
||||
// and opengl_state_list)
|
||||
@@ -113,6 +153,48 @@ namespace glfw
|
||||
// Returns 0 if not found
|
||||
IGL_INLINE size_t mesh_index(const int id) const;
|
||||
|
||||
////////////////////////////
|
||||
// Multi-viewport methods //
|
||||
////////////////////////////
|
||||
|
||||
// Return the current viewport, or the viewport corresponding to a given unique identifier
|
||||
//
|
||||
// Inputs:
|
||||
// core_id unique identifier corresponding to the desired viewport (current viewport if 0)
|
||||
IGL_INLINE ViewerCore& core(unsigned core_id = 0);
|
||||
IGL_INLINE const ViewerCore& core(unsigned core_id = 0) const;
|
||||
|
||||
// Append a new "slot" for a viewport (i.e., copy properties of the current viewport, only
|
||||
// changing the viewport size/position)
|
||||
//
|
||||
// Inputs:
|
||||
// viewport Vector specifying the viewport origin and size in screen coordinates.
|
||||
// append_empty If true, existing meshes are hidden on the new viewport.
|
||||
//
|
||||
// Returns the unique id of the newly inserted viewport. There can be a maximum of 31
|
||||
// viewports created in the same viewport. Erasing a viewport does not change the id of
|
||||
// other existing viewports
|
||||
IGL_INLINE int append_core(Eigen::Vector4f viewport, bool append_empty = false);
|
||||
|
||||
// Erase a viewport
|
||||
//
|
||||
// Inputs:
|
||||
// index index of the viewport to erase
|
||||
IGL_INLINE bool erase_core(const size_t index);
|
||||
|
||||
// Retrieve viewport index from its unique identifier
|
||||
// Returns 0 if not found
|
||||
IGL_INLINE size_t core_index(const int id) const;
|
||||
|
||||
// Change selected_core_index to the viewport containing the mouse
|
||||
// (current_mouse_x, current_mouse_y)
|
||||
IGL_INLINE void select_hovered_core();
|
||||
|
||||
public:
|
||||
//////////////////////
|
||||
// Member variables //
|
||||
//////////////////////
|
||||
|
||||
// Alec: I call this data_list instead of just data to avoid confusion with
|
||||
// old "data" variable.
|
||||
// Stores all the data that should be visualized
|
||||
@@ -121,8 +203,12 @@ namespace glfw
|
||||
size_t selected_data_index;
|
||||
int next_data_id;
|
||||
GLFWwindow* window;
|
||||
|
||||
// Stores all the viewing options
|
||||
ViewerCore core;
|
||||
std::vector<ViewerCore> core_list;
|
||||
size_t selected_core_index;
|
||||
int next_core_id;
|
||||
|
||||
// List of registered plugins
|
||||
std::vector<ViewerPlugin*> plugins;
|
||||
// Temporary data stored when the mouse button is pressed
|
||||
@@ -148,6 +234,7 @@ namespace glfw
|
||||
std::function<bool(Viewer& viewer, int mouse_x, int mouse_y)> callback_mouse_move;
|
||||
std::function<bool(Viewer& viewer, float delta_y)> callback_mouse_scroll;
|
||||
std::function<bool(Viewer& viewer, unsigned int key, int modifiers)> callback_key_pressed;
|
||||
std::function<bool(Viewer& viewer, int w, int h)> callback_post_resize;
|
||||
// THESE SHOULD BE DEPRECATED:
|
||||
std::function<bool(Viewer& viewer, unsigned int key, int modifiers)> callback_key_down;
|
||||
std::function<bool(Viewer& viewer, unsigned int key, int modifiers)> callback_key_up;
|
||||
@@ -164,7 +251,7 @@ namespace glfw
|
||||
void* callback_key_up_data;
|
||||
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
|
||||
@@ -14,169 +14,89 @@
|
||||
// * remove Preview3D from comments
|
||||
// * clean comments
|
||||
#include <string>
|
||||
#include <igl/igl_inline.h>
|
||||
#include "../../igl_inline.h"
|
||||
#include <vector>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
namespace glfw
|
||||
{
|
||||
|
||||
// Abstract class for plugins
|
||||
// All plugins MUST have this class as their parent and may implement any/all
|
||||
// the callbacks marked `virtual` here.
|
||||
//
|
||||
// /////For an example of a basic plugins see plugins/skeleton.h
|
||||
//
|
||||
// Return value of callbacks: returning true to any of the callbacks tells
|
||||
// Viewer that the event has been handled and that it should not be passed to
|
||||
// other plugins or to other internal functions of Viewer
|
||||
|
||||
// Forward declaration of the viewer
|
||||
class Viewer;
|
||||
|
||||
class ViewerPlugin
|
||||
{
|
||||
public:
|
||||
IGL_INLINE ViewerPlugin()
|
||||
{plugin_name = "dummy";}
|
||||
|
||||
virtual ~ViewerPlugin(){}
|
||||
|
||||
// This function is called when the viewer is initialized (no mesh will be loaded at this stage)
|
||||
IGL_INLINE virtual void init(Viewer *_viewer)
|
||||
namespace opengl
|
||||
{
|
||||
viewer = _viewer;
|
||||
namespace glfw
|
||||
{
|
||||
|
||||
|
||||
// Forward declaration of the viewer
|
||||
class Viewer;
|
||||
|
||||
/// Abstract class for plugins
|
||||
/// All plugins MUST have this class as their parent and may implement any/all
|
||||
/// the callbacks marked `virtual` here.
|
||||
///
|
||||
/// Return value of callbacks: returning true to any of the callbacks tells
|
||||
/// Viewer that the event has been handled and that it should not be passed to
|
||||
/// other plugins or to other internal functions of Viewer
|
||||
class ViewerPlugin
|
||||
{
|
||||
public:
|
||||
IGL_INLINE ViewerPlugin() {plugin_name = "dummy";}
|
||||
virtual ~ViewerPlugin(){}
|
||||
/// This function is called when the viewer is initialized (no mesh will be loaded at this stage)
|
||||
IGL_INLINE virtual void init(Viewer *_viewer) { viewer = _viewer; }
|
||||
/// This function is called before shutdown
|
||||
IGL_INLINE virtual void shutdown() { }
|
||||
/// This function is called before a mesh is loaded
|
||||
IGL_INLINE virtual bool load(std::string /*filename*/) { return false; }
|
||||
/// This function is called before a mesh is saved
|
||||
IGL_INLINE virtual bool save(std::string /*filename*/) { return false; }
|
||||
/// This function is called when the scene is serialized
|
||||
IGL_INLINE virtual bool serialize(std::vector<char>& /*buffer*/) const
|
||||
{ return false; }
|
||||
/// This function is called when the scene is deserialized
|
||||
IGL_INLINE virtual bool deserialize(const std::vector<char>& /*buffer*/)
|
||||
{ return false; }
|
||||
/// Runs immediately after a new mesh has been loaded.
|
||||
IGL_INLINE virtual bool post_load() { return false; }
|
||||
/// This function is called before the draw procedure of Viewer
|
||||
IGL_INLINE virtual bool pre_draw() { return false; }
|
||||
/// This function is called after the draw procedure of Viewer
|
||||
IGL_INLINE virtual bool post_draw() { return false; }
|
||||
/// This function is called after the window has been resized
|
||||
IGL_INLINE virtual void post_resize(int /*w*/, int /*h*/) { }
|
||||
IGL_INLINE virtual bool mouse_down(int /*button*/, int /*modifier*/)
|
||||
{ return false; }
|
||||
IGL_INLINE virtual bool mouse_up(int /*button*/, int /*modifier*/)
|
||||
{ return false; }
|
||||
IGL_INLINE virtual bool mouse_move(int /*mouse_x*/, int /*mouse_y*/)
|
||||
{ return false; }
|
||||
IGL_INLINE virtual bool mouse_scroll(float /*delta_y*/)
|
||||
{ return false; }
|
||||
IGL_INLINE virtual bool key_pressed(unsigned int /*key*/, int /*modifiers*/)
|
||||
{ return false; }
|
||||
IGL_INLINE virtual bool key_down(int /*key*/, int /*modifiers*/)
|
||||
{ return false; }
|
||||
IGL_INLINE virtual bool key_up(int /*key*/, int /*modifiers*/)
|
||||
{ return false; }
|
||||
std::string plugin_name;
|
||||
protected:
|
||||
// Pointer to the main Viewer class
|
||||
Viewer *viewer;
|
||||
};
|
||||
|
||||
namespace serialization
|
||||
{
|
||||
inline void serialize(const ViewerPlugin& obj,std::vector<char>& buffer)
|
||||
{
|
||||
obj.serialize(buffer);
|
||||
}
|
||||
|
||||
inline void deserialize(ViewerPlugin& obj,const std::vector<char>& buffer)
|
||||
{
|
||||
obj.deserialize(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// This function is called before shutdown
|
||||
IGL_INLINE virtual void shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
// This function is called before a mesh is loaded
|
||||
IGL_INLINE virtual bool load(std::string filename)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function is called before a mesh is saved
|
||||
IGL_INLINE virtual bool save(std::string filename)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function is called when the scene is serialized
|
||||
IGL_INLINE virtual bool serialize(std::vector<char>& buffer) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function is called when the scene is deserialized
|
||||
IGL_INLINE virtual bool deserialize(const std::vector<char>& buffer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Runs immediately after a new mesh has been loaded.
|
||||
IGL_INLINE virtual bool post_load()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function is called before the draw procedure of Preview3D
|
||||
IGL_INLINE virtual bool pre_draw()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function is called after the draw procedure of Preview3D
|
||||
IGL_INLINE virtual bool post_draw()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function is called after the window has been resized
|
||||
IGL_INLINE virtual void post_resize(int w, int h)
|
||||
{
|
||||
}
|
||||
|
||||
// This function is called when the mouse button is pressed
|
||||
// - button can be GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON or GLUT_RIGHT_BUTTON
|
||||
// - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
|
||||
IGL_INLINE virtual bool mouse_down(int button, int modifier)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function is called when the mouse button is released
|
||||
// - button can be GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON or GLUT_RIGHT_BUTTON
|
||||
// - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
|
||||
IGL_INLINE virtual bool mouse_up(int button, int modifier)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function is called every time the mouse is moved
|
||||
// - mouse_x and mouse_y are the new coordinates of the mouse pointer in screen coordinates
|
||||
IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function is called every time the scroll wheel is moved
|
||||
// Note: this callback is not working with every glut implementation
|
||||
IGL_INLINE virtual bool mouse_scroll(float delta_y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function is called when a keyboard key is pressed. Unlike key_down
|
||||
// this will reveal the actual character being sent (not just the physical
|
||||
// key)
|
||||
// - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
|
||||
IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function is called when a keyboard key is down
|
||||
// - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
|
||||
IGL_INLINE virtual bool key_down(int key, int modifiers)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function is called when a keyboard key is release
|
||||
// - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
|
||||
IGL_INLINE virtual bool key_up(int key, int modifiers)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string plugin_name;
|
||||
protected:
|
||||
// Pointer to the main Viewer class
|
||||
Viewer *viewer;
|
||||
};
|
||||
|
||||
namespace serialization
|
||||
{
|
||||
inline void serialize(const ViewerPlugin& obj,std::vector<char>& buffer)
|
||||
{
|
||||
obj.serialize(buffer);
|
||||
}
|
||||
|
||||
inline void deserialize(ViewerPlugin& obj,const std::vector<char>& buffer)
|
||||
{
|
||||
obj.deserialize(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
IGL_INLINE bool igl::opengl::glfw::background_window(GLFWwindow* & window)
|
||||
{
|
||||
if(!glfwInit()) return false;
|
||||
glfwSetErrorCallback([](int id,const char* m){std::cerr<<m<<std::endl;});
|
||||
glfwSetErrorCallback([](int /*id*/,const char* m){std::cerr<<m<<std::endl;});
|
||||
glfwWindowHint(GLFW_SAMPLES, 4);
|
||||
// Use 3.2 core profile
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||
// Use 4.1 core profile
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
// Use background window
|
||||
|
||||
@@ -11,17 +11,16 @@ namespace igl
|
||||
{
|
||||
namespace glfw
|
||||
{
|
||||
// Create a background window with a valid core profile opengl context
|
||||
// set to current.
|
||||
//
|
||||
// After you're finished with this window you may call
|
||||
// `glfwDestroyWindow(window)`
|
||||
//
|
||||
// After you're finished with glfw you should call `glfwTerminate()`
|
||||
//
|
||||
// Outputs:
|
||||
// window pointer to glfw window
|
||||
// Returns true iff success
|
||||
/// Create a background window with a valid core profile opengl context
|
||||
/// set to current.
|
||||
///
|
||||
/// After you're finished with this window you may call
|
||||
/// `glfwDestroyWindow(window)`
|
||||
///
|
||||
/// After you're finished with glfw you should call `glfwTerminate()`
|
||||
///
|
||||
/// @param[out] window pointer to glfw window
|
||||
/// @return true iff success
|
||||
IGL_INLINE bool background_window(GLFWwindow* & window);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
#define IGL_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <imgui/imgui.h>
|
||||
#include "ImGuiTraits.h"
|
||||
#include <imgui.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <cstddef>
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Extend ImGui by populating its namespace directly
|
||||
@@ -25,38 +27,38 @@ namespace ImGui
|
||||
|
||||
static auto vector_getter = [](void* vec, int idx, const char** out_text)
|
||||
{
|
||||
auto& vector = *static_cast<std::vector<std::string>*>(vec);
|
||||
if (idx < 0 || idx >= static_cast<int>(vector.size())) { return false; }
|
||||
*out_text = vector.at(idx).c_str();
|
||||
return true;
|
||||
auto& vector = *static_cast<std::vector<std::string>*>(vec);
|
||||
if (idx < 0 || idx >= static_cast<int>(vector.size())) { return false; }
|
||||
*out_text = vector.at(idx).c_str();
|
||||
return true;
|
||||
};
|
||||
|
||||
inline bool Combo(const char* label, int* idx, std::vector<std::string>& values)
|
||||
{
|
||||
if (values.empty()) { return false; }
|
||||
return Combo(label, idx, vector_getter,
|
||||
static_cast<void*>(&values), values.size());
|
||||
if (values.empty()) { return false; }
|
||||
return Combo(label, idx, vector_getter,
|
||||
static_cast<void*>(&values), values.size());
|
||||
}
|
||||
|
||||
inline bool Combo(const char* label, int* idx, std::function<const char *(int)> getter, int items_count)
|
||||
{
|
||||
auto func = [](void* data, int i, const char** out_text) {
|
||||
auto &getter = *reinterpret_cast<std::function<const char *(int)> *>(data);
|
||||
const char *s = getter(i);
|
||||
if (s) { *out_text = s; return true; }
|
||||
else { return false; }
|
||||
};
|
||||
return Combo(label, idx, func, reinterpret_cast<void *>(&getter), items_count);
|
||||
auto func = [](void* data, int i, const char** out_text) {
|
||||
auto &getter = *reinterpret_cast<std::function<const char *(int)> *>(data);
|
||||
const char *s = getter(i);
|
||||
if (s) { *out_text = s; return true; }
|
||||
else { return false; }
|
||||
};
|
||||
return Combo(label, idx, func, reinterpret_cast<void *>(&getter), items_count);
|
||||
}
|
||||
|
||||
inline bool ListBox(const char* label, int* idx, std::vector<std::string>& values)
|
||||
{
|
||||
if (values.empty()) { return false; }
|
||||
return ListBox(label, idx, vector_getter,
|
||||
static_cast<void*>(&values), values.size());
|
||||
if (values.empty()) { return false; }
|
||||
return ListBox(label, idx, vector_getter,
|
||||
static_cast<void*>(&values), values.size());
|
||||
}
|
||||
|
||||
inline bool InputText(const char* label, std::string &str, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL)
|
||||
inline bool InputText(const char* label, std::string &str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL)
|
||||
{
|
||||
char buf[1024];
|
||||
std::fill_n(buf, 1024, 0);
|
||||
@@ -69,6 +71,45 @@ inline bool InputText(const char* label, std::string &str, ImGuiInputTextFlags f
|
||||
return false;
|
||||
}
|
||||
|
||||
// template<typename T>
|
||||
// inline bool DragScalar(const char *label, T* value, void* v, float v_speed, const void* v_min = NULL, const void* v_max = NULL, const char* format = NULL, float power = 1.0f)
|
||||
// {
|
||||
// const char *fmt = format;
|
||||
// if (format == nullptr) {
|
||||
// fmt = ImGuiDataTypeTraits<T>::format;
|
||||
// }
|
||||
// return DragScalar(label, ImGuiDataTypeTraits<T>::value, value, &min, &max, fmt);
|
||||
// }
|
||||
|
||||
// template<typename T>
|
||||
// inline bool InputScalar(const char *label, T* value, T min = 0, T max = 0, const char* format = nulltptr)
|
||||
// {
|
||||
// const char *fmt = format;
|
||||
// if (format == nullptr) {
|
||||
// fmt = ImGuiDataTypeTraits<T>::format;
|
||||
// }
|
||||
// return InputScalar(label, ImGuiDataTypeTraits<T>::value, value, &min, &max, fmt);
|
||||
// }
|
||||
|
||||
template<typename T>
|
||||
inline bool SliderScalar(const char *label, T* value, T min = 0, T max = 0, const char* format = "")
|
||||
{
|
||||
const char *fmt = format;
|
||||
if (format == nullptr) {
|
||||
fmt = ImGuiDataTypeTraits<T>::format;
|
||||
}
|
||||
return SliderScalar(label, ImGuiDataTypeTraits<T>::value, value, &min, &max, fmt);
|
||||
}
|
||||
|
||||
template<typename Getter, typename Setter>
|
||||
inline bool Checkbox(const char* label, Getter get, Setter set)
|
||||
{
|
||||
bool value = get();
|
||||
bool ret = ImGui::Checkbox(label, &value);
|
||||
set(value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace ImGui
|
||||
|
||||
#endif // IGL_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2022 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// Copyright (C) 2018 Jérémie Dumas <jeremie.dumas@ens-lyon.org>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
@@ -7,13 +8,9 @@
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include "ImGuiMenu.h"
|
||||
#include <igl/project.h>
|
||||
#include <imgui/imgui.h>
|
||||
#include <imgui_impl_glfw_gl3.h>
|
||||
#include <imgui_fonts_droid_sans.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include "ImGuiHelpers.h"
|
||||
#include <imgui.h>
|
||||
#include <iostream>
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace igl
|
||||
{
|
||||
@@ -24,124 +21,14 @@ namespace glfw
|
||||
namespace imgui
|
||||
{
|
||||
|
||||
IGL_INLINE void ImGuiMenu::init(igl::opengl::glfw::Viewer *_viewer)
|
||||
// Is this needed?
|
||||
IGL_INLINE void ImGuiMenu::init( Viewer *_viewer, ImGuiPlugin *_plugin)
|
||||
{ viewer = _viewer; plugin = _plugin; }
|
||||
|
||||
IGL_INLINE void ImGuiMenu::shutdown() { }
|
||||
|
||||
IGL_INLINE void ImGuiMenu::draw()
|
||||
{
|
||||
ViewerPlugin::init(_viewer);
|
||||
// Setup ImGui binding
|
||||
if (_viewer)
|
||||
{
|
||||
if (context_ == nullptr)
|
||||
{
|
||||
context_ = ImGui::CreateContext();
|
||||
}
|
||||
ImGui_ImplGlfwGL3_Init(viewer->window, false);
|
||||
ImGui::GetIO().IniFilename = nullptr;
|
||||
ImGui::StyleColorsDark();
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
style.FrameRounding = 5.0f;
|
||||
reload_font();
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void ImGuiMenu::reload_font(int font_size)
|
||||
{
|
||||
hidpi_scaling_ = hidpi_scaling();
|
||||
pixel_ratio_ = pixel_ratio();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.Fonts->Clear();
|
||||
io.Fonts->AddFontFromMemoryCompressedTTF(droid_sans_compressed_data,
|
||||
droid_sans_compressed_size, font_size * hidpi_scaling_);
|
||||
io.FontGlobalScale = 1.0 / pixel_ratio_;
|
||||
}
|
||||
|
||||
IGL_INLINE void ImGuiMenu::shutdown()
|
||||
{
|
||||
// Cleanup
|
||||
ImGui_ImplGlfwGL3_Shutdown();
|
||||
ImGui::DestroyContext(context_);
|
||||
context_ = nullptr;
|
||||
}
|
||||
|
||||
IGL_INLINE bool ImGuiMenu::pre_draw()
|
||||
{
|
||||
glfwPollEvents();
|
||||
|
||||
// Check whether window dpi has changed
|
||||
float scaling = hidpi_scaling();
|
||||
if (std::abs(scaling - hidpi_scaling_) > 1e-5)
|
||||
{
|
||||
reload_font();
|
||||
ImGui_ImplGlfwGL3_InvalidateDeviceObjects();
|
||||
}
|
||||
|
||||
ImGui_ImplGlfwGL3_NewFrame();
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE bool ImGuiMenu::post_draw()
|
||||
{
|
||||
draw_menu();
|
||||
ImGui::Render();
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE void ImGuiMenu::post_resize(int width, int height)
|
||||
{
|
||||
if (context_)
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = float(width);
|
||||
ImGui::GetIO().DisplaySize.y = float(height);
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse IO
|
||||
IGL_INLINE bool ImGuiMenu::mouse_down(int button, int modifier)
|
||||
{
|
||||
ImGui_ImplGlfwGL3_MouseButtonCallback(viewer->window, button, GLFW_PRESS, modifier);
|
||||
return ImGui::GetIO().WantCaptureMouse;
|
||||
}
|
||||
|
||||
IGL_INLINE bool ImGuiMenu::mouse_up(int button, int modifier)
|
||||
{
|
||||
return ImGui::GetIO().WantCaptureMouse;
|
||||
}
|
||||
|
||||
IGL_INLINE bool ImGuiMenu::mouse_move(int mouse_x, int mouse_y)
|
||||
{
|
||||
return ImGui::GetIO().WantCaptureMouse;
|
||||
}
|
||||
|
||||
IGL_INLINE bool ImGuiMenu::mouse_scroll(float delta_y)
|
||||
{
|
||||
ImGui_ImplGlfwGL3_ScrollCallback(viewer->window, 0.f, delta_y);
|
||||
return ImGui::GetIO().WantCaptureMouse;
|
||||
}
|
||||
|
||||
// Keyboard IO
|
||||
IGL_INLINE bool ImGuiMenu::key_pressed(unsigned int key, int modifiers)
|
||||
{
|
||||
ImGui_ImplGlfwGL3_CharCallback(nullptr, key);
|
||||
return ImGui::GetIO().WantCaptureKeyboard;
|
||||
}
|
||||
|
||||
IGL_INLINE bool ImGuiMenu::key_down(int key, int modifiers)
|
||||
{
|
||||
ImGui_ImplGlfwGL3_KeyCallback(viewer->window, key, 0, GLFW_PRESS, modifiers);
|
||||
return ImGui::GetIO().WantCaptureKeyboard;
|
||||
}
|
||||
|
||||
IGL_INLINE bool ImGuiMenu::key_up(int key, int modifiers)
|
||||
{
|
||||
ImGui_ImplGlfwGL3_KeyCallback(viewer->window, key, 0, GLFW_RELEASE, modifiers);
|
||||
return ImGui::GetIO().WantCaptureKeyboard;
|
||||
}
|
||||
|
||||
// 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(); }
|
||||
@@ -153,10 +40,8 @@ IGL_INLINE void ImGuiMenu::draw_menu()
|
||||
|
||||
IGL_INLINE void ImGuiMenu::draw_viewer_window()
|
||||
{
|
||||
float menu_width = 180.f * menu_scaling();
|
||||
ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiSetCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f), ImGuiSetCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(menu_width, -1.0f), ImVec2(menu_width, -1.0f));
|
||||
ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f), ImGuiCond_FirstUseEver);
|
||||
bool _viewer_menu_visible = true;
|
||||
ImGui::Begin(
|
||||
"Viewer", &_viewer_menu_visible,
|
||||
@@ -175,7 +60,7 @@ IGL_INLINE void ImGuiMenu::draw_viewer_menu()
|
||||
// Workspace
|
||||
if (ImGui::CollapsingHeader("Workspace", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
float w = ImGui::GetContentRegionAvailWidth();
|
||||
float w = ImGui::GetContentRegionAvail().x;
|
||||
float p = ImGui::GetStyle().FramePadding.x;
|
||||
if (ImGui::Button("Load##Workspace", ImVec2((w-p)/2.f, 0)))
|
||||
{
|
||||
@@ -191,7 +76,7 @@ IGL_INLINE void ImGuiMenu::draw_viewer_menu()
|
||||
// Mesh
|
||||
if (ImGui::CollapsingHeader("Mesh", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
float w = ImGui::GetContentRegionAvailWidth();
|
||||
float w = ImGui::GetContentRegionAvail().x;
|
||||
float p = ImGui::GetStyle().FramePadding.x;
|
||||
if (ImGui::Button("Load##Mesh", ImVec2((w-p)/2.f, 0)))
|
||||
{
|
||||
@@ -209,7 +94,7 @@ IGL_INLINE void ImGuiMenu::draw_viewer_menu()
|
||||
{
|
||||
if (ImGui::Button("Center object", ImVec2(-1, 0)))
|
||||
{
|
||||
viewer->core.align_camera_center(viewer->data().V, viewer->data().F);
|
||||
viewer->core().align_camera_center(viewer->data().V, viewer->data().F);
|
||||
}
|
||||
if (ImGui::Button("Snap canonical view", ImVec2(-1, 0)))
|
||||
{
|
||||
@@ -218,54 +103,63 @@ IGL_INLINE void ImGuiMenu::draw_viewer_menu()
|
||||
|
||||
// Zoom
|
||||
ImGui::PushItemWidth(80 * menu_scaling());
|
||||
ImGui::DragFloat("Zoom", &(viewer->core.camera_zoom), 0.05f, 0.1f, 20.0f);
|
||||
ImGui::DragFloat("Zoom", &(viewer->core().camera_zoom), 0.05f, 0.1f, 20.0f);
|
||||
|
||||
// Select rotation type
|
||||
int rotation_type = static_cast<int>(viewer->core.rotation_type);
|
||||
int rotation_type = static_cast<int>(viewer->core().rotation_type);
|
||||
static Eigen::Quaternionf trackball_angle = Eigen::Quaternionf::Identity();
|
||||
static bool orthographic = true;
|
||||
if (ImGui::Combo("Camera Type", &rotation_type, "Trackball\0Two Axes\0002D Mode\0\0"))
|
||||
{
|
||||
using RT = igl::opengl::ViewerCore::RotationType;
|
||||
auto new_type = static_cast<RT>(rotation_type);
|
||||
if (new_type != viewer->core.rotation_type)
|
||||
if (new_type != viewer->core().rotation_type)
|
||||
{
|
||||
if (new_type == RT::ROTATION_TYPE_NO_ROTATION)
|
||||
{
|
||||
trackball_angle = viewer->core.trackball_angle;
|
||||
orthographic = viewer->core.orthographic;
|
||||
viewer->core.trackball_angle = Eigen::Quaternionf::Identity();
|
||||
viewer->core.orthographic = true;
|
||||
trackball_angle = viewer->core().trackball_angle;
|
||||
orthographic = viewer->core().orthographic;
|
||||
viewer->core().trackball_angle = Eigen::Quaternionf::Identity();
|
||||
viewer->core().orthographic = true;
|
||||
}
|
||||
else if (viewer->core.rotation_type == RT::ROTATION_TYPE_NO_ROTATION)
|
||||
else if (viewer->core().rotation_type == RT::ROTATION_TYPE_NO_ROTATION)
|
||||
{
|
||||
viewer->core.trackball_angle = trackball_angle;
|
||||
viewer->core.orthographic = orthographic;
|
||||
viewer->core().trackball_angle = trackball_angle;
|
||||
viewer->core().orthographic = orthographic;
|
||||
}
|
||||
viewer->core.set_rotation_type(new_type);
|
||||
viewer->core().set_rotation_type(new_type);
|
||||
}
|
||||
}
|
||||
|
||||
// Orthographic view
|
||||
ImGui::Checkbox("Orthographic view", &(viewer->core.orthographic));
|
||||
ImGui::Checkbox("Orthographic view", &(viewer->core().orthographic));
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
// Helper for setting viewport specific mesh options
|
||||
auto make_checkbox = [&](const char *label, unsigned int &option)
|
||||
{
|
||||
return ImGui::Checkbox(label,
|
||||
[&]() { return viewer->core().is_set(option); },
|
||||
[&](bool value) { return viewer->core().set(option, value); }
|
||||
);
|
||||
};
|
||||
|
||||
// Draw options
|
||||
if (ImGui::CollapsingHeader("Draw Options", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
if (ImGui::Checkbox("Face-based", &(viewer->data().face_based)))
|
||||
{
|
||||
viewer->data().set_face_based(viewer->data().face_based);
|
||||
viewer->data().dirty = MeshGL::DIRTY_ALL;
|
||||
}
|
||||
ImGui::Checkbox("Show texture", &(viewer->data().show_texture));
|
||||
make_checkbox("Show texture", viewer->data().show_texture);
|
||||
if (ImGui::Checkbox("Invert normals", &(viewer->data().invert_normals)))
|
||||
{
|
||||
viewer->data().dirty |= igl::opengl::MeshGL::DIRTY_NORMAL;
|
||||
}
|
||||
ImGui::Checkbox("Show overlay", &(viewer->data().show_overlay));
|
||||
ImGui::Checkbox("Show overlay depth", &(viewer->data().show_overlay_depth));
|
||||
ImGui::ColorEdit4("Background", viewer->core.background_color.data(),
|
||||
make_checkbox("Show overlay", viewer->data().show_overlay);
|
||||
make_checkbox("Show overlay depth", viewer->data().show_overlay_depth);
|
||||
ImGui::ColorEdit4("Background", viewer->core().background_color.data(),
|
||||
ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_PickerHueWheel);
|
||||
ImGui::ColorEdit4("Line color", viewer->data().line_color.data(),
|
||||
ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_PickerHueWheel);
|
||||
@@ -277,107 +171,14 @@ IGL_INLINE void ImGuiMenu::draw_viewer_menu()
|
||||
// Overlays
|
||||
if (ImGui::CollapsingHeader("Overlays", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
ImGui::Checkbox("Wireframe", &(viewer->data().show_lines));
|
||||
ImGui::Checkbox("Fill", &(viewer->data().show_faces));
|
||||
ImGui::Checkbox("Show vertex labels", &(viewer->data().show_vertid));
|
||||
ImGui::Checkbox("Show faces labels", &(viewer->data().show_faceid));
|
||||
make_checkbox("Wireframe", viewer->data().show_lines);
|
||||
make_checkbox("Fill", viewer->data().show_faces);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void ImGuiMenu::draw_labels_window()
|
||||
{
|
||||
// Text labels
|
||||
ImGui::SetNextWindowPos(ImVec2(0,0), ImGuiSetCond_Always);
|
||||
ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize, ImGuiSetCond_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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
if (data.labels_positions.rows() > 0)
|
||||
{
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void ImGuiMenu::draw_text(Eigen::Vector3d pos, Eigen::Vector3d normal, const std::string &text)
|
||||
{
|
||||
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(0, 0, 10, 255)),
|
||||
&text[0], &text[0] + text.size());
|
||||
}
|
||||
|
||||
IGL_INLINE float ImGuiMenu::pixel_ratio()
|
||||
{
|
||||
// Computes pixel ratio for hidpi devices
|
||||
int buf_size[2];
|
||||
int win_size[2];
|
||||
GLFWwindow* window = glfwGetCurrentContext();
|
||||
glfwGetFramebufferSize(window, &buf_size[0], &buf_size[1]);
|
||||
glfwGetWindowSize(window, &win_size[0], &win_size[1]);
|
||||
return (float) buf_size[0] / (float) win_size[0];
|
||||
}
|
||||
|
||||
IGL_INLINE float ImGuiMenu::hidpi_scaling()
|
||||
{
|
||||
// Computes scaling factor for hidpi devices
|
||||
float xscale, yscale;
|
||||
GLFWwindow* window = glfwGetCurrentContext();
|
||||
glfwGetWindowContentScale(window, &xscale, &yscale);
|
||||
return 0.5 * (xscale + yscale);
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
} // end namespace
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2022 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// Copyright (C) 2018 Jérémie Dumas <jeremie.dumas@ens-lyon.org>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
@@ -8,103 +9,47 @@
|
||||
#ifndef IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H
|
||||
#define IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <igl/opengl/glfw/Viewer.h>
|
||||
#include <igl/opengl/glfw/ViewerPlugin.h>
|
||||
#include <igl/igl_inline.h>
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Forward declarations
|
||||
struct ImGuiContext;
|
||||
#include "ImGuiPlugin.h"
|
||||
#include "ImGuiWidget.h"
|
||||
#include "../../../igl_inline.h"
|
||||
#include <memory>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
namespace glfw
|
||||
{
|
||||
namespace imgui
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
namespace glfw
|
||||
{
|
||||
namespace imgui
|
||||
{
|
||||
/// Widget for a menu bar and a viewer window.
|
||||
class ImGuiMenu : public ImGuiWidget
|
||||
{
|
||||
public:
|
||||
IGL_INLINE virtual void init(Viewer *_viewer, ImGuiPlugin *_plugin) override;
|
||||
IGL_INLINE virtual void shutdown() override;
|
||||
IGL_INLINE virtual void draw() override;
|
||||
// Can be overwritten by `callback_draw_viewer_window`
|
||||
IGL_INLINE virtual void draw_viewer_window();
|
||||
// Can be overwritten by `callback_draw_viewer_menu`
|
||||
IGL_INLINE virtual void draw_viewer_menu();
|
||||
// Can be overwritten by `callback_draw_custom_window`
|
||||
IGL_INLINE virtual void draw_custom_window() { }
|
||||
// Customizable callbacks
|
||||
std::function<void(void)> callback_draw_viewer_window;
|
||||
std::function<void(void)> callback_draw_viewer_menu;
|
||||
std::function<void(void)> callback_draw_custom_window;
|
||||
float menu_scaling()
|
||||
{ return plugin->hidpi_scaling() / plugin->pixel_ratio(); }
|
||||
};
|
||||
|
||||
class ImGuiMenu : public igl::opengl::glfw::ViewerPlugin
|
||||
{
|
||||
protected:
|
||||
// Hidpi scaling to be used for text rendering.
|
||||
float hidpi_scaling_;
|
||||
|
||||
// Ratio between the framebuffer size and the window size.
|
||||
// May be different from the hipdi scaling!
|
||||
float pixel_ratio_;
|
||||
|
||||
// ImGui Context
|
||||
ImGuiContext * context_ = nullptr;
|
||||
|
||||
public:
|
||||
IGL_INLINE virtual void init(igl::opengl::glfw::Viewer *_viewer) override;
|
||||
|
||||
IGL_INLINE virtual void reload_font(int font_size = 13);
|
||||
|
||||
IGL_INLINE virtual void shutdown() override;
|
||||
|
||||
IGL_INLINE virtual bool pre_draw() override;
|
||||
|
||||
IGL_INLINE virtual bool post_draw() override;
|
||||
|
||||
IGL_INLINE virtual void post_resize(int width, int height) override;
|
||||
|
||||
// Mouse IO
|
||||
IGL_INLINE virtual bool mouse_down(int button, int modifier) override;
|
||||
|
||||
IGL_INLINE virtual bool mouse_up(int button, int modifier) override;
|
||||
|
||||
IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y) override;
|
||||
|
||||
IGL_INLINE virtual bool mouse_scroll(float delta_y) override;
|
||||
|
||||
// Keyboard IO
|
||||
IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers) override;
|
||||
|
||||
IGL_INLINE virtual bool key_down(int key, int modifiers) override;
|
||||
|
||||
IGL_INLINE virtual bool key_up(int key, int modifiers) override;
|
||||
|
||||
// Draw menu
|
||||
IGL_INLINE virtual void draw_menu();
|
||||
|
||||
// Can be overwritten by `callback_draw_viewer_window`
|
||||
IGL_INLINE virtual void draw_viewer_window();
|
||||
|
||||
// Can be overwritten by `callback_draw_viewer_menu`
|
||||
IGL_INLINE virtual void draw_viewer_menu();
|
||||
|
||||
// Can be overwritten by `callback_draw_custom_window`
|
||||
IGL_INLINE virtual void draw_custom_window() { }
|
||||
|
||||
// Easy-to-customize callbacks
|
||||
std::function<void(void)> callback_draw_viewer_window;
|
||||
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, const std::string &text);
|
||||
|
||||
IGL_INLINE float pixel_ratio();
|
||||
|
||||
IGL_INLINE float hidpi_scaling();
|
||||
|
||||
float menu_scaling() { return hidpi_scaling_ / pixel_ratio_; }
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
} // end namespace
|
||||
} // end namespace
|
||||
} // end namespace
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "ImGuiMenu.cpp"
|
||||
#endif
|
||||
|
||||
#endif // IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H
|
||||
#endif
|
||||
|
||||
211
deps_src/libigl/igl/opengl/glfw/imgui/ImGuiPlugin.cpp
Normal file
211
deps_src/libigl/igl/opengl/glfw/imgui/ImGuiPlugin.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2022 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// Copyright (C) 2018 Jérémie Dumas <jeremie.dumas@ens-lyon.org>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include "ImGuiPlugin.h"
|
||||
#include "ImGuiHelpers.h"
|
||||
#include "../../../project.h"
|
||||
#include <backends/imgui_impl_glfw.h>
|
||||
#include <backends/imgui_impl_opengl3.h>
|
||||
#include <imgui.h>
|
||||
#include <imgui_fonts_droid_sans.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
namespace glfw
|
||||
{
|
||||
namespace imgui
|
||||
{
|
||||
|
||||
IGL_INLINE void ImGuiPlugin::init(igl::opengl::glfw::Viewer *_viewer)
|
||||
{
|
||||
ViewerPlugin::init(_viewer);
|
||||
// Setup ImGui binding
|
||||
if (_viewer)
|
||||
{
|
||||
IMGUI_CHECKVERSION();
|
||||
if (!context_)
|
||||
{
|
||||
// Single global context by default, but can be overridden by the user
|
||||
static ImGuiContext * __global_context = ImGui::CreateContext();
|
||||
context_ = __global_context;
|
||||
}
|
||||
const char* glsl_version = "#version 150";
|
||||
ImGui_ImplGlfw_InitForOpenGL(viewer->window, false);
|
||||
ImGui_ImplOpenGL3_Init(glsl_version);
|
||||
ImGui::GetIO().IniFilename = nullptr;
|
||||
ImGui::StyleColorsDark();
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
style.FrameRounding = 5.0f;
|
||||
reload_font();
|
||||
}
|
||||
init_widgets();
|
||||
}
|
||||
|
||||
IGL_INLINE void ImGuiPlugin::init_widgets()
|
||||
{
|
||||
// Init all widgets
|
||||
for(auto & widget : widgets) { widget->init(viewer, this); }
|
||||
}
|
||||
IGL_INLINE void ImGuiPlugin::reload_font(int font_size)
|
||||
{
|
||||
hidpi_scaling_ = hidpi_scaling();
|
||||
pixel_ratio_ = pixel_ratio();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.Fonts->Clear();
|
||||
io.Fonts->AddFontFromMemoryCompressedTTF(droid_sans_compressed_data,
|
||||
droid_sans_compressed_size, font_size * hidpi_scaling_);
|
||||
io.FontGlobalScale = 1.0 / pixel_ratio_;
|
||||
}
|
||||
|
||||
IGL_INLINE void ImGuiPlugin::shutdown()
|
||||
{
|
||||
// Cleanup
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
// User is responsible for destroying context if a custom context is given
|
||||
// ImGui::DestroyContext(*context_);
|
||||
}
|
||||
|
||||
IGL_INLINE bool ImGuiPlugin::pre_draw()
|
||||
{
|
||||
glfwPollEvents();
|
||||
|
||||
// Check whether window dpi has changed
|
||||
float scaling = hidpi_scaling();
|
||||
if (std::abs(scaling - hidpi_scaling_) > 1e-5)
|
||||
{
|
||||
reload_font();
|
||||
ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
}
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE bool ImGuiPlugin::post_draw()
|
||||
{
|
||||
for(auto & widget : widgets){ widget->draw(); }
|
||||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE void ImGuiPlugin::post_resize(int width, int height)
|
||||
{
|
||||
if (context_)
|
||||
{
|
||||
ImGui::GetIO().DisplaySize.x = float(width);
|
||||
ImGui::GetIO().DisplaySize.y = float(height);
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse IO
|
||||
IGL_INLINE bool ImGuiPlugin::mouse_down(int button, int modifier)
|
||||
{
|
||||
ImGui_ImplGlfw_MouseButtonCallback(viewer->window, button, GLFW_PRESS, modifier);
|
||||
if(ImGui::GetIO().WantCaptureMouse){ return true; }
|
||||
for( auto & widget : widgets)
|
||||
{
|
||||
if(widget->mouse_down(button, modifier)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE bool ImGuiPlugin::mouse_up(int button, int modifier)
|
||||
{
|
||||
//return ImGui::GetIO().WantCaptureMouse;
|
||||
// !! Should not steal mouse up
|
||||
for( auto & widget : widgets)
|
||||
{
|
||||
widget->mouse_up(button, modifier);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE bool ImGuiPlugin::mouse_move(int mouse_x, int mouse_y)
|
||||
{
|
||||
if(ImGui::GetIO().WantCaptureMouse){ return true; }
|
||||
for( auto & widget : widgets)
|
||||
{
|
||||
if(widget->mouse_move(mouse_x, mouse_y)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE bool ImGuiPlugin::mouse_scroll(float delta_y)
|
||||
{
|
||||
ImGui_ImplGlfw_ScrollCallback(viewer->window, 0.f, delta_y);
|
||||
return ImGui::GetIO().WantCaptureMouse;
|
||||
}
|
||||
|
||||
// Keyboard IO
|
||||
IGL_INLINE bool ImGuiPlugin::key_pressed(unsigned int key, int modifiers)
|
||||
{
|
||||
ImGui_ImplGlfw_CharCallback(nullptr, key);
|
||||
if(ImGui::GetIO().WantCaptureKeyboard) { return true; }
|
||||
for(auto & widget : widgets)
|
||||
{
|
||||
if(widget->key_pressed(key,modifiers)) {return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE bool ImGuiPlugin::key_down(int key, int modifiers)
|
||||
{
|
||||
ImGui_ImplGlfw_KeyCallback(viewer->window, key, 0, GLFW_PRESS, modifiers);
|
||||
if(ImGui::GetIO().WantCaptureKeyboard) { return true; }
|
||||
for(auto & widget : widgets)
|
||||
{
|
||||
if(widget->key_down(key,modifiers)) {return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE bool ImGuiPlugin::key_up(int key, int modifiers)
|
||||
{
|
||||
ImGui_ImplGlfw_KeyCallback(viewer->window, key, 0, GLFW_RELEASE, modifiers);
|
||||
if(ImGui::GetIO().WantCaptureKeyboard) { return true; }
|
||||
for(auto & widget : widgets)
|
||||
{
|
||||
if(widget->key_up(key,modifiers)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE float ImGuiPlugin::pixel_ratio()
|
||||
{
|
||||
// Computes pixel ratio for hidpi devices
|
||||
int buf_size[2];
|
||||
int win_size[2];
|
||||
GLFWwindow* window = glfwGetCurrentContext();
|
||||
glfwGetFramebufferSize(window, &buf_size[0], &buf_size[1]);
|
||||
glfwGetWindowSize(window, &win_size[0], &win_size[1]);
|
||||
return (float) buf_size[0] / (float) win_size[0];
|
||||
}
|
||||
|
||||
IGL_INLINE float ImGuiPlugin::hidpi_scaling()
|
||||
{
|
||||
// Computes scaling factor for hidpi devices
|
||||
float xscale, yscale;
|
||||
GLFWwindow* window = glfwGetCurrentContext();
|
||||
glfwGetWindowContentScale(window, &xscale, &yscale);
|
||||
return 0.5 * (xscale + yscale);
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
} // end namespace
|
||||
} // end namespace
|
||||
} // end namespace
|
||||
|
||||
78
deps_src/libigl/igl/opengl/glfw/imgui/ImGuiPlugin.h
Normal file
78
deps_src/libigl/igl/opengl/glfw/imgui/ImGuiPlugin.h
Normal file
@@ -0,0 +1,78 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2022 Alec Jacobson <alecjacobson@gmail.com>
|
||||
// Copyright (C) 2018 Jérémie Dumas <jeremie.dumas@ens-lyon.org>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_OPENGL_GLFW_IMGUI_IMGUIPLUGIN_H
|
||||
#define IGL_OPENGL_GLFW_IMGUI_IMGUIPLUGIN_H
|
||||
|
||||
#include "../Viewer.h"
|
||||
#include "../ViewerPlugin.h"
|
||||
#include "../../../igl_inline.h"
|
||||
#include "ImGuiWidget.h"
|
||||
|
||||
// Forward declarations
|
||||
struct ImGuiContext;
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
namespace glfw
|
||||
{
|
||||
namespace imgui
|
||||
{
|
||||
// Forward declaration of child widget abstract type
|
||||
class ImGuiWidget;
|
||||
/// Plugin for the viewer to enable imgui widgets
|
||||
class ImGuiPlugin : public igl::opengl::glfw::ViewerPlugin
|
||||
{
|
||||
protected:
|
||||
// Hidpi scaling to be used for text rendering.
|
||||
float hidpi_scaling_;
|
||||
// Ratio between the framebuffer size and the window size.
|
||||
// May be different from the hipdi scaling!
|
||||
float pixel_ratio_;
|
||||
// ImGui Context
|
||||
ImGuiContext * context_ = nullptr;
|
||||
public:
|
||||
// List of registered widgets
|
||||
std::vector<ImGuiWidget*> widgets;
|
||||
public:
|
||||
IGL_INLINE virtual void init(igl::opengl::glfw::Viewer *_viewer) override;
|
||||
IGL_INLINE void init_widgets();
|
||||
IGL_INLINE virtual void reload_font(int font_size = 13);
|
||||
IGL_INLINE virtual void shutdown() override;
|
||||
IGL_INLINE virtual bool pre_draw() override;
|
||||
IGL_INLINE virtual bool post_draw() override;
|
||||
IGL_INLINE virtual void post_resize(int width, int height) override;
|
||||
IGL_INLINE virtual bool mouse_down(int button, int modifier) override;
|
||||
IGL_INLINE virtual bool mouse_up(int button, int modifier) override;
|
||||
IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y) override;
|
||||
IGL_INLINE virtual bool mouse_scroll(float delta_y) override;
|
||||
// Keyboard IO
|
||||
IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers) override;
|
||||
IGL_INLINE virtual bool key_down(int key, int modifiers) override;
|
||||
IGL_INLINE virtual bool key_up(int key, int modifiers) override;
|
||||
IGL_INLINE void draw_text(
|
||||
const Eigen::Vector3d pos,
|
||||
const Eigen::Vector3d normal,
|
||||
const std::string &text,
|
||||
const Eigen::Vector4f color = Eigen::Vector4f(0,0,0.04,1)); // old default color
|
||||
IGL_INLINE float pixel_ratio();
|
||||
IGL_INLINE float hidpi_scaling();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "ImGuiPlugin.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
69
deps_src/libigl/igl/opengl/glfw/imgui/ImGuiTraits.h
Normal file
69
deps_src/libigl/igl/opengl/glfw/imgui/ImGuiTraits.h
Normal file
@@ -0,0 +1,69 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2018 Jérémie Dumas <jeremie.dumas@ens-lyon.org>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_OPENGL_GLFW_IMGUI_IMGUITRAITS_H
|
||||
#define IGL_OPENGL_GLFW_IMGUI_IMGUITRAITS_H
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
// Extend ImGui by populating its namespace directly
|
||||
namespace ImGui
|
||||
{
|
||||
|
||||
// Infer ImGuiDataType enum based on actual type
|
||||
template<typename T>
|
||||
class ImGuiDataTypeTraits
|
||||
{
|
||||
static const ImGuiDataType value; // link error
|
||||
static const char * format;
|
||||
};
|
||||
|
||||
template<>
|
||||
class ImGuiDataTypeTraits<int>
|
||||
{
|
||||
static constexpr ImGuiDataType value = ImGuiDataType_S32;
|
||||
static constexpr const char *format = "%d";
|
||||
};
|
||||
|
||||
template<>
|
||||
class ImGuiDataTypeTraits<unsigned int>
|
||||
{
|
||||
static constexpr ImGuiDataType value = ImGuiDataType_U32;
|
||||
static constexpr const char *format = "%u";
|
||||
};
|
||||
|
||||
template<>
|
||||
class ImGuiDataTypeTraits<long long>
|
||||
{
|
||||
static constexpr ImGuiDataType value = ImGuiDataType_S64;
|
||||
static constexpr const char *format = "%lld";
|
||||
};
|
||||
|
||||
template<>
|
||||
class ImGuiDataTypeTraits<unsigned long long>
|
||||
{
|
||||
static constexpr ImGuiDataType value = ImGuiDataType_U64;
|
||||
static constexpr const char *format = "%llu";
|
||||
};
|
||||
|
||||
template<>
|
||||
class ImGuiDataTypeTraits<float>
|
||||
{
|
||||
static constexpr ImGuiDataType value = ImGuiDataType_Float;
|
||||
static constexpr const char *format = "%.3f";
|
||||
};
|
||||
|
||||
template<>
|
||||
class ImGuiDataTypeTraits<double>
|
||||
{
|
||||
static constexpr ImGuiDataType value = ImGuiDataType_Double;
|
||||
static constexpr const char *format = "%.6f";
|
||||
};
|
||||
|
||||
} // namespace ImGui
|
||||
|
||||
#endif // IGL_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H
|
||||
65
deps_src/libigl/igl/opengl/glfw/imgui/ImGuiWidget.h
Normal file
65
deps_src/libigl/igl/opengl/glfw/imgui/ImGuiWidget.h
Normal file
@@ -0,0 +1,65 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2022 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_OPENGL_GLFW_IMGUI_IMGUIWIDGET_H
|
||||
#define IGL_OPENGL_GLFW_IMGUI_IMGUIWIDGET_H
|
||||
|
||||
#include "ImGuiPlugin.h"
|
||||
#include "ImGuiWidget.h"
|
||||
#include "../../../igl_inline.h"
|
||||
#include <memory>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
namespace glfw
|
||||
{
|
||||
class Viewer;
|
||||
namespace imgui
|
||||
{
|
||||
// Forward declaration of the parent plugin
|
||||
class ImGuiPlugin;
|
||||
/// Abstract class for imgui "widgets". A widget is something that uses
|
||||
/// imgui, but doesn't own the entire imgui IO stack: the single
|
||||
/// ImGuiPlugin owns that and widgets are registered with it.
|
||||
class ImGuiWidget
|
||||
{
|
||||
public:
|
||||
IGL_INLINE ImGuiWidget(){ name = "dummy"; }
|
||||
virtual ~ImGuiWidget(){}
|
||||
IGL_INLINE virtual void init(Viewer *_viewer, ImGuiPlugin *_plugin)
|
||||
{ viewer = _viewer; plugin = _plugin; }
|
||||
IGL_INLINE virtual void shutdown() {}
|
||||
IGL_INLINE virtual void draw() {}
|
||||
IGL_INLINE virtual bool mouse_down(int /*button*/, int /*modifier*/)
|
||||
{ return false;}
|
||||
IGL_INLINE virtual bool mouse_up(int /*button*/, int /*modifier*/)
|
||||
{ return false;}
|
||||
IGL_INLINE virtual bool mouse_move(int /*mouse_x*/, int /*mouse_y*/)
|
||||
{ return false;}
|
||||
IGL_INLINE virtual bool key_pressed(unsigned int /*key*/, int /*modifiers*/)
|
||||
{ return false;}
|
||||
IGL_INLINE virtual bool key_down(int /*key*/, int /*modifiers*/)
|
||||
{ return false;}
|
||||
IGL_INLINE virtual bool key_up(int /*key*/, int /*modifiers*/)
|
||||
{ return false;}
|
||||
std::string name;
|
||||
protected:
|
||||
// Pointer to ImGuiPlugin's parent viewer
|
||||
Viewer *viewer;
|
||||
// Pointer to parent ImGuiPlugin class
|
||||
ImGuiPlugin *plugin;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
43
deps_src/libigl/igl/opengl/glfw/imgui/ImGuizmoWidget.cpp
Normal file
43
deps_src/libigl/igl/opengl/glfw/imgui/ImGuizmoWidget.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "ImGuizmoWidget.h"
|
||||
#include <imgui.h>
|
||||
#include <backends/imgui_impl_glfw.h>
|
||||
#include <backends/imgui_impl_opengl3.h>
|
||||
#include <imgui_fonts_droid_sans.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
|
||||
|
||||
IGL_INLINE void ImGuizmoWidget::init(Viewer *_viewer, ImGuiPlugin *_plugin)
|
||||
{
|
||||
ImGuiWidget::init(_viewer,_plugin);
|
||||
}
|
||||
|
||||
IGL_INLINE void ImGuizmoWidget::draw()
|
||||
{
|
||||
if(!visible){ return; }
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0);
|
||||
ImGuizmo::BeginFrame();
|
||||
ImGui::PopStyleVar();
|
||||
// Don't draw the Viewer's default menu: draw just the ImGuizmo
|
||||
Eigen::Matrix4f view = (viewer->core().view / viewer->core().camera_zoom);
|
||||
Eigen::Matrix4f proj = viewer->core().proj;
|
||||
if(viewer->core().orthographic){ view(2,3) -= 1000;/* Hack depth */ }
|
||||
// ImGuizmo doesn't like a lot of scaling in view, shift it to T
|
||||
const float z = viewer->core().camera_base_zoom;
|
||||
const Eigen::Matrix4f S =
|
||||
(Eigen::Matrix4f()<< z,0,0,0, 0,z,0,0, 0,0,z,0, 0,0,0,1).finished();
|
||||
view = (view * S.inverse()).eval();
|
||||
const Eigen::Matrix4f T0 = T;
|
||||
T = (S * T).eval();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);
|
||||
ImGuizmo::Manipulate(
|
||||
view.data(),proj.data(),operation,ImGuizmo::LOCAL,T.data(),NULL,NULL);
|
||||
// invert scaling that was shifted onto T
|
||||
T = (S.inverse() * T).eval();
|
||||
const float diff = (T-T0).array().abs().maxCoeff();
|
||||
// Only call if actually changed; otherwise, triggers on all mouse events
|
||||
if( diff > 1e-7) { callback(T); }
|
||||
}
|
||||
|
||||
}}}}
|
||||
36
deps_src/libigl/igl/opengl/glfw/imgui/ImGuizmoWidget.h
Normal file
36
deps_src/libigl/igl/opengl/glfw/imgui/ImGuizmoWidget.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef IGL_OPENGL_GFLW_IMGUI_IMGUIZMOPLUGIN_H
|
||||
#define IGL_OPENGL_GFLW_IMGUI_IMGUIZMOPLUGIN_H
|
||||
#include "../../../igl_inline.h"
|
||||
#include "ImGuiMenu.h"
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
#include <ImGuizmo.h>
|
||||
#include <Eigen/Dense>
|
||||
|
||||
namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
|
||||
|
||||
/// Widget for a guizmo (3D transform manipulator)
|
||||
class ImGuizmoWidget : public ImGuiWidget
|
||||
{
|
||||
public:
|
||||
// callback(T) called when the stored transform T changes
|
||||
std::function<void(const Eigen::Matrix4f &)> callback;
|
||||
// Whether to display
|
||||
bool visible = true;
|
||||
// whether rotating, translating or scaling
|
||||
ImGuizmo::OPERATION operation;
|
||||
// stored transformation
|
||||
Eigen::Matrix4f T;
|
||||
// Initilize with rotate operation on an identity transform (at origin)
|
||||
ImGuizmoWidget():operation(ImGuizmo::ROTATE),T(Eigen::Matrix4f::Identity()){};
|
||||
IGL_INLINE virtual void init(Viewer *_viewer, ImGuiPlugin *_plugin) override;
|
||||
IGL_INLINE virtual void draw() override;
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "ImGuizmoWidget.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
215
deps_src/libigl/igl/opengl/glfw/imgui/SelectionWidget.cpp
Normal file
215
deps_src/libigl/igl/opengl/glfw/imgui/SelectionWidget.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2022 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "SelectionWidget.h"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <backends/imgui_impl_glfw.h>
|
||||
#include <backends/imgui_impl_opengl3.h>
|
||||
#include <imgui_fonts_droid_sans.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include "../../../PI.h"
|
||||
|
||||
namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
|
||||
|
||||
IGL_INLINE void SelectionWidget::init(Viewer *_viewer, ImGuiPlugin *_plugin)
|
||||
{
|
||||
ImGuiWidget::init(_viewer,_plugin);
|
||||
std::cout<<R"(
|
||||
igl::opengl::glfw::imgui::SelectionWidget usage:
|
||||
[drag] Draw a 2D selection
|
||||
l Turn on and toggle between lasso and polygonal lasso tool
|
||||
M,m Turn on and toggle between rectangular and circular marquee tool
|
||||
V,v Turn off interactive selection
|
||||
)";
|
||||
}
|
||||
IGL_INLINE void SelectionWidget::draw()
|
||||
{
|
||||
if(mode == OFF){ return; }
|
||||
// Is this call necessary?
|
||||
ImGui::GetIO();
|
||||
|
||||
float width, height;
|
||||
float highdpi = 1.0;
|
||||
{
|
||||
int fwidth, fheight;
|
||||
glfwGetFramebufferSize(viewer->window, &fwidth, &fheight);
|
||||
int iwidth, iheight;
|
||||
glfwGetWindowSize(viewer->window, &iwidth, &iheight);
|
||||
highdpi = float(iwidth)/float(fwidth);
|
||||
// highdpi
|
||||
width = (float)iwidth;
|
||||
height = (float)iheight;
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowPos( ImVec2(0,0) );
|
||||
ImGui::SetNextWindowSize(ImVec2(width,height), ImGuiCond_Always);
|
||||
|
||||
ImGui::Begin("testing", nullptr,
|
||||
ImGuiWindowFlags_NoBackground
|
||||
| ImGuiWindowFlags_NoTitleBar
|
||||
| ImGuiWindowFlags_NoResize
|
||||
| ImGuiWindowFlags_NoMove
|
||||
| ImGuiWindowFlags_NoScrollbar
|
||||
| ImGuiWindowFlags_NoSavedSettings
|
||||
| ImGuiWindowFlags_NoInputs);
|
||||
|
||||
ImDrawList* list = ImGui::GetWindowDrawList();
|
||||
for(int pass = 0;pass<2;pass++)
|
||||
{
|
||||
for(auto & p : L)
|
||||
{
|
||||
list->PathLineTo({ highdpi*p(0),height-highdpi*p(1) });
|
||||
}
|
||||
const bool closed = !(mode==LASSO || mode==POLYGONAL_LASSO) || !(is_down || is_drawing);
|
||||
if(pass == 0)
|
||||
{
|
||||
list->PathStroke(IM_COL32(255, 255, 255, 255), closed, 2);
|
||||
}else
|
||||
{
|
||||
list->PathStroke(IM_COL32(0, 0, 0, 255), closed, 1);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
}
|
||||
|
||||
IGL_INLINE bool SelectionWidget::mouse_down(int /*button*/, int modifier)
|
||||
{
|
||||
if(mode == OFF || (modifier & IGL_MOD_ALT) ){ return false;}
|
||||
is_down = true;
|
||||
has_moved_since_down = false;
|
||||
if(!is_drawing)
|
||||
{
|
||||
L.clear();
|
||||
is_drawing = true;
|
||||
}
|
||||
M.row(0) = xy(viewer);
|
||||
M.row(1) = M.row(0);
|
||||
L.emplace_back(M.row(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
IGL_INLINE bool SelectionWidget::mouse_up(int /*button*/, int /*modifier*/)
|
||||
{
|
||||
is_down = false;
|
||||
// are we done? Check first and last lasso point (need at least 3 (2 real
|
||||
// points + 1 mouse-mouse point))
|
||||
if(is_drawing &&
|
||||
(mode!=POLYGONAL_LASSO ||(L.size()>=3&&(L[0]-L[L.size()-1]).norm()<=10.0)))
|
||||
{
|
||||
if(callback){ callback();}
|
||||
is_drawing = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE bool SelectionWidget::mouse_move(int /*mouse_x*/, int /*mouse_y*/)
|
||||
{
|
||||
if(!is_drawing){ return false; }
|
||||
if(!has_moved_since_down)
|
||||
{
|
||||
if(mode == POLYGONAL_LASSO) { L.emplace_back(L[L.size()-1]); }
|
||||
has_moved_since_down = true;
|
||||
}
|
||||
M.row(1) = xy(viewer);
|
||||
switch(mode)
|
||||
{
|
||||
case RECTANGULAR_MARQUEE:
|
||||
rect(M,L);
|
||||
break;
|
||||
case ELLIPTICAL_MARQUEE:
|
||||
circle(M,L);
|
||||
break;
|
||||
case POLYGONAL_LASSO:
|
||||
// Over write last point
|
||||
L[L.size()-1] = xy(viewer);
|
||||
break;
|
||||
case LASSO:
|
||||
L.emplace_back(xy(viewer));
|
||||
break;
|
||||
default: assert(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IGL_INLINE bool SelectionWidget::key_pressed(unsigned int key, int /*modifiers*/)
|
||||
{
|
||||
Mode old = mode;
|
||||
if(OFF_KEY.find(char(key)) != std::string::npos)
|
||||
{
|
||||
mode = OFF;
|
||||
}else if(LASSO_KEY.find(char(key)) != std::string::npos)
|
||||
{
|
||||
if(mode == LASSO)
|
||||
{
|
||||
mode = POLYGONAL_LASSO;
|
||||
}else/*if(mode == POLYGONAL_LASSO)*/
|
||||
{
|
||||
mode = LASSO;
|
||||
}
|
||||
}else if(MARQUEE_KEY.find(char(key)) != std::string::npos)
|
||||
{
|
||||
if(mode == RECTANGULAR_MARQUEE)
|
||||
{
|
||||
mode = ELLIPTICAL_MARQUEE;
|
||||
}else/*if(mode == ELLIPTICAL_MARQUEE)*/
|
||||
{
|
||||
mode = RECTANGULAR_MARQUEE;
|
||||
}
|
||||
}
|
||||
if(old != mode)
|
||||
{
|
||||
clear();
|
||||
if(callback_post_mode_change){ callback_post_mode_change(old); }
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE void SelectionWidget::clear()
|
||||
{
|
||||
M.setZero();
|
||||
L.clear();
|
||||
is_drawing = false;
|
||||
is_down = false;
|
||||
};
|
||||
|
||||
IGL_INLINE void SelectionWidget::circle(const Eigen::Matrix<float,2,2> & M, std::vector<Eigen::RowVector2f> & L)
|
||||
{
|
||||
L.clear();
|
||||
L.reserve(64);
|
||||
const float r = (M.row(1)-M.row(0)).norm();
|
||||
for(float th = 0;th<2.*igl::PI;th+=0.1)
|
||||
{
|
||||
L.emplace_back(M(0,0)+r*cos(th),M(0,1)+r*sin(th));
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void SelectionWidget::rect(const Eigen::Matrix<float,2,2> & M, std::vector<Eigen::RowVector2f> & L)
|
||||
{
|
||||
L.resize(4);
|
||||
L[0] = Eigen::RowVector2f(M(0,0),M(0,1));
|
||||
L[1] = Eigen::RowVector2f(M(1,0),M(0,1));
|
||||
L[2] = Eigen::RowVector2f(M(1,0),M(1,1));
|
||||
L[3] = Eigen::RowVector2f(M(0,0),M(1,1));
|
||||
}
|
||||
|
||||
IGL_INLINE Eigen::RowVector2f SelectionWidget::xy(const Viewer * vr)
|
||||
{
|
||||
return Eigen::RowVector2f(
|
||||
vr->current_mouse_x,
|
||||
vr->core().viewport(3) - vr->current_mouse_y);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
65
deps_src/libigl/igl/opengl/glfw/imgui/SelectionWidget.h
Normal file
65
deps_src/libigl/igl/opengl/glfw/imgui/SelectionWidget.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#ifndef IGL_OPENGL_GFLW_IMGUI_SELECTIONWIDGET_H
|
||||
#define IGL_OPENGL_GFLW_IMGUI_SELECTIONWIDGET_H
|
||||
#include "../../../igl_inline.h"
|
||||
#include "ImGuiWidget.h"
|
||||
#include <Eigen/Dense>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
|
||||
|
||||
/// Widget for selecting a region of the screen
|
||||
class SelectionWidget: public ImGuiWidget
|
||||
{
|
||||
public:
|
||||
// customizable hotkeys
|
||||
/// Hot key to start marquee
|
||||
std::string MARQUEE_KEY = "Mm";
|
||||
// leave 'L' for show_lines in viewer
|
||||
/// Hot key to start lasso
|
||||
std::string LASSO_KEY = "l";
|
||||
/// Hot key to stop selection
|
||||
std::string OFF_KEY = "Vv";
|
||||
/// Selection modes
|
||||
enum Mode
|
||||
{
|
||||
OFF = 0,
|
||||
RECTANGULAR_MARQUEE = 1,
|
||||
ELLIPTICAL_MARQUEE = 2,
|
||||
POLYGONAL_LASSO = 3,
|
||||
LASSO = 4,
|
||||
NUM_MODES = 5
|
||||
} mode = RECTANGULAR_MARQUEE;
|
||||
bool is_down = false;
|
||||
bool has_moved_since_down = false;
|
||||
bool is_drawing = false;
|
||||
// min and max corners of 2D rectangular marquee
|
||||
Eigen::Matrix<float,2,2> M = Eigen::Matrix<float,2,2>::Zero();
|
||||
// list of points of 2D lasso marquee
|
||||
std::vector<Eigen::RowVector2f> L;
|
||||
// callback called when slection is completed (usually on mouse_up)
|
||||
std::function<void(void)> callback;
|
||||
// callback called after mode is changed
|
||||
std::function<void(Mode)> callback_post_mode_change;
|
||||
IGL_INLINE virtual void init(Viewer *_viewer, ImGuiPlugin *_plugin) override;
|
||||
IGL_INLINE virtual void draw() override;
|
||||
IGL_INLINE virtual bool mouse_down(int button, int modifier) override;
|
||||
IGL_INLINE virtual bool mouse_up(int button, int modifier) override;
|
||||
IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y) override;
|
||||
IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers) override;
|
||||
IGL_INLINE void clear();
|
||||
// helpers
|
||||
IGL_INLINE static void circle(const Eigen::Matrix<float,2,2> & M, std::vector<Eigen::RowVector2f> & L);
|
||||
IGL_INLINE static void rect(const Eigen::Matrix<float,2,2> & M, std::vector<Eigen::RowVector2f> & L);
|
||||
IGL_INLINE static Eigen::RowVector2f xy(const Viewer * v);
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
#include "SelectionWidget.cpp"
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,8 +1,7 @@
|
||||
#ifdef IGL_OPENGL_4
|
||||
|
||||
#include "map_texture.h"
|
||||
#include "background_window.h"
|
||||
#include "../create_shader_program.h"
|
||||
#include "../bind_vertex_attrib_array.h"
|
||||
|
||||
#include "../gl.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
@@ -30,75 +29,45 @@ IGL_INLINE bool igl::opengl::glfw::map_texture(
|
||||
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedU>
|
||||
IGL_INLINE bool igl::opengl::glfw::map_texture(
|
||||
const Eigen::MatrixBase<DerivedV> & _V,
|
||||
const Eigen::MatrixBase<DerivedF> & _F,
|
||||
const Eigen::MatrixBase<DerivedU> & _U,
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedU> & U,
|
||||
const unsigned char * in_data,
|
||||
const int w,
|
||||
const int h,
|
||||
const int nc,
|
||||
const int in_w,
|
||||
const int in_h,
|
||||
const int in_nc,
|
||||
std::vector<unsigned char> & out_data,
|
||||
int & out_w,
|
||||
int & out_h,
|
||||
int & out_nc)
|
||||
{
|
||||
const auto fail = [](const std::string msg)
|
||||
GLenum format = -1;
|
||||
switch(in_nc)
|
||||
{
|
||||
std::cerr<<msg<<std::endl;
|
||||
glfwTerminate();
|
||||
return false;
|
||||
};
|
||||
// Force inputs to be RowMajor at the cost of a copy
|
||||
Eigen::Matrix<
|
||||
double,
|
||||
DerivedV::RowsAtCompileTime,
|
||||
DerivedV::ColsAtCompileTime,
|
||||
Eigen::RowMajor> V = _V.template cast<double>();
|
||||
Eigen::Matrix<
|
||||
double,
|
||||
DerivedU::RowsAtCompileTime,
|
||||
DerivedU::ColsAtCompileTime,
|
||||
Eigen::RowMajor> U = _U.template cast<double>();
|
||||
Eigen::Matrix<
|
||||
int,
|
||||
DerivedF::RowsAtCompileTime,
|
||||
DerivedF::ColsAtCompileTime,
|
||||
Eigen::RowMajor> F = _F.template cast<int>();
|
||||
const int dim = U.cols();
|
||||
GLFWwindow * window;
|
||||
if(!background_window(window))
|
||||
{
|
||||
fail("Could not initialize glfw window");
|
||||
case 1: format = GL_RED; break;
|
||||
case 2: format = GL_RG; break;
|
||||
case 3: format = GL_RGB; break;
|
||||
case 4: format = GL_RGBA; break;
|
||||
default: assert(false && "Unsupported number of channels"); break;
|
||||
}
|
||||
|
||||
GLFWwindow * window = nullptr;
|
||||
igl::opengl::glfw::background_window(window);
|
||||
// Compile each shader
|
||||
std::string vertex_shader = dim == 2 ?
|
||||
R"(
|
||||
#version 330 core
|
||||
layout(location = 0) in vec2 position;
|
||||
layout(location = 1) in vec2 tex_coord_v;
|
||||
out vec2 tex_coord_f;
|
||||
void main()
|
||||
{
|
||||
tex_coord_f = vec2(tex_coord_v.x,1.-tex_coord_v.y);
|
||||
gl_Position = vec4( 2.*position.x-1., 2.*(1.-position.y)-1., 0.,1.);
|
||||
}
|
||||
)"
|
||||
:
|
||||
R"(
|
||||
#version 330 core
|
||||
std::string vertex_shader = R"(
|
||||
#version 400
|
||||
layout(location = 0) in vec3 position;
|
||||
layout(location = 1) in vec2 tex_coord_v;
|
||||
out vec2 tex_coord_f;
|
||||
void main()
|
||||
{
|
||||
tex_coord_f = vec2(tex_coord_v.x,1.-tex_coord_v.y);
|
||||
gl_Position = vec4( 2.*position.x-1., 2.*(1.-position.y)-1., position.z,1.);
|
||||
gl_Position = vec4(2.*position.x-1.,2.*(1.-position.y)-1., position.z,1.);
|
||||
}
|
||||
)"
|
||||
;
|
||||
std::string fragment_shader = R"(
|
||||
#version 330 core
|
||||
#version 400
|
||||
layout(location = 0) out vec3 color;
|
||||
uniform sampler2D tex;
|
||||
in vec2 tex_coord_f;
|
||||
@@ -109,53 +78,44 @@ void main()
|
||||
)";
|
||||
GLuint prog_id =
|
||||
igl::opengl::create_shader_program(vertex_shader,fragment_shader,{});
|
||||
glUniform1i(glGetUniformLocation(prog_id, "tex"),0);
|
||||
|
||||
using Scalar = float;
|
||||
using MatrixXS3 = Eigen::Matrix<Scalar,Eigen::Dynamic,3,Eigen::RowMajor>;
|
||||
MatrixXS3 V_vbo = MatrixXS3::Zero(V.rows(),3);
|
||||
V_vbo.leftCols(V.cols()) = V.template cast<Scalar>();
|
||||
MatrixXS3 U_vbo = MatrixXS3::Zero(U.rows(),3);
|
||||
U_vbo.leftCols(U.cols()) = U.template cast<Scalar>();
|
||||
Eigen::Matrix<unsigned, Eigen::Dynamic, 3, Eigen::RowMajor> F_vbo =
|
||||
F.template cast<unsigned>();
|
||||
|
||||
// Generate and attach buffers to vertex array
|
||||
glDisable(GL_CULL_FACE);
|
||||
GLuint VAO = 0;
|
||||
glGenVertexArrays(1,&VAO);
|
||||
glBindVertexArray(VAO);
|
||||
GLuint ibo,vbo,tbo;
|
||||
GLuint ibo,vbo,tbo,tex;
|
||||
glGenBuffers(1,&ibo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*F.size(), F.data(), GL_STATIC_DRAW);
|
||||
glGenBuffers(1,&vbo);
|
||||
glEnableVertexAttribArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER,vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(double)*U.size(), U.data(), GL_STATIC_DRAW);
|
||||
glVertexAttribLPointer(0, U.cols(), GL_DOUBLE, U.cols() * sizeof(GLdouble), (GLvoid*)0);
|
||||
glGenBuffers(1,&tbo);
|
||||
glEnableVertexAttribArray(1);
|
||||
glBindBuffer(GL_ARRAY_BUFFER,tbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(double)*V.size(), V.data(), GL_STATIC_DRAW);
|
||||
glVertexAttribLPointer(1, V.cols(), GL_DOUBLE, V.cols() * sizeof(GLdouble), (GLvoid*)0);
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
// Prepare texture
|
||||
GLuint in_tex;
|
||||
GLenum format;
|
||||
{
|
||||
format = nc==1 ? GL_RED : (nc==3 ? GL_RGB : (nc == 4 ? GL_RGBA : GL_FALSE));
|
||||
glGenTextures(1, &in_tex);
|
||||
glBindTexture(GL_TEXTURE_2D, in_tex);
|
||||
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_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w, h, 0,format, GL_UNSIGNED_BYTE, in_data);
|
||||
}
|
||||
glGenTextures(1,&tex);
|
||||
|
||||
|
||||
out_w = in_w;
|
||||
out_h = in_h;
|
||||
glClearColor(0,0,1,1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glViewport(0,0,out_w,out_h);
|
||||
|
||||
// Prepare framebuffer
|
||||
GLuint fb = 0;
|
||||
GLuint out_tex;
|
||||
|
||||
glGenFramebuffers(1, &fb);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb);
|
||||
GLuint out_tex;
|
||||
glGenTextures(1, &out_tex);
|
||||
glBindTexture(GL_TEXTURE_2D, out_tex);
|
||||
// always use float for internal storage
|
||||
assert(out_nc == 3);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, out_w, out_h, 0,GL_RGB, GL_FLOAT, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0,format, out_w, out_h, 0,format, GL_FLOAT, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, out_tex, 0);
|
||||
@@ -165,40 +125,39 @@ void main()
|
||||
}
|
||||
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
fail("framebuffer setup failed.");
|
||||
glfwTerminate();
|
||||
return false;
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb);
|
||||
// clear screen and set viewport
|
||||
glClearColor(0.0,1.0,0.0,0.);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glViewport(0,0,out_w,out_h);
|
||||
// Attach shader program
|
||||
|
||||
glUseProgram(prog_id);
|
||||
glActiveTexture(GL_TEXTURE0 + 0);
|
||||
glBindTexture(GL_TEXTURE_2D, in_tex);
|
||||
// Draw mesh as wireframe
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
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);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, format, in_w, in_h, 0, format, GL_UNSIGNED_BYTE, in_data);
|
||||
glUniform1i(glGetUniformLocation(prog_id,"tex"), 0);
|
||||
|
||||
igl::opengl::bind_vertex_attrib_array(prog_id,"position", vbo, U_vbo, true);
|
||||
igl::opengl::bind_vertex_attrib_array(prog_id,"tex_coord_v", tbo, V_vbo, true);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glBindVertexArray(VAO);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*F_vbo.size(), F_vbo.data(), GL_DYNAMIC_DRAW);
|
||||
glDrawElements(GL_TRIANGLES, F.size(), GL_UNSIGNED_INT, 0);
|
||||
glBindVertexArray(0);
|
||||
// Write into memory
|
||||
assert(out_nc == 3);
|
||||
|
||||
out_nc = in_nc;
|
||||
out_data.resize(out_nc*out_w*out_h);
|
||||
glBindTexture(GL_TEXTURE_2D, out_tex);
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, format, GL_UNSIGNED_BYTE, &out_data[0]);
|
||||
// OpenGL cleanup
|
||||
glDeleteBuffers(1,&fb);
|
||||
glDeleteBuffers(1,&ibo);
|
||||
glDeleteBuffers(1,&vbo);
|
||||
glDeleteBuffers(1,&tbo);
|
||||
glDeleteTextures(1,&in_tex);
|
||||
glDeleteTextures(1,&out_tex);
|
||||
glDeleteVertexArrays(1,&VAO);
|
||||
glUseProgram(0);
|
||||
glDeleteProgram(prog_id);
|
||||
// GLFW cleanup
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, format, GL_UNSIGNED_BYTE, out_data.data());
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -206,6 +165,5 @@ void main()
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template bool igl::opengl::glfw::map_texture<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, unsigned char const*, int, int, int, std::vector<unsigned char, std::allocator<unsigned char> >&);
|
||||
template bool igl::opengl::glfw::map_texture<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::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&, unsigned char const*, int, int, int, std::vector<unsigned char, std::allocator<unsigned char> >&, int&, int&, int&);
|
||||
#endif
|
||||
|
||||
#endif // IGL_OPENGL_4
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#ifndef IGL_OPENGL_GLFW_MAP_TEXTURE_H
|
||||
#define IGL_OPENGL_GLFW_MAP_TEXTURE_H
|
||||
|
||||
#ifdef IGL_OPENGL_4
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <vector>
|
||||
@@ -13,30 +11,22 @@ namespace igl
|
||||
{
|
||||
namespace glfw
|
||||
{
|
||||
// Given a mesh (V,F) in [0,1]² and new positions (U) and a texture image
|
||||
// (in_data), _render_ a new image (out_data) of the same size.
|
||||
// Inputs:
|
||||
// V #V by 2 list of undeformed mesh vertex positions (matching texture)
|
||||
// F #F by 3 list of mesh triangle indices into V
|
||||
// U #U by 2 list of deformed vertex positions
|
||||
// in_data w*h*nc array of color values, channels, then columns, then
|
||||
// rows (e.g., what stbi_image returns and expects)
|
||||
// w width
|
||||
// h height
|
||||
// nc number of channels
|
||||
// Outputs:
|
||||
// out_data h*w*nc list of output colors in same order as input
|
||||
//
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedU>
|
||||
IGL_INLINE bool map_texture(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedU> & U,
|
||||
const unsigned char * in_data,
|
||||
const int w,
|
||||
const int h,
|
||||
const int nc,
|
||||
std::vector<unsigned char> & out_data);
|
||||
/// Given a mesh (V,F) in [0,1]² and new positions (U) and a texture image
|
||||
/// (in_data), _render_ a new image (out_data) of the same size.
|
||||
/// @param[in] V #V by 2 list of undeformed mesh vertex positions ∈ [0,1]²
|
||||
/// @param[in] F #F by 3 list of mesh triangle indices into V
|
||||
/// @param[in] U #U by 2 list of deformed vertex positions ∈ [0,1]²
|
||||
/// @param[in] in_data w*h*nc array of color values, channels, then columns, then
|
||||
/// rows (e.g., what stbi_image returns and expects)
|
||||
/// @param[in] w width
|
||||
/// @param[in] h height
|
||||
/// @param[in] nc number of channels
|
||||
/// @param[out] out_data h*w*nc list of output colors in same order as input
|
||||
/// @param[out] out_w width of output image
|
||||
/// @param[out] out_h height of output image
|
||||
/// @param[out] out_nc number of channels of output image
|
||||
///
|
||||
/// \pre Seems like w,h should be equal.
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedU>
|
||||
IGL_INLINE bool map_texture(
|
||||
const Eigen::MatrixBase<DerivedV> & _V,
|
||||
@@ -50,6 +40,17 @@ namespace igl
|
||||
int & out_w,
|
||||
int & out_h,
|
||||
int & out_nc);
|
||||
/// \overload
|
||||
template <typename DerivedV, typename DerivedF, typename DerivedU>
|
||||
IGL_INLINE bool map_texture(
|
||||
const Eigen::MatrixBase<DerivedV> & V,
|
||||
const Eigen::MatrixBase<DerivedF> & F,
|
||||
const Eigen::MatrixBase<DerivedU> & U,
|
||||
const unsigned char * in_data,
|
||||
const int w,
|
||||
const int h,
|
||||
const int nc,
|
||||
std::vector<unsigned char> & out_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,6 +59,4 @@ namespace igl
|
||||
# include "map_texture.cpp"
|
||||
#endif
|
||||
|
||||
#endif // IGL_OPENGL_4
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "init_render_to_texture.h"
|
||||
#include "gl.h"
|
||||
#include <cassert>
|
||||
#include "../IGL_ASSERT.h"
|
||||
|
||||
IGL_INLINE void igl::opengl::init_render_to_texture(
|
||||
const size_t width,
|
||||
@@ -66,7 +66,7 @@ IGL_INLINE void igl::opengl::init_render_to_texture(
|
||||
//Does the GPU support current FBO configuration?
|
||||
GLenum status;
|
||||
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
assert(status == GL_FRAMEBUFFER_COMPLETE);
|
||||
IGL_ASSERT(status == GL_FRAMEBUFFER_COMPLETE);
|
||||
// Unbind to clean up
|
||||
if(!depth_texture)
|
||||
{
|
||||
|
||||
@@ -14,47 +14,46 @@ namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Create a frame buffer that renders color to a RGBA texture a depth to a
|
||||
// "render buffer".
|
||||
//
|
||||
// After calling this, you can use with something like:
|
||||
//
|
||||
// glBindFramebuffer(GL_FRAMEBUFFER, fbo_id);
|
||||
// if(!depth_texture)
|
||||
// {
|
||||
// glBindRenderbuffer(GL_RENDERBUFFER, d_id);
|
||||
// }
|
||||
// //
|
||||
// // draw scene ...
|
||||
// //
|
||||
// // clean up
|
||||
// glBindFramebuffer(GL_FRAMEBUFFER,0);
|
||||
// if(!depth_texture)
|
||||
// {
|
||||
// glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
// }
|
||||
// // Later ...
|
||||
// glActiveTexture(GL_TEXTURE0+0);
|
||||
// glBindTexture(GL_TEXTURE_2D,tex_id);
|
||||
// if(depth_texture)
|
||||
// {
|
||||
// glActiveTexture(GL_TEXTURE0+1);
|
||||
// glBindTexture(GL_TEXTURE_2D,d_id);
|
||||
// }
|
||||
// // draw textures
|
||||
//
|
||||
//
|
||||
//
|
||||
// Inputs:
|
||||
// width image width
|
||||
// height image height
|
||||
// depth_texture whether to create a texture for depth or to create a
|
||||
// render buffer for depth
|
||||
// Outputs:
|
||||
// tex_id id of the texture
|
||||
// fbo_id id of the frame buffer object
|
||||
// d_id id of the depth texture or frame buffer object
|
||||
//
|
||||
/// Create a frame buffer that renders color to a RGBA texture a depth to a
|
||||
/// "render buffer".
|
||||
///
|
||||
/// After calling this, you can use with something like:
|
||||
///
|
||||
/// \code{cpp}
|
||||
/// glBindFramebuffer(GL_FRAMEBUFFER, fbo_id);
|
||||
/// if(!depth_texture)
|
||||
/// {
|
||||
/// glBindRenderbuffer(GL_RENDERBUFFER, d_id);
|
||||
/// }
|
||||
/// //
|
||||
/// // draw scene ...
|
||||
/// //
|
||||
/// // clean up
|
||||
/// glBindFramebuffer(GL_FRAMEBUFFER,0);
|
||||
/// if(!depth_texture)
|
||||
/// {
|
||||
/// glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
/// }
|
||||
/// // Later ...
|
||||
/// glActiveTexture(GL_TEXTURE0+0);
|
||||
/// glBindTexture(GL_TEXTURE_2D,tex_id);
|
||||
/// if(depth_texture)
|
||||
/// {
|
||||
/// glActiveTexture(GL_TEXTURE0+1);
|
||||
/// glBindTexture(GL_TEXTURE_2D,d_id);
|
||||
/// }
|
||||
/// // draw textures
|
||||
/// \endcode
|
||||
///
|
||||
///
|
||||
/// @param[in] width image width
|
||||
/// @param[in] height image height
|
||||
/// @param[in] depth_texture whether to create a texture for depth or to create a
|
||||
/// render buffer for depth
|
||||
/// @param[out] tex_id id of the texture
|
||||
/// @param[out] fbo_id id of the frame buffer object
|
||||
/// @param[out] d_id id of the depth texture or frame buffer object
|
||||
///
|
||||
IGL_INLINE void init_render_to_texture(
|
||||
const size_t width,
|
||||
const size_t height,
|
||||
@@ -62,7 +61,8 @@ namespace igl
|
||||
GLuint & tex_id,
|
||||
GLuint & fbo_id,
|
||||
GLuint & d_id);
|
||||
// Wrapper with depth_texture = false for legacy reasons
|
||||
/// \overload
|
||||
/// \brief Wrapper with depth_texture = false for legacy reasons
|
||||
IGL_INLINE void init_render_to_texture(
|
||||
const size_t width,
|
||||
const size_t height,
|
||||
|
||||
@@ -15,17 +15,16 @@ namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Creates and compiles a shader from a given string
|
||||
//
|
||||
// Inputs:
|
||||
// src string containing GLSL shader code
|
||||
// type GLSL type of shader, one of:
|
||||
// GL_VERTEX_SHADER
|
||||
// GL_FRAGMENT_SHADER
|
||||
// GL_GEOMETRY_SHADER
|
||||
// Returns index id of the newly created shader, 0 on error
|
||||
//
|
||||
// Will immediately return 0 if src is empty.
|
||||
/// Creates and compiles a shader from a given string
|
||||
///
|
||||
/// @param[in] src string containing GLSL shader code
|
||||
/// @param[in] type GLSL type of shader, one of:
|
||||
/// GL_VERTEX_SHADER
|
||||
/// GL_FRAGMENT_SHADER
|
||||
/// GL_GEOMETRY_SHADER
|
||||
/// @return index id of the newly created shader, 0 on error
|
||||
///
|
||||
/// Will immediately return 0 if src is empty.
|
||||
IGL_INLINE GLuint load_shader(
|
||||
const std::string & src,const GLenum type);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,9 @@ namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Inputs:
|
||||
// obj OpenGL index of program to print info log about
|
||||
/// Print the information log for a program object
|
||||
///
|
||||
/// @param[in] obj OpenGL index of program to print info log about
|
||||
IGL_INLINE void print_program_info_log(const GLuint obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Inputs:
|
||||
// obj OpenGL index of shader to print info log about
|
||||
/// Print the info log for a shader object
|
||||
/// @param[in] obj OpenGL index of shader to print info log about
|
||||
IGL_INLINE void print_shader_info_log(const GLuint obj);
|
||||
}
|
||||
}
|
||||
|
||||
46
deps_src/libigl/igl/opengl/read_pixels.cpp
Normal file
46
deps_src/libigl/igl/opengl/read_pixels.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "read_pixels.h"
|
||||
|
||||
template <typename T>
|
||||
void igl::opengl::read_pixels(
|
||||
const GLuint width,
|
||||
const GLuint height,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & R,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & G,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & B,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & A,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & D)
|
||||
{
|
||||
R.resize(width,height);
|
||||
G.resize(width,height);
|
||||
B.resize(width,height);
|
||||
A.resize(width,height);
|
||||
D.resize(width,height);
|
||||
typedef typename std::conditional< std::is_floating_point<T>::value,GLfloat,GLubyte>::type GLType;
|
||||
GLenum type = std::is_floating_point<T>::value ? GL_FLOAT : GL_UNSIGNED_BYTE;
|
||||
GLType* pixels = (GLType*)calloc(width*height*4,sizeof(GLType));
|
||||
GLType * depth = (GLType*)calloc(width*height*1,sizeof(GLType));
|
||||
glReadPixels(0, 0,width, height,GL_RGBA, type, pixels);
|
||||
glReadPixels(0, 0,width, height,GL_DEPTH_COMPONENT, type, depth);
|
||||
int count = 0;
|
||||
for (unsigned j=0; j<height; ++j)
|
||||
{
|
||||
for (unsigned i=0; i<width; ++i)
|
||||
{
|
||||
R(i,j) = pixels[count*4+0];
|
||||
G(i,j) = pixels[count*4+1];
|
||||
B(i,j) = pixels[count*4+2];
|
||||
A(i,j) = pixels[count*4+3];
|
||||
D(i,j) = depth[count*1+0];
|
||||
++count;
|
||||
}
|
||||
}
|
||||
// Clean up
|
||||
free(pixels);
|
||||
free(depth);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
template void igl::opengl::read_pixels<unsigned char>(unsigned int, unsigned int, Eigen::Matrix<unsigned char, -1, -1, 0, -1, -1>&, Eigen::Matrix<unsigned char, -1, -1, 0, -1, -1>&, Eigen::Matrix<unsigned char, -1, -1, 0, -1, -1>&, Eigen::Matrix<unsigned char, -1, -1, 0, -1, -1>&, Eigen::Matrix<unsigned char, -1, -1, 0, -1, -1>&);
|
||||
template void igl::opengl::read_pixels<double>(unsigned int, unsigned int, 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>&);
|
||||
template void igl::opengl::read_pixels<float>(unsigned int, unsigned int, 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>&);
|
||||
#endif
|
||||
38
deps_src/libigl/igl/opengl/read_pixels.h
Normal file
38
deps_src/libigl/igl/opengl/read_pixels.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef IGL_OPENGL_READ_PIXELS_H
|
||||
#define IGL_OPENGL_READ_PIXELS_H
|
||||
|
||||
#include "../igl_inline.h"
|
||||
#include "gl.h"
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
/// Read full viewport into color, alpha and depth arrays suitable for
|
||||
/// igl::png::writePNG
|
||||
///
|
||||
/// @param[in] width width of viewport
|
||||
/// @param[in] height height of viewport
|
||||
/// @param[out] R width by height list of red values
|
||||
/// @param[out] G width by height list of green values
|
||||
/// @param[out] B width by height list of blue values
|
||||
/// @param[out] A width by height list of alpha values
|
||||
/// @param[out] D width by height list of depth values
|
||||
template <typename T>
|
||||
IGL_INLINE void read_pixels(
|
||||
const GLuint width,
|
||||
const GLuint height,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & R,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & G,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & B,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & A,
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & D);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
#include "read_pixels.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -19,12 +19,11 @@ namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Print last OpenGL error to stderr prefixed by specified id string
|
||||
// Inputs:
|
||||
// id string to appear before any error msgs
|
||||
// Returns result of glGetError()
|
||||
/// Print last OpenGL error to stderr prefixed by specified id string
|
||||
/// @param[in] id string to appear before any error msgs
|
||||
/// @return result of glGetError()
|
||||
IGL_INLINE GLenum report_gl_error(const std::string id);
|
||||
// No prefix
|
||||
/// \overload
|
||||
IGL_INLINE GLenum report_gl_error();
|
||||
}
|
||||
}
|
||||
|
||||
45
deps_src/libigl/igl/opengl/stb/render_to_file.cpp
Normal file
45
deps_src/libigl/igl/opengl/stb/render_to_file.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "render_to_file.h"
|
||||
#include "../../stb/write_image.h"
|
||||
#include <stb_image_write.h>
|
||||
|
||||
#include "../gl.h"
|
||||
|
||||
IGL_INLINE bool igl::opengl::stb::render_to_file(
|
||||
const std::string filename,
|
||||
const int width,
|
||||
const int height,
|
||||
const bool alpha)
|
||||
{
|
||||
unsigned char * data = new unsigned char[4*width*height];
|
||||
glReadPixels(
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
data);
|
||||
//img->flip();
|
||||
if(!alpha)
|
||||
{
|
||||
for(int i = 0;i<width;i++)
|
||||
for(int j = 0;j<height;j++)
|
||||
{
|
||||
data[4*(i+j*width)+3] = 255;
|
||||
}
|
||||
}
|
||||
const bool ret = igl::stb::write_image(filename,width,height,data);
|
||||
delete [] data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#endif
|
||||
41
deps_src/libigl/igl/opengl/stb/render_to_file.h
Normal file
41
deps_src/libigl/igl/opengl/stb/render_to_file.h
Normal file
@@ -0,0 +1,41 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_OPENGL_STB_RENDER_TO_PNG_H
|
||||
#define IGL_OPENGL_STB_RENDER_TO_PNG_H
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
#include <string>
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
namespace stb
|
||||
{
|
||||
/// Render current open GL image to an image file
|
||||
///
|
||||
/// @param[in] filename path to output file
|
||||
/// @param[in] width width of scene and resulting image
|
||||
/// @param[in] height height of scene and resulting image
|
||||
/// @param[in] alpha whether to include alpha channel
|
||||
/// @return true only if no errors occurred
|
||||
///
|
||||
/// \see igl::stb::write_image, render_to_file_async
|
||||
IGL_INLINE bool render_to_file(
|
||||
const std::string filename,
|
||||
const int width,
|
||||
const int height,
|
||||
const bool alpha = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "render_to_file.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
53
deps_src/libigl/igl/opengl/stb/render_to_file_async.cpp
Normal file
53
deps_src/libigl/igl/opengl/stb/render_to_file_async.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#include "render_to_file_async.h"
|
||||
#include "../../stb/write_image.h"
|
||||
#include "../gl.h"
|
||||
#include <stb_image_write.h>
|
||||
|
||||
static IGL_INLINE bool render_to_file_async_helper(
|
||||
unsigned char * img, int width, int height,
|
||||
const std::string filename,
|
||||
const bool alpha)
|
||||
{
|
||||
//img->flip();
|
||||
if(!alpha)
|
||||
{
|
||||
for(int i = 0;i<width;i++)
|
||||
for(int j = 0;j<height;j++)
|
||||
{
|
||||
img[4*(i+j*width)+3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
const bool ret = igl::stb::write_image(filename,width,height,img);
|
||||
delete [] img;
|
||||
return ret;
|
||||
}
|
||||
|
||||
IGL_INLINE std::thread igl::opengl::stb::render_to_file_async(
|
||||
const std::string filename,
|
||||
const int width,
|
||||
const int height,
|
||||
const bool alpha)
|
||||
{
|
||||
// Part that should serial
|
||||
unsigned char * data = new unsigned char[width*height];
|
||||
glReadPixels(
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
data);
|
||||
// Part that should be asynchronous
|
||||
std::thread t(render_to_file_async_helper,data,width,height,filename,alpha);
|
||||
t.detach();
|
||||
return t;
|
||||
}
|
||||
46
deps_src/libigl/igl/opengl/stb/render_to_file_async.h
Normal file
46
deps_src/libigl/igl/opengl/stb/render_to_file_async.h
Normal file
@@ -0,0 +1,46 @@
|
||||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_OPENGL_STB_RENDER_TO_PNG_ASYNC_H
|
||||
#define IGL_OPENGL_STB_RENDER_TO_PNG_ASYNC_H
|
||||
#include "../../igl_inline.h"
|
||||
#include <thread>
|
||||
//#include <boost/thread/thread.hpp>
|
||||
|
||||
#include <string>
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
namespace stb
|
||||
{
|
||||
// History:
|
||||
// added multithreaded parameter and support, Alec Sept 3, 2012
|
||||
//
|
||||
/// Render current open GL image to file using a separate thread
|
||||
///
|
||||
/// @param[in] filename path to output image file
|
||||
/// @param[in] width width of scene and resulting image
|
||||
/// @param[in] height height of scene and resulting image
|
||||
/// @param[in] alpha whether to include alpha channel
|
||||
/// @return true only if no errors occurred
|
||||
///
|
||||
/// \see render_to_file
|
||||
IGL_INLINE std::thread render_to_file_async(
|
||||
const std::string filename,
|
||||
const int width,
|
||||
const int height,
|
||||
const bool alpha = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "render_to_file_async.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -15,11 +15,11 @@ namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Convert a GL uniform variable type (say, returned from
|
||||
// glGetActiveUniform) and output a string naming that type
|
||||
// Inputs:
|
||||
// type enum for given type
|
||||
// Returns string name of that type
|
||||
/// Convert a GL uniform variable type (say, returned from
|
||||
/// glGetActiveUniform) and output a string naming that type
|
||||
///
|
||||
/// @param[in] type enum for given type
|
||||
/// @return string name of that type
|
||||
IGL_INLINE std::string uniform_type_to_string(const GLenum type);
|
||||
}
|
||||
}
|
||||
|
||||
67
deps_src/libigl/igl/opengl/verasansmono_compressed.cpp
Normal file
67
deps_src/libigl/igl/opengl/verasansmono_compressed.cpp
Normal file
File diff suppressed because one or more lines are too long
19
deps_src/libigl/igl/opengl/verasansmono_compressed.h
Normal file
19
deps_src/libigl/igl/opengl/verasansmono_compressed.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef IGL_OPENGL_VERASANSMONO_COMPRESSED_H
|
||||
#define IGL_OPENGL_VERASANSMONO_COMPRESSED_H
|
||||
|
||||
#include "../igl_inline.h"
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
/// Decompress the vera sans mono font atlas
|
||||
IGL_INLINE void decompress_verasansmono_atlas(unsigned char* _fontatlas);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "verasansmono_compressed.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "vertex_array.h"
|
||||
#include <igl/opengl/report_gl_error.h>
|
||||
#include "report_gl_error.h"
|
||||
#include "../IGL_ASSERT.h"
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
@@ -41,7 +42,7 @@ IGL_INLINE void igl::opengl::vertex_array(
|
||||
const auto size_FScalar = sizeof(typename DerivedF::Scalar);
|
||||
glBufferData(GL_ARRAY_BUFFER,size_VScalar*V.size(),V.data(),GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eab_id);
|
||||
assert(sizeof(GLuint) == size_FScalar && "F type does not match GLuint");
|
||||
IGL_ASSERT(sizeof(GLuint) == size_FScalar && "F type does not match GLuint");
|
||||
glBufferData(
|
||||
GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*F.size(), F.data(), GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(
|
||||
|
||||
@@ -1,30 +1,28 @@
|
||||
#ifndef IGL_OPENGL_VERTEX_ARRAY_H
|
||||
#define IGL_OPENGL_VERTEX_ARRAY_H
|
||||
#include <igl/opengl/../igl_inline.h>
|
||||
#include <igl/opengl/gl.h>
|
||||
#include "../igl_inline.h"
|
||||
#include "gl.h"
|
||||
#include <Eigen/Core>
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Create a GL_VERTEX_ARRAY for a given mesh (V,F)
|
||||
//
|
||||
// Inputs:
|
||||
// V #V by dim list of mesh vertex positions
|
||||
// F #F by 3 list of mesh triangle indices into V
|
||||
// Outputs:
|
||||
// va_id id of vertex array
|
||||
// ab_id id of array buffer (vertex buffer object)
|
||||
// eab_id id of element array buffer (element/face buffer object)
|
||||
//
|
||||
/// Create a GL_VERTEX_ARRAY for a given mesh (V,F)
|
||||
///
|
||||
/// @param[in] V #V by dim list of mesh vertex positions
|
||||
/// @param[in] F #F by 3 list of mesh triangle indices into V
|
||||
/// @param[out] va_id id of vertex array
|
||||
/// @param[out] ab_id id of array buffer (vertex buffer object)
|
||||
/// @param[out] eab_id id of element array buffer (element/face buffer object)
|
||||
///
|
||||
/// \note Unlike most libigl functions, the **input** Eigen matrices must
|
||||
/// be `Eigen::PlainObjectBase` because we want to directly access it's
|
||||
/// underlying storage. It cannot be `Eigen::MatrixBase` (see
|
||||
/// http://stackoverflow.com/questions/25094948/)
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE void vertex_array(
|
||||
// Note: Unlike most libigl functions, the **input** Eigen matrices must
|
||||
// be `Eigen::PlainObjectBase` because we want to directly access it's
|
||||
// underlying storage. It cannot be `Eigen::MatrixBase` (see
|
||||
// http://stackoverflow.com/questions/25094948/)
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
GLuint & va_id,
|
||||
|
||||
Reference in New Issue
Block a user