diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index afe79330d..89e46a55d 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -48,10 +48,6 @@ __PACKAGE__->mk_accessors( qw(_quat init volumes cutting_plane_z cut_lines_vertices - bed_shape - bed_triangles - bed_grid_lines - bed_polygon background _mouse_pos _hover_volume_idx @@ -124,14 +120,16 @@ use constant SELECTED_COLOR => [0,1,0,1]; # For mesh selection: Mouse hovers over the object, but object not selected yet - dark green. use constant HOVER_COLOR => [0.4,0.9,0,1]; -# phi / theta angles to orient the camera. -use constant VIEW_DEFAULT => [45.0,45.0]; -use constant VIEW_LEFT => [90.0,90.0]; -use constant VIEW_RIGHT => [-90.0,90.0]; -use constant VIEW_TOP => [0.0,0.0]; -use constant VIEW_BOTTOM => [0.0,180.0]; -use constant VIEW_FRONT => [0.0,90.0]; -use constant VIEW_REAR => [180.0,90.0]; +#============================================================================================================================== +## phi / theta angles to orient the camera. +#use constant VIEW_DEFAULT => [45.0,45.0]; +#use constant VIEW_LEFT => [90.0,90.0]; +#use constant VIEW_RIGHT => [-90.0,90.0]; +#use constant VIEW_TOP => [0.0,0.0]; +#use constant VIEW_BOTTOM => [0.0,180.0]; +#use constant VIEW_FRONT => [0.0,90.0]; +#use constant VIEW_REAR => [180.0,90.0]; +#============================================================================================================================== use constant MANIPULATION_IDLE => 0; use constant MANIPULATION_DRAGGING => 1; @@ -547,17 +545,21 @@ sub mouse_event { $self->mouse_to_3d($e->GetX, $e->GetY, 0), $self->mouse_to_3d($e->GetX, $e->GetY, 1)) ->intersect_plane($self->_drag_start_pos->z); - # Clip the new position, so the object center remains close to the bed. - { - $cur_pos->translate(@{$self->_drag_volume_center_offset}); - my $cur_pos2 = Slic3r::Point->new(scale($cur_pos->x), scale($cur_pos->y)); - if (! $self->bed_polygon->contains_point($cur_pos2)) { - my $ip = $self->bed_polygon->point_projection($cur_pos2); - $cur_pos->set_x(unscale($ip->x)); - $cur_pos->set_y(unscale($ip->y)); - } - $cur_pos->translate(@{$self->_drag_volume_center_offset->negative}); - } +#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ +# >>>>>>>>>>>>>>>>>>>>>>>>>> TEMPORARY DISABLED DUE TO bed_polygon REMOVAL <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +# +# # Clip the new position, so the object center remains close to the bed. +# { +# $cur_pos->translate(@{$self->_drag_volume_center_offset}); +# my $cur_pos2 = Slic3r::Point->new(scale($cur_pos->x), scale($cur_pos->y)); +# if (! $self->bed_polygon->contains_point($cur_pos2)) { +# my $ip = $self->bed_polygon->point_projection($cur_pos2); +# $cur_pos->set_x(unscale($ip->x)); +# $cur_pos->set_y(unscale($ip->y)); +# } +# $cur_pos->translate(@{$self->_drag_volume_center_offset->negative}); +# } +#$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ # Calculate the translation vector. my $vector = $self->_drag_start_pos->vector_to($cur_pos); # Get the volume being dragged. @@ -980,83 +982,76 @@ sub max_bounding_box { #============================================================================================================================== } -# Used by ObjectCutDialog and ObjectPartsPanel to generate a rectangular ground plane -# to support the scene objects. -sub set_auto_bed_shape { - my ($self, $bed_shape) = @_; - - # draw a default square bed around object center - my $max_size = max(@{ $self->volumes_bounding_box->size }); - my $center = $self->volumes_bounding_box->center; - $self->set_bed_shape([ - [ $center->x - $max_size, $center->y - $max_size ], #-- - [ $center->x + $max_size, $center->y - $max_size ], #-- - [ $center->x + $max_size, $center->y + $max_size ], #++ - [ $center->x - $max_size, $center->y + $max_size ], #++ - ]); - # Set the origin for painting of the coordinate system axes. #============================================================================================================================== - Slic3r::GUI::_3DScene::set_bed_origin($self, Slic3r::Pointf->new(@$center[X,Y])); +## Used by ObjectCutDialog and ObjectPartsPanel to generate a rectangular ground plane +## to support the scene objects. +#sub set_auto_bed_shape { +# my ($self, $bed_shape) = @_; +# +# # draw a default square bed around object center +# my $max_size = max(@{ $self->volumes_bounding_box->size }); +# my $center = $self->volumes_bounding_box->center; +# $self->set_bed_shape([ +# [ $center->x - $max_size, $center->y - $max_size ], #-- +# [ $center->x + $max_size, $center->y - $max_size ], #-- +# [ $center->x + $max_size, $center->y + $max_size ], #++ +# [ $center->x - $max_size, $center->y + $max_size ], #++ +# ]); +# # Set the origin for painting of the coordinate system axes. # $self->origin(Slic3r::Pointf->new(@$center[X,Y])); -#============================================================================================================================== -} - -# Set the bed shape to a single closed 2D polygon (array of two element arrays), -# triangulate the bed and store the triangles into $self->bed_triangles, -# fills the $self->bed_grid_lines and sets $self->origin. -# Sets $self->bed_polygon to limit the object placement. -sub set_bed_shape { - my ($self, $bed_shape) = @_; - - $self->bed_shape($bed_shape); -#============================================================================================================================== - Slic3r::GUI::_3DScene::set_bed_shape($self, $bed_shape); -#============================================================================================================================== - - # triangulate bed - my $expolygon = Slic3r::ExPolygon->new([ map [map scale($_), @$_], @$bed_shape ]); - my $bed_bb = $expolygon->bounding_box; - - { - my @points = (); - foreach my $triangle (@{ $expolygon->triangulate }) { - push @points, map {+ unscale($_->x), unscale($_->y), GROUND_Z } @$triangle; - } - $self->bed_triangles(OpenGL::Array->new_list(GL_FLOAT, @points)); - } - - { - my @polylines = (); - for (my $x = $bed_bb->x_min; $x <= $bed_bb->x_max; $x += scale 10) { - push @polylines, Slic3r::Polyline->new([$x,$bed_bb->y_min], [$x,$bed_bb->y_max]); - } - for (my $y = $bed_bb->y_min; $y <= $bed_bb->y_max; $y += scale 10) { - push @polylines, Slic3r::Polyline->new([$bed_bb->x_min,$y], [$bed_bb->x_max,$y]); - } - # clip with a slightly grown expolygon because our lines lay on the contours and - # may get erroneously clipped - my @lines = map Slic3r::Line->new(@$_[0,-1]), - @{intersection_pl(\@polylines, [ @{$expolygon->offset(+scaled_epsilon)} ])}; - - # append bed contours - push @lines, map @{$_->lines}, @$expolygon; - - my @points = (); - foreach my $line (@lines) { - push @points, map {+ unscale($_->x), unscale($_->y), GROUND_Z } @$line; #)) - } - $self->bed_grid_lines(OpenGL::Array->new_list(GL_FLOAT, @points)); - } - - # Set the origin for painting of the coordinate system axes. -#============================================================================================================================== - Slic3r::GUI::_3DScene::set_bed_origin($self, Slic3r::Pointf->new(0,0)); +#} +# +## Set the bed shape to a single closed 2D polygon (array of two element arrays), +## triangulate the bed and store the triangles into $self->bed_triangles, +## fills the $self->bed_grid_lines and sets $self->origin. +## Sets $self->bed_polygon to limit the object placement. +#sub set_bed_shape { +# my ($self, $bed_shape) = @_; +# +# $self->bed_shape($bed_shape); +# +# # triangulate bed +# my $expolygon = Slic3r::ExPolygon->new([ map [map scale($_), @$_], @$bed_shape ]); +# my $bed_bb = $expolygon->bounding_box; +# +# { +# my @points = (); +# foreach my $triangle (@{ $expolygon->triangulate }) { +# push @points, map {+ unscale($_->x), unscale($_->y), GROUND_Z } @$triangle; +# } +# $self->bed_triangles(OpenGL::Array->new_list(GL_FLOAT, @points)); +# } +# +# { +# my @polylines = (); +# for (my $x = $bed_bb->x_min; $x <= $bed_bb->x_max; $x += scale 10) { +# push @polylines, Slic3r::Polyline->new([$x,$bed_bb->y_min], [$x,$bed_bb->y_max]); +# } +# for (my $y = $bed_bb->y_min; $y <= $bed_bb->y_max; $y += scale 10) { +# push @polylines, Slic3r::Polyline->new([$bed_bb->x_min,$y], [$bed_bb->x_max,$y]); +# } +# # clip with a slightly grown expolygon because our lines lay on the contours and +# # may get erroneously clipped +# my @lines = map Slic3r::Line->new(@$_[0,-1]), +# @{intersection_pl(\@polylines, [ @{$expolygon->offset(+scaled_epsilon)} ])}; +# +# # append bed contours +# push @lines, map @{$_->lines}, @$expolygon; +# +# my @points = (); +# foreach my $line (@lines) { +# push @points, map {+ unscale($_->x), unscale($_->y), GROUND_Z } @$line; #)) +# } +# $self->bed_grid_lines(OpenGL::Array->new_list(GL_FLOAT, @points)); +# } +# +# # Set the origin for painting of the coordinate system axes. # $self->origin(Slic3r::Pointf->new(0,0)); +# +# $self->bed_polygon(offset_ex([$expolygon->contour], $bed_bb->radius * 1.7, JT_ROUND, scale(0.5))->[0]->contour->clone); +#} #============================================================================================================================== - $self->bed_polygon(offset_ex([$expolygon->contour], $bed_bb->radius * 1.7, JT_ROUND, scale(0.5))->[0]->contour->clone); -} - sub deselect_volumes { my ($self) = @_; $_->set_selected(0) for @{$self->volumes}; @@ -1518,33 +1513,37 @@ sub Render { # draw ground my $ground_z = GROUND_Z; - if ($self->bed_triangles) { - glDisable(GL_DEPTH_TEST); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glEnableClientState(GL_VERTEX_ARRAY); - glColor4f(0.8, 0.6, 0.5, 0.4); - glNormal3d(0,0,1); - glVertexPointer_c(3, GL_FLOAT, 0, $self->bed_triangles->ptr()); - glDrawArrays(GL_TRIANGLES, 0, $self->bed_triangles->elements / 3); - glDisableClientState(GL_VERTEX_ARRAY); - - # we need depth test for grid, otherwise it would disappear when looking - # the object from below - glEnable(GL_DEPTH_TEST); +#============================================================================================================================== + Slic3r::GUI::_3DScene::render($self); - # draw grid - glLineWidth(3); - glColor4f(0.2, 0.2, 0.2, 0.4); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer_c(3, GL_FLOAT, 0, $self->bed_grid_lines->ptr()); - glDrawArrays(GL_LINES, 0, $self->bed_grid_lines->elements / 3); - glDisableClientState(GL_VERTEX_ARRAY); - - glDisable(GL_BLEND); - } +# if ($self->bed_triangles) { +# glDisable(GL_DEPTH_TEST); +# +# glEnable(GL_BLEND); +# glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +# +# glEnableClientState(GL_VERTEX_ARRAY); +# glColor4f(0.8, 0.6, 0.5, 0.4); +# glNormal3d(0,0,1); +# glVertexPointer_c(3, GL_FLOAT, 0, $self->bed_triangles->ptr()); +# glDrawArrays(GL_TRIANGLES, 0, $self->bed_triangles->elements / 3); +# glDisableClientState(GL_VERTEX_ARRAY); +# +# # we need depth test for grid, otherwise it would disappear when looking +# # the object from below +# glEnable(GL_DEPTH_TEST); +# +# # draw grid +# glLineWidth(3); +# glColor4f(0.2, 0.2, 0.2, 0.4); +# glEnableClientState(GL_VERTEX_ARRAY); +# glVertexPointer_c(3, GL_FLOAT, 0, $self->bed_grid_lines->ptr()); +# glDrawArrays(GL_LINES, 0, $self->bed_grid_lines->elements / 3); +# glDisableClientState(GL_VERTEX_ARRAY); +# +# glDisable(GL_BLEND); +# } +#============================================================================================================================== my $volumes_bb = $self->volumes_bounding_box; diff --git a/lib/Slic3r/GUI/Plater/3D.pm b/lib/Slic3r/GUI/Plater/3D.pm index c9c954276..2706df509 100644 --- a/lib/Slic3r/GUI/Plater/3D.pm +++ b/lib/Slic3r/GUI/Plater/3D.pm @@ -255,7 +255,10 @@ sub reload_scene { sub update_bed_size { my ($self) = @_; - $self->set_bed_shape($self->{config}->bed_shape); +#============================================================================================================================== + Slic3r::GUI::_3DScene::set_bed_shape($self, $self->{config}->bed_shape); +# $self->set_bed_shape($self->{config}->bed_shape); +#============================================================================================================================== } # Called by the Platter wxNotebook when this page is activated. diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index b746de98f..88aab7786 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -474,7 +474,10 @@ sub set_z_idx_high sub set_bed_shape { my ($self, $bed_shape) = @_; - $self->canvas->set_bed_shape($bed_shape); +#============================================================================================================================== + Slic3r::GUI::_3DScene::set_bed_shape($self->canvas, $bed_shape); +# $self->canvas->set_bed_shape($bed_shape); +#============================================================================================================================== } sub set_number_extruders { diff --git a/lib/Slic3r/GUI/Plater/ObjectCutDialog.pm b/lib/Slic3r/GUI/Plater/ObjectCutDialog.pm index f0f50a4f3..6d3234ff3 100644 --- a/lib/Slic3r/GUI/Plater/ObjectCutDialog.pm +++ b/lib/Slic3r/GUI/Plater/ObjectCutDialog.pm @@ -113,7 +113,10 @@ sub new { if ($Slic3r::GUI::have_OpenGL) { $canvas = $self->{canvas} = Slic3r::GUI::3DScene->new($self); $canvas->load_object($self->{model_object}, undef, undef, [0]); - $canvas->set_auto_bed_shape; +#============================================================================================================================== + Slic3r::GUI::_3DScene::set_auto_bed_shape($canvas); +# $canvas->set_auto_bed_shape; +#============================================================================================================================== $canvas->SetSize([500,500]); $canvas->SetMinSize($canvas->GetSize); } diff --git a/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm b/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm index 322491f9e..ee1bf22d1 100644 --- a/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm +++ b/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm @@ -160,7 +160,10 @@ sub new { }); $canvas->load_object($self->{model_object}, undef, undef, [0]); - $canvas->set_auto_bed_shape; +#============================================================================================================================== + Slic3r::GUI::_3DScene::set_auto_bed_shape($canvas); +# $canvas->set_auto_bed_shape; +#============================================================================================================================== $canvas->SetSize([500,700]); $canvas->update_volumes_colors_by_extruder($self->GetParent->GetParent->GetParent->{config}); } diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index ed2b7f8b8..f5193668b 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -1747,6 +1747,16 @@ void _3DScene::resize(wxGLCanvas* canvas, unsigned int w, unsigned int h) s_canvas_mgr.resize(canvas, w, h); } +bool _3DScene::is_dirty(wxGLCanvas* canvas) +{ + return s_canvas_mgr.is_dirty(canvas); +} + +void _3DScene::set_dirty(wxGLCanvas* canvas, bool dirty) +{ + s_canvas_mgr.set_dirty(canvas, dirty); +} + bool _3DScene::is_shown_on_screen(wxGLCanvas* canvas) { return s_canvas_mgr.is_shown_on_screen(canvas); @@ -1767,6 +1777,11 @@ void _3DScene::set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape) return s_canvas_mgr.set_bed_shape(canvas, shape); } +void _3DScene::set_auto_bed_shape(wxGLCanvas* canvas) +{ + return s_canvas_mgr.set_auto_bed_shape(canvas); +} + Pointf _3DScene::get_bed_origin(wxGLCanvas* canvas) { return s_canvas_mgr.get_bed_origin(canvas); @@ -1793,16 +1808,6 @@ BoundingBoxf3 _3DScene::get_max_bounding_box(wxGLCanvas* canvas) return s_canvas_mgr.get_max_bounding_box(canvas); } -bool _3DScene::is_dirty(wxGLCanvas* canvas) -{ - return s_canvas_mgr.is_dirty(canvas); -} - -void _3DScene::set_dirty(wxGLCanvas* canvas, bool dirty) -{ - s_canvas_mgr.set_dirty(canvas, dirty); -} - unsigned int _3DScene::get_camera_type(wxGLCanvas* canvas) { return s_canvas_mgr.get_camera_type(canvas); @@ -1883,6 +1888,11 @@ void _3DScene::select_view(wxGLCanvas* canvas, const std::string& direction) s_canvas_mgr.select_view(canvas, direction); } +void _3DScene::render(wxGLCanvas* canvas) +{ + s_canvas_mgr.render(canvas); +} + void _3DScene::register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback) { s_canvas_mgr.register_on_viewport_changed_callback(canvas, callback); diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 5010d9c2c..8d6345f97 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -544,12 +544,16 @@ public: static void resize(wxGLCanvas* canvas, unsigned int w, unsigned int h); + static bool is_dirty(wxGLCanvas* canvas); + static void set_dirty(wxGLCanvas* canvas, bool dirty); + static bool is_shown_on_screen(wxGLCanvas* canvas); static GLVolumeCollection* get_volumes(wxGLCanvas* canvas); static void set_volumes(wxGLCanvas* canvas, GLVolumeCollection* volumes); static void set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape); + static void set_auto_bed_shape(wxGLCanvas* canvas); static Pointf get_bed_origin(wxGLCanvas* canvas); static void set_bed_origin(wxGLCanvas* canvas, const Pointf* origin); @@ -558,9 +562,6 @@ public: static BoundingBoxf3 get_volumes_bounding_box(wxGLCanvas* canvas); static BoundingBoxf3 get_max_bounding_box(wxGLCanvas* canvas); - static bool is_dirty(wxGLCanvas* canvas); - static void set_dirty(wxGLCanvas* canvas, bool dirty); - static unsigned int get_camera_type(wxGLCanvas* canvas); static void set_camera_type(wxGLCanvas* canvas, unsigned int type); static std::string get_camera_type_as_string(wxGLCanvas* canvas); @@ -584,6 +585,8 @@ public: static void zoom_to_volumes(wxGLCanvas* canvas); static void select_view(wxGLCanvas* canvas, const std::string& direction); + static void render(wxGLCanvas* canvas); + static void register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback); // static void _glew_init(); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 940a5b79c..2e4b15af4 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1,6 +1,7 @@ #include "GLCanvas3D.hpp" #include "../../slic3r/GUI/3DScene.hpp" +#include "../../libslic3r/ClipperUtils.hpp" #include @@ -8,6 +9,7 @@ static const bool TURNTABLE_MODE = true; static const float GIMBALL_LOCK_THETA_MAX = 180.0f; +static const float GROUND_Z = -0.02f; // phi / theta angles to orient the camera. static const float VIEW_DEFAULT[2] = { 45.0f, 45.0f }; @@ -21,6 +23,65 @@ static const float VIEW_REAR[2] = { 180.0f, 90.0f }; namespace Slic3r { namespace GUI { +bool GeometryBuffer::set_from_triangles(const Polygons& triangles, float z) +{ + m_data.clear(); + + unsigned int size = 9 * (unsigned int)triangles.size(); + if (size == 0) + return false; + + m_data = std::vector(size, 0.0f); + + unsigned int coord = 0; + for (const Polygon& t : triangles) + { + for (unsigned int v = 0; v < 3; ++v) + { + const Point& p = t.points[v]; + m_data[coord++] = (float)unscale(p.x); + m_data[coord++] = (float)unscale(p.y); + m_data[coord++] = z; + } + } + + return true; +} + +bool GeometryBuffer::set_from_lines(const Lines& lines, float z) +{ + m_data.clear(); + + unsigned int size = 6 * (unsigned int)lines.size(); + if (size == 0) + return false; + + m_data = std::vector(size, 0.0f); + + unsigned int coord = 0; + for (const Line& l : lines) + { + m_data[coord++] = (float)unscale(l.a.x); + m_data[coord++] = (float)unscale(l.a.y); + m_data[coord++] = z; + m_data[coord++] = (float)unscale(l.b.x); + m_data[coord++] = (float)unscale(l.b.y); + m_data[coord++] = z; + } + + return true; +} + +const float* GeometryBuffer::get_data() const +{ + return m_data.data(); +} + +unsigned int GeometryBuffer::get_data_size() const +{ + return (unsigned int)m_data.size(); +} + GLCanvas3D::Camera::Camera() : m_type(CT_Ortho) , m_zoom(1.0f) @@ -120,7 +181,23 @@ const Pointfs& GLCanvas3D::Bed::get_shape() const void GLCanvas3D::Bed::set_shape(const Pointfs& shape) { m_shape = shape; + _calc_bounding_box(); + + ExPolygon poly; + for (const Pointf& p : m_shape) + { + poly.contour.append(Point(scale_(p.x), scale_(p.y))); + } + + _calc_triangles(poly); + + const BoundingBox& bed_bbox = poly.contour.bounding_box(); + _calc_gridlines(poly, bed_bbox); + + m_polygon = offset_ex(poly.contour, bed_bbox.radius() * 1.7, jtRound, scale_(0.5))[0].contour; + + set_origin(Pointf(0.0, 0.0)); } const BoundingBoxf3& GLCanvas3D::Bed::get_bounding_box() const @@ -138,6 +215,43 @@ void GLCanvas3D::Bed::set_origin(const Pointf& origin) m_origin = origin; } +void GLCanvas3D::Bed::render() +{ + unsigned int triangles_vcount = m_triangles.get_data_size() / 3; + if (triangles_vcount > 0) + { + ::glDisable(GL_DEPTH_TEST); + + ::glEnable(GL_BLEND); + ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + ::glEnableClientState(GL_VERTEX_ARRAY); + + ::glColor4f(0.8f, 0.6f, 0.5f, 0.4f); + ::glNormal3d(0.0f, 0.0f, 1.0f); + ::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_triangles.get_data()); + ::glDrawArrays(GL_TRIANGLES, 0, triangles_vcount); +// ::glDisableClientState(GL_VERTEX_ARRAY); + + // we need depth test for grid, otherwise it would disappear when looking + // the object from below + glEnable(GL_DEPTH_TEST); + + // draw grid + unsigned int gridlines_vcount = m_gridlines.get_data_size() / 3; + + ::glLineWidth(3.0f); + ::glColor4f(0.2f, 0.2f, 0.2f, 0.4f); +// ::glEnableClientState(GL_VERTEX_ARRAY); + ::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_gridlines.get_data()); + ::glDrawArrays(GL_LINES, 0, gridlines_vcount); + + ::glDisableClientState(GL_VERTEX_ARRAY); + + ::glDisable(GL_BLEND); + } +} + void GLCanvas3D::Bed::_calc_bounding_box() { m_bounding_box = BoundingBoxf3(); @@ -147,6 +261,44 @@ void GLCanvas3D::Bed::_calc_bounding_box() } } +void GLCanvas3D::Bed::_calc_triangles(const ExPolygon& poly) +{ + Polygons triangles; + poly.triangulate(&triangles); + + if (!m_triangles.set_from_triangles(triangles, GROUND_Z)) + printf("Unable to create bed triangles\n"); +} + +void GLCanvas3D::Bed::_calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox) +{ + Polylines axes_lines; + for (coord_t x = bed_bbox.min.x; x <= bed_bbox.max.x; x += scale_(10.0)) + { + Polyline line; + line.append(Point(x, bed_bbox.min.y)); + line.append(Point(x, bed_bbox.max.y)); + axes_lines.push_back(line); + } + for (coord_t y = bed_bbox.min.y; y <= bed_bbox.max.y; y += scale_(10.0)) + { + Polyline line; + line.append(Point(bed_bbox.min.x, y)); + line.append(Point(bed_bbox.max.x, y)); + axes_lines.push_back(line); + } + + // clip with a slightly grown expolygon because our lines lay on the contours and may get erroneously clipped + Lines gridlines = to_lines(intersection_pl(axes_lines, offset(poly, SCALED_EPSILON))); + + // append bed contours + Lines contour_lines = to_lines(poly); + std::copy(contour_lines.begin(), contour_lines.end(), std::back_inserter(gridlines)); + + if (!m_gridlines.set_from_lines(gridlines, GROUND_Z)) + printf("Unable to create bed grid lines\n"); +} + GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, wxGLContext* context) : m_canvas(canvas) , m_context(context) @@ -167,6 +319,16 @@ void GLCanvas3D::set_current() m_canvas->SetCurrent(*m_context); } +bool GLCanvas3D::is_dirty() const +{ + return m_dirty; +} + +void GLCanvas3D::set_dirty(bool dirty) +{ + m_dirty = dirty; +} + bool GLCanvas3D::is_shown_on_screen() const { return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false; @@ -254,6 +416,26 @@ void GLCanvas3D::set_bed_shape(const Pointfs& shape) m_bed.set_shape(shape); } +void GLCanvas3D::set_auto_bed_shape() +{ + // draw a default square bed around object center + const BoundingBoxf3& bbox = volumes_bounding_box(); + coordf_t max_size = bbox.max_size(); + const Pointf3& center = bbox.center(); + + Pointfs bed_shape; + bed_shape.reserve(4); + bed_shape.emplace_back(center.x - max_size, center.y - max_size); + bed_shape.emplace_back(center.x + max_size, center.y - max_size); + bed_shape.emplace_back(center.x + max_size, center.y + max_size); + bed_shape.emplace_back(center.x - max_size, center.y + max_size); + + set_bed_shape(bed_shape); + + // Set the origin for painting of the coordinate system axes. + set_bed_origin(Pointf(center.x, center.y)); +} + const Pointf& GLCanvas3D::get_bed_origin() const { return m_bed.get_origin(); @@ -264,16 +446,6 @@ void GLCanvas3D::set_bed_origin(const Pointf& origin) m_bed.set_origin(origin); } -bool GLCanvas3D::is_dirty() const -{ - return m_dirty; -} - -void GLCanvas3D::set_dirty(bool dirty) -{ - m_dirty = dirty; -} - GLCanvas3D::Camera::EType GLCanvas3D::get_camera_type() const { return m_camera.get_type(); @@ -408,6 +580,11 @@ void GLCanvas3D::select_view(const std::string& direction) } } +void GLCanvas3D::render() +{ + m_bed.render(); +} + void GLCanvas3D::register_on_viewport_changed_callback(void* callback) { if (callback != nullptr) diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index 7568dec39..f3b459b96 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -12,9 +12,22 @@ class wxIdleEvent; namespace Slic3r { class GLVolumeCollection; +class ExPolygon; namespace GUI { +class GeometryBuffer +{ + std::vector m_data; + +public: + bool set_from_triangles(const Polygons& triangles, float z); + bool set_from_lines(const Lines& lines, float z); + + const float* get_data() const; + unsigned int get_data_size() const; +}; + class GLCanvas3D { public: @@ -65,6 +78,9 @@ public: Pointfs m_shape; BoundingBoxf3 m_bounding_box; Pointf m_origin; + Polygon m_polygon; + GeometryBuffer m_triangles; + GeometryBuffer m_gridlines; public: const Pointfs& get_shape() const; @@ -75,8 +91,12 @@ public: const Pointf& get_origin() const; void set_origin(const Pointf& origin); + void render(); + private: void _calc_bounding_box(); + void _calc_triangles(const ExPolygon& poly); + void _calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox); }; private: @@ -98,6 +118,9 @@ public: void set_current(); + bool is_dirty() const; + void set_dirty(bool dirty); + bool is_shown_on_screen() const; void resize(unsigned int w, unsigned int h); @@ -105,14 +128,17 @@ public: GLVolumeCollection* get_volumes(); void set_volumes(GLVolumeCollection* volumes); + // Set the bed shape to a single closed 2D polygon(array of two element arrays), + // triangulate the bed and store the triangles into m_bed.m_triangles, + // fills the m_bed.m_grid_lines and sets m_bed.m_origin. + // Sets m_bed.m_polygon to limit the object placement. void set_bed_shape(const Pointfs& shape); + // Used by ObjectCutDialog and ObjectPartsPanel to generate a rectangular ground plane to support the scene objects. + void set_auto_bed_shape(); const Pointf& get_bed_origin() const; void set_bed_origin(const Pointf& origin); - bool is_dirty() const; - void set_dirty(bool dirty); - Camera::EType get_camera_type() const; void set_camera_type(Camera::EType type); std::string get_camera_type_as_string() const; @@ -140,6 +166,8 @@ public: void zoom_to_volumes(); void select_view(const std::string& direction); + void render(); + void register_on_viewport_changed_callback(void* callback); void on_size(wxSizeEvent& evt); diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp index f5b76fe60..f4b367c95 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -147,6 +147,19 @@ bool GLCanvas3DManager::layer_editing_allowed() const return m_layer_editing.allowed; } +bool GLCanvas3DManager::is_dirty(wxGLCanvas* canvas) const +{ + CanvasesMap::const_iterator it = _get_canvas(canvas); + return (it != m_canvases.end()) ? it->second->is_dirty() : false; +} + +void GLCanvas3DManager::set_dirty(wxGLCanvas* canvas, bool dirty) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->set_dirty(dirty); +} + bool GLCanvas3DManager::is_shown_on_screen(wxGLCanvas* canvas) const { CanvasesMap::const_iterator it = _get_canvas(canvas); @@ -180,6 +193,13 @@ void GLCanvas3DManager::set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape) it->second->set_bed_shape(shape); } +void GLCanvas3DManager::set_auto_bed_shape(wxGLCanvas* canvas) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->set_auto_bed_shape(); +} + Pointf GLCanvas3DManager::get_bed_origin(wxGLCanvas* canvas) const { CanvasesMap::const_iterator it = _get_canvas(canvas); @@ -211,19 +231,6 @@ BoundingBoxf3 GLCanvas3DManager::get_max_bounding_box(wxGLCanvas* canvas) return (it != m_canvases.end()) ? it->second->max_bounding_box() : BoundingBoxf3(); } -bool GLCanvas3DManager::is_dirty(wxGLCanvas* canvas) const -{ - CanvasesMap::const_iterator it = _get_canvas(canvas); - return (it != m_canvases.end()) ? it->second->is_dirty() : false; -} - -void GLCanvas3DManager::set_dirty(wxGLCanvas* canvas, bool dirty) -{ - CanvasesMap::iterator it = _get_canvas(canvas); - if (it != m_canvases.end()) - it->second->set_dirty(dirty); -} - unsigned int GLCanvas3DManager::get_camera_type(wxGLCanvas* canvas) const { CanvasesMap::const_iterator it = _get_canvas(canvas); @@ -335,6 +342,13 @@ void GLCanvas3DManager::select_view(wxGLCanvas* canvas, const std::string& direc it->second->select_view(direction); } +void GLCanvas3DManager::render(wxGLCanvas* canvas) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->render(); +} + void GLCanvas3DManager::register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback) { CanvasesMap::iterator it = _get_canvas(canvas); diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp index c1ce8048c..bf0b9c066 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -52,6 +52,9 @@ public: bool use_VBOs() const; bool layer_editing_allowed() const; + bool is_dirty(wxGLCanvas* canvas) const; + void set_dirty(wxGLCanvas* canvas, bool dirty); + bool is_shown_on_screen(wxGLCanvas* canvas) const; void resize(wxGLCanvas* canvas, unsigned int w, unsigned int h); @@ -60,6 +63,7 @@ public: void set_volumes(wxGLCanvas* canvas, GLVolumeCollection* volumes); void set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape); + void set_auto_bed_shape(wxGLCanvas* canvas); Pointf get_bed_origin(wxGLCanvas* canvas) const; void set_bed_origin(wxGLCanvas* canvas, const Pointf& origin); @@ -68,9 +72,6 @@ public: BoundingBoxf3 get_volumes_bounding_box(wxGLCanvas* canvas); BoundingBoxf3 get_max_bounding_box(wxGLCanvas* canvas); - bool is_dirty(wxGLCanvas* canvas) const; - void set_dirty(wxGLCanvas* canvas, bool dirty); - unsigned int get_camera_type(wxGLCanvas* canvas) const; void set_camera_type(wxGLCanvas* canvas, unsigned int type); std::string get_camera_type_as_string(wxGLCanvas* canvas) const; @@ -94,6 +95,8 @@ public: void zoom_to_volumes(wxGLCanvas* canvas); void select_view(wxGLCanvas* canvas, const std::string& direction); + void render(wxGLCanvas* canvas); + void register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback); private: diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 7211cc513..c62c7e958 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -215,6 +215,12 @@ set_bed_shape(canvas, shape) CODE: _3DScene::set_bed_shape((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), shape); +void +set_auto_bed_shape(canvas) + SV *canvas; + CODE: + _3DScene::set_auto_bed_shape((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas")); + Clone get_bed_origin(canvas) SV *canvas; @@ -393,6 +399,12 @@ select_view(canvas, direction) std::string direction; CODE: _3DScene::select_view((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), direction); + +void +render(canvas) + SV *canvas; + CODE: + _3DScene::render((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas")); void register_on_viewport_changed_callback(canvas, callback)