mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-12-05 08:41:06 -07:00
Merged branch 'dev_native' into lm_sla_supports_auto
Added igl library files
This commit is contained in:
commit
7681d00ee5
2865 changed files with 142806 additions and 22325 deletions
313
src/igl/opengl/MeshGL.cpp
Normal file
313
src/igl/opengl/MeshGL.cpp
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@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 "MeshGL.h"
|
||||
#include "bind_vertex_attrib_array.h"
|
||||
#include "create_shader_program.h"
|
||||
#include "destroy_shader_program.h"
|
||||
#include <iostream>
|
||||
|
||||
IGL_INLINE void igl::opengl::MeshGL::init_buffers()
|
||||
{
|
||||
// Mesh: Vertex Array Object & Buffer objects
|
||||
glGenVertexArrays(1, &vao_mesh);
|
||||
glBindVertexArray(vao_mesh);
|
||||
glGenBuffers(1, &vbo_V);
|
||||
glGenBuffers(1, &vbo_V_normals);
|
||||
glGenBuffers(1, &vbo_V_ambient);
|
||||
glGenBuffers(1, &vbo_V_diffuse);
|
||||
glGenBuffers(1, &vbo_V_specular);
|
||||
glGenBuffers(1, &vbo_V_uv);
|
||||
glGenBuffers(1, &vbo_F);
|
||||
glGenTextures(1, &vbo_tex);
|
||||
|
||||
// Line overlay
|
||||
glGenVertexArrays(1, &vao_overlay_lines);
|
||||
glBindVertexArray(vao_overlay_lines);
|
||||
glGenBuffers(1, &vbo_lines_F);
|
||||
glGenBuffers(1, &vbo_lines_V);
|
||||
glGenBuffers(1, &vbo_lines_V_colors);
|
||||
|
||||
// Point overlay
|
||||
glGenVertexArrays(1, &vao_overlay_points);
|
||||
glBindVertexArray(vao_overlay_points);
|
||||
glGenBuffers(1, &vbo_points_F);
|
||||
glGenBuffers(1, &vbo_points_V);
|
||||
glGenBuffers(1, &vbo_points_V_colors);
|
||||
|
||||
dirty = MeshGL::DIRTY_ALL;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::MeshGL::free_buffers()
|
||||
{
|
||||
if (is_initialized)
|
||||
{
|
||||
glDeleteVertexArrays(1, &vao_mesh);
|
||||
glDeleteVertexArrays(1, &vao_overlay_lines);
|
||||
glDeleteVertexArrays(1, &vao_overlay_points);
|
||||
|
||||
glDeleteBuffers(1, &vbo_V);
|
||||
glDeleteBuffers(1, &vbo_V_normals);
|
||||
glDeleteBuffers(1, &vbo_V_ambient);
|
||||
glDeleteBuffers(1, &vbo_V_diffuse);
|
||||
glDeleteBuffers(1, &vbo_V_specular);
|
||||
glDeleteBuffers(1, &vbo_V_uv);
|
||||
glDeleteBuffers(1, &vbo_F);
|
||||
glDeleteBuffers(1, &vbo_lines_F);
|
||||
glDeleteBuffers(1, &vbo_lines_V);
|
||||
glDeleteBuffers(1, &vbo_lines_V_colors);
|
||||
glDeleteBuffers(1, &vbo_points_F);
|
||||
glDeleteBuffers(1, &vbo_points_V);
|
||||
glDeleteBuffers(1, &vbo_points_V_colors);
|
||||
|
||||
glDeleteTextures(1, &vbo_tex);
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::MeshGL::bind_mesh()
|
||||
{
|
||||
glBindVertexArray(vao_mesh);
|
||||
glUseProgram(shader_mesh);
|
||||
bind_vertex_attrib_array(shader_mesh,"position", vbo_V, V_vbo, dirty & MeshGL::DIRTY_POSITION);
|
||||
bind_vertex_attrib_array(shader_mesh,"normal", vbo_V_normals, V_normals_vbo, dirty & MeshGL::DIRTY_NORMAL);
|
||||
bind_vertex_attrib_array(shader_mesh,"Ka", vbo_V_ambient, V_ambient_vbo, dirty & MeshGL::DIRTY_AMBIENT);
|
||||
bind_vertex_attrib_array(shader_mesh,"Kd", vbo_V_diffuse, V_diffuse_vbo, dirty & MeshGL::DIRTY_DIFFUSE);
|
||||
bind_vertex_attrib_array(shader_mesh,"Ks", vbo_V_specular, V_specular_vbo, dirty & MeshGL::DIRTY_SPECULAR);
|
||||
bind_vertex_attrib_array(shader_mesh,"texcoord", vbo_V_uv, V_uv_vbo, dirty & MeshGL::DIRTY_UV);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_F);
|
||||
if (dirty & MeshGL::DIRTY_FACE)
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*F_vbo.size(), F_vbo.data(), GL_DYNAMIC_DRAW);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, vbo_tex);
|
||||
if (dirty & 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);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_u, tex_v, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.data());
|
||||
}
|
||||
glUniform1i(glGetUniformLocation(shader_mesh,"tex"), 0);
|
||||
dirty &= ~MeshGL::DIRTY_MESH;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::MeshGL::bind_overlay_lines()
|
||||
{
|
||||
bool is_dirty = dirty & MeshGL::DIRTY_OVERLAY_LINES;
|
||||
|
||||
glBindVertexArray(vao_overlay_lines);
|
||||
glUseProgram(shader_overlay_lines);
|
||||
bind_vertex_attrib_array(shader_overlay_lines,"position", vbo_lines_V, lines_V_vbo, is_dirty);
|
||||
bind_vertex_attrib_array(shader_overlay_lines,"color", vbo_lines_V_colors, lines_V_colors_vbo, is_dirty);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_lines_F);
|
||||
if (is_dirty)
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*lines_F_vbo.size(), lines_F_vbo.data(), GL_DYNAMIC_DRAW);
|
||||
|
||||
dirty &= ~MeshGL::DIRTY_OVERLAY_LINES;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::MeshGL::bind_overlay_points()
|
||||
{
|
||||
bool is_dirty = dirty & MeshGL::DIRTY_OVERLAY_POINTS;
|
||||
|
||||
glBindVertexArray(vao_overlay_points);
|
||||
glUseProgram(shader_overlay_points);
|
||||
bind_vertex_attrib_array(shader_overlay_points,"position", vbo_points_V, points_V_vbo, is_dirty);
|
||||
bind_vertex_attrib_array(shader_overlay_points,"color", vbo_points_V_colors, points_V_colors_vbo, is_dirty);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_points_F);
|
||||
if (is_dirty)
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*points_F_vbo.size(), points_F_vbo.data(), GL_DYNAMIC_DRAW);
|
||||
|
||||
dirty &= ~MeshGL::DIRTY_OVERLAY_POINTS;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::MeshGL::draw_mesh(bool solid)
|
||||
{
|
||||
glPolygonMode(GL_FRONT_AND_BACK, solid ? GL_FILL : GL_LINE);
|
||||
|
||||
/* Avoid Z-buffer fighting between filled triangles & wireframe lines */
|
||||
if (solid)
|
||||
{
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(1.0, 1.0);
|
||||
}
|
||||
glDrawElements(GL_TRIANGLES, 3*F_vbo.rows(), GL_UNSIGNED_INT, 0);
|
||||
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::MeshGL::draw_overlay_lines()
|
||||
{
|
||||
glDrawElements(GL_LINES, lines_F_vbo.rows(), GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
|
||||
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::init()
|
||||
{
|
||||
if(is_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
is_initialized = true;
|
||||
std::string mesh_vertex_shader_string =
|
||||
R"(#version 150
|
||||
uniform mat4 view;
|
||||
uniform mat4 proj;
|
||||
uniform mat4 normal_matrix;
|
||||
in vec3 position;
|
||||
in vec3 normal;
|
||||
out vec3 position_eye;
|
||||
out vec3 normal_eye;
|
||||
in vec4 Ka;
|
||||
in vec4 Kd;
|
||||
in vec4 Ks;
|
||||
in vec2 texcoord;
|
||||
out vec2 texcoordi;
|
||||
out vec4 Kai;
|
||||
out vec4 Kdi;
|
||||
out vec4 Ksi;
|
||||
|
||||
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;
|
||||
}
|
||||
)";
|
||||
|
||||
std::string mesh_fragment_shader_string =
|
||||
R"(#version 150
|
||||
uniform mat4 view;
|
||||
uniform mat4 proj;
|
||||
uniform vec4 fixed_color;
|
||||
in vec3 position_eye;
|
||||
in vec3 normal_eye;
|
||||
uniform vec3 light_position_eye;
|
||||
vec3 Ls = vec3 (1, 1, 1);
|
||||
vec3 Ld = vec3 (1, 1, 1);
|
||||
vec3 La = vec3 (1, 1, 1);
|
||||
in vec4 Ksi;
|
||||
in vec4 Kdi;
|
||||
in vec4 Kai;
|
||||
in vec2 texcoordi;
|
||||
uniform sampler2D tex;
|
||||
uniform float specular_exponent;
|
||||
uniform float lighting_factor;
|
||||
uniform float texture_factor;
|
||||
out vec4 outColor;
|
||||
void main()
|
||||
{
|
||||
vec3 Ia = La * vec3(Kai); // ambient intensity
|
||||
|
||||
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
|
||||
|
||||
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;
|
||||
}
|
||||
)";
|
||||
|
||||
std::string overlay_vertex_shader_string =
|
||||
R"(#version 150
|
||||
uniform mat4 view;
|
||||
uniform mat4 proj;
|
||||
in vec3 position;
|
||||
in vec3 color;
|
||||
out vec3 color_frag;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = proj * view * vec4 (position, 1.0);
|
||||
color_frag = color;
|
||||
}
|
||||
)";
|
||||
|
||||
std::string overlay_fragment_shader_string =
|
||||
R"(#version 150
|
||||
in vec3 color_frag;
|
||||
out vec4 outColor;
|
||||
void main()
|
||||
{
|
||||
outColor = vec4(color_frag, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
std::string overlay_point_fragment_shader_string =
|
||||
R"(#version 150
|
||||
in vec3 color_frag;
|
||||
out vec4 outColor;
|
||||
void main()
|
||||
{
|
||||
if (length(gl_PointCoord - vec2(0.5)) > 0.5)
|
||||
discard;
|
||||
outColor = vec4(color_frag, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
init_buffers();
|
||||
create_shader_program(
|
||||
mesh_vertex_shader_string,
|
||||
mesh_fragment_shader_string,
|
||||
{},
|
||||
shader_mesh);
|
||||
create_shader_program(
|
||||
overlay_vertex_shader_string,
|
||||
overlay_fragment_shader_string,
|
||||
{},
|
||||
shader_overlay_lines);
|
||||
create_shader_program(
|
||||
overlay_vertex_shader_string,
|
||||
overlay_point_fragment_shader_string,
|
||||
{},
|
||||
shader_overlay_points);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::MeshGL::free()
|
||||
{
|
||||
const auto free = [](GLuint & id)
|
||||
{
|
||||
if(id)
|
||||
{
|
||||
destroy_shader_program(id);
|
||||
id = 0;
|
||||
}
|
||||
};
|
||||
|
||||
if (is_initialized)
|
||||
{
|
||||
free(shader_mesh);
|
||||
free(shader_overlay_lines);
|
||||
free(shader_overlay_points);
|
||||
free_buffers();
|
||||
}
|
||||
}
|
||||
133
src/igl/opengl/MeshGL.h
Normal file
133
src/igl/opengl/MeshGL.h
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@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_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 <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
class MeshGL
|
||||
{
|
||||
public:
|
||||
typedef unsigned int GLuint;
|
||||
|
||||
enum DirtyFlags
|
||||
{
|
||||
DIRTY_NONE = 0x0000,
|
||||
DIRTY_POSITION = 0x0001,
|
||||
DIRTY_UV = 0x0002,
|
||||
DIRTY_NORMAL = 0x0004,
|
||||
DIRTY_AMBIENT = 0x0008,
|
||||
DIRTY_DIFFUSE = 0x0010,
|
||||
DIRTY_SPECULAR = 0x0020,
|
||||
DIRTY_TEXTURE = 0x0040,
|
||||
DIRTY_FACE = 0x0080,
|
||||
DIRTY_MESH = 0x00FF,
|
||||
DIRTY_OVERLAY_LINES = 0x0100,
|
||||
DIRTY_OVERLAY_POINTS = 0x0200,
|
||||
DIRTY_ALL = 0x03FF
|
||||
};
|
||||
|
||||
bool is_initialized = false;
|
||||
GLuint vao_mesh;
|
||||
GLuint vao_overlay_lines;
|
||||
GLuint vao_overlay_points;
|
||||
GLuint shader_mesh;
|
||||
GLuint shader_overlay_lines;
|
||||
GLuint shader_overlay_points;
|
||||
|
||||
GLuint vbo_V; // Vertices of the current mesh (#V x 3)
|
||||
GLuint vbo_V_uv; // UV coordinates for the current mesh (#V x 2)
|
||||
GLuint vbo_V_normals; // Vertices of the current mesh (#V x 3)
|
||||
GLuint vbo_V_ambient; // Ambient material (#V x 3)
|
||||
GLuint vbo_V_diffuse; // Diffuse material (#V x 3)
|
||||
GLuint vbo_V_specular; // Specular material (#V x 3)
|
||||
|
||||
GLuint vbo_F; // Faces of the mesh (#F x 3)
|
||||
GLuint vbo_tex; // Texture
|
||||
|
||||
GLuint vbo_lines_F; // Indices of the line overlay
|
||||
GLuint vbo_lines_V; // Vertices of the line overlay
|
||||
GLuint vbo_lines_V_colors; // Color values of the line overlay
|
||||
GLuint vbo_points_F; // Indices of the point overlay
|
||||
GLuint vbo_points_V; // Vertices of the point overlay
|
||||
GLuint vbo_points_V_colors; // Color values of the point overlay
|
||||
|
||||
// Temporary copy of the content of each VBO
|
||||
typedef Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> RowMatrixXf;
|
||||
RowMatrixXf V_vbo;
|
||||
RowMatrixXf V_normals_vbo;
|
||||
RowMatrixXf V_ambient_vbo;
|
||||
RowMatrixXf V_diffuse_vbo;
|
||||
RowMatrixXf V_specular_vbo;
|
||||
RowMatrixXf V_uv_vbo;
|
||||
RowMatrixXf lines_V_vbo;
|
||||
RowMatrixXf lines_V_colors_vbo;
|
||||
RowMatrixXf points_V_vbo;
|
||||
RowMatrixXf points_V_colors_vbo;
|
||||
|
||||
int tex_u;
|
||||
int tex_v;
|
||||
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;
|
||||
|
||||
// Initialize shaders and buffers
|
||||
IGL_INLINE void init();
|
||||
|
||||
// Release all resources
|
||||
IGL_INLINE void free();
|
||||
|
||||
// Create a new set of OpenGL buffer objects
|
||||
IGL_INLINE void init_buffers();
|
||||
|
||||
// Bind the underlying OpenGL buffer objects for subsequent mesh draw calls
|
||||
IGL_INLINE void bind_mesh();
|
||||
|
||||
/// Draw the currently buffered mesh (either solid or wireframe)
|
||||
IGL_INLINE void draw_mesh(bool solid);
|
||||
|
||||
// Bind the underlying OpenGL buffer objects for subsequent line overlay draw calls
|
||||
IGL_INLINE void bind_overlay_lines();
|
||||
|
||||
/// Draw the currently buffered line overlay
|
||||
IGL_INLINE void draw_overlay_lines();
|
||||
|
||||
// Bind the underlying OpenGL buffer objects for subsequent point overlay draw calls
|
||||
IGL_INLINE void bind_overlay_points();
|
||||
|
||||
/// Draw the currently buffered point overlay
|
||||
IGL_INLINE void draw_overlay_points();
|
||||
|
||||
// Release the OpenGL buffer objects
|
||||
IGL_INLINE void free_buffers();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "MeshGL.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
391
src/igl/opengl/ViewerCore.cpp
Normal file
391
src/igl/opengl/ViewerCore.cpp
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@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 "ViewerCore.h"
|
||||
#include "gl.h"
|
||||
#include "../quat_to_mat.h"
|
||||
#include "../snap_to_fixed_up.h"
|
||||
#include "../look_at.h"
|
||||
#include "../frustum.h"
|
||||
#include "../ortho.h"
|
||||
#include "../massmatrix.h"
|
||||
#include "../barycenter.h"
|
||||
#include "../PI.h"
|
||||
#include <Eigen/Geometry>
|
||||
#include <iostream>
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::align_camera_center(
|
||||
const Eigen::MatrixXd& V,
|
||||
const Eigen::MatrixXi& F)
|
||||
{
|
||||
if(V.rows() == 0)
|
||||
return;
|
||||
|
||||
get_scale_and_shift_to_fit_mesh(V,F,camera_base_zoom,camera_base_translation);
|
||||
// Rather than crash on empty mesh...
|
||||
if(V.size() > 0)
|
||||
{
|
||||
object_scale = (V.colwise().maxCoeff() - V.colwise().minCoeff()).norm();
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::get_scale_and_shift_to_fit_mesh(
|
||||
const Eigen::MatrixXd& V,
|
||||
const Eigen::MatrixXi& F,
|
||||
float& zoom,
|
||||
Eigen::Vector3f& shift)
|
||||
{
|
||||
if (V.rows() == 0)
|
||||
return;
|
||||
|
||||
Eigen::MatrixXd BC;
|
||||
if (F.rows() <= 1)
|
||||
{
|
||||
BC = V;
|
||||
} else
|
||||
{
|
||||
igl::barycenter(V,F,BC);
|
||||
}
|
||||
return get_scale_and_shift_to_fit_mesh(BC,zoom,shift);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::align_camera_center(
|
||||
const Eigen::MatrixXd& V)
|
||||
{
|
||||
if(V.rows() == 0)
|
||||
return;
|
||||
|
||||
get_scale_and_shift_to_fit_mesh(V,camera_base_zoom,camera_base_translation);
|
||||
// Rather than crash on empty mesh...
|
||||
if(V.size() > 0)
|
||||
{
|
||||
object_scale = (V.colwise().maxCoeff() - V.colwise().minCoeff()).norm();
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::get_scale_and_shift_to_fit_mesh(
|
||||
const Eigen::MatrixXd& V,
|
||||
float& zoom,
|
||||
Eigen::Vector3f& shift)
|
||||
{
|
||||
if (V.rows() == 0)
|
||||
return;
|
||||
|
||||
auto min_point = V.colwise().minCoeff();
|
||||
auto max_point = V.colwise().maxCoeff();
|
||||
auto centroid = (0.5*(min_point + max_point)).eval();
|
||||
shift.setConstant(0);
|
||||
shift.head(centroid.size()) = -centroid.cast<float>();
|
||||
zoom = 2.0 / (max_point-min_point).array().abs().maxCoeff();
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::clear_framebuffers()
|
||||
{
|
||||
glClearColor(background_color[0],
|
||||
background_color[1],
|
||||
background_color[2],
|
||||
background_color[3]);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::draw(
|
||||
ViewerData& data,
|
||||
bool update_matrices)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
|
||||
if (depth_test)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
else
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
/* Bind and potentially refresh mesh/line/point data */
|
||||
if (data.dirty)
|
||||
{
|
||||
data.updateGL(data, data.invert_normals,data.meshgl);
|
||||
data.dirty = MeshGL::DIRTY_NONE;
|
||||
}
|
||||
data.meshgl.bind_mesh();
|
||||
|
||||
// Initialize uniform
|
||||
glViewport(viewport(0), viewport(1), viewport(2), viewport(3));
|
||||
|
||||
if(update_matrices)
|
||||
{
|
||||
view = Eigen::Matrix4f::Identity();
|
||||
proj = Eigen::Matrix4f::Identity();
|
||||
norm = Eigen::Matrix4f::Identity();
|
||||
|
||||
float width = viewport(2);
|
||||
float height = viewport(3);
|
||||
|
||||
// Set view
|
||||
look_at( camera_eye, camera_center, camera_up, view);
|
||||
view = view
|
||||
* (trackball_angle * Eigen::Scaling(camera_zoom * camera_base_zoom)
|
||||
* Eigen::Translation3f(camera_translation + camera_base_translation)).matrix();
|
||||
|
||||
norm = view.inverse().transpose();
|
||||
|
||||
// Set projection
|
||||
if (orthographic)
|
||||
{
|
||||
float length = (camera_eye - camera_center).norm();
|
||||
float h = tan(camera_view_angle/360.0 * igl::PI) * (length);
|
||||
ortho(-h*width/height, h*width/height, -h, h, camera_dnear, camera_dfar,proj);
|
||||
}
|
||||
else
|
||||
{
|
||||
float fH = tan(camera_view_angle / 360.0 * igl::PI) * camera_dnear;
|
||||
float fW = fH * (double)width/(double)height;
|
||||
frustum(-fW, fW, -fH, fH, camera_dnear, camera_dfar,proj);
|
||||
}
|
||||
}
|
||||
|
||||
// Send transformations to the GPU
|
||||
GLint viewi = glGetUniformLocation(data.meshgl.shader_mesh,"view");
|
||||
GLint proji = glGetUniformLocation(data.meshgl.shader_mesh,"proj");
|
||||
GLint normi = glGetUniformLocation(data.meshgl.shader_mesh,"normal_matrix");
|
||||
glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
|
||||
glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
|
||||
glUniformMatrix4fv(normi, 1, GL_FALSE, norm.data());
|
||||
|
||||
// Light parameters
|
||||
GLint specular_exponenti = glGetUniformLocation(data.meshgl.shader_mesh,"specular_exponent");
|
||||
GLint light_position_eyei = glGetUniformLocation(data.meshgl.shader_mesh,"light_position_eye");
|
||||
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");
|
||||
|
||||
glUniform1f(specular_exponenti, data.shininess);
|
||||
glUniform3fv(light_position_eyei, 1, light_position.data());
|
||||
glUniform1f(lighting_factori, lighting_factor); // enables lighting
|
||||
glUniform4f(fixed_colori, 0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
if (data.V.rows()>0)
|
||||
{
|
||||
// Render fill
|
||||
if (data.show_faces)
|
||||
{
|
||||
// Texture
|
||||
glUniform1f(texture_factori, data.show_texture ? 1.0f : 0.0f);
|
||||
data.meshgl.draw_mesh(true);
|
||||
glUniform1f(texture_factori, 0.0f);
|
||||
}
|
||||
|
||||
// Render wireframe
|
||||
if (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.meshgl.draw_mesh(false);
|
||||
glUniform4f(fixed_colori, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.show_overlay)
|
||||
{
|
||||
if (data.show_overlay_depth)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
else
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
if (data.lines.rows() > 0)
|
||||
{
|
||||
data.meshgl.bind_overlay_lines();
|
||||
viewi = glGetUniformLocation(data.meshgl.shader_overlay_lines,"view");
|
||||
proji = glGetUniformLocation(data.meshgl.shader_overlay_lines,"proj");
|
||||
|
||||
glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
|
||||
glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
|
||||
// This must be enabled, otherwise glLineWidth has no effect
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glLineWidth(data.line_width);
|
||||
|
||||
data.meshgl.draw_overlay_lines();
|
||||
}
|
||||
|
||||
if (data.points.rows() > 0)
|
||||
{
|
||||
data.meshgl.bind_overlay_points();
|
||||
viewi = glGetUniformLocation(data.meshgl.shader_overlay_points,"view");
|
||||
proji = glGetUniformLocation(data.meshgl.shader_overlay_points,"proj");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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,
|
||||
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
|
||||
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A)
|
||||
{
|
||||
assert(R.rows() == G.rows() && G.rows() == B.rows() && B.rows() == A.rows());
|
||||
assert(R.cols() == G.cols() && G.cols() == B.cols() && B.cols() == A.cols());
|
||||
|
||||
unsigned width = R.rows();
|
||||
unsigned height = R.cols();
|
||||
|
||||
// https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing
|
||||
unsigned int framebuffer;
|
||||
glGenFramebuffers(1, &framebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
// create a multisampled color attachment texture
|
||||
unsigned int textureColorBufferMultiSampled;
|
||||
glGenTextures(1, &textureColorBufferMultiSampled);
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled);
|
||||
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA, width, height, GL_TRUE);
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled, 0);
|
||||
// create a (also multisampled) renderbuffer object for depth and stencil attachments
|
||||
unsigned int rbo;
|
||||
glGenRenderbuffers(1, &rbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
|
||||
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
// configure second post-processing framebuffer
|
||||
unsigned int intermediateFBO;
|
||||
glGenFramebuffers(1, &intermediateFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
|
||||
// create a color attachment texture
|
||||
unsigned int screenTexture;
|
||||
glGenTextures(1, &screenTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, screenTexture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0); // we only need a color buffer
|
||||
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
|
||||
// Clear the buffer
|
||||
glClearColor(background_color(0), background_color(1), background_color(2), 0.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
// Save old viewport
|
||||
Eigen::Vector4f viewport_ori = viewport;
|
||||
viewport << 0,0,width,height;
|
||||
// Draw
|
||||
draw(data,update_matrices);
|
||||
// Restore viewport
|
||||
viewport = viewport_ori;
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO);
|
||||
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
|
||||
// Copy back in the given Eigen matrices
|
||||
GLubyte* pixels = (GLubyte*)calloc(width*height*4,sizeof(GLubyte));
|
||||
glReadPixels(0, 0,width, height,GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
// Clean up
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glDeleteTextures(1, &screenTexture);
|
||||
glDeleteTextures(1, &textureColorBufferMultiSampled);
|
||||
glDeleteFramebuffers(1, &framebuffer);
|
||||
glDeleteFramebuffers(1, &intermediateFBO);
|
||||
glDeleteRenderbuffers(1, &rbo);
|
||||
|
||||
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];
|
||||
++count;
|
||||
}
|
||||
}
|
||||
// Clean up
|
||||
free(pixels);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::set_rotation_type(
|
||||
const igl::opengl::ViewerCore::RotationType & value)
|
||||
{
|
||||
using namespace Eigen;
|
||||
using namespace std;
|
||||
const RotationType old_rotation_type = rotation_type;
|
||||
rotation_type = value;
|
||||
if(rotation_type == ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP &&
|
||||
old_rotation_type != ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP)
|
||||
{
|
||||
snap_to_fixed_up(Quaternionf(trackball_angle),trackball_angle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE igl::opengl::ViewerCore::ViewerCore()
|
||||
{
|
||||
// Default colors
|
||||
background_color << 0.3f, 0.3f, 0.5f, 1.0f;
|
||||
|
||||
// Default lights settings
|
||||
light_position << 0.0f, 0.3f, 0.0f;
|
||||
lighting_factor = 1.0f; //on
|
||||
|
||||
// Default trackball
|
||||
trackball_angle = Eigen::Quaternionf::Identity();
|
||||
set_rotation_type(ViewerCore::ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP);
|
||||
|
||||
// Camera parameters
|
||||
camera_base_zoom = 1.0f;
|
||||
camera_zoom = 1.0f;
|
||||
orthographic = false;
|
||||
camera_view_angle = 45.0;
|
||||
camera_dnear = 1.0;
|
||||
camera_dfar = 100.0;
|
||||
camera_base_translation << 0, 0, 0;
|
||||
camera_translation << 0, 0, 0;
|
||||
camera_eye << 0, 0, 5;
|
||||
camera_center << 0, 0, 0;
|
||||
camera_up << 0, 1, 0;
|
||||
|
||||
depth_test = true;
|
||||
|
||||
is_animating = false;
|
||||
animation_max_fps = 30.;
|
||||
|
||||
viewport.setZero();
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::init()
|
||||
{
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerCore::shut()
|
||||
{
|
||||
}
|
||||
199
src/igl/opengl/ViewerCore.h
Normal file
199
src/igl/opengl/ViewerCore.h
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@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_VIEWERCORE_H
|
||||
#define IGL_OPENGL_VIEWERCORE_H
|
||||
|
||||
#include <igl/opengl/MeshGL.h>
|
||||
#include <igl/opengl/ViewerData.h>
|
||||
|
||||
#include <igl/igl_inline.h>
|
||||
#include <Eigen/Geometry>
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
// Basic class of the 3D mesh viewer
|
||||
// TODO: write documentation
|
||||
|
||||
class ViewerCore
|
||||
{
|
||||
public:
|
||||
IGL_INLINE ViewerCore();
|
||||
|
||||
// Initialization
|
||||
IGL_INLINE void init();
|
||||
|
||||
// Shutdown
|
||||
IGL_INLINE void shut();
|
||||
|
||||
// Serialization code
|
||||
IGL_INLINE void InitSerialization();
|
||||
|
||||
|
||||
// ------------------- Camera control functions
|
||||
|
||||
// Adjust the view to see the entire model
|
||||
IGL_INLINE void align_camera_center(
|
||||
const Eigen::MatrixXd& V,
|
||||
const Eigen::MatrixXi& F);
|
||||
|
||||
// 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,
|
||||
const Eigen::MatrixXi& F,
|
||||
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
|
||||
IGL_INLINE void clear_framebuffers();
|
||||
|
||||
// Draw everything
|
||||
//
|
||||
// data cannot be const because it is being set to "clean"
|
||||
IGL_INLINE void draw(ViewerData& data, bool update_matrices = true);
|
||||
IGL_INLINE void 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,
|
||||
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
|
||||
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A);
|
||||
|
||||
// Trackball angle (quaternion)
|
||||
enum RotationType
|
||||
{
|
||||
ROTATION_TYPE_TRACKBALL = 0,
|
||||
ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1,
|
||||
ROTATION_TYPE_NO_ROTATION = 2,
|
||||
NUM_ROTATION_TYPES = 3
|
||||
};
|
||||
IGL_INLINE void set_rotation_type(const RotationType & value);
|
||||
|
||||
// ------------------- Properties
|
||||
|
||||
// Colors
|
||||
Eigen::Vector4f background_color;
|
||||
|
||||
// Lighting
|
||||
Eigen::Vector3f light_position;
|
||||
float lighting_factor;
|
||||
|
||||
RotationType rotation_type;
|
||||
Eigen::Quaternionf trackball_angle;
|
||||
|
||||
// Camera parameters
|
||||
float camera_base_zoom;
|
||||
float camera_zoom;
|
||||
bool orthographic;
|
||||
Eigen::Vector3f camera_base_translation;
|
||||
Eigen::Vector3f camera_translation;
|
||||
Eigen::Vector3f camera_eye;
|
||||
Eigen::Vector3f camera_up;
|
||||
Eigen::Vector3f camera_center;
|
||||
float camera_view_angle;
|
||||
float camera_dnear;
|
||||
float camera_dfar;
|
||||
|
||||
bool depth_test;
|
||||
|
||||
// Animation
|
||||
bool is_animating;
|
||||
double animation_max_fps;
|
||||
|
||||
// Caches the two-norm between the min/max point of the bounding box
|
||||
float object_scale;
|
||||
|
||||
// Viewport size
|
||||
Eigen::Vector4f viewport;
|
||||
|
||||
// Save the OpenGL transformation matrices used for the previous rendering pass
|
||||
Eigen::Matrix4f view;
|
||||
Eigen::Matrix4f proj;
|
||||
Eigen::Matrix4f norm;
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include <igl/serialize.h>
|
||||
namespace igl {
|
||||
namespace serialization {
|
||||
|
||||
inline void serialization(bool s, igl::opengl::ViewerCore& obj, std::vector<char>& buffer)
|
||||
{
|
||||
|
||||
SERIALIZE_MEMBER(background_color);
|
||||
|
||||
SERIALIZE_MEMBER(light_position);
|
||||
SERIALIZE_MEMBER(lighting_factor);
|
||||
|
||||
SERIALIZE_MEMBER(trackball_angle);
|
||||
SERIALIZE_MEMBER(rotation_type);
|
||||
|
||||
SERIALIZE_MEMBER(camera_base_zoom);
|
||||
SERIALIZE_MEMBER(camera_zoom);
|
||||
SERIALIZE_MEMBER(orthographic);
|
||||
SERIALIZE_MEMBER(camera_base_translation);
|
||||
SERIALIZE_MEMBER(camera_translation);
|
||||
SERIALIZE_MEMBER(camera_view_angle);
|
||||
SERIALIZE_MEMBER(camera_dnear);
|
||||
SERIALIZE_MEMBER(camera_dfar);
|
||||
SERIALIZE_MEMBER(camera_eye);
|
||||
SERIALIZE_MEMBER(camera_center);
|
||||
SERIALIZE_MEMBER(camera_up);
|
||||
|
||||
SERIALIZE_MEMBER(depth_test);
|
||||
SERIALIZE_MEMBER(is_animating);
|
||||
SERIALIZE_MEMBER(animation_max_fps);
|
||||
|
||||
SERIALIZE_MEMBER(object_scale);
|
||||
|
||||
SERIALIZE_MEMBER(viewport);
|
||||
SERIALIZE_MEMBER(view);
|
||||
SERIALIZE_MEMBER(proj);
|
||||
SERIALIZE_MEMBER(norm);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void serialize(const igl::opengl::ViewerCore& obj, std::vector<char>& buffer)
|
||||
{
|
||||
serialization(true, const_cast<igl::opengl::ViewerCore&>(obj), buffer);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void deserialize(igl::opengl::ViewerCore& obj, const std::vector<char>& buffer)
|
||||
{
|
||||
serialization(false, obj, const_cast<std::vector<char>&>(buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "ViewerCore.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
691
src/igl/opengl/ViewerData.cpp
Normal file
691
src/igl/opengl/ViewerData.cpp
Normal file
|
|
@ -0,0 +1,691 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@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 "ViewerData.h"
|
||||
|
||||
#include "../per_face_normals.h"
|
||||
#include "../material_colors.h"
|
||||
#include "../parula.h"
|
||||
#include "../per_vertex_normals.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),
|
||||
point_size(30),
|
||||
line_width(0.5f),
|
||||
line_color(0,0,0,1),
|
||||
shininess(35.0f),
|
||||
id(-1)
|
||||
{
|
||||
clear();
|
||||
};
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_face_based(bool newvalue)
|
||||
{
|
||||
if (face_based != newvalue)
|
||||
{
|
||||
face_based = newvalue;
|
||||
dirty = MeshGL::DIRTY_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers that draws the most common meshes
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_mesh(
|
||||
const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
Eigen::MatrixXd V_temp;
|
||||
|
||||
// If V only has two columns, pad with a column of zeros
|
||||
if (_V.cols() == 2)
|
||||
{
|
||||
V_temp = Eigen::MatrixXd::Zero(_V.rows(),3);
|
||||
V_temp.block(0,0,_V.rows(),2) = _V;
|
||||
}
|
||||
else
|
||||
V_temp = _V;
|
||||
|
||||
if (V.rows() == 0 && F.rows() == 0)
|
||||
{
|
||||
V = V_temp;
|
||||
F = _F;
|
||||
|
||||
compute_normals();
|
||||
uniform_colors(
|
||||
Eigen::Vector3d(GOLD_AMBIENT[0], GOLD_AMBIENT[1], GOLD_AMBIENT[2]),
|
||||
Eigen::Vector3d(GOLD_DIFFUSE[0], GOLD_DIFFUSE[1], GOLD_DIFFUSE[2]),
|
||||
Eigen::Vector3d(GOLD_SPECULAR[0], GOLD_SPECULAR[1], GOLD_SPECULAR[2]));
|
||||
|
||||
grid_texture();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_V.rows() == V.rows() && _F.rows() == F.rows())
|
||||
{
|
||||
V = V_temp;
|
||||
F = _F;
|
||||
}
|
||||
else
|
||||
cerr << "ERROR (set_mesh): The new mesh has a different number of vertices/faces. Please clear the mesh before plotting."<<endl;
|
||||
}
|
||||
dirty |= MeshGL::DIRTY_FACE | MeshGL::DIRTY_POSITION;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_vertices(const Eigen::MatrixXd& _V)
|
||||
{
|
||||
V = _V;
|
||||
assert(F.size() == 0 || F.maxCoeff() < V.rows());
|
||||
dirty |= MeshGL::DIRTY_POSITION;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_normals(const Eigen::MatrixXd& N)
|
||||
{
|
||||
using namespace std;
|
||||
if (N.rows() == V.rows())
|
||||
{
|
||||
set_face_based(false);
|
||||
V_normals = N;
|
||||
}
|
||||
else if (N.rows() == F.rows() || N.rows() == F.rows()*3)
|
||||
{
|
||||
set_face_based(true);
|
||||
F_normals = N;
|
||||
}
|
||||
else
|
||||
cerr << "ERROR (set_normals): Please provide a normal per face, per corner or per vertex."<<endl;
|
||||
dirty |= MeshGL::DIRTY_NORMAL;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_colors(const Eigen::MatrixXd &C)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
if(C.rows()>0 && C.cols() == 1)
|
||||
{
|
||||
Eigen::MatrixXd C3;
|
||||
igl::parula(C,true,C3);
|
||||
return set_colors(C3);
|
||||
}
|
||||
// Ambient color should be darker color
|
||||
const auto ambient = [](const MatrixXd & C)->MatrixXd
|
||||
{
|
||||
MatrixXd T = 0.1*C;
|
||||
T.col(3) = C.col(3);
|
||||
return T;
|
||||
};
|
||||
// Specular color should be a less saturated and darker color: dampened
|
||||
// highlights
|
||||
const auto specular = [](const MatrixXd & C)->MatrixXd
|
||||
{
|
||||
const double grey = 0.3;
|
||||
MatrixXd T = grey+0.1*(C.array()-grey);
|
||||
T.col(3) = C.col(3);
|
||||
return T;
|
||||
};
|
||||
if (C.rows() == 1)
|
||||
{
|
||||
for (unsigned i=0;i<V_material_diffuse.rows();++i)
|
||||
{
|
||||
if (C.cols() == 3)
|
||||
V_material_diffuse.row(i) << C.row(0),1;
|
||||
else if (C.cols() == 4)
|
||||
V_material_diffuse.row(i) << C.row(0);
|
||||
}
|
||||
V_material_ambient = ambient(V_material_diffuse);
|
||||
V_material_specular = specular(V_material_diffuse);
|
||||
|
||||
for (unsigned i=0;i<F_material_diffuse.rows();++i)
|
||||
{
|
||||
if (C.cols() == 3)
|
||||
F_material_diffuse.row(i) << C.row(0),1;
|
||||
else if (C.cols() == 4)
|
||||
F_material_diffuse.row(i) << C.row(0);
|
||||
}
|
||||
F_material_ambient = ambient(F_material_diffuse);
|
||||
F_material_specular = specular(F_material_diffuse);
|
||||
}
|
||||
else if (C.rows() == V.rows())
|
||||
{
|
||||
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);
|
||||
}
|
||||
else if (C.rows() == F.rows())
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
cerr << "ERROR (set_colors): Please provide a single color, or a color per face or per vertex."<<endl;
|
||||
dirty |= MeshGL::DIRTY_DIFFUSE;
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
cerr << "ERROR (set_UV): Please provide uv per vertex."<<endl;;
|
||||
dirty |= MeshGL::DIRTY_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,
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B)
|
||||
{
|
||||
texture_R = R;
|
||||
texture_G = G;
|
||||
texture_B = B;
|
||||
texture_A = Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>::Constant(R.rows(),R.cols(),255);
|
||||
dirty |= MeshGL::DIRTY_TEXTURE;
|
||||
}
|
||||
|
||||
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,
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
|
||||
const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A)
|
||||
{
|
||||
texture_R = R;
|
||||
texture_G = G;
|
||||
texture_B = B;
|
||||
texture_A = A;
|
||||
dirty |= MeshGL::DIRTY_TEXTURE;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_points(
|
||||
const Eigen::MatrixXd& P,
|
||||
const Eigen::MatrixXd& C)
|
||||
{
|
||||
// clear existing points
|
||||
points.resize(0,0);
|
||||
add_points(P,C);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::add_points(const Eigen::MatrixXd& P, const Eigen::MatrixXd& C)
|
||||
{
|
||||
Eigen::MatrixXd P_temp;
|
||||
|
||||
// If P only has two columns, pad with a column of zeros
|
||||
if (P.cols() == 2)
|
||||
{
|
||||
P_temp = Eigen::MatrixXd::Zero(P.rows(),3);
|
||||
P_temp.block(0,0,P.rows(),2) = P;
|
||||
}
|
||||
else
|
||||
P_temp = P;
|
||||
|
||||
int lastid = points.rows();
|
||||
points.conservativeResize(points.rows() + P_temp.rows(),6);
|
||||
for (unsigned i=0; i<P_temp.rows(); ++i)
|
||||
points.row(lastid+i) << P_temp.row(i), i<C.rows() ? C.row(i) : C.row(C.rows()-1);
|
||||
|
||||
dirty |= MeshGL::DIRTY_OVERLAY_POINTS;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::set_edges(
|
||||
const Eigen::MatrixXd& P,
|
||||
const Eigen::MatrixXi& E,
|
||||
const Eigen::MatrixXd& C)
|
||||
{
|
||||
using namespace Eigen;
|
||||
lines.resize(E.rows(),9);
|
||||
assert(C.cols() == 3);
|
||||
for(int e = 0;e<E.rows();e++)
|
||||
{
|
||||
RowVector3d color;
|
||||
if(C.size() == 3)
|
||||
{
|
||||
color<<C;
|
||||
}else if(C.rows() == E.rows())
|
||||
{
|
||||
color<<C.row(e);
|
||||
}
|
||||
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::add_edges(const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C)
|
||||
{
|
||||
Eigen::MatrixXd P1_temp,P2_temp;
|
||||
|
||||
// If P1 only has two columns, pad with a column of zeros
|
||||
if (P1.cols() == 2)
|
||||
{
|
||||
P1_temp = Eigen::MatrixXd::Zero(P1.rows(),3);
|
||||
P1_temp.block(0,0,P1.rows(),2) = P1;
|
||||
P2_temp = Eigen::MatrixXd::Zero(P2.rows(),3);
|
||||
P2_temp.block(0,0,P2.rows(),2) = P2;
|
||||
}
|
||||
else
|
||||
{
|
||||
P1_temp = P1;
|
||||
P2_temp = P2;
|
||||
}
|
||||
|
||||
int lastid = lines.rows();
|
||||
lines.conservativeResize(lines.rows() + P1_temp.rows(),9);
|
||||
for (unsigned i=0; i<P1_temp.rows(); ++i)
|
||||
lines.row(lastid+i) << P1_temp.row(i), P2_temp.row(i), i<C.rows() ? C.row(i) : C.row(C.rows()-1);
|
||||
|
||||
dirty |= MeshGL::DIRTY_OVERLAY_LINES;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::add_label(const Eigen::VectorXd& P, const std::string& str)
|
||||
{
|
||||
Eigen::RowVectorXd P_temp;
|
||||
|
||||
// If P only has two columns, pad with a column of zeros
|
||||
if (P.size() == 2)
|
||||
{
|
||||
P_temp = Eigen::RowVectorXd::Zero(3);
|
||||
P_temp << P.transpose(), 0;
|
||||
}
|
||||
else
|
||||
P_temp = P;
|
||||
|
||||
int lastid = labels_positions.rows();
|
||||
labels_positions.conservativeResize(lastid+1, 3);
|
||||
labels_positions.row(lastid) = P_temp;
|
||||
labels_strings.push_back(str);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::clear()
|
||||
{
|
||||
V = Eigen::MatrixXd (0,3);
|
||||
F = Eigen::MatrixXi (0,3);
|
||||
|
||||
F_material_ambient = Eigen::MatrixXd (0,4);
|
||||
F_material_diffuse = Eigen::MatrixXd (0,4);
|
||||
F_material_specular = Eigen::MatrixXd (0,4);
|
||||
|
||||
V_material_ambient = Eigen::MatrixXd (0,4);
|
||||
V_material_diffuse = Eigen::MatrixXd (0,4);
|
||||
V_material_specular = Eigen::MatrixXd (0,4);
|
||||
|
||||
F_normals = Eigen::MatrixXd (0,3);
|
||||
V_normals = Eigen::MatrixXd (0,3);
|
||||
|
||||
V_uv = Eigen::MatrixXd (0,2);
|
||||
F_uv = Eigen::MatrixXi (0,3);
|
||||
|
||||
lines = Eigen::MatrixXd (0,9);
|
||||
points = Eigen::MatrixXd (0,6);
|
||||
labels_positions = Eigen::MatrixXd (0,3);
|
||||
labels_strings.clear();
|
||||
|
||||
face_based = 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);
|
||||
dirty |= MeshGL::DIRTY_NORMAL;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::uniform_colors(
|
||||
const Eigen::Vector3d& ambient,
|
||||
const Eigen::Vector3d& diffuse,
|
||||
const Eigen::Vector3d& specular)
|
||||
{
|
||||
Eigen::Vector4d ambient4;
|
||||
Eigen::Vector4d diffuse4;
|
||||
Eigen::Vector4d specular4;
|
||||
|
||||
ambient4 << ambient, 1;
|
||||
diffuse4 << diffuse, 1;
|
||||
specular4 << specular, 1;
|
||||
|
||||
uniform_colors(ambient4,diffuse4,specular4);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::uniform_colors(
|
||||
const Eigen::Vector4d& ambient,
|
||||
const Eigen::Vector4d& diffuse,
|
||||
const Eigen::Vector4d& specular)
|
||||
{
|
||||
V_material_ambient.resize(V.rows(),4);
|
||||
V_material_diffuse.resize(V.rows(),4);
|
||||
V_material_specular.resize(V.rows(),4);
|
||||
|
||||
for (unsigned i=0; i<V.rows();++i)
|
||||
{
|
||||
V_material_ambient.row(i) = ambient;
|
||||
V_material_diffuse.row(i) = diffuse;
|
||||
V_material_specular.row(i) = specular;
|
||||
}
|
||||
|
||||
F_material_ambient.resize(F.rows(),4);
|
||||
F_material_diffuse.resize(F.rows(),4);
|
||||
F_material_specular.resize(F.rows(),4);
|
||||
|
||||
for (unsigned i=0; i<F.rows();++i)
|
||||
{
|
||||
F_material_ambient.row(i) = ambient;
|
||||
F_material_diffuse.row(i) = diffuse;
|
||||
F_material_specular.row(i) = specular;
|
||||
}
|
||||
dirty |= MeshGL::DIRTY_SPECULAR | MeshGL::DIRTY_DIFFUSE | MeshGL::DIRTY_AMBIENT;
|
||||
}
|
||||
|
||||
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);
|
||||
for (unsigned i=0; i<size; ++i)
|
||||
{
|
||||
for (unsigned j=0; j<size; ++j)
|
||||
{
|
||||
texture_R(i,j) = 0;
|
||||
if ((i<size2 && j<size2) || (i>=size2 && j>=size2))
|
||||
texture_R(i,j) = 255;
|
||||
}
|
||||
}
|
||||
|
||||
texture_G = texture_R;
|
||||
texture_B = texture_R;
|
||||
texture_A = Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>::Constant(texture_R.rows(),texture_R.cols(),255);
|
||||
dirty |= MeshGL::DIRTY_TEXTURE;
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::ViewerData::updateGL(
|
||||
const igl::opengl::ViewerData& data,
|
||||
const bool invert_normals,
|
||||
igl::opengl::MeshGL& meshgl
|
||||
)
|
||||
{
|
||||
if (!meshgl.is_initialized)
|
||||
{
|
||||
meshgl.init();
|
||||
}
|
||||
|
||||
bool per_corner_uv = (data.F_uv.rows() == data.F.rows());
|
||||
bool per_corner_normals = (data.F_normals.rows() == 3 * data.F.rows());
|
||||
|
||||
meshgl.dirty |= data.dirty;
|
||||
|
||||
// Input:
|
||||
// X #F by dim quantity
|
||||
// Output:
|
||||
// X_vbo #F*3 by dim scattering per corner
|
||||
const auto per_face = [&data](
|
||||
const Eigen::MatrixXd & X,
|
||||
MeshGL::RowMatrixXf & X_vbo)
|
||||
{
|
||||
assert(X.cols() == 4);
|
||||
X_vbo.resize(data.F.rows()*3,4);
|
||||
for (unsigned i=0; i<data.F.rows();++i)
|
||||
for (unsigned j=0;j<3;++j)
|
||||
X_vbo.row(i*3+j) = X.row(i).cast<float>();
|
||||
};
|
||||
|
||||
// Input:
|
||||
// X #V by dim quantity
|
||||
// Output:
|
||||
// X_vbo #F*3 by dim scattering per corner
|
||||
const auto per_corner = [&data](
|
||||
const Eigen::MatrixXd & X,
|
||||
MeshGL::RowMatrixXf & X_vbo)
|
||||
{
|
||||
X_vbo.resize(data.F.rows()*3,X.cols());
|
||||
for (unsigned i=0; i<data.F.rows();++i)
|
||||
for (unsigned j=0;j<3;++j)
|
||||
X_vbo.row(i*3+j) = X.row(data.F(i,j)).cast<float>();
|
||||
};
|
||||
|
||||
if (!data.face_based)
|
||||
{
|
||||
if (!(per_corner_uv || per_corner_normals))
|
||||
{
|
||||
// Vertex positions
|
||||
if (meshgl.dirty & MeshGL::DIRTY_POSITION)
|
||||
meshgl.V_vbo = data.V.cast<float>();
|
||||
|
||||
// Vertex normals
|
||||
if (meshgl.dirty & MeshGL::DIRTY_NORMAL)
|
||||
{
|
||||
meshgl.V_normals_vbo = data.V_normals.cast<float>();
|
||||
if (invert_normals)
|
||||
meshgl.V_normals_vbo = -meshgl.V_normals_vbo;
|
||||
}
|
||||
|
||||
// Per-vertex material settings
|
||||
if (meshgl.dirty & MeshGL::DIRTY_AMBIENT)
|
||||
meshgl.V_ambient_vbo = data.V_material_ambient.cast<float>();
|
||||
if (meshgl.dirty & MeshGL::DIRTY_DIFFUSE)
|
||||
meshgl.V_diffuse_vbo = data.V_material_diffuse.cast<float>();
|
||||
if (meshgl.dirty & MeshGL::DIRTY_SPECULAR)
|
||||
meshgl.V_specular_vbo = data.V_material_specular.cast<float>();
|
||||
|
||||
// Face indices
|
||||
if (meshgl.dirty & MeshGL::DIRTY_FACE)
|
||||
meshgl.F_vbo = data.F.cast<unsigned>();
|
||||
|
||||
// Texture coordinates
|
||||
if (meshgl.dirty & MeshGL::DIRTY_UV)
|
||||
{
|
||||
meshgl.V_uv_vbo = data.V_uv.cast<float>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Per vertex properties with per corner UVs
|
||||
if (meshgl.dirty & MeshGL::DIRTY_POSITION)
|
||||
{
|
||||
per_corner(data.V,meshgl.V_vbo);
|
||||
}
|
||||
|
||||
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>();
|
||||
}
|
||||
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>();
|
||||
}
|
||||
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>();
|
||||
}
|
||||
|
||||
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>();
|
||||
|
||||
|
||||
if (invert_normals)
|
||||
meshgl.V_normals_vbo = -meshgl.V_normals_vbo;
|
||||
}
|
||||
|
||||
if (meshgl.dirty & MeshGL::DIRTY_FACE)
|
||||
{
|
||||
meshgl.F_vbo.resize(data.F.rows(),3);
|
||||
for (unsigned i=0; i<data.F.rows();++i)
|
||||
meshgl.F_vbo.row(i) << i*3+0, i*3+1, i*3+2;
|
||||
}
|
||||
|
||||
if (meshgl.dirty & MeshGL::DIRTY_UV)
|
||||
{
|
||||
meshgl.V_uv_vbo.resize(data.F.rows()*3,2);
|
||||
for (unsigned i=0; i<data.F.rows();++i)
|
||||
for (unsigned j=0;j<3;++j)
|
||||
meshgl.V_uv_vbo.row(i*3+j) =
|
||||
data.V_uv.row(per_corner_uv ?
|
||||
data.F_uv(i,j) : data.F(i,j)).cast<float>();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (meshgl.dirty & MeshGL::DIRTY_POSITION)
|
||||
{
|
||||
per_corner(data.V,meshgl.V_vbo);
|
||||
}
|
||||
if (meshgl.dirty & MeshGL::DIRTY_AMBIENT)
|
||||
{
|
||||
per_face(data.F_material_ambient,meshgl.V_ambient_vbo);
|
||||
}
|
||||
if (meshgl.dirty & MeshGL::DIRTY_DIFFUSE)
|
||||
{
|
||||
per_face(data.F_material_diffuse,meshgl.V_diffuse_vbo);
|
||||
}
|
||||
if (meshgl.dirty & MeshGL::DIRTY_SPECULAR)
|
||||
{
|
||||
per_face(data.F_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.F_normals.row(i).cast<float>();
|
||||
|
||||
if (invert_normals)
|
||||
meshgl.V_normals_vbo = -meshgl.V_normals_vbo;
|
||||
}
|
||||
|
||||
if (meshgl.dirty & MeshGL::DIRTY_FACE)
|
||||
{
|
||||
meshgl.F_vbo.resize(data.F.rows(),3);
|
||||
for (unsigned i=0; i<data.F.rows();++i)
|
||||
meshgl.F_vbo.row(i) << i*3+0, i*3+1, i*3+2;
|
||||
}
|
||||
|
||||
if (meshgl.dirty & MeshGL::DIRTY_UV)
|
||||
{
|
||||
meshgl.V_uv_vbo.resize(data.F.rows()*3,2);
|
||||
for (unsigned i=0; i<data.F.rows();++i)
|
||||
for (unsigned j=0;j<3;++j)
|
||||
meshgl.V_uv_vbo.row(i*3+j) = data.V_uv.row(per_corner_uv ? data.F_uv(i,j) : data.F(i,j)).cast<float>();
|
||||
}
|
||||
}
|
||||
|
||||
if (meshgl.dirty & MeshGL::DIRTY_TEXTURE)
|
||||
{
|
||||
meshgl.tex_u = data.texture_R.rows();
|
||||
meshgl.tex_v = data.texture_R.cols();
|
||||
meshgl.tex.resize(data.texture_R.size()*4);
|
||||
for (unsigned i=0;i<data.texture_R.size();++i)
|
||||
{
|
||||
meshgl.tex(i*4+0) = data.texture_R(i);
|
||||
meshgl.tex(i*4+1) = data.texture_G(i);
|
||||
meshgl.tex(i*4+2) = data.texture_B(i);
|
||||
meshgl.tex(i*4+3) = data.texture_A(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (meshgl.dirty & MeshGL::DIRTY_OVERLAY_LINES)
|
||||
{
|
||||
meshgl.lines_V_vbo.resize(data.lines.rows()*2,3);
|
||||
meshgl.lines_V_colors_vbo.resize(data.lines.rows()*2,3);
|
||||
meshgl.lines_F_vbo.resize(data.lines.rows()*2,1);
|
||||
for (unsigned i=0; i<data.lines.rows();++i)
|
||||
{
|
||||
meshgl.lines_V_vbo.row(2*i+0) = data.lines.block<1, 3>(i, 0).cast<float>();
|
||||
meshgl.lines_V_vbo.row(2*i+1) = data.lines.block<1, 3>(i, 3).cast<float>();
|
||||
meshgl.lines_V_colors_vbo.row(2*i+0) = data.lines.block<1, 3>(i, 6).cast<float>();
|
||||
meshgl.lines_V_colors_vbo.row(2*i+1) = data.lines.block<1, 3>(i, 6).cast<float>();
|
||||
meshgl.lines_F_vbo(2*i+0) = 2*i+0;
|
||||
meshgl.lines_F_vbo(2*i+1) = 2*i+1;
|
||||
}
|
||||
}
|
||||
|
||||
if (meshgl.dirty & MeshGL::DIRTY_OVERLAY_POINTS)
|
||||
{
|
||||
meshgl.points_V_vbo.resize(data.points.rows(),3);
|
||||
meshgl.points_V_colors_vbo.resize(data.points.rows(),3);
|
||||
meshgl.points_F_vbo.resize(data.points.rows(),1);
|
||||
for (unsigned i=0; i<data.points.rows();++i)
|
||||
{
|
||||
meshgl.points_V_vbo.row(i) = data.points.block<1, 3>(i, 0).cast<float>();
|
||||
meshgl.points_V_colors_vbo.row(i) = data.points.block<1, 3>(i, 3).cast<float>();
|
||||
meshgl.points_F_vbo(i) = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
276
src/igl/opengl/ViewerData.h
Normal file
276
src/igl/opengl/ViewerData.h
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@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_VIEWERDATA_H
|
||||
#define IGL_VIEWERDATA_H
|
||||
|
||||
#include "../igl_inline.h"
|
||||
#include "MeshGL.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 ViewerData
|
||||
{
|
||||
public:
|
||||
ViewerData();
|
||||
|
||||
// Empty all fields
|
||||
IGL_INLINE void clear();
|
||||
|
||||
// Change the visualization mode, invalidating the cache if necessary
|
||||
IGL_INLINE void set_face_based(bool newvalue);
|
||||
|
||||
// Helpers that can draw the most common meshes
|
||||
IGL_INLINE void set_mesh(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F);
|
||||
IGL_INLINE void set_vertices(const Eigen::MatrixXd& V);
|
||||
IGL_INLINE void set_normals(const Eigen::MatrixXd& N);
|
||||
|
||||
// Set the color of the mesh
|
||||
//
|
||||
// Inputs:
|
||||
// C #V|#F|1 by 3 list of 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
|
||||
//
|
||||
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);
|
||||
|
||||
// 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)
|
||||
IGL_INLINE void set_points(
|
||||
const Eigen::MatrixXd& P,
|
||||
const Eigen::MatrixXd& C);
|
||||
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)
|
||||
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?
|
||||
IGL_INLINE void add_edges (const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C);
|
||||
IGL_INLINE void add_label (const Eigen::VectorXd& P, const std::string& str);
|
||||
|
||||
// Computes the normals of the mesh
|
||||
IGL_INLINE void compute_normals();
|
||||
|
||||
// Assigns uniform colors to all faces/vertices
|
||||
IGL_INLINE void uniform_colors(
|
||||
const Eigen::Vector3d& diffuse,
|
||||
const Eigen::Vector3d& ambient,
|
||||
const Eigen::Vector3d& specular);
|
||||
|
||||
// Assigns uniform colors to all faces/vertices
|
||||
IGL_INLINE void uniform_colors(
|
||||
const Eigen::Vector4d& ambient,
|
||||
const Eigen::Vector4d& diffuse,
|
||||
const Eigen::Vector4d& specular);
|
||||
|
||||
// Generates a default grid texture
|
||||
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)
|
||||
|
||||
// Per face attributes
|
||||
Eigen::MatrixXd F_normals; // One normal per face
|
||||
|
||||
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 vertex attributes
|
||||
Eigen::MatrixXd V_normals; // One normal per vertex
|
||||
|
||||
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
|
||||
|
||||
// UV parametrization
|
||||
Eigen::MatrixXd V_uv; // UV vertices
|
||||
Eigen::MatrixXi F_uv; // optional faces for UVs
|
||||
|
||||
// Texture
|
||||
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_R;
|
||||
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_G;
|
||||
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_B;
|
||||
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),
|
||||
// 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
|
||||
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
|
||||
Eigen::MatrixXd labels_positions;
|
||||
std::vector<std::string> labels_strings;
|
||||
|
||||
// Marks dirty buffers that need to be uploaded to OpenGL
|
||||
uint32_t dirty;
|
||||
|
||||
// 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;
|
||||
bool invert_normals;
|
||||
|
||||
// Point size / line width
|
||||
float point_size;
|
||||
float line_width;
|
||||
Eigen::Vector4f line_color;
|
||||
|
||||
// Shape material
|
||||
float shininess;
|
||||
|
||||
// Unique identifier
|
||||
int id;
|
||||
|
||||
// OpenGL representation of the mesh
|
||||
igl::opengl::MeshGL meshgl;
|
||||
|
||||
// Update contents from a 'Data' instance
|
||||
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>
|
||||
namespace igl
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
inline void serialization(bool s, igl::opengl::ViewerData& obj, std::vector<char>& buffer)
|
||||
{
|
||||
SERIALIZE_MEMBER(V);
|
||||
SERIALIZE_MEMBER(F);
|
||||
SERIALIZE_MEMBER(F_normals);
|
||||
SERIALIZE_MEMBER(F_material_ambient);
|
||||
SERIALIZE_MEMBER(F_material_diffuse);
|
||||
SERIALIZE_MEMBER(F_material_specular);
|
||||
SERIALIZE_MEMBER(V_normals);
|
||||
SERIALIZE_MEMBER(V_material_ambient);
|
||||
SERIALIZE_MEMBER(V_material_diffuse);
|
||||
SERIALIZE_MEMBER(V_material_specular);
|
||||
SERIALIZE_MEMBER(V_uv);
|
||||
SERIALIZE_MEMBER(F_uv);
|
||||
SERIALIZE_MEMBER(texture_R);
|
||||
SERIALIZE_MEMBER(texture_G);
|
||||
SERIALIZE_MEMBER(texture_B);
|
||||
SERIALIZE_MEMBER(texture_A);
|
||||
SERIALIZE_MEMBER(lines);
|
||||
SERIALIZE_MEMBER(points);
|
||||
SERIALIZE_MEMBER(labels_positions);
|
||||
SERIALIZE_MEMBER(labels_strings);
|
||||
SERIALIZE_MEMBER(dirty);
|
||||
SERIALIZE_MEMBER(face_based);
|
||||
SERIALIZE_MEMBER(show_faces);
|
||||
SERIALIZE_MEMBER(show_lines);
|
||||
SERIALIZE_MEMBER(invert_normals);
|
||||
SERIALIZE_MEMBER(show_overlay);
|
||||
SERIALIZE_MEMBER(show_overlay_depth);
|
||||
SERIALIZE_MEMBER(show_vertid);
|
||||
SERIALIZE_MEMBER(show_faceid);
|
||||
SERIALIZE_MEMBER(show_texture);
|
||||
SERIALIZE_MEMBER(point_size);
|
||||
SERIALIZE_MEMBER(line_width);
|
||||
SERIALIZE_MEMBER(line_color);
|
||||
SERIALIZE_MEMBER(shininess);
|
||||
SERIALIZE_MEMBER(id);
|
||||
}
|
||||
template<>
|
||||
inline void serialize(const igl::opengl::ViewerData& obj, std::vector<char>& buffer)
|
||||
{
|
||||
serialization(true, const_cast<igl::opengl::ViewerData&>(obj), buffer);
|
||||
}
|
||||
template<>
|
||||
inline void deserialize(igl::opengl::ViewerData& obj, const std::vector<char>& buffer)
|
||||
{
|
||||
serialization(false, obj, const_cast<std::vector<char>&>(buffer));
|
||||
obj.dirty = igl::opengl::MeshGL::DIRTY_ALL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "ViewerData.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
24
src/igl/opengl/bind_vertex_attrib_array.cpp
Normal file
24
src/igl/opengl/bind_vertex_attrib_array.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#include "bind_vertex_attrib_array.h"
|
||||
|
||||
IGL_INLINE GLint igl::opengl::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)
|
||||
{
|
||||
GLint id = glGetAttribLocation(program_shader, name.c_str());
|
||||
if (id < 0)
|
||||
return id;
|
||||
if (M.size() == 0)
|
||||
{
|
||||
glDisableVertexAttribArray(id);
|
||||
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);
|
||||
glEnableVertexAttribArray(id);
|
||||
return id;
|
||||
}
|
||||
32
src/igl/opengl/bind_vertex_attrib_array.h
Normal file
32
src/igl/opengl/bind_vertex_attrib_array.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef IGL_OPENGL_BIND_VERTEX_ATTRIB_ARRAY_H
|
||||
#define IGL_OPENGL_BIND_VERTEX_ATTRIB_ARRAY_H
|
||||
#include "gl.h"
|
||||
#include "../igl_inline.h"
|
||||
#include <Eigen/Core>
|
||||
#include <string>
|
||||
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
|
||||
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);
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
#include "bind_vertex_attrib_array.cpp"
|
||||
#endif
|
||||
#endif
|
||||
46
src/igl/opengl/create_index_vbo.cpp
Normal file
46
src/igl/opengl/create_index_vbo.cpp
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/.
|
||||
#include "create_index_vbo.h"
|
||||
|
||||
// http://www.songho.ca/opengl/gl_vbo.html#create
|
||||
IGL_INLINE void igl::opengl::create_index_vbo(
|
||||
const Eigen::MatrixXi & F,
|
||||
GLuint & F_vbo_id)
|
||||
{
|
||||
// Generate Buffers
|
||||
glGenBuffers(1,&F_vbo_id);
|
||||
// Bind Buffers
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,F_vbo_id);
|
||||
// Copy data to buffers
|
||||
// We expect a matrix with each vertex position on a row, we then want to
|
||||
// pass this data to OpenGL reading across rows (row-major)
|
||||
if(F.Options & Eigen::RowMajor)
|
||||
{
|
||||
glBufferData(
|
||||
GL_ELEMENT_ARRAY_BUFFER,
|
||||
sizeof(int)*F.size(),
|
||||
F.data(),
|
||||
GL_STATIC_DRAW);
|
||||
}else
|
||||
{
|
||||
// Create temporary copy of transpose
|
||||
Eigen::MatrixXi FT = F.transpose();
|
||||
// If its column major then we need to temporarily store a transpose
|
||||
glBufferData(
|
||||
GL_ELEMENT_ARRAY_BUFFER,
|
||||
sizeof(int)*F.size(),
|
||||
FT.data(),
|
||||
GL_STATIC_DRAW);
|
||||
}
|
||||
// bind with 0, so, switch back to normal pointer operation
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#endif
|
||||
35
src/igl/opengl/create_index_vbo.h
Normal file
35
src/igl/opengl/create_index_vbo.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// 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_CREATE_INDEX_VBO_H
|
||||
#define IGL_OPENGL_CREATE_INDEX_VBO_H
|
||||
#include "../igl_inline.h"
|
||||
#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
|
||||
//
|
||||
IGL_INLINE void create_index_vbo(
|
||||
const Eigen::MatrixXi & F,
|
||||
GLuint & F_vbo_id);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "create_index_vbo.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
43
src/igl/opengl/create_mesh_vbo.cpp
Normal file
43
src/igl/opengl/create_mesh_vbo.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// 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 "create_mesh_vbo.h"
|
||||
|
||||
#include "create_vector_vbo.h"
|
||||
#include "create_index_vbo.h"
|
||||
|
||||
// http://www.songho.ca/opengl/gl_vbo.html#create
|
||||
IGL_INLINE void igl::opengl::create_mesh_vbo(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
GLuint & V_vbo_id,
|
||||
GLuint & F_vbo_id)
|
||||
{
|
||||
// Create VBO for vertex position vectors
|
||||
create_vector_vbo(V,V_vbo_id);
|
||||
// Create VBO for face index lists
|
||||
create_index_vbo(F,F_vbo_id);
|
||||
}
|
||||
|
||||
// http://www.songho.ca/opengl/gl_vbo.html#create
|
||||
IGL_INLINE void igl::opengl::create_mesh_vbo(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
const Eigen::MatrixXd & N,
|
||||
GLuint & V_vbo_id,
|
||||
GLuint & F_vbo_id,
|
||||
GLuint & N_vbo_id)
|
||||
{
|
||||
// Create VBOs for faces and vertices
|
||||
create_mesh_vbo(V,F,V_vbo_id,F_vbo_id);
|
||||
// Create VBO for normal vectors
|
||||
create_vector_vbo(N,N_vbo_id);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#endif
|
||||
61
src/igl/opengl/create_mesh_vbo.h
Normal file
61
src/igl/opengl/create_mesh_vbo.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// 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_CREATE_MESH_VBO_H
|
||||
#define IGL_OPENGL_CREATE_MESH_VBO_H
|
||||
#include "../igl_inline.h"
|
||||
#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
|
||||
//
|
||||
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
|
||||
IGL_INLINE void create_mesh_vbo(
|
||||
const Eigen::MatrixXd & V,
|
||||
const Eigen::MatrixXi & F,
|
||||
const Eigen::MatrixXd & N,
|
||||
GLuint & V_vbo_id,
|
||||
GLuint & F_vbo_id,
|
||||
GLuint & N_vbo_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "create_mesh_vbo.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
141
src/igl/opengl/create_shader_program.cpp
Normal file
141
src/igl/opengl/create_shader_program.cpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
// 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 "create_shader_program.h"
|
||||
|
||||
#include "load_shader.h"
|
||||
#include "print_program_info_log.h"
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
|
||||
IGL_INLINE bool igl::opengl::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)
|
||||
{
|
||||
using namespace std;
|
||||
if(vert_source == "" && frag_source == "")
|
||||
{
|
||||
cerr<<
|
||||
"create_shader_program() could not create shader program,"
|
||||
" both .vert and .frag source given were empty"<<endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// create program
|
||||
id = glCreateProgram();
|
||||
if(id == 0)
|
||||
{
|
||||
cerr<<"create_shader_program() could not create shader program."<<endl;
|
||||
return false;
|
||||
}
|
||||
GLuint g = 0,f = 0,v = 0;
|
||||
|
||||
if(geom_source != "")
|
||||
{
|
||||
// load vertex shader
|
||||
g = igl::opengl::load_shader(geom_source.c_str(),GL_GEOMETRY_SHADER);
|
||||
if(g == 0)
|
||||
{
|
||||
cerr<<"geometry shader failed to compile."<<endl;
|
||||
return false;
|
||||
}
|
||||
glAttachShader(id,g);
|
||||
}
|
||||
|
||||
if(vert_source != "")
|
||||
{
|
||||
// load vertex shader
|
||||
v = igl::opengl::load_shader(vert_source.c_str(),GL_VERTEX_SHADER);
|
||||
if(v == 0)
|
||||
{
|
||||
cerr<<"vertex shader failed to compile."<<endl;
|
||||
return false;
|
||||
}
|
||||
glAttachShader(id,v);
|
||||
}
|
||||
|
||||
if(frag_source != "")
|
||||
{
|
||||
// load fragment shader
|
||||
f = igl::opengl::load_shader(frag_source.c_str(),GL_FRAGMENT_SHADER);
|
||||
if(f == 0)
|
||||
{
|
||||
cerr<<"fragment shader failed to compile."<<endl;
|
||||
return false;
|
||||
}
|
||||
glAttachShader(id,f);
|
||||
}
|
||||
|
||||
// loop over attributes
|
||||
for(
|
||||
std::map<std::string,GLuint>::const_iterator ait = attrib.begin();
|
||||
ait != attrib.end();
|
||||
ait++)
|
||||
{
|
||||
glBindAttribLocation(
|
||||
id,
|
||||
(*ait).second,
|
||||
(*ait).first.c_str());
|
||||
}
|
||||
// Link program
|
||||
glLinkProgram(id);
|
||||
const auto & detach = [&id](const GLuint shader)
|
||||
{
|
||||
if(shader)
|
||||
{
|
||||
glDetachShader(id,shader);
|
||||
glDeleteShader(shader);
|
||||
}
|
||||
};
|
||||
detach(g);
|
||||
detach(f);
|
||||
detach(v);
|
||||
|
||||
// print log if any
|
||||
igl::opengl::print_program_info_log(id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IGL_INLINE bool igl::opengl::create_shader_program(
|
||||
const std::string & vert_source,
|
||||
const std::string & frag_source,
|
||||
const std::map<std::string,GLuint> & attrib,
|
||||
GLuint & prog_id)
|
||||
{
|
||||
return create_shader_program("",vert_source,frag_source,attrib,prog_id);
|
||||
}
|
||||
|
||||
|
||||
IGL_INLINE GLuint igl::opengl::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 prog_id = 0;
|
||||
create_shader_program(geom_source,vert_source,frag_source,attrib,prog_id);
|
||||
return prog_id;
|
||||
}
|
||||
|
||||
IGL_INLINE GLuint igl::opengl::create_shader_program(
|
||||
const std::string & vert_source,
|
||||
const std::string & frag_source,
|
||||
const std::map<std::string,GLuint> & attrib)
|
||||
{
|
||||
GLuint prog_id = 0;
|
||||
create_shader_program(vert_source,frag_source,attrib,prog_id);
|
||||
return prog_id;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#endif
|
||||
|
||||
64
src/igl/opengl/create_shader_program.h
Normal file
64
src/igl/opengl/create_shader_program.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// 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_CREATE_SHADER_PROGRAM_H
|
||||
#define IGL_OPENGL_CREATE_SHADER_PROGRAM_H
|
||||
#include "../igl_inline.h"
|
||||
#include "gl.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
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
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
IGL_INLINE GLuint create_shader_program(
|
||||
const std::string & vert_source,
|
||||
const std::string & frag_source,
|
||||
const std::map<std::string,GLuint> &attrib);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "create_shader_program.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
57
src/igl/opengl/create_vector_vbo.cpp
Normal file
57
src/igl/opengl/create_vector_vbo.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// 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 "create_vector_vbo.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
// http://www.songho.ca/opengl/gl_vbo.html#create
|
||||
template <typename T>
|
||||
IGL_INLINE void igl::opengl::create_vector_vbo(
|
||||
const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & V,
|
||||
GLuint & V_vbo_id)
|
||||
{
|
||||
//// Expects that input is list of 3D vectors along rows
|
||||
//assert(V.cols() == 3);
|
||||
|
||||
// Generate Buffers
|
||||
glGenBuffers(1,&V_vbo_id);
|
||||
// Bind Buffers
|
||||
glBindBuffer(GL_ARRAY_BUFFER,V_vbo_id);
|
||||
// Copy data to buffers
|
||||
// We expect a matrix with each vertex position on a row, we then want to
|
||||
// pass this data to OpenGL reading across rows (row-major)
|
||||
if(V.Options & Eigen::RowMajor)
|
||||
{
|
||||
glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
sizeof(T)*V.size(),
|
||||
V.data(),
|
||||
GL_STATIC_DRAW);
|
||||
}else
|
||||
{
|
||||
// Create temporary copy of transpose
|
||||
Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> VT = V.transpose();
|
||||
// If its column major then we need to temporarily store a transpose
|
||||
glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
sizeof(T)*V.size(),
|
||||
VT.data(),
|
||||
GL_STATIC_DRAW);
|
||||
}
|
||||
// bind with 0, so, switch back to normal pointer operation
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::opengl::create_vector_vbo<int>(Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, unsigned int&);
|
||||
// generated by autoexplicit.sh
|
||||
template void igl::opengl::create_vector_vbo<double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, unsigned int&);
|
||||
#endif
|
||||
|
||||
38
src/igl/opengl/create_vector_vbo.h
Normal file
38
src/igl/opengl/create_vector_vbo.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// 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_CREATE_VECTOR_VBO_H
|
||||
#define IGL_OPENGL_CREATE_VECTOR_VBO_H
|
||||
#include "../igl_inline.h"
|
||||
#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
|
||||
//
|
||||
template <typename T>
|
||||
IGL_INLINE void create_vector_vbo(
|
||||
const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & V,
|
||||
GLuint & V_vbo_id);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "create_vector_vbo.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
50
src/igl/opengl/destroy_shader_program.cpp
Normal file
50
src/igl/opengl/destroy_shader_program.cpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// 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 "destroy_shader_program.h"
|
||||
#include "report_gl_error.h"
|
||||
#include <cstdio>
|
||||
|
||||
IGL_INLINE bool igl::opengl::destroy_shader_program(const GLuint id)
|
||||
{
|
||||
// Don't try to destroy id == 0 (no shader program)
|
||||
if(id == 0)
|
||||
{
|
||||
fprintf(stderr,"Error: destroy_shader_program() id = %d"
|
||||
" but must should be positive\n",id);
|
||||
return false;
|
||||
}
|
||||
// Get each attached shader one by one and detach and delete it
|
||||
GLsizei count;
|
||||
// shader id
|
||||
GLuint s;
|
||||
do
|
||||
{
|
||||
// Try to get at most *1* attached shader
|
||||
glGetAttachedShaders(id,1,&count,&s);
|
||||
GLenum err = igl::opengl::report_gl_error();
|
||||
if (GL_NO_ERROR != err)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Check that we actually got *1*
|
||||
if(count == 1)
|
||||
{
|
||||
// Detach and delete this shader
|
||||
glDetachShader(id,s);
|
||||
glDeleteShader(s);
|
||||
}
|
||||
}while(count > 0);
|
||||
// Now that all of the shaders are gone we can just delete the program
|
||||
glDeleteProgram(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#endif
|
||||
|
||||
35
src/igl/opengl/destroy_shader_program.h
Normal file
35
src/igl/opengl/destroy_shader_program.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// 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_DESTROY_SHADER_PROGRAM_H
|
||||
#define IGL_OPENGL_DESTROY_SHADER_PROGRAM_H
|
||||
#include "../igl_inline.h"
|
||||
#include "gl.h"
|
||||
|
||||
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
|
||||
IGL_INLINE bool destroy_shader_program(const GLuint id);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "destroy_shader_program.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
25
src/igl/opengl/gl.h
Normal file
25
src/igl/opengl/gl.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013, 2017 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_GL_H
|
||||
#define IGL_OPENGL_GL_H
|
||||
|
||||
#ifdef IGL_OPENGL2_GL_H
|
||||
# error "igl/opengl2/gl.h already included"
|
||||
#endif
|
||||
|
||||
// Always use this:
|
||||
// #include "gl.h"
|
||||
// Instead of:
|
||||
// #include <OpenGL/gl3.h>
|
||||
// or
|
||||
// #include <GL/gl.h>
|
||||
//
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#endif
|
||||
30
src/igl/opengl/gl_type_size.cpp
Normal file
30
src/igl/opengl/gl_type_size.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// 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 "gl_type_size.h"
|
||||
#include <cassert>
|
||||
|
||||
IGL_INLINE int igl::opengl::gl_type_size(const GLenum type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case GL_DOUBLE:
|
||||
return 8;
|
||||
break;
|
||||
case GL_FLOAT:
|
||||
return 4;
|
||||
break;
|
||||
case GL_INT:
|
||||
return 4;
|
||||
break;
|
||||
default:
|
||||
// should handle all other GL_[types]
|
||||
assert(false && "Implementation incomplete.");
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
28
src/igl/opengl/gl_type_size.h
Normal file
28
src/igl/opengl/gl_type_size.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// 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_GL_TYPE_SIZE_H
|
||||
#define IGL_OPENGL_GL_TYPE_SIZE_H
|
||||
#include "../igl_inline.h"
|
||||
#include "gl.h"
|
||||
|
||||
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
|
||||
IGL_INLINE int gl_type_size(const GLenum type);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "gl_type_size.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
950
src/igl/opengl/glfw/Viewer.cpp
Normal file
950
src/igl/opengl/glfw/Viewer.cpp
Normal file
|
|
@ -0,0 +1,950 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@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 "Viewer.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <Eigen/LU>
|
||||
|
||||
#include "../gl.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <cassert>
|
||||
|
||||
#include <igl/project.h>
|
||||
#include <igl/get_seconds.h>
|
||||
#include <igl/readOBJ.h>
|
||||
#include <igl/readOFF.h>
|
||||
#include <igl/adjacency_list.h>
|
||||
#include <igl/writeOBJ.h>
|
||||
#include <igl/writeOFF.h>
|
||||
#include <igl/massmatrix.h>
|
||||
#include <igl/file_dialog_open.h>
|
||||
#include <igl/file_dialog_save.h>
|
||||
#include <igl/quat_mult.h>
|
||||
#include <igl/axis_angle_to_quat.h>
|
||||
#include <igl/trackball.h>
|
||||
#include <igl/two_axis_valuator_fixed_up.h>
|
||||
#include <igl/snap_to_canonical_view_quat.h>
|
||||
#include <igl/unproject.h>
|
||||
#include <igl/serialize.h>
|
||||
|
||||
// Internal global variables used for glfw event handling
|
||||
static igl::opengl::glfw::Viewer * __viewer;
|
||||
static double highdpi = 1;
|
||||
static double scroll_x = 0;
|
||||
static double scroll_y = 0;
|
||||
|
||||
static void glfw_mouse_press(GLFWwindow* window, int button, int action, int modifier)
|
||||
{
|
||||
|
||||
igl::opengl::glfw::Viewer::MouseButton mb;
|
||||
|
||||
if (button == GLFW_MOUSE_BUTTON_1)
|
||||
mb = igl::opengl::glfw::Viewer::MouseButton::Left;
|
||||
else if (button == GLFW_MOUSE_BUTTON_2)
|
||||
mb = igl::opengl::glfw::Viewer::MouseButton::Right;
|
||||
else //if (button == GLFW_MOUSE_BUTTON_3)
|
||||
mb = igl::opengl::glfw::Viewer::MouseButton::Middle;
|
||||
|
||||
if (action == GLFW_PRESS)
|
||||
__viewer->mouse_down(mb,modifier);
|
||||
else
|
||||
__viewer->mouse_up(mb,modifier);
|
||||
}
|
||||
|
||||
static void glfw_error_callback(int error, const char* description)
|
||||
{
|
||||
fputs(description, stderr);
|
||||
}
|
||||
|
||||
static void glfw_char_mods_callback(GLFWwindow* window, unsigned int codepoint, int modifier)
|
||||
{
|
||||
__viewer->key_pressed(codepoint, modifier);
|
||||
}
|
||||
|
||||
static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int modifier)
|
||||
{
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
|
||||
if (action == GLFW_PRESS)
|
||||
__viewer->key_down(key, modifier);
|
||||
else if(action == GLFW_RELEASE)
|
||||
__viewer->key_up(key, modifier);
|
||||
}
|
||||
|
||||
static void glfw_window_size(GLFWwindow* window, int width, int height)
|
||||
{
|
||||
int w = width*highdpi;
|
||||
int h = height*highdpi;
|
||||
|
||||
__viewer->post_resize(w, h);
|
||||
|
||||
}
|
||||
|
||||
static void glfw_mouse_move(GLFWwindow* window, double x, double y)
|
||||
{
|
||||
__viewer->mouse_move(x*highdpi, y*highdpi);
|
||||
}
|
||||
|
||||
static void glfw_mouse_scroll(GLFWwindow* window, double x, double y)
|
||||
{
|
||||
using namespace std;
|
||||
scroll_x += x;
|
||||
scroll_y += y;
|
||||
|
||||
__viewer->mouse_scroll(y);
|
||||
}
|
||||
|
||||
static void glfw_drop_callback(GLFWwindow *window,int count,const char **filenames)
|
||||
{
|
||||
}
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
namespace glfw
|
||||
{
|
||||
|
||||
IGL_INLINE int Viewer::launch(bool resizable,bool fullscreen)
|
||||
{
|
||||
// TODO return values are being ignored...
|
||||
launch_init(resizable,fullscreen);
|
||||
launch_rendering(true);
|
||||
launch_shut();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
IGL_INLINE int Viewer::launch_init(bool resizable,bool fullscreen)
|
||||
{
|
||||
glfwSetErrorCallback(glfw_error_callback);
|
||||
if (!glfwInit())
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
glfwWindowHint(GLFW_SAMPLES, 8);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
#ifdef __APPLE__
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
#endif
|
||||
if(fullscreen)
|
||||
{
|
||||
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
|
||||
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
|
||||
window = glfwCreateWindow(mode->width,mode->height,"libigl viewer",monitor,nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (core.viewport.tail<2>().any()) {
|
||||
window = glfwCreateWindow(core.viewport(2),core.viewport(3),"libigl viewer",nullptr,nullptr);
|
||||
} else {
|
||||
window = glfwCreateWindow(1280,800,"libigl viewer",nullptr,nullptr);
|
||||
}
|
||||
}
|
||||
if (!window)
|
||||
{
|
||||
glfwTerminate();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
glfwMakeContextCurrent(window);
|
||||
// Load OpenGL and its extensions
|
||||
if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress))
|
||||
{
|
||||
printf("Failed to load OpenGL and its extensions\n");
|
||||
return(-1);
|
||||
}
|
||||
#if defined(DEBUG) || defined(_DEBUG)
|
||||
printf("OpenGL Version %d.%d loaded\n", GLVersion.major, GLVersion.minor);
|
||||
int major, minor, rev;
|
||||
major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
|
||||
minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
|
||||
rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);
|
||||
printf("OpenGL version received: %d.%d.%d\n", major, minor, rev);
|
||||
printf("Supported OpenGL is %s\n", (const char*)glGetString(GL_VERSION));
|
||||
printf("Supported GLSL is %s\n", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
#endif
|
||||
glfwSetInputMode(window,GLFW_CURSOR,GLFW_CURSOR_NORMAL);
|
||||
// Initialize FormScreen
|
||||
__viewer = this;
|
||||
// Register callbacks
|
||||
glfwSetKeyCallback(window, glfw_key_callback);
|
||||
glfwSetCursorPosCallback(window,glfw_mouse_move);
|
||||
glfwSetWindowSizeCallback(window,glfw_window_size);
|
||||
glfwSetMouseButtonCallback(window,glfw_mouse_press);
|
||||
glfwSetScrollCallback(window,glfw_mouse_scroll);
|
||||
glfwSetCharModsCallback(window,glfw_char_mods_callback);
|
||||
glfwSetDropCallback(window,glfw_drop_callback);
|
||||
// Handle retina displays (windows and mac)
|
||||
int width, height;
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
int width_window, height_window;
|
||||
glfwGetWindowSize(window, &width_window, &height_window);
|
||||
highdpi = width/width_window;
|
||||
glfw_window_size(window,width_window,height_window);
|
||||
//opengl.init();
|
||||
core.align_camera_center(data().V,data().F);
|
||||
// Initialize IGL viewer
|
||||
init();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
IGL_INLINE bool Viewer::launch_rendering(bool loop)
|
||||
{
|
||||
// glfwMakeContextCurrent(window);
|
||||
// Rendering loop
|
||||
const int num_extra_frames = 5;
|
||||
int frame_counter = 0;
|
||||
while (!glfwWindowShouldClose(window))
|
||||
{
|
||||
double tic = get_seconds();
|
||||
draw();
|
||||
glfwSwapBuffers(window);
|
||||
if(core.is_animating || frame_counter++ < num_extra_frames)
|
||||
{
|
||||
glfwPollEvents();
|
||||
// In microseconds
|
||||
double duration = 1000000.*(get_seconds()-tic);
|
||||
const double min_duration = 1000000./core.animation_max_fps;
|
||||
if(duration<min_duration)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::microseconds((int)(min_duration-duration)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
glfwWaitEvents();
|
||||
frame_counter = 0;
|
||||
}
|
||||
if (!loop)
|
||||
return !glfwWindowShouldClose(window);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
IGL_INLINE void Viewer::launch_shut()
|
||||
{
|
||||
for(auto & data : data_list)
|
||||
{
|
||||
data.meshgl.free();
|
||||
}
|
||||
core.shut();
|
||||
shutdown_plugins();
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
return;
|
||||
}
|
||||
|
||||
IGL_INLINE void Viewer::init()
|
||||
{
|
||||
core.init();
|
||||
|
||||
if (callback_init)
|
||||
if (callback_init(*this))
|
||||
return;
|
||||
|
||||
init_plugins();
|
||||
}
|
||||
|
||||
IGL_INLINE void Viewer::init_plugins()
|
||||
{
|
||||
// Init all plugins
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
{
|
||||
plugins[i]->init(this);
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void Viewer::shutdown_plugins()
|
||||
{
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
{
|
||||
plugins[i]->shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE Viewer::Viewer():
|
||||
data_list(1),
|
||||
selected_data_index(0),
|
||||
next_data_id(1)
|
||||
{
|
||||
window = nullptr;
|
||||
data_list.front().id = 0;
|
||||
|
||||
// Temporary variables initialization
|
||||
down = false;
|
||||
hack_never_moved = true;
|
||||
scroll_position = 0.0f;
|
||||
|
||||
// Per face
|
||||
data().set_face_based(false);
|
||||
|
||||
// C-style callbacks
|
||||
callback_init = nullptr;
|
||||
callback_pre_draw = nullptr;
|
||||
callback_post_draw = nullptr;
|
||||
callback_mouse_down = nullptr;
|
||||
callback_mouse_up = nullptr;
|
||||
callback_mouse_move = nullptr;
|
||||
callback_mouse_scroll = nullptr;
|
||||
callback_key_down = nullptr;
|
||||
callback_key_up = nullptr;
|
||||
|
||||
callback_init_data = nullptr;
|
||||
callback_pre_draw_data = nullptr;
|
||||
callback_post_draw_data = nullptr;
|
||||
callback_mouse_down_data = nullptr;
|
||||
callback_mouse_up_data = nullptr;
|
||||
callback_mouse_move_data = nullptr;
|
||||
callback_mouse_scroll_data = nullptr;
|
||||
callback_key_down_data = nullptr;
|
||||
callback_key_up_data = nullptr;
|
||||
|
||||
#ifndef IGL_VIEWER_VIEWER_QUIET
|
||||
const std::string usage(R"(igl::opengl::glfw::Viewer usage:
|
||||
[drag] Rotate scene
|
||||
A,a Toggle animation (tight draw loop)
|
||||
F,f Toggle face based
|
||||
I,i Toggle invert normals
|
||||
L,l Toggle wireframe
|
||||
O,o Toggle orthographic/perspective projection
|
||||
T,t Toggle filled faces
|
||||
Z Snap to canonical view
|
||||
[,] Toggle between rotation control types (trackball, two-axis
|
||||
valuator with fixed up, 2D mode with no rotation))
|
||||
<,> Toggle between models
|
||||
; Toggle vertex labels
|
||||
: Toggle face labels)"
|
||||
);
|
||||
std::cout<<usage<<std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
IGL_INLINE Viewer::~Viewer()
|
||||
{
|
||||
}
|
||||
|
||||
IGL_INLINE bool Viewer::load_mesh_from_file(
|
||||
const std::string & mesh_file_name_string)
|
||||
{
|
||||
|
||||
// first try to load it with a plugin
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
{
|
||||
if (plugins[i]->load(mesh_file_name_string))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new data slot and set to selected
|
||||
if(!(data().F.rows() == 0 && data().V.rows() == 0))
|
||||
{
|
||||
append_mesh();
|
||||
}
|
||||
data().clear();
|
||||
|
||||
size_t last_dot = mesh_file_name_string.rfind('.');
|
||||
if (last_dot == std::string::npos)
|
||||
{
|
||||
std::cerr<<"Error: No file extension found in "<<
|
||||
mesh_file_name_string<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string extension = mesh_file_name_string.substr(last_dot+1);
|
||||
|
||||
if (extension == "off" || extension =="OFF")
|
||||
{
|
||||
Eigen::MatrixXd V;
|
||||
Eigen::MatrixXi F;
|
||||
if (!igl::readOFF(mesh_file_name_string, V, F))
|
||||
return false;
|
||||
data().set_mesh(V,F);
|
||||
}
|
||||
else if (extension == "obj" || extension =="OBJ")
|
||||
{
|
||||
Eigen::MatrixXd corner_normals;
|
||||
Eigen::MatrixXi fNormIndices;
|
||||
|
||||
Eigen::MatrixXd UV_V;
|
||||
Eigen::MatrixXi UV_F;
|
||||
Eigen::MatrixXd V;
|
||||
Eigen::MatrixXi F;
|
||||
|
||||
if (!(
|
||||
igl::readOBJ(
|
||||
mesh_file_name_string,
|
||||
V, UV_V, corner_normals, F, UV_F, fNormIndices)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
data().set_mesh(V,F);
|
||||
data().set_uv(UV_V,UV_F);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// unrecognized file type
|
||||
printf("Error: %s is not a recognized file type.\n",extension.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
data().compute_normals();
|
||||
data().uniform_colors(Eigen::Vector3d(51.0/255.0,43.0/255.0,33.3/255.0),
|
||||
Eigen::Vector3d(255.0/255.0,228.0/255.0,58.0/255.0),
|
||||
Eigen::Vector3d(255.0/255.0,235.0/255.0,80.0/255.0));
|
||||
|
||||
// Alec: why?
|
||||
if (data().V_uv.rows() == 0)
|
||||
{
|
||||
data().grid_texture();
|
||||
}
|
||||
|
||||
core.align_camera_center(data().V,data().F);
|
||||
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
if (plugins[i]->post_load())
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IGL_INLINE bool Viewer::save_mesh_to_file(
|
||||
const std::string & mesh_file_name_string)
|
||||
{
|
||||
// first try to load it with a plugin
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
if (plugins[i]->save(mesh_file_name_string))
|
||||
return true;
|
||||
|
||||
size_t last_dot = mesh_file_name_string.rfind('.');
|
||||
if (last_dot == std::string::npos)
|
||||
{
|
||||
// No file type determined
|
||||
std::cerr<<"Error: No file extension found in "<<
|
||||
mesh_file_name_string<<std::endl;
|
||||
return false;
|
||||
}
|
||||
std::string extension = mesh_file_name_string.substr(last_dot+1);
|
||||
if (extension == "off" || extension =="OFF")
|
||||
{
|
||||
return igl::writeOFF(
|
||||
mesh_file_name_string,data().V,data().F);
|
||||
}
|
||||
else if (extension == "obj" || extension =="OBJ")
|
||||
{
|
||||
Eigen::MatrixXd corner_normals;
|
||||
Eigen::MatrixXi fNormIndices;
|
||||
|
||||
Eigen::MatrixXd UV_V;
|
||||
Eigen::MatrixXi UV_F;
|
||||
|
||||
return igl::writeOBJ(mesh_file_name_string,
|
||||
data().V,
|
||||
data().F,
|
||||
corner_normals, fNormIndices, UV_V, UV_F);
|
||||
}
|
||||
else
|
||||
{
|
||||
// unrecognized file type
|
||||
printf("Error: %s is not a recognized file type.\n",extension.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IGL_INLINE bool Viewer::key_pressed(unsigned int unicode_key,int modifiers)
|
||||
{
|
||||
if (callback_key_pressed)
|
||||
if (callback_key_pressed(*this,unicode_key,modifiers))
|
||||
return true;
|
||||
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
{
|
||||
if (plugins[i]->key_pressed(unicode_key, modifiers))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
switch(unicode_key)
|
||||
{
|
||||
case 'A':
|
||||
case 'a':
|
||||
{
|
||||
core.is_animating = !core.is_animating;
|
||||
return true;
|
||||
}
|
||||
case 'F':
|
||||
case 'f':
|
||||
{
|
||||
data().set_face_based(!data().face_based);
|
||||
return true;
|
||||
}
|
||||
case 'I':
|
||||
case 'i':
|
||||
{
|
||||
data().dirty |= MeshGL::DIRTY_NORMAL;
|
||||
data().invert_normals = !data().invert_normals;
|
||||
return true;
|
||||
}
|
||||
case 'L':
|
||||
case 'l':
|
||||
{
|
||||
data().show_lines = !data().show_lines;
|
||||
return true;
|
||||
}
|
||||
case 'O':
|
||||
case 'o':
|
||||
{
|
||||
core.orthographic = !core.orthographic;
|
||||
return true;
|
||||
}
|
||||
case 'T':
|
||||
case 't':
|
||||
{
|
||||
data().show_faces = !data().show_faces;
|
||||
return true;
|
||||
}
|
||||
case 'Z':
|
||||
{
|
||||
snap_to_canonical_quaternion();
|
||||
return true;
|
||||
}
|
||||
case '[':
|
||||
case ']':
|
||||
{
|
||||
if(core.rotation_type == ViewerCore::ROTATION_TYPE_TRACKBALL)
|
||||
core.set_rotation_type(ViewerCore::ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP);
|
||||
else
|
||||
core.set_rotation_type(ViewerCore::ROTATION_TYPE_TRACKBALL);
|
||||
|
||||
return true;
|
||||
}
|
||||
case '<':
|
||||
case '>':
|
||||
{
|
||||
selected_data_index =
|
||||
(selected_data_index + data_list.size() + (unicode_key=='>'?1:-1))%data_list.size();
|
||||
return true;
|
||||
}
|
||||
case ';':
|
||||
data().show_vertid = !data().show_vertid;
|
||||
return true;
|
||||
case ':':
|
||||
data().show_faceid = !data().show_faceid;
|
||||
return true;
|
||||
default: break;//do nothing
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE bool Viewer::key_down(int key,int modifiers)
|
||||
{
|
||||
if (callback_key_down)
|
||||
if (callback_key_down(*this,key,modifiers))
|
||||
return true;
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
if (plugins[i]->key_down(key, modifiers))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE bool Viewer::key_up(int key,int modifiers)
|
||||
{
|
||||
if (callback_key_up)
|
||||
if (callback_key_up(*this,key,modifiers))
|
||||
return true;
|
||||
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
if (plugins[i]->key_up(key, modifiers))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IGL_INLINE bool Viewer::mouse_down(MouseButton button,int modifier)
|
||||
{
|
||||
// Remember mouse location at down even if used by callback/plugin
|
||||
down_mouse_x = current_mouse_x;
|
||||
down_mouse_y = current_mouse_y;
|
||||
|
||||
if (callback_mouse_down)
|
||||
if (callback_mouse_down(*this,static_cast<int>(button),modifier))
|
||||
return true;
|
||||
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
if(plugins[i]->mouse_down(static_cast<int>(button),modifier))
|
||||
return true;
|
||||
|
||||
down = true;
|
||||
|
||||
down_translation = core.camera_translation;
|
||||
|
||||
|
||||
// Initialization code for the trackball
|
||||
Eigen::RowVector3d center;
|
||||
if (data().V.rows() == 0)
|
||||
{
|
||||
center << 0,0,0;
|
||||
}else
|
||||
{
|
||||
center = data().V.colwise().sum()/data().V.rows();
|
||||
}
|
||||
|
||||
Eigen::Vector3f coord =
|
||||
igl::project(
|
||||
Eigen::Vector3f(center(0),center(1),center(2)),
|
||||
core.view,
|
||||
core.proj,
|
||||
core.viewport);
|
||||
down_mouse_z = coord[2];
|
||||
down_rotation = core.trackball_angle;
|
||||
|
||||
mouse_mode = MouseMode::Rotation;
|
||||
|
||||
switch (button)
|
||||
{
|
||||
case MouseButton::Left:
|
||||
if (core.rotation_type == ViewerCore::ROTATION_TYPE_NO_ROTATION) {
|
||||
mouse_mode = MouseMode::Translation;
|
||||
} else {
|
||||
mouse_mode = MouseMode::Rotation;
|
||||
}
|
||||
break;
|
||||
|
||||
case MouseButton::Right:
|
||||
mouse_mode = MouseMode::Translation;
|
||||
break;
|
||||
|
||||
default:
|
||||
mouse_mode = MouseMode::None;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IGL_INLINE bool Viewer::mouse_up(MouseButton button,int modifier)
|
||||
{
|
||||
down = false;
|
||||
|
||||
if (callback_mouse_up)
|
||||
if (callback_mouse_up(*this,static_cast<int>(button),modifier))
|
||||
return true;
|
||||
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
if(plugins[i]->mouse_up(static_cast<int>(button),modifier))
|
||||
return true;
|
||||
|
||||
mouse_mode = MouseMode::None;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IGL_INLINE bool Viewer::mouse_move(int mouse_x,int mouse_y)
|
||||
{
|
||||
if(hack_never_moved)
|
||||
{
|
||||
down_mouse_x = mouse_x;
|
||||
down_mouse_y = mouse_y;
|
||||
hack_never_moved = false;
|
||||
}
|
||||
current_mouse_x = mouse_x;
|
||||
current_mouse_y = mouse_y;
|
||||
|
||||
if (callback_mouse_move)
|
||||
if (callback_mouse_move(*this,mouse_x,mouse_y))
|
||||
return true;
|
||||
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
if (plugins[i]->mouse_move(mouse_x, mouse_y))
|
||||
return true;
|
||||
|
||||
if (down)
|
||||
{
|
||||
switch (mouse_mode)
|
||||
{
|
||||
case MouseMode::Rotation:
|
||||
{
|
||||
switch(core.rotation_type)
|
||||
{
|
||||
default:
|
||||
assert(false && "Unknown rotation type");
|
||||
case ViewerCore::ROTATION_TYPE_NO_ROTATION:
|
||||
break;
|
||||
case ViewerCore::ROTATION_TYPE_TRACKBALL:
|
||||
igl::trackball(
|
||||
core.viewport(2),
|
||||
core.viewport(3),
|
||||
2.0f,
|
||||
down_rotation,
|
||||
down_mouse_x,
|
||||
down_mouse_y,
|
||||
mouse_x,
|
||||
mouse_y,
|
||||
core.trackball_angle);
|
||||
break;
|
||||
case ViewerCore::ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP:
|
||||
igl::two_axis_valuator_fixed_up(
|
||||
core.viewport(2),core.viewport(3),
|
||||
2.0,
|
||||
down_rotation,
|
||||
down_mouse_x, down_mouse_y, mouse_x, mouse_y,
|
||||
core.trackball_angle);
|
||||
break;
|
||||
}
|
||||
//Eigen::Vector4f snapq = core.trackball_angle;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MouseMode::Translation:
|
||||
{
|
||||
//translation
|
||||
Eigen::Vector3f pos1 = igl::unproject(Eigen::Vector3f(mouse_x, core.viewport[3] - mouse_y, down_mouse_z), core.view, core.proj, core.viewport);
|
||||
Eigen::Vector3f pos0 = igl::unproject(Eigen::Vector3f(down_mouse_x, core.viewport[3] - down_mouse_y, down_mouse_z), core.view, core.proj, core.viewport);
|
||||
|
||||
Eigen::Vector3f diff = pos1 - pos0;
|
||||
core.camera_translation = down_translation + Eigen::Vector3f(diff[0],diff[1],diff[2]);
|
||||
|
||||
break;
|
||||
}
|
||||
case MouseMode::Zoom:
|
||||
{
|
||||
float delta = 0.001f * (mouse_x - down_mouse_x + mouse_y - down_mouse_y);
|
||||
core.camera_zoom *= 1 + delta;
|
||||
down_mouse_x = mouse_x;
|
||||
down_mouse_y = mouse_y;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IGL_INLINE bool Viewer::mouse_scroll(float delta_y)
|
||||
{
|
||||
scroll_position += delta_y;
|
||||
|
||||
if (callback_mouse_scroll)
|
||||
if (callback_mouse_scroll(*this,delta_y))
|
||||
return true;
|
||||
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
if (plugins[i]->mouse_scroll(delta_y))
|
||||
return true;
|
||||
|
||||
// Only zoom if there's actually a change
|
||||
if(delta_y != 0)
|
||||
{
|
||||
float mult = (1.0+((delta_y>0)?1.:-1.)*0.05);
|
||||
const float min_zoom = 0.1f;
|
||||
core.camera_zoom = (core.camera_zoom * mult > min_zoom ? core.camera_zoom * mult : min_zoom);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IGL_INLINE bool Viewer::load_scene()
|
||||
{
|
||||
std::string fname = igl::file_dialog_open();
|
||||
if(fname.length() == 0)
|
||||
return false;
|
||||
return load_scene(fname);
|
||||
}
|
||||
|
||||
IGL_INLINE bool Viewer::load_scene(std::string fname)
|
||||
{
|
||||
igl::deserialize(core,"Core",fname.c_str());
|
||||
igl::deserialize(data(),"Data",fname.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
IGL_INLINE bool Viewer::save_scene()
|
||||
{
|
||||
std::string fname = igl::file_dialog_save();
|
||||
if (fname.length() == 0)
|
||||
return false;
|
||||
return save_scene(fname);
|
||||
}
|
||||
|
||||
IGL_INLINE bool Viewer::save_scene(std::string fname)
|
||||
{
|
||||
igl::serialize(core,"Core",fname.c_str(),true);
|
||||
igl::serialize(data(),"Data",fname.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IGL_INLINE void Viewer::draw()
|
||||
{
|
||||
using namespace std;
|
||||
using namespace Eigen;
|
||||
|
||||
int width, height;
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
|
||||
int width_window, height_window;
|
||||
glfwGetWindowSize(window, &width_window, &height_window);
|
||||
|
||||
auto highdpi_tmp = width/width_window;
|
||||
|
||||
if(fabs(highdpi_tmp-highdpi)>1e-8)
|
||||
{
|
||||
post_resize(width, height);
|
||||
highdpi=highdpi_tmp;
|
||||
}
|
||||
|
||||
core.clear_framebuffers();
|
||||
if (callback_pre_draw)
|
||||
{
|
||||
if (callback_pre_draw(*this))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
{
|
||||
if (plugins[i]->pre_draw())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
for(int i = 0;i<data_list.size();i++)
|
||||
{
|
||||
core.draw(data_list[i]);
|
||||
}
|
||||
if (callback_post_draw)
|
||||
{
|
||||
if (callback_post_draw(*this))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
{
|
||||
if (plugins[i]->post_draw())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void Viewer::resize(int w,int h)
|
||||
{
|
||||
if (window) {
|
||||
glfwSetWindowSize(window, w/highdpi, h/highdpi);
|
||||
}
|
||||
post_resize(w, h);
|
||||
}
|
||||
|
||||
IGL_INLINE void Viewer::post_resize(int w,int h)
|
||||
{
|
||||
core.viewport = Eigen::Vector4f(0,0,w,h);
|
||||
for (unsigned int i = 0; i<plugins.size(); ++i)
|
||||
{
|
||||
plugins[i]->post_resize(w, h);
|
||||
}
|
||||
}
|
||||
|
||||
IGL_INLINE void Viewer::snap_to_canonical_quaternion()
|
||||
{
|
||||
Eigen::Quaternionf snapq = this->core.trackball_angle;
|
||||
igl::snap_to_canonical_view_quat(snapq,1.0f,this->core.trackball_angle);
|
||||
}
|
||||
|
||||
IGL_INLINE void Viewer::open_dialog_load_mesh()
|
||||
{
|
||||
std::string fname = igl::file_dialog_open();
|
||||
|
||||
if (fname.length() == 0)
|
||||
return;
|
||||
|
||||
this->load_mesh_from_file(fname.c_str());
|
||||
}
|
||||
|
||||
IGL_INLINE void Viewer::open_dialog_save_mesh()
|
||||
{
|
||||
std::string fname = igl::file_dialog_save();
|
||||
|
||||
if(fname.length() == 0)
|
||||
return;
|
||||
|
||||
this->save_mesh_to_file(fname.c_str());
|
||||
}
|
||||
|
||||
IGL_INLINE ViewerData& Viewer::data()
|
||||
{
|
||||
assert(!data_list.empty() && "data_list should never be empty");
|
||||
assert(
|
||||
(selected_data_index >= 0 && selected_data_index < data_list.size()) &&
|
||||
"selected_data_index should be in bounds");
|
||||
return data_list[selected_data_index];
|
||||
}
|
||||
|
||||
IGL_INLINE int Viewer::append_mesh()
|
||||
{
|
||||
assert(data_list.size() >= 1);
|
||||
|
||||
data_list.emplace_back();
|
||||
selected_data_index = data_list.size()-1;
|
||||
data_list.back().id = next_data_id++;
|
||||
return data_list.back().id;
|
||||
}
|
||||
|
||||
IGL_INLINE bool Viewer::erase_mesh(const size_t index)
|
||||
{
|
||||
assert((index >= 0 && index < data_list.size()) && "index should be in bounds");
|
||||
assert(data_list.size() >= 1);
|
||||
if(data_list.size() == 1)
|
||||
{
|
||||
// Cannot remove last mesh
|
||||
return false;
|
||||
}
|
||||
data_list[index].meshgl.free();
|
||||
data_list.erase(data_list.begin() + index);
|
||||
if(selected_data_index >= index && selected_data_index>0)
|
||||
{
|
||||
selected_data_index--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IGL_INLINE size_t Viewer::mesh_index(const int id) const {
|
||||
for (size_t i = 0; i < data_list.size(); ++i)
|
||||
{
|
||||
if (data_list[i].id == id)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace
|
||||
} // end namespace
|
||||
}
|
||||
178
src/igl/opengl/glfw/Viewer.h
Normal file
178
src/igl/opengl/glfw/Viewer.h
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@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_VIEWER_H
|
||||
#define IGL_OPENGL_GLFW_VIEWER_H
|
||||
|
||||
#ifndef IGL_OPENGL_4
|
||||
#define IGL_OPENGL_4
|
||||
#endif
|
||||
|
||||
#include "../../igl_inline.h"
|
||||
#include "../MeshGL.h"
|
||||
#include "../ViewerCore.h"
|
||||
#include "../ViewerData.h"
|
||||
#include "ViewerPlugin.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
#define IGL_MOD_SHIFT 0x0001
|
||||
#define IGL_MOD_CONTROL 0x0002
|
||||
#define IGL_MOD_ALT 0x0004
|
||||
#define IGL_MOD_SUPER 0x0008
|
||||
|
||||
struct GLFWwindow;
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
namespace glfw
|
||||
{
|
||||
// GLFW-based mesh viewer
|
||||
class Viewer
|
||||
{
|
||||
public:
|
||||
// UI Enumerations
|
||||
enum class MouseButton {Left, Middle, Right};
|
||||
enum class MouseMode { None, Rotation, Zoom, Pan, Translation} mouse_mode;
|
||||
IGL_INLINE int launch(bool resizable = true,bool fullscreen = false);
|
||||
IGL_INLINE int launch_init(bool resizable = true,bool fullscreen = false);
|
||||
IGL_INLINE bool launch_rendering(bool loop = true);
|
||||
IGL_INLINE void launch_shut();
|
||||
IGL_INLINE void init();
|
||||
IGL_INLINE void init_plugins();
|
||||
IGL_INLINE void shutdown_plugins();
|
||||
Viewer();
|
||||
~Viewer();
|
||||
// Mesh IO
|
||||
IGL_INLINE bool load_mesh_from_file(const std::string & mesh_file_name);
|
||||
IGL_INLINE bool save_mesh_to_file(const std::string & mesh_file_name);
|
||||
// Callbacks
|
||||
IGL_INLINE bool key_pressed(unsigned int unicode_key,int modifier);
|
||||
IGL_INLINE bool key_down(int key,int modifier);
|
||||
IGL_INLINE bool key_up(int key,int modifier);
|
||||
IGL_INLINE bool mouse_down(MouseButton button,int modifier);
|
||||
IGL_INLINE bool mouse_up(MouseButton button,int modifier);
|
||||
IGL_INLINE bool mouse_move(int mouse_x,int mouse_y);
|
||||
IGL_INLINE bool mouse_scroll(float delta_y);
|
||||
// Scene IO
|
||||
IGL_INLINE bool load_scene();
|
||||
IGL_INLINE bool load_scene(std::string fname);
|
||||
IGL_INLINE bool save_scene();
|
||||
IGL_INLINE bool save_scene(std::string fname);
|
||||
// Draw everything
|
||||
IGL_INLINE void draw();
|
||||
// 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
|
||||
// Helper functions
|
||||
IGL_INLINE void snap_to_canonical_quaternion();
|
||||
IGL_INLINE void open_dialog_load_mesh();
|
||||
IGL_INLINE void open_dialog_save_mesh();
|
||||
IGL_INLINE ViewerData& data();
|
||||
|
||||
// Append a new "slot" for a mesh (i.e., create empty entires at the end of
|
||||
// the data_list and opengl_state_list.
|
||||
//
|
||||
// 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();
|
||||
|
||||
// Erase a mesh (i.e., its corresponding data and state entires in data_list
|
||||
// and opengl_state_list)
|
||||
//
|
||||
// Inputs:
|
||||
// index index of mesh to erase
|
||||
// Returns whether erasure was successful <=> cannot erase last mesh
|
||||
//
|
||||
// Side Effects:
|
||||
// If selected_data_index is greater than or equal to index then it is
|
||||
// decremented
|
||||
// Example:
|
||||
// // Erase all mesh slots except first and clear remaining mesh
|
||||
// viewer.selected_data_index = viewer.data_list.size()-1;
|
||||
// while(viewer.erase_mesh(viewer.selected_data_index)){};
|
||||
// viewer.data().clear();
|
||||
//
|
||||
IGL_INLINE bool erase_mesh(const size_t index);
|
||||
|
||||
// Retrieve mesh index from its unique identifier
|
||||
// Returns 0 if not found
|
||||
IGL_INLINE size_t mesh_index(const int id) const;
|
||||
|
||||
// Alec: I call this data_list instead of just data to avoid confusion with
|
||||
// old "data" variable.
|
||||
// Stores all the data that should be visualized
|
||||
std::vector<ViewerData> data_list;
|
||||
|
||||
size_t selected_data_index;
|
||||
int next_data_id;
|
||||
GLFWwindow* window;
|
||||
// Stores all the viewing options
|
||||
ViewerCore core;
|
||||
// List of registered plugins
|
||||
std::vector<ViewerPlugin*> plugins;
|
||||
// Temporary data stored when the mouse button is pressed
|
||||
Eigen::Quaternionf down_rotation;
|
||||
int current_mouse_x;
|
||||
int current_mouse_y;
|
||||
int down_mouse_x;
|
||||
int down_mouse_y;
|
||||
float down_mouse_z;
|
||||
Eigen::Vector3f down_translation;
|
||||
bool down;
|
||||
bool hack_never_moved;
|
||||
// Keep track of the global position of the scrollwheel
|
||||
float scroll_position;
|
||||
// C++-style functions
|
||||
//
|
||||
// Returns **true** if action should be cancelled.
|
||||
std::function<bool(Viewer& viewer)> callback_init;
|
||||
std::function<bool(Viewer& viewer)> callback_pre_draw;
|
||||
std::function<bool(Viewer& viewer)> callback_post_draw;
|
||||
std::function<bool(Viewer& viewer, int button, int modifier)> callback_mouse_down;
|
||||
std::function<bool(Viewer& viewer, int button, int modifier)> callback_mouse_up;
|
||||
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;
|
||||
// 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;
|
||||
// Pointers to per-callback data
|
||||
void* callback_init_data;
|
||||
void* callback_pre_draw_data;
|
||||
void* callback_post_draw_data;
|
||||
void* callback_mouse_down_data;
|
||||
void* callback_mouse_up_data;
|
||||
void* callback_mouse_move_data;
|
||||
void* callback_mouse_scroll_data;
|
||||
void* callback_key_pressed_data;
|
||||
void* callback_key_down_data;
|
||||
void* callback_key_up_data;
|
||||
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
} // end namespace
|
||||
} // end namespace
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "Viewer.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
182
src/igl/opengl/glfw/ViewerPlugin.h
Normal file
182
src/igl/opengl/glfw/ViewerPlugin.h
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@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_VIEWERPLUGIN_H
|
||||
#define IGL_OPENGL_GLFW_VIEWERPLUGIN_H
|
||||
|
||||
// TODO:
|
||||
// * create plugins/skeleton.h
|
||||
// * pass time in draw function
|
||||
// * remove Preview3D from comments
|
||||
// * clean comments
|
||||
#include <string>
|
||||
#include <igl/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)
|
||||
{
|
||||
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 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
|
||||
30
src/igl/opengl/glfw/background_window.cpp
Normal file
30
src/igl/opengl/glfw/background_window.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include "background_window.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
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;});
|
||||
glfwWindowHint(GLFW_SAMPLES, 4);
|
||||
// Use 3.2 core profile
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
// Use background window
|
||||
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
|
||||
window = glfwCreateWindow(1, 1,"", NULL, NULL);
|
||||
if(!window) return false;
|
||||
glfwMakeContextCurrent(window);
|
||||
if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress))
|
||||
{
|
||||
printf("Failed to load OpenGL and its extensions");
|
||||
}
|
||||
glGetError(); // pull and safely ignore unhandled errors like GL_INVALID_ENUM
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// Explicit template instantiation
|
||||
#endif
|
||||
34
src/igl/opengl/glfw/background_window.h
Normal file
34
src/igl/opengl/glfw/background_window.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef IGL_OPENGL_GLFW_BACKGROUND_WINDOW_H
|
||||
#define IGL_OPENGL_GLFW_BACKGROUND_WINDOW_H
|
||||
#include "../../igl_inline.h"
|
||||
|
||||
#include "../gl.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
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
|
||||
IGL_INLINE bool background_window(GLFWwindow* & window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "background_window.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
74
src/igl/opengl/glfw/imgui/ImGuiHelpers.h
Normal file
74
src/igl/opengl/glfw/imgui/ImGuiHelpers.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// 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_IMGUIHELPERS_H
|
||||
#define IGL_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <imgui/imgui.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Extend ImGui by populating its namespace directly
|
||||
//
|
||||
// Code snippets taken from there:
|
||||
// https://eliasdaler.github.io/using-imgui-with-sfml-pt2/
|
||||
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;
|
||||
};
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
inline bool InputText(const char* label, std::string &str, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL)
|
||||
{
|
||||
char buf[1024];
|
||||
std::fill_n(buf, 1024, 0);
|
||||
std::copy_n(str.begin(), std::min(1024, (int) str.size()), buf);
|
||||
if (ImGui::InputText(label, buf, 1024, flags, callback, user_data))
|
||||
{
|
||||
str = std::string(buf);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ImGui
|
||||
|
||||
#endif // IGL_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H
|
||||
385
src/igl/opengl/glfw/imgui/ImGuiMenu.cpp
Normal file
385
src/igl/opengl/glfw/imgui/ImGuiMenu.cpp
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
// 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/.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#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 <iostream>
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
namespace glfw
|
||||
{
|
||||
namespace imgui
|
||||
{
|
||||
|
||||
IGL_INLINE void ImGuiMenu::init(igl::opengl::glfw::Viewer *_viewer)
|
||||
{
|
||||
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(); }
|
||||
|
||||
// Other windows
|
||||
if (callback_draw_custom_window) { callback_draw_custom_window(); }
|
||||
else { draw_custom_window(); }
|
||||
}
|
||||
|
||||
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));
|
||||
bool _viewer_menu_visible = true;
|
||||
ImGui::Begin(
|
||||
"Viewer", &_viewer_menu_visible,
|
||||
ImGuiWindowFlags_NoSavedSettings
|
||||
| ImGuiWindowFlags_AlwaysAutoResize
|
||||
);
|
||||
ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.4f);
|
||||
if (callback_draw_viewer_menu) { callback_draw_viewer_menu(); }
|
||||
else { draw_viewer_menu(); }
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
IGL_INLINE void ImGuiMenu::draw_viewer_menu()
|
||||
{
|
||||
// Workspace
|
||||
if (ImGui::CollapsingHeader("Workspace", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
float w = ImGui::GetContentRegionAvailWidth();
|
||||
float p = ImGui::GetStyle().FramePadding.x;
|
||||
if (ImGui::Button("Load##Workspace", ImVec2((w-p)/2.f, 0)))
|
||||
{
|
||||
viewer->load_scene();
|
||||
}
|
||||
ImGui::SameLine(0, p);
|
||||
if (ImGui::Button("Save##Workspace", ImVec2((w-p)/2.f, 0)))
|
||||
{
|
||||
viewer->save_scene();
|
||||
}
|
||||
}
|
||||
|
||||
// Mesh
|
||||
if (ImGui::CollapsingHeader("Mesh", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
float w = ImGui::GetContentRegionAvailWidth();
|
||||
float p = ImGui::GetStyle().FramePadding.x;
|
||||
if (ImGui::Button("Load##Mesh", ImVec2((w-p)/2.f, 0)))
|
||||
{
|
||||
viewer->open_dialog_load_mesh();
|
||||
}
|
||||
ImGui::SameLine(0, p);
|
||||
if (ImGui::Button("Save##Mesh", ImVec2((w-p)/2.f, 0)))
|
||||
{
|
||||
viewer->open_dialog_save_mesh();
|
||||
}
|
||||
}
|
||||
|
||||
// Viewing options
|
||||
if (ImGui::CollapsingHeader("Viewing Options", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
if (ImGui::Button("Center object", ImVec2(-1, 0)))
|
||||
{
|
||||
viewer->core.align_camera_center(viewer->data().V, viewer->data().F);
|
||||
}
|
||||
if (ImGui::Button("Snap canonical view", ImVec2(-1, 0)))
|
||||
{
|
||||
viewer->snap_to_canonical_quaternion();
|
||||
}
|
||||
|
||||
// Zoom
|
||||
ImGui::PushItemWidth(80 * menu_scaling());
|
||||
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);
|
||||
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 == 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;
|
||||
}
|
||||
else if (viewer->core.rotation_type == RT::ROTATION_TYPE_NO_ROTATION)
|
||||
{
|
||||
viewer->core.trackball_angle = trackball_angle;
|
||||
viewer->core.orthographic = orthographic;
|
||||
}
|
||||
viewer->core.set_rotation_type(new_type);
|
||||
}
|
||||
}
|
||||
|
||||
// Orthographic view
|
||||
ImGui::Checkbox("Orthographic view", &(viewer->core.orthographic));
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
ImGui::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(),
|
||||
ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_PickerHueWheel);
|
||||
ImGui::ColorEdit4("Line color", viewer->data().line_color.data(),
|
||||
ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_PickerHueWheel);
|
||||
ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.3f);
|
||||
ImGui::DragFloat("Shininess", &(viewer->data().shininess), 0.05f, 0.0f, 100.0f);
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
} // end namespace
|
||||
} // end namespace
|
||||
110
src/igl/opengl/glfw/imgui/ImGuiMenu.h
Normal file
110
src/igl/opengl/glfw/imgui/ImGuiMenu.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
// 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_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;
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
namespace glfw
|
||||
{
|
||||
namespace imgui
|
||||
{
|
||||
|
||||
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
|
||||
211
src/igl/opengl/glfw/map_texture.cpp
Normal file
211
src/igl/opengl/glfw/map_texture.cpp
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
#ifdef IGL_OPENGL_4
|
||||
|
||||
#include "map_texture.h"
|
||||
#include "background_window.h"
|
||||
#include "../create_shader_program.h"
|
||||
|
||||
#include "../gl.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
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 unsigned char * in_data,
|
||||
const int w,
|
||||
const int h,
|
||||
const int nc,
|
||||
std::vector<unsigned char> & out_data)
|
||||
{
|
||||
int out_w = w;
|
||||
int out_h = h;
|
||||
int out_nc = nc;
|
||||
return map_texture(_V,_F,_U,in_data,w,h,nc,out_data,out_w,out_h,out_nc);
|
||||
}
|
||||
|
||||
|
||||
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 unsigned char * in_data,
|
||||
const int w,
|
||||
const int h,
|
||||
const int nc,
|
||||
std::vector<unsigned char> & out_data,
|
||||
int & out_w,
|
||||
int & out_h,
|
||||
int & out_nc)
|
||||
{
|
||||
const auto fail = [](const std::string msg)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
// 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
|
||||
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.);
|
||||
}
|
||||
)"
|
||||
;
|
||||
std::string fragment_shader = R"(
|
||||
#version 330 core
|
||||
layout(location = 0) out vec3 color;
|
||||
uniform sampler2D tex;
|
||||
in vec2 tex_coord_f;
|
||||
void main()
|
||||
{
|
||||
color = texture(tex,tex_coord_f).rgb;
|
||||
}
|
||||
)";
|
||||
GLuint prog_id =
|
||||
igl::opengl::create_shader_program(vertex_shader,fragment_shader,{});
|
||||
glUniform1i(glGetUniformLocation(prog_id, "tex"),0);
|
||||
// Generate and attach buffers to vertex array
|
||||
glDisable(GL_CULL_FACE);
|
||||
GLuint VAO = 0;
|
||||
glGenVertexArrays(1,&VAO);
|
||||
glBindVertexArray(VAO);
|
||||
GLuint ibo,vbo,tbo;
|
||||
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);
|
||||
}
|
||||
// Prepare framebuffer
|
||||
GLuint fb = 0;
|
||||
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);
|
||||
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);
|
||||
{
|
||||
GLenum bufs[1] = {GL_COLOR_ATTACHMENT0};
|
||||
glDrawBuffers(1, bufs);
|
||||
}
|
||||
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
fail("framebuffer setup failed.");
|
||||
}
|
||||
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
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glBindVertexArray(VAO);
|
||||
glDrawElements(GL_TRIANGLES, F.size(), GL_UNSIGNED_INT, 0);
|
||||
glBindVertexArray(0);
|
||||
// Write into memory
|
||||
assert(out_nc == 3);
|
||||
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
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
// 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> >&);
|
||||
#endif
|
||||
|
||||
#endif // IGL_OPENGL_4
|
||||
63
src/igl/opengl/glfw/map_texture.h
Normal file
63
src/igl/opengl/glfw/map_texture.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#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>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
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);
|
||||
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,
|
||||
int & out_w,
|
||||
int & out_h,
|
||||
int & out_nc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "map_texture.cpp"
|
||||
#endif
|
||||
|
||||
#endif // IGL_OPENGL_4
|
||||
|
||||
#endif
|
||||
86
src/igl/opengl/init_render_to_texture.cpp
Normal file
86
src/igl/opengl/init_render_to_texture.cpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 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 "init_render_to_texture.h"
|
||||
#include "gl.h"
|
||||
#include <cassert>
|
||||
|
||||
IGL_INLINE void igl::opengl::init_render_to_texture(
|
||||
const size_t width,
|
||||
const size_t height,
|
||||
const bool depth_texture,
|
||||
GLuint & tex_id,
|
||||
GLuint & fbo_id,
|
||||
GLuint & d_id)
|
||||
{
|
||||
using namespace std;
|
||||
// http://www.opengl.org/wiki/Framebuffer_Object_Examples#Quick_example.2C_render_to_texture_.282D.29
|
||||
const auto & gen_tex = [](GLuint & tex_id)
|
||||
{
|
||||
glGenTextures(1, &tex_id);
|
||||
glBindTexture(GL_TEXTURE_2D, tex_id);
|
||||
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);
|
||||
};
|
||||
gen_tex(tex_id);
|
||||
//NULL means reserve texture memory, but texels are undefined
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_BGRA, GL_FLOAT, NULL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glGenFramebuffers(1, &fbo_id);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id);
|
||||
//Attach 2D texture to this FBO
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex_id, 0);
|
||||
if(depth_texture)
|
||||
{
|
||||
// Generate a depth texture
|
||||
gen_tex(d_id);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_DEPTH_COMPONENT32,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
GL_DEPTH_COMPONENT,
|
||||
GL_FLOAT,
|
||||
NULL);
|
||||
glFramebufferTexture2D(
|
||||
GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D,d_id,0);
|
||||
}else
|
||||
{
|
||||
// Attach a depth buffer
|
||||
glGenRenderbuffers(1, &d_id);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, d_id);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT24,width,height);
|
||||
glFramebufferRenderbuffer(
|
||||
GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,d_id);
|
||||
}
|
||||
|
||||
//Does the GPU support current FBO configuration?
|
||||
GLenum status;
|
||||
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
assert(status == GL_FRAMEBUFFER_COMPLETE);
|
||||
// Unbind to clean up
|
||||
if(!depth_texture)
|
||||
{
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
IGL_INLINE void igl::opengl::init_render_to_texture(
|
||||
const size_t width,
|
||||
const size_t height,
|
||||
GLuint & tex_id,
|
||||
GLuint & fbo_id,
|
||||
GLuint & dfbo_id)
|
||||
{
|
||||
return init_render_to_texture(width,height,false,tex_id,fbo_id,dfbo_id);
|
||||
}
|
||||
77
src/igl/opengl/init_render_to_texture.h
Normal file
77
src/igl/opengl/init_render_to_texture.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2015 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_INIT_RENDER_TO_TEXTURE_H
|
||||
#define IGL_OPENGL_INIT_RENDER_TO_TEXTURE_H
|
||||
#include "../igl_inline.h"
|
||||
#include "gl.h"
|
||||
#include <cstdlib>
|
||||
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
|
||||
//
|
||||
IGL_INLINE void init_render_to_texture(
|
||||
const size_t width,
|
||||
const size_t height,
|
||||
const bool depth_texture,
|
||||
GLuint & tex_id,
|
||||
GLuint & fbo_id,
|
||||
GLuint & d_id);
|
||||
// Wrapper with depth_texture = false for legacy reasons
|
||||
IGL_INLINE void init_render_to_texture(
|
||||
const size_t width,
|
||||
const size_t height,
|
||||
GLuint & tex_id,
|
||||
GLuint & fbo_id,
|
||||
GLuint & dfbo_id);
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "init_render_to_texture.cpp"
|
||||
#endif
|
||||
#endif
|
||||
34
src/igl/opengl/load_shader.cpp
Normal file
34
src/igl/opengl/load_shader.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// 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 "load_shader.h"
|
||||
|
||||
// Copyright Denis Kovacs 4/10/08
|
||||
#include "print_shader_info_log.h"
|
||||
#include <cstdio>
|
||||
IGL_INLINE GLuint igl::opengl::load_shader(
|
||||
const std::string & src,const GLenum type)
|
||||
{
|
||||
if(src.empty())
|
||||
{
|
||||
return (GLuint) 0;
|
||||
}
|
||||
|
||||
GLuint s = glCreateShader(type);
|
||||
if(s == 0)
|
||||
{
|
||||
fprintf(stderr,"Error: load_shader() failed to create shader.\n");
|
||||
return 0;
|
||||
}
|
||||
// Pass shader source string
|
||||
const char *c = src.c_str();
|
||||
glShaderSource(s, 1, &c, NULL);
|
||||
glCompileShader(s);
|
||||
// Print info log (if any)
|
||||
igl::opengl::print_shader_info_log(s);
|
||||
return s;
|
||||
}
|
||||
38
src/igl/opengl/load_shader.h
Normal file
38
src/igl/opengl/load_shader.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// 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_LOAD_SHADER_H
|
||||
#define IGL_OPENGL_LOAD_SHADER_H
|
||||
#include "../igl_inline.h"
|
||||
#include "gl.h"
|
||||
#include <string>
|
||||
|
||||
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.
|
||||
IGL_INLINE GLuint load_shader(
|
||||
const std::string & src,const GLenum type);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "load_shader.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
28
src/igl/opengl/print_program_info_log.cpp
Normal file
28
src/igl/opengl/print_program_info_log.cpp
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// 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 "print_program_info_log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <stdlib.h>
|
||||
// Copyright Denis Kovacs 4/10/08
|
||||
IGL_INLINE void igl::opengl::print_program_info_log(const GLuint obj)
|
||||
{
|
||||
GLint infologLength = 0;
|
||||
GLint charsWritten = 0;
|
||||
char *infoLog;
|
||||
|
||||
glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
|
||||
|
||||
if (infologLength > 0)
|
||||
{
|
||||
infoLog = (char *)malloc(infologLength);
|
||||
glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
|
||||
printf("%s\n",infoLog);
|
||||
free(infoLog);
|
||||
}
|
||||
}
|
||||
27
src/igl/opengl/print_program_info_log.h
Normal file
27
src/igl/opengl/print_program_info_log.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// 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_PRINT_PROGRAM_INFO_LOG_H
|
||||
#define IGL_OPENGL_PRINT_PROGRAM_INFO_LOG_H
|
||||
#include "../igl_inline.h"
|
||||
#include "gl.h"
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Inputs:
|
||||
// obj OpenGL index of program to print info log about
|
||||
IGL_INLINE void print_program_info_log(const GLuint obj);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "print_program_info_log.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
29
src/igl/opengl/print_shader_info_log.cpp
Normal file
29
src/igl/opengl/print_shader_info_log.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// 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 "print_shader_info_log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <stdlib.h>
|
||||
// Copyright Denis Kovacs 4/10/08
|
||||
IGL_INLINE void igl::opengl::print_shader_info_log(const GLuint obj)
|
||||
{
|
||||
GLint infologLength = 0;
|
||||
GLint charsWritten = 0;
|
||||
char *infoLog;
|
||||
|
||||
// Get shader info log from opengl
|
||||
glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
|
||||
// Only print if there is something in the log
|
||||
if (infologLength > 0)
|
||||
{
|
||||
infoLog = (char *)malloc(infologLength);
|
||||
glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
|
||||
printf("%s\n",infoLog);
|
||||
free(infoLog);
|
||||
}
|
||||
}
|
||||
27
src/igl/opengl/print_shader_info_log.h
Normal file
27
src/igl/opengl/print_shader_info_log.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// 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_PRINT_SHADER_INFO_LOG_H
|
||||
#define IGL_OPENGL_PRINT_SHADER_INFO_LOG_H
|
||||
#include "../igl_inline.h"
|
||||
#include "gl.h"
|
||||
|
||||
namespace igl
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
// Inputs:
|
||||
// obj OpenGL index of shader to print info log about
|
||||
IGL_INLINE void print_shader_info_log(const GLuint obj);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "print_shader_info_log.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
61
src/igl/opengl/report_gl_error.cpp
Normal file
61
src/igl/opengl/report_gl_error.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// 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 "report_gl_error.h"
|
||||
#include "../verbose.h"
|
||||
#include <cstdio>
|
||||
|
||||
IGL_INLINE GLenum igl::opengl::report_gl_error(const std::string id)
|
||||
{
|
||||
// http://stackoverflow.com/q/28485180/148668
|
||||
|
||||
// gluErrorString was deprecated
|
||||
const auto gluErrorString = [](GLenum errorCode)->const char *
|
||||
{
|
||||
switch(errorCode)
|
||||
{
|
||||
default:
|
||||
return "unknown error code";
|
||||
case GL_NO_ERROR:
|
||||
return "no error";
|
||||
case GL_INVALID_ENUM:
|
||||
return "invalid enumerant";
|
||||
case GL_INVALID_VALUE:
|
||||
return "invalid value";
|
||||
case GL_INVALID_OPERATION:
|
||||
return "invalid operation";
|
||||
#ifndef GL_VERSION_3_0
|
||||
case GL_STACK_OVERFLOW:
|
||||
return "stack overflow";
|
||||
case GL_STACK_UNDERFLOW:
|
||||
return "stack underflow";
|
||||
case GL_TABLE_TOO_LARGE:
|
||||
return "table too large";
|
||||
#endif
|
||||
case GL_OUT_OF_MEMORY:
|
||||
return "out of memory";
|
||||
#ifdef GL_EXT_framebuffer_object
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
|
||||
return "invalid framebuffer operation";
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
GLenum err = glGetError();
|
||||
if(GL_NO_ERROR != err)
|
||||
{
|
||||
verbose("GL_ERROR: ");
|
||||
fprintf(stderr,"%s%s\n",id.c_str(),gluErrorString(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
IGL_INLINE GLenum igl::opengl::report_gl_error()
|
||||
{
|
||||
return igl::opengl::report_gl_error(std::string(""));
|
||||
}
|
||||
|
||||
36
src/igl/opengl/report_gl_error.h
Normal file
36
src/igl/opengl/report_gl_error.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// 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_REPORT_GL_ERROR_H
|
||||
#define IGL_OPENGL_REPORT_GL_ERROR_H
|
||||
#include "../igl_inline.h"
|
||||
|
||||
// Hack to allow both opengl/ and opengl2 to use this (we shouldn't allow this)
|
||||
#ifndef __gl_h_
|
||||
# include "gl.h"
|
||||
#endif
|
||||
#include <string>
|
||||
|
||||
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()
|
||||
IGL_INLINE GLenum report_gl_error(const std::string id);
|
||||
// No prefix
|
||||
IGL_INLINE GLenum report_gl_error();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "report_gl_error.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
71
src/igl/opengl/uniform_type_to_string.cpp
Normal file
71
src/igl/opengl/uniform_type_to_string.cpp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// 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 "uniform_type_to_string.h"
|
||||
|
||||
IGL_INLINE std::string igl::opengl::uniform_type_to_string(const GLenum type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case GL_FLOAT:
|
||||
return "GL_FLOAT";
|
||||
case GL_FLOAT_VEC2:
|
||||
return "GL_FLOAT_VEC2";
|
||||
case GL_FLOAT_VEC3:
|
||||
return "GL_FLOAT_VEC3";
|
||||
case GL_FLOAT_VEC4:
|
||||
return "GL_FLOAT_VEC4";
|
||||
case GL_INT:
|
||||
return "GL_INT";
|
||||
case GL_INT_VEC2:
|
||||
return "GL_INT_VEC2";
|
||||
case GL_INT_VEC3:
|
||||
return "GL_INT_VEC3";
|
||||
case GL_INT_VEC4:
|
||||
return "GL_INT_VEC4";
|
||||
case GL_BOOL:
|
||||
return "GL_BOOL";
|
||||
case GL_BOOL_VEC2:
|
||||
return "GL_BOOL_VEC2";
|
||||
case GL_BOOL_VEC3:
|
||||
return "GL_BOOL_VEC3";
|
||||
case GL_BOOL_VEC4:
|
||||
return "GL_BOOL_VEC4";
|
||||
case GL_FLOAT_MAT2:
|
||||
return "GL_FLOAT_MAT2";
|
||||
case GL_FLOAT_MAT3:
|
||||
return "GL_FLOAT_MAT3";
|
||||
case GL_FLOAT_MAT4:
|
||||
return "GL_FLOAT_MAT4";
|
||||
case GL_FLOAT_MAT2x3:
|
||||
return "GL_FLOAT_MAT2x3";
|
||||
case GL_FLOAT_MAT2x4:
|
||||
return "GL_FLOAT_MAT2x4";
|
||||
case GL_FLOAT_MAT3x2:
|
||||
return "GL_FLOAT_MAT3x2";
|
||||
case GL_FLOAT_MAT3x4:
|
||||
return "GL_FLOAT_MAT3x4";
|
||||
case GL_FLOAT_MAT4x2:
|
||||
return "GL_FLOAT_MAT4x2";
|
||||
case GL_FLOAT_MAT4x3:
|
||||
return "GL_FLOAT_MAT4x3";
|
||||
case GL_SAMPLER_1D:
|
||||
return "GL_SAMPLER_1D";
|
||||
case GL_SAMPLER_2D:
|
||||
return "GL_SAMPLER_2D";
|
||||
case GL_SAMPLER_3D:
|
||||
return "GL_SAMPLER_3D";
|
||||
case GL_SAMPLER_CUBE:
|
||||
return "GL_SAMPLER_CUBE";
|
||||
case GL_SAMPLER_1D_SHADOW:
|
||||
return "GL_SAMPLER_1D_SHADOW";
|
||||
case GL_SAMPLER_2D_SHADOW:
|
||||
return "GL_SAMPLER_2D_SHADOW";
|
||||
default:
|
||||
return "UNKNOWN_TYPE";
|
||||
}
|
||||
}
|
||||
31
src/igl/opengl/uniform_type_to_string.h
Normal file
31
src/igl/opengl/uniform_type_to_string.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// 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_UNIFORM_TYPE_TO_STRING_H
|
||||
#define IGL_OPENGL_UNIFORM_TYPE_TO_STRING_H
|
||||
#include "../igl_inline.h"
|
||||
#include "gl.h"
|
||||
#include <string>
|
||||
|
||||
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
|
||||
IGL_INLINE std::string uniform_type_to_string(const GLenum type);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "uniform_type_to_string.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
61
src/igl/opengl/vertex_array.cpp
Normal file
61
src/igl/opengl/vertex_array.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#include "vertex_array.h"
|
||||
#include <igl/opengl/report_gl_error.h>
|
||||
|
||||
template <
|
||||
typename DerivedV,
|
||||
typename DerivedF>
|
||||
IGL_INLINE void igl::opengl::vertex_array(
|
||||
const Eigen::PlainObjectBase<DerivedV> & V,
|
||||
const Eigen::PlainObjectBase<DerivedF> & F,
|
||||
GLuint & va_id,
|
||||
GLuint & ab_id,
|
||||
GLuint & eab_id)
|
||||
{
|
||||
// Inputs should be in RowMajor storage. If not, we have no choice but to
|
||||
// create a copy.
|
||||
if(!(V.Options & Eigen::RowMajor))
|
||||
{
|
||||
Eigen::Matrix<
|
||||
typename DerivedV::Scalar,
|
||||
DerivedV::RowsAtCompileTime,
|
||||
DerivedV::ColsAtCompileTime,
|
||||
Eigen::RowMajor> VR = V;
|
||||
return vertex_array(VR,F,va_id,ab_id,eab_id);
|
||||
}
|
||||
if(!(F.Options & Eigen::RowMajor))
|
||||
{
|
||||
Eigen::Matrix<
|
||||
typename DerivedF::Scalar,
|
||||
DerivedF::RowsAtCompileTime,
|
||||
DerivedF::ColsAtCompileTime,
|
||||
Eigen::RowMajor> FR = F;
|
||||
return vertex_array(V,FR,va_id,ab_id,eab_id);
|
||||
}
|
||||
// Generate and attach buffers to vertex array
|
||||
glGenVertexArrays(1, &va_id);
|
||||
glGenBuffers(1, &ab_id);
|
||||
glGenBuffers(1, &eab_id);
|
||||
glBindVertexArray(va_id);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ab_id);
|
||||
const auto size_VScalar = sizeof(typename DerivedV::Scalar);
|
||||
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");
|
||||
glBufferData(
|
||||
GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*F.size(), F.data(), GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(
|
||||
0,
|
||||
V.cols(),
|
||||
size_VScalar==sizeof(float)?GL_FLOAT:GL_DOUBLE,
|
||||
GL_FALSE,
|
||||
V.cols()*size_VScalar,
|
||||
(GLvoid*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
#ifdef IGL_STATIC_LIBRARY
|
||||
template void igl::opengl::vertex_array<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, unsigned int&, unsigned int&, unsigned int&);
|
||||
#endif
|
||||
38
src/igl/opengl/vertex_array.h
Normal file
38
src/igl/opengl/vertex_array.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef IGL_OPENGL_VERTEX_ARRAY_H
|
||||
#define IGL_OPENGL_VERTEX_ARRAY_H
|
||||
#include <igl/opengl/../igl_inline.h>
|
||||
#include <igl/opengl/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)
|
||||
//
|
||||
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,
|
||||
GLuint & ab_id,
|
||||
GLuint & eab_id);
|
||||
}
|
||||
}
|
||||
#ifndef IGL_STATIC_LIBRARY
|
||||
# include "vertex_array.cpp"
|
||||
#endif
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue