mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-11-29 13:51:06 -07:00
Building igl statically and moving to the dep scripts
Fixing dep build script on Windows and removing some warnings. Use bundled igl by default. Not building with the dependency scripts if not explicitly stated. This way, it will stay in Fix the libigl patch to include C source files in header only mode.
This commit is contained in:
parent
89e39e3895
commit
2ae2672ee9
1095 changed files with 181 additions and 5 deletions
313
src/libigl/igl/opengl/MeshGL.cpp
Normal file
313
src/libigl/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/libigl/igl/opengl/MeshGL.h
Normal file
133
src/libigl/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/libigl/igl/opengl/ViewerCore.cpp
Normal file
391
src/libigl/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/libigl/igl/opengl/ViewerCore.h
Normal file
199
src/libigl/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/libigl/igl/opengl/ViewerData.cpp
Normal file
691
src/libigl/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/libigl/igl/opengl/ViewerData.h
Normal file
276
src/libigl/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/libigl/igl/opengl/bind_vertex_attrib_array.cpp
Normal file
24
src/libigl/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/libigl/igl/opengl/bind_vertex_attrib_array.h
Normal file
32
src/libigl/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/libigl/igl/opengl/create_index_vbo.cpp
Normal file
46
src/libigl/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/libigl/igl/opengl/create_index_vbo.h
Normal file
35
src/libigl/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/libigl/igl/opengl/create_mesh_vbo.cpp
Normal file
43
src/libigl/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/libigl/igl/opengl/create_mesh_vbo.h
Normal file
61
src/libigl/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/libigl/igl/opengl/create_shader_program.cpp
Normal file
141
src/libigl/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/libigl/igl/opengl/create_shader_program.h
Normal file
64
src/libigl/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/libigl/igl/opengl/create_vector_vbo.cpp
Normal file
57
src/libigl/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/libigl/igl/opengl/create_vector_vbo.h
Normal file
38
src/libigl/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/libigl/igl/opengl/destroy_shader_program.cpp
Normal file
50
src/libigl/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/libigl/igl/opengl/destroy_shader_program.h
Normal file
35
src/libigl/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/libigl/igl/opengl/gl.h
Normal file
25
src/libigl/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/libigl/igl/opengl/gl_type_size.cpp
Normal file
30
src/libigl/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/libigl/igl/opengl/gl_type_size.h
Normal file
28
src/libigl/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/libigl/igl/opengl/glfw/Viewer.cpp
Normal file
950
src/libigl/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/libigl/igl/opengl/glfw/Viewer.h
Normal file
178
src/libigl/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/libigl/igl/opengl/glfw/ViewerPlugin.h
Normal file
182
src/libigl/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/libigl/igl/opengl/glfw/background_window.cpp
Normal file
30
src/libigl/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/libigl/igl/opengl/glfw/background_window.h
Normal file
34
src/libigl/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/libigl/igl/opengl/glfw/imgui/ImGuiHelpers.h
Normal file
74
src/libigl/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/libigl/igl/opengl/glfw/imgui/ImGuiMenu.cpp
Normal file
385
src/libigl/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/libigl/igl/opengl/glfw/imgui/ImGuiMenu.h
Normal file
110
src/libigl/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/libigl/igl/opengl/glfw/map_texture.cpp
Normal file
211
src/libigl/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/libigl/igl/opengl/glfw/map_texture.h
Normal file
63
src/libigl/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/libigl/igl/opengl/init_render_to_texture.cpp
Normal file
86
src/libigl/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/libigl/igl/opengl/init_render_to_texture.h
Normal file
77
src/libigl/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/libigl/igl/opengl/load_shader.cpp
Normal file
34
src/libigl/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/libigl/igl/opengl/load_shader.h
Normal file
38
src/libigl/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/libigl/igl/opengl/print_program_info_log.cpp
Normal file
28
src/libigl/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/libigl/igl/opengl/print_program_info_log.h
Normal file
27
src/libigl/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/libigl/igl/opengl/print_shader_info_log.cpp
Normal file
29
src/libigl/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/libigl/igl/opengl/print_shader_info_log.h
Normal file
27
src/libigl/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/libigl/igl/opengl/report_gl_error.cpp
Normal file
61
src/libigl/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/libigl/igl/opengl/report_gl_error.h
Normal file
36
src/libigl/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/libigl/igl/opengl/uniform_type_to_string.cpp
Normal file
71
src/libigl/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/libigl/igl/opengl/uniform_type_to_string.h
Normal file
31
src/libigl/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/libigl/igl/opengl/vertex_array.cpp
Normal file
61
src/libigl/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/libigl/igl/opengl/vertex_array.h
Normal file
38
src/libigl/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