33#error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library"
37#include <easy3d/core/model.h>
38#include <easy3d/core/surface_mesh.h>
39#include <easy3d/core/graph.h>
40#include <easy3d/core/point_cloud.h>
41#include <easy3d/core/poly_mesh.h>
42#include <easy3d/renderer/opengl.h>
43#include <easy3d/renderer/opengl_util.h>
44#include <easy3d/renderer/opengl_error.h>
45#include <easy3d/renderer/renderer.h>
46#include <easy3d/renderer/manipulator.h>
47#include <easy3d/renderer/shader_program.h>
48#include <easy3d/renderer/shader_manager.h>
49#include <easy3d/renderer/transform.h>
50#include <easy3d/renderer/shape.h>
51#include <easy3d/renderer/camera.h>
52#include <easy3d/renderer/manipulated_camera_frame.h>
53#include <easy3d/renderer/drawable_points.h>
54#include <easy3d/renderer/drawable_lines.h>
55#include <easy3d/renderer/drawable_triangles.h>
56#include <easy3d/renderer/text_renderer.h>
57#include <easy3d/renderer/texture_manager.h>
58#include <easy3d/renderer/framebuffer_object.h>
59#include <easy3d/fileio/point_cloud_io.h>
60#include <easy3d/fileio/graph_io.h>
61#include <easy3d/fileio/surface_mesh_io.h>
62#include <easy3d/fileio/poly_mesh_io.h>
63#include <easy3d/fileio/ply_reader_writer.h>
64#include <easy3d/fileio/point_cloud_io_ptx.h>
65#include <easy3d/util/resource.h>
66#include <easy3d/util/file_system.h>
67#include <easy3d/util/setting.h>
75 wxBEGIN_EVENT_TABLE(Viewer, wxGLCanvas)
76 EVT_SIZE(Viewer::OnSize)
77 EVT_PAINT(Viewer::OnPaint)
78 EVT_MOUSE_EVENTS(Viewer::OnMouse)
79 EVT_KEY_DOWN(Viewer::OnKeyDown)
84 const wxGLAttributes& glAttrs,
89 const wxString &title)
90 : wxGLCanvas(parent, glAttrs,
id, pos, size, style | wxFULL_REPAINT_ON_RESIZE, title)
94 , drawable_axes_(
nullptr)
102 const int gl_major = 3;
103 const int gl_minor = 2;
104 VLOG(1) <<
"OpenGL version requested: " << gl_major <<
"." << gl_minor;
106 wxGLContextAttrs ctxAttrs;
107 ctxAttrs.PlatformDefaults().CoreProfile().OGLVersion(gl_major, gl_minor).EndList();
108 gl_context_ =
new wxGLContext(
this,
nullptr, &ctxAttrs);
110 if (!gl_context_->IsOK()) {
111 LOG(ERROR) <<
"OpenGL version error. This app needs an OpenGL 3.2 capable driver.";
113 gl_context_ =
nullptr;
117 camera_ =
new Camera;
118 camera_->setType(Camera::PERSPECTIVE);
119 camera_->setUpVector(
vec3(0, 0, 1));
120 camera_->setViewDirection(
vec3(-1, 0, 0));
121 camera_->showEntireScene();
129 delete drawable_axes_;
134 ShaderManager::terminate();
138 LOG(INFO) <<
"viewer terminated. Bye!";
142 void Viewer::init() {
144 if (OpenglUtil::init()) {
151 opengl::setup_gl_debug_callback();
153 VLOG(1) <<
"OpenGL vendor: " << glGetString(GL_VENDOR);
154 VLOG(1) <<
"OpenGL renderer: " << glGetString(GL_RENDERER);
155 VLOG(1) <<
"OpenGL version received: " << glGetString(GL_VERSION);
156 VLOG(1) <<
"GLSL version received: " << glGetString(GL_SHADING_LANGUAGE_VERSION);
157 VLOG(1) <<
"Number of samplers per pixel: " << OpenglUtil::samples();
159 glEnable(GL_DEPTH_TEST);
160 glDepthFunc(GL_LESS);
162 glDepthRange(0.0f, 1.0f);
164 glClearColor(background_color_[0], background_color_[1], background_color_[2], background_color_[3]);
169 GetClientSize(&w, &h);
171 glViewport(0, 0,
static_cast<int>(
static_cast<float>(w) *
dpi_scaling()),
static_cast<int>(
static_cast<float>(h) *
dpi_scaling()));
181 auto mesh =
new SurfaceMesh;
182 mesh->set_name(
"bunny");
183 for (
const auto& p : points)
185 for (std::size_t i=0; i<indices.size(); i+=3)
186 mesh->add_triangle(SurfaceMesh::Vertex(
static_cast<int>(indices[i])), SurfaceMesh::Vertex(
static_cast<int>(indices[i+1])), SurfaceMesh::Vertex(
static_cast<int>(indices[i+2])));
189 LOG(INFO) <<
"program initialized by creating a SurfaceMesh of the bunny model";
195 for (
auto m : models_) {
196 delete m->renderer();
197 delete m->manipulator();
202 for (
auto d : drawables_)
209 const_cast<Viewer*
>(
this)->Refresh();
213 void Viewer::OnPaint(wxPaintEvent & WXUNUSED(event)) {
217 SetCurrent(*gl_context_);
237 void Viewer::OnSize(wxSizeEvent & event) {
239 auto size =
event.GetSize();
240 const int w = size.GetWidth();
241 const int h = size.GetHeight();
243 glViewport(0, 0,
static_cast<int>(
static_cast<float>(w) *
dpi_scaling()),
static_cast<int>(
static_cast<float>(h) *
dpi_scaling()));
247 void Viewer::OnMouse(wxMouseEvent &event) {
248 static bool left_down =
false, right_down =
false;
249 static int prev_x =
event.GetX(), prev_y =
event.GetY();
251 if (event.ButtonDown(wxMOUSE_BTN_ANY)) {
253 if (event.LeftDown()) left_down =
true;
254 else if (event.RightDown()) right_down =
true;
256 else if (event.ButtonUp(wxMOUSE_BTN_ANY)) {
258 if (event.LeftUp()) left_down =
false;
259 else if (event.RightUp()) right_down =
false;
261 else if (event.Dragging()) {
262 const int x =
event.GetX();
263 const int y =
event.GetY();
264 const int dx = x - prev_x;
265 const int dy = y - prev_y;
269 camera_->
frame()->
action_translate(x, y, dx, dy, camera_, ManipulatedFrame::NONE);
272 const int rot =
event.GetWheelRotation();
274 camera_->
frame()->
action_zoom(rot > 0 ? 1 : -1, camera_);
277 prev_x =
event.GetX();
278 prev_y =
event.GetY();
282 void Viewer::OnKeyDown(wxKeyEvent &event) {
283 if (event.GetUnicodeKey() == wxKeyCode(
'A') && event.GetModifiers() == wxMOD_NONE) {
285 drawable_axes_->
set_visible(!drawable_axes_->
is_visible());
287 else if (event.GetUnicodeKey() == wxKeyCode(
'C') && event.GetModifiers() == wxMOD_NONE) {
290 }
else if (event.GetUnicodeKey() == wxKeyCode(
'F') && event.GetModifiers() == wxMOD_NONE) {
292 }
else if (event.GetUnicodeKey() == wxKeyCode(
'M') && event.GetModifiers() == wxMOD_NONE) {
296 d->set_smooth_shading(!d->smooth_shading());
298 }
else if (event.GetUnicodeKey() == wxKeyCode(
'P') && event.GetModifiers() == wxMOD_NONE) {
299 if (camera_->
type() == Camera::PERSPECTIVE)
300 camera_->
setType(Camera::ORTHOGRAPHIC);
302 camera_->
setType(Camera::PERSPECTIVE);
303 }
else if (event.GetUnicodeKey() == WXK_SPACE && event.GetModifiers() == wxMOD_NONE) {
313 else if (event.GetUnicodeKey() == wxKeyCode(
'[') && event.GetModifiers() == wxMOD_NONE) {
314 for (
auto m: models_) {
315 for (
auto d: m->renderer()->lines_drawables()) {
316 float size = d->line_width() - 1.0f;
319 d->set_line_width(size);
323 else if (event.GetUnicodeKey() == wxKeyCode(
']') && event.GetModifiers() == wxMOD_NONE) {
324 for (
auto m: models_) {
325 for (
auto d: m->renderer()->lines_drawables()) {
326 float size = d->line_width() + 1.0f;
327 d->set_line_width(size);
331 else if (event.GetUnicodeKey() == wxKeyCode(
'-') && event.GetModifiers() == wxMOD_NONE) {
332 for (
auto m: models_) {
333 for (
auto d: m->renderer()->points_drawables()) {
334 float size = d->point_size() - 1.0f;
337 d->set_point_size(size);
341 else if (event.GetUnicodeKey() == wxKeyCode(
'=') && event.GetModifiers() == wxMOD_NONE) {
342 for (
auto m: models_) {
343 for (
auto d: m->renderer()->points_drawables()) {
344 float size = d->point_size() + 1.0f;
345 d->set_point_size(size);
349 else if (event.GetUnicodeKey() == wxKeyCode(
',') && event.GetModifiers() == wxMOD_NONE) {
353 model_idx_ = int((model_idx_ - 1 + models_.size()) % models_.size());
354 if (model_idx_ >= 0) {
356 std::cout <<
"current model: " << model_idx_ <<
", " << models_[model_idx_]->name() << std::endl;
359 else if (event.GetUnicodeKey() == wxKeyCode(
'.') && event.GetModifiers() == wxMOD_NONE) {
363 model_idx_ = int((model_idx_ + 1) % models_.size());
364 if (model_idx_ >= 0) {
366 std::cout <<
"current model: " << model_idx_ <<
", " << models_[model_idx_]->name() << std::endl;
369 else if (event.GetUnicodeKey() == WXK_DELETE && event.GetModifiers() == wxMOD_NONE) {
373 else if (event.GetUnicodeKey() == wxKeyCode(
'E') && event.GetModifiers() == wxMOD_NONE) {
377 edges->set_visible(!edges->is_visible());
380 else if (event.GetUnicodeKey() == wxKeyCode(
'V') && event.GetModifiers() == wxMOD_NONE) {
384 vertices->set_visible(!vertices->is_visible());
387 else if (event.GetUnicodeKey() == wxKeyCode(
'B') && event.GetModifiers() == wxMOD_NONE) {
390 auto drawable = mesh->renderer()->get_lines_drawable(
"borders");
392 drawable->set_visible(!drawable->is_visible());
395 else if (event.GetUnicodeKey() == wxKeyCode(
'L') &&
event.GetModifiers() == wxMOD_NONE) {
398 auto drawable = mesh->renderer()->get_points_drawable(
"locks");
400 drawable->set_visible(!drawable->is_visible());
403 else if (event.GetUnicodeKey() == wxKeyCode(
'D') &&
event.GetModifiers() == wxMOD_NONE) {
405 auto &output = std::cout;
410 output <<
"model is a surface mesh. #face: " << std::to_string(model->n_faces())
411 <<
", #vertex: " + std::to_string(model->n_vertices())
412 <<
", #edge: " + std::to_string(model->n_edges()) << std::endl;
415 output <<
"model is a point cloud. #vertex: " + std::to_string(model->n_vertices()) << std::endl;
418 output <<
"model is a graph. #vertex: " + std::to_string(model->n_vertices())
419 <<
", #edge: " + std::to_string(model->n_edges()) << std::endl;
422 if (!
current_model()->renderer()->points_drawables().empty()) {
423 output <<
"points drawables:\n";
424 for (
auto d:
current_model()->renderer()->points_drawables())
425 d->buffer_stats(output);
427 if (!
current_model()->renderer()->lines_drawables().empty()) {
428 output <<
"lines drawables:\n";
430 d->buffer_stats(output);
432 if (!
current_model()->renderer()->triangles_drawables().empty()) {
433 output <<
"triangles drawables:\n";
434 for (
auto d:
current_model()->renderer()->triangles_drawables())
435 d->buffer_stats(output);
442 else if (event.GetUnicodeKey() == wxKeyCode(
'R') && event.GetModifiers() == wxMOD_NONE) {
444 ShaderManager::reload();
452 if (!model && models_.empty() && drawables_.empty()) {
457 auto visual_box = [](
const Model *m) ->
Box3 {
458 Box3 box = m->bounding_box();
459 for (
auto d : m->renderer()->points_drawables()) box.
grow(d->bounding_box());
460 for (
auto d : m->renderer()->lines_drawables()) box.grow(d->bounding_box());
461 for (
auto d : m->renderer()->triangles_drawables()) box.grow(d->bounding_box());
467 box = visual_box(model);
469 for (
auto m : models_)
470 box.grow(visual_box(m));
471 for (
auto d : drawables_)
472 box.grow(d->bounding_box());
475 if (box.is_valid()) {
484 return static_cast<float>(wxWindow::GetContentScaleFactor());
488 Model *
Viewer::add_model(
const std::string &file_path,
bool create_default_drawables) {
490 for (
auto m: models_) {
491 if (m->name() == file_name) {
492 LOG(WARNING) <<
"model has already been added to the viewer: " << file_name;
498 bool is_ply_mesh =
false;
502 Model *model =
nullptr;
503 if ((ext ==
"ply" && is_ply_mesh) || ext ==
"obj" || ext ==
"off" || ext ==
"stl" || ext ==
"sm" ||
504 ext ==
"geojson" || ext ==
"trilist") {
508 }
else if (ext ==
"plm" || ext ==
"pm" || ext ==
"mesh") {
512 io::PointCloudIO_ptx serializer(file_name);
513 PointCloud *cloud =
nullptr;
514 while ((cloud = serializer.load_next())) {
515 model =
add_model(cloud, create_default_drawables);
524 model->set_name(file_name);
525 add_model(model, create_default_drawables);
533 LOG(WARNING) <<
"model is NULL.";
536 for (
auto m: models_) {
538 LOG(WARNING) <<
"model has already been added to the viewer: " << m->
name();
545 int pre_idx = model_idx_;
546 models_.push_back(model);
547 model_idx_ =
static_cast<int>(models_.size()) - 1;
549 if (model_idx_ != pre_idx) {
551 LOG(INFO) <<
"current model: " << model_idx_ <<
", " << models_[model_idx_]->name();
559 LOG(WARNING) <<
"model is NULL.";
563 auto pos = std::find(models_.begin(), models_.end(), model);
564 if (pos != models_.end()) {
565 int pre_idx = model_idx_;
566 const std::string name = model->name();
568 delete model->renderer();
569 delete model->manipulator();
571 model_idx_ =
static_cast<int>(models_.size()) - 1;
572 LOG(INFO) <<
"model deleted: " << name;
574 if (model_idx_ != pre_idx) {
576 LOG(INFO) <<
"current model: " << model_idx_ <<
", " << models_[model_idx_]->name();
580 LOG(WARNING) <<
"no such model: " << model->name();
589 if (model_idx_ < models_.size())
590 return models_[model_idx_];
595 bool Viewer::save_current_model(
const std::string &file_name)
const {
598 LOG(ERROR) <<
"no model exists";
603 if (
dynamic_cast<const PointCloud *
>(m))
605 else if (
dynamic_cast<const SurfaceMesh *
>(m))
607 else if (
dynamic_cast<const Graph *
>(m))
608 saved =
GraphIO::save(file_name,
dynamic_cast<const Graph *
>(m));
611 LOG(INFO) <<
"file successfully saved";
618 SetCurrent(*gl_context_);
623 FramebufferObject fbo(w, h, OpenglUtil::samples());
624 fbo.add_color_buffer();
625 fbo.add_depth_buffer();
630 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
632 glClearColor(background_color_[0], background_color_[1], background_color_[2], background_color_[3]);
633 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
635 const_cast<Viewer *
>(
this)->draw();
640 return fbo.snapshot_color(0, file_name);
643 return fbo.snapshot_depth(file_name);
650 LOG(WARNING) <<
"drawable is NULL.";
653 for (
auto d : drawables_) {
655 LOG(WARNING) <<
"drawable has already been added to the viewer.";
660 drawables_.push_back(drawable);
667 LOG(WARNING) <<
"drawable is NULL";
671 auto pos = std::find(drawables_.begin(), drawables_.end(), drawable);
672 if (pos != drawables_.end()) {
673 drawables_.erase(pos);
677 LOG(WARNING) <<
"no such drawable: " << drawable->name();
683 void Viewer::draw_corner_axes()
const {
684 ShaderProgram *program = ShaderManager::get_program(
"surface/surface");
686 std::vector<ShaderProgram::Attribute> attributes = {
687 ShaderProgram::Attribute(ShaderProgram::POSITION,
"vtx_position"),
688 ShaderProgram::Attribute(ShaderProgram::TEXCOORD,
"vtx_texcoord"),
689 ShaderProgram::Attribute(ShaderProgram::COLOR,
"vtx_color"),
690 ShaderProgram::Attribute(ShaderProgram::NORMAL,
"vtx_normal")
692 program = ShaderManager::create_program_from_files(
"surface/surface", attributes);
697 if (!drawable_axes_) {
700 std::vector<vec3> points, normals, colors;
701 shape::create_cylinder(0.03, 10,
vec3(0, 0, 0),
vec3(base, 0, 0),
vec3(1, 0, 0), points, normals, colors);
702 shape::create_cylinder(0.03, 10,
vec3(0, 0, 0),
vec3(0, base, 0),
vec3(0, 1, 0), points, normals, colors);
703 shape::create_cylinder(0.03, 10,
vec3(0, 0, 0),
vec3(0, 0, base),
vec3(0, 0, 1), points, normals, colors);
704 shape::create_cone(0.06, 20,
vec3(base, 0, 0),
vec3(base + head, 0, 0),
vec3(1, 0, 0), points, normals,
706 shape::create_cone(0.06, 20,
vec3(0, base, 0),
vec3(0, base + head, 0),
vec3(0, 1, 0), points, normals,
708 shape::create_cone(0.06, 20,
vec3(0, 0, base),
vec3(0, 0, base + head),
vec3(0, 0, 1), points, normals,
710 shape::create_sphere(
vec3(0, 0, 0), 0.06, 20, 20,
vec3(0, 1, 1), points, normals, colors);
711 const_cast<Viewer*
>(
this)->drawable_axes_ =
new TrianglesDrawable(
"corner_axes");
713 drawable_axes_->
update_normal_buffer(normals);
714 drawable_axes_->
update_color_buffer(colors);
717 if (!drawable_axes_->is_visible())
722 glGetIntegerv(GL_VIEWPORT,
viewport);
724 static int corner_frame_size =
static_cast<int>(100 *
dpi_scaling());
725 glViewport(0, 0, corner_frame_size, corner_frame_size);
729 glDepthRange(0, 0.01f);
733 const mat4 &MVP = proj * view;
743 program->set_uniform(
"MVP", MVP)
746 ->set_uniform(
"lighting",
true)
747 ->set_uniform(
"two_sides_lighting",
false)
748 ->set_uniform(
"smooth_shading",
true)
749 ->set_uniform(
"wLightPos", wLightPos)
750 ->set_uniform(
"wCamPos", wCamPos)
751 ->set_uniform(
"ssaoEnabled",
false)
752 ->set_uniform(
"per_vertex_color",
true)
753 ->set_uniform(
"distinct_back_color",
false)
755 ->set_block_uniform(
"Material",
"specular", setting::material_specular)
756 ->set_block_uniform(
"Material",
"shininess", &setting::material_shininess)
757 ->set_uniform(
"highlight",
false)
758 ->set_uniform(
"clippingPlaneEnabled",
false)
759 ->set_uniform(
"selected",
false)
761 ->set_uniform(
"use_texture",
false);
767 glDepthRange(0.0f, 1.0f);
771 void Viewer::pre_draw() {
772 glClearColor(background_color_[0], background_color_[1], background_color_[2], 1.0f);
774 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
778 void Viewer::post_draw() {
780 if (texter_ && texter_->
num_fonts() >=2) {
781 const float font_size = 15.0f;
783 texter_->
draw(
"Easy3D", offset, offset, font_size, 0);
791 void Viewer::draw()
const {
794 glEnable(GL_SCISSOR_TEST);
796 glGetIntegerv(GL_VIEWPORT,
viewport);
798 for (
const auto m : models_) {
799 for (
auto d : m->renderer()->triangles_drawables())
803 for (
const auto m : models_) {
804 for (
auto d : m->renderer()->lines_drawables())
811 for (
const auto m : models_) {
812 if (!m->renderer()->is_visible())
818 std::size_t count = 0;
819 for (
auto d : m->renderer()->lines_drawables()) {
820 if (d->is_visible()) {
821 d->draw(camera_); easy3d_debug_log_gl_error
826 for (
auto d : m->renderer()->points_drawables()) {
828 d->draw(camera_); easy3d_debug_log_gl_error
832 glEnable(GL_POLYGON_OFFSET_FILL);
833 glPolygonOffset(0.5f, -0.0001f);
835 for (
auto d : m->renderer()->triangles_drawables()) {
837 d->draw(camera_); easy3d_debug_log_gl_error
840 glDisable(GL_POLYGON_OFFSET_FILL);
843 for (
auto d : drawables_) {
void showEntireScene() const
Definition: camera.cpp:709
quat orientation() const
Definition: camera.cpp:946
void setScreenWidthAndHeight(int width, int height)
Definition: camera.cpp:168
vec3 pivotPoint() const
Definition: camera.cpp:978
void setType(Type type)
Definition: camera.cpp:272
const mat4 & modelViewMatrix() const
Definition: camera.cpp:498
vec3 position() const
Definition: camera.cpp:905
Type type() const
Returns the Camera::Type of the Camera. Set by setType(). Mainly used by loadProjectionMatrix().
Definition: camera.h:267
ManipulatedCameraFrame * frame() const
Returns the ManipulatedFrame attached to the Camera.
Definition: camera.h:438
void setSceneBoundingBox(const vec3 &min, const vec3 &max)
Definition: camera.cpp:542
void update_vertex_buffer(const std::vector< vec3 > &vertices, bool dynamic=false)
Creates/Updates a single buffer.
Definition: drawable.cpp:142
void gl_draw() const
Definition: drawable.cpp:224
void alignWithFrame(const Frame *const frame, bool move=false, float threshold=0.0f)
Definition: frame.cpp:757
void grow(const Point &p)
Definition: box.h:216
static Graph * load(const std::string &file_name)
Reads a graph from file file_name.
Definition: graph_io.cpp:37
static bool save(const std::string &file_name, const Graph *graph)
Saves graph to file file_name.
Definition: graph_io.cpp:72
void action_rotate(int mouse_x, int mouse_y, int mouse_dx, int mouse_dy, Camera *camera, ScreenAxis axis) override
Definition: manipulated_camera_frame.cpp:71
virtual void action_end()
Definition: manipulated_frame.cpp:99
virtual void action_start()
Definition: manipulated_frame.cpp:95
static Mat< N, M, float > identity()
Static constructor return an N x M identity matrix. see also load_identity()
Definition: mat.h:483
void set_renderer(Renderer *r)
Sets the renderer of this model.
Definition: model.h:92
const std::string & name() const
The name of a model.
Definition: model.h:60
virtual void property_stats(std::ostream &output) const
Prints the names of all properties to an output stream (e.g., std::cout).
Definition: model.h:86
Renderer * renderer()
Gets the renderer of this model.
Definition: model.h:94
static void viewport(int &x, int &y, int &width, int &height)
Definition: opengl_util.cpp:222
static bool save(const std::string &file_name, const PointCloud *cloud)
Saves a point_cloud to a file.
Definition: point_cloud_io.cpp:83
static PointCloud * load(const std::string &file_name)
Reads a point cloud from file file_name.
Definition: point_cloud_io.cpp:37
static PolyMesh * load(const std::string &file_name)
Reads a polyhedral mesh from a file.
Definition: poly_mesh_io.cpp:37
Quat inverse() const
Inversion. Returns the inverse Quaternion (inverse rotation). Result has a negated axis() direction a...
Definition: quat.h:266
Mat4< FT > matrix() const
Returns the Quaternion associated 4x4 rotation matrix. Use glMultMatrixf(q.matrix()) to apply the rot...
Definition: quat.h:603
const std::vector< TrianglesDrawable * > & triangles_drawables() const
Definition: renderer.h:172
LinesDrawable * get_lines_drawable(const std::string &name) const
Definition: renderer.cpp:295
PointsDrawable * get_points_drawable(const std::string &name) const
Definition: renderer.cpp:286
void set_property_coloring(Location color_location, const std::string &color_name="")
Definition: state.cpp:97
static SurfaceMesh * load(const std::string &file_name)
Reads a surface mesh from a file.
Definition: surface_mesh_io.cpp:37
static bool save(const std::string &file_name, const SurfaceMesh *mesh)
Saves a surface mesh to a file.
Definition: surface_mesh_io.cpp:84
float draw(const std::string &text, float x, float y, float font_size, int font_id=0, const vec3 &font_color=vec3(0, 0, 0), bool upper_left=true) const
Definition: text_renderer.cpp:818
bool add_font(const std::string &font_file)
Definition: text_renderer.cpp:741
std::size_t num_fonts() const
Definition: text_renderer.h:76
static void terminate()
destroy all textures.
Definition: texture_manager.cpp:149
static std::size_t num_instances(const std::string &file_name, const std::string &element_name)
A quick check of the number of instances of a type of element. The typical use is to determine if a P...
std::string convert_to_native_style(const std::string &path)
Convert a path string such that it uses the current platform's path separators.
std::string simple_name(const std::string &path)
Gets file name without path but with extension (e.g, /a/b/c.Ext => c.Ext)
std::string extension(const std::string &path, bool lower=true)
Query the file extension without dot (e.g., /a/b/c.Ext => Ext).
void initialize(bool info_to_stdout=false, bool warning_to_stdcout=true, bool error_to_stdcout=true, bool verbose_to_stdcout=false, const std::string &log_file="default", int verbosity_threshold=9)
Initializes the logging module.
bool is_initialized()
Returns whether the logging has been initialized.
const std::vector< vec3 > bunny_vertices
Definition: resource.cpp:84
const std::vector< unsigned int > bunny_indices
Definition: resource.cpp:541
std::string directory()
Returns the resource directory (containing color maps, shaders, textures, fonts, etc....
Definition: resource.cpp:45
vec4 highlight_color
highlight: color for highlighted/selected primitives
Definition: setting.cpp:38
vec4 light_position
lighting
Definition: setting.cpp:40
vec4 background_color
background color of the viewer
Definition: setting.cpp:36
vec4 material_ambient
material
Definition: setting.cpp:43
void create_sphere(const vec3 ¢er, double radius, int slices, int stacks, const vec3 &color, std::vector< vec3 > &points, std::vector< vec3 > &normals, std::vector< vec3 > &colors)
Generates data (points, normals, and colors) for a 3D sphere.
Definition: shape.cpp:767
void create_cylinder(double radius, int slices, const vec3 &s, const vec3 &t, const vec3 &color, std::vector< vec3 > &points, std::vector< vec3 > &normals, std::vector< vec3 > &colors)
Prepares data (points, normals, and colors) for a 3D cylinder defined by two 3D points s and t.
Definition: shape.cpp:839
void create_cone(double radius, int slices, const vec3 &s, const vec3 &t, const vec3 &color, std::vector< vec3 > &points, std::vector< vec3 > &normals, std::vector< vec3 > &colors)
Prepares data (points, normals, and colors) for a 3D cone defined by two 3D points b and t....
Definition: shape.cpp:884
Vec< 3, float > vec3
A 3D point/vector of float type.
Definition: types.h:45
GenericBox< 3, float > Box3
A 3D axis-aligned bounding box of float type.
Definition: types.h:109
int connect(SIGNAL *signal, FUNCTION const &slot)
Connects a function to the signal.
Definition: signal.h:202
Mat< N, N, T > inverse(const Mat< N, N, T > &m)
Return the inverse of N x N (square) matrix m.
Definition: mat.h:977
Mat4< float > mat4
A 4 by 4 matrix of float type.
Definition: types.h:68
35#include <easy3d/core/model.h>
36#include <easy3d/core/surface_mesh.h>
37#include <easy3d/algo/surface_mesh_subdivision.h>
38#include <easy3d/renderer/renderer.h>
39#include <easy3d/util/file_system.h>
44 wxDEFINE_EVENT(VIEW_FIT_SCREEN, wxCommandEvent);
45 wxDEFINE_EVENT(VIEW_SNAPSHOT, wxCommandEvent);
46 wxDEFINE_EVENT(EDIT_SUBDIVISION, wxCommandEvent);
48 wxBEGIN_EVENT_TABLE(Window, wxFrame)
49 EVT_MENU(wxID_OPEN, Window::menuFileOpen)
50 EVT_MENU(wxID_SAVE, Window::menuFileSave)
51 EVT_MENU(wxID_EXIT, Window::menuFileExit)
52 EVT_MENU(VIEW_FIT_SCREEN, Window::menuViewFitScreen)
53 EVT_MENU(VIEW_SNAPSHOT, Window::menuViewSnapshot)
54 EVT_MENU(EDIT_SUBDIVISION, Window::menuEditSubdivision)
55 EVT_MENU(wxID_HELP, Window::menuHelpAbout)
59 Window::Window(wxFrame *parent,
const wxString &title,
const wxPoint &pos,
const wxSize &size,
long style)
60 : wxFrame(parent, wxID_ANY, title, pos, size, style) {
62 SetIcon(wxICON(sample));
64 SetIcon(wxIcon(std::string(RESOURCE_DIR) +
"/icons/sample.xpm"));
68 auto fileMenu =
new wxMenu;
69 fileMenu->Append(wxID_OPEN,
"&Open...\tCTRL-O");
70 fileMenu->Append(wxID_SAVE,
"&Save...\tCTRL-S");
71 fileMenu->AppendSeparator();
72 fileMenu->Append(wxID_EXIT,
"E&xit\tALT-X");
75 auto viewMenu =
new wxMenu;
76 viewMenu->Append(VIEW_FIT_SCREEN,
"&Fit screen\tF");
77 viewMenu->Append(VIEW_SNAPSHOT,
"&Snapshot...\tS");
80 auto editMenu =
new wxMenu;
81 editMenu->Append(EDIT_SUBDIVISION,
"&Subdivision");
84 auto helpMenu =
new wxMenu;
85 helpMenu->Append(wxID_HELP,
"&About");
87 auto menuBar =
new wxMenuBar;
88 menuBar->Append(fileMenu,
"&File");
89 menuBar->Append(viewMenu,
"&View");
90 menuBar->Append(editMenu,
"&Edit");
91 menuBar->Append(helpMenu,
"&Help");
94 wxGLAttributes glAttrib;
95 glAttrib.PlatformDefaults().RGBA().DoubleBuffer().Depth(24).Stencil(8).SampleBuffers(1).Samplers(4).EndList();
96 viewer_ =
new Viewer(
this, glAttrib, wxID_ANY, wxDefaultPosition, GetClientSize(), wxDEFAULT_FRAME_STYLE, title);
102 void Window::menuFileOpen(wxCommandEvent & WXUNUSED(event)) {
103 const std::string &title =
"Choose a file";
104 wxString filename = wxFileSelector(title,
"",
"",
"",
105 "Surface Mesh (*.ply;*.obj;*.off;*.stl;*.sm;*.geojson;*.trilist)|"
106 "*.ply;*.obj;*.off;*.stl;*.sm;*.geojson;*.trilist|"
107 "Point Cloud (*.ply;*.bin;*.ptx;*.las;*.laz;*.xyz;*.bxyz;*.vg;*.bvg;*.ptx)|"
108 "*.ply;*.bin;*.ptx;*.las;*.laz;*.xyz;*.bxyz;*.vg;*.bvg;*.ptx|"
109 "Polyhedral Mesh (*.plm;*.pm;*.mesh)|"
111 "Graph (*.ply)|*.ply",
114 if (!filename.IsEmpty()) {
115 auto model = viewer_->add_model(filename.ToStdString(),
true);
117 viewer_->fit_screen(model);
122 void Window::menuFileSave(wxCommandEvent & WXUNUSED(event)) {
123 const Model *m = viewer_->current_model();
125 LOG(WARNING) <<
"no model exists";
129 std::string name = m->name();
133 const std::string &title =
"Please specify a file name";
138 "Surface Mesh (*.ply;*.obj;*.off;*.stl;*.sm)|"
139 "*.ply;*.obj;*.off;*.stl;*.sm|"
140 "Point Cloud (*.ply;*.bin;*.las;*.laz;*.xyz;*.bxyz;*.vg;*.bvg)|"
141 "*.ply;*.bin;*.las;*.laz;*.xyz;*.bxyz;*.vg;*.bvg|"
142 "Polyhedral Mesh (*.plm;*.pm;*.mesh)|"
144 "Graph (*.ply)|*.ply",
147 if (!filename.IsEmpty())
148 viewer_->save_current_model(filename.ToStdString());
152 void Window::menuViewSnapshot(wxCommandEvent &event) {
153 const std::string &title =
"Please specify an image file name";
154 std::string name(
"untitled.png");
156 if (viewer_->current_model())
163 "Image Files (*.png;*.jpg;*.bmp;*.ppm;*.tga)|"
164 "*.png;*.jpg;*.bmp;*.ppm;*.tga",
167 if (!filename.IsEmpty())
168 viewer_->snapshot(filename.ToStdString(),
true);
172 void Window::menuFileExit(wxCommandEvent & WXUNUSED(event)) {
178 void Window::menuViewFitScreen(wxCommandEvent &) {
179 viewer_->fit_screen();
183 void Window::menuEditSubdivision(wxCommandEvent &) {
184 auto mesh =
dynamic_cast<SurfaceMesh*
>(viewer_->current_model());
186 LOG(WARNING) <<
"current model is not a SurfaceMesh (or model does not exist)";
191 mesh->renderer()->update();
196 void Window::menuHelpAbout(wxCommandEvent & WXUNUSED(event)) {
197 wxMessageBox(
"Easy3D viewer based on wxWidgets");
static bool loop(SurfaceMesh *mesh)
The Loop subdivision.
Definition: surface_mesh_subdivision.cpp:179
std::string parent_directory(const std::string &path)
Query the parent path from full name of a file or directory (e.g., /a/b/c.Ext => /a/b)
std::string replace_extension(std::string const &path, const std::string &ext)
Replaces the extension of the given file with 'ext'. If the file name does not have an extension,...