From 5fc8fdee112808b03baf651da17d4c826893336f Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Fri, 18 May 2018 13:02:47 +0200
Subject: [PATCH] 3DScene axes moved to c++

---
 lib/Slic3r/GUI/3DScene.pm                 | 53 ++++++-------
 lib/Slic3r/GUI/Plater/ObjectCutDialog.pm  |  4 +
 lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm |  4 +
 xs/src/slic3r/GUI/3DScene.cpp             | 37 ++++++---
 xs/src/slic3r/GUI/3DScene.hpp             | 10 ++-
 xs/src/slic3r/GUI/GLCanvas3D.cpp          | 93 ++++++++++++++++++-----
 xs/src/slic3r/GUI/GLCanvas3D.hpp          | 30 ++++++--
 xs/src/slic3r/GUI/GLCanvas3DManager.cpp   | 46 +++++++----
 xs/src/slic3r/GUI/GLCanvas3DManager.hpp   | 10 ++-
 xs/xsp/GUI_3DScene.xsp                    | 51 +++++++++----
 10 files changed, 244 insertions(+), 94 deletions(-)

diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm
index e2fdcaaca..23b87d661 100644
--- a/lib/Slic3r/GUI/3DScene.pm
+++ b/lib/Slic3r/GUI/3DScene.pm
@@ -1551,35 +1551,36 @@ sub Render {
     
     my $volumes_bb = $self->volumes_bounding_box;
     
-    {
-        # draw axes
-        # disable depth testing so that axes are not covered by ground
-        glDisable(GL_DEPTH_TEST);
 #==============================================================================================================================
-        my $origin = Slic3r::GUI::_3DScene::get_bed_origin($self);
+    Slic3r::GUI::_3DScene::render_axes($self);
+    
+#    {
+#       # draw axes
+#        # disable depth testing so that axes are not covered by ground
+#        glDisable(GL_DEPTH_TEST);
 #        my $origin = $self->origin;
+#        my $axis_len = $self->use_plain_shader ? 0.3 * max(@{ $self->bed_bounding_box->size }) : 2 * max(@{ $volumes_bb->size });
+#        glLineWidth(2);
+#        glBegin(GL_LINES);
+#        # draw line for x axis
+#        glColor3f(1, 0, 0);
+#        glVertex3f(@$origin, $ground_z);
+#        glVertex3f($origin->x + $axis_len, $origin->y, $ground_z);  #,,
+#        # draw line for y axis
+#        glColor3f(0, 1, 0);
+#        glVertex3f(@$origin, $ground_z);
+#        glVertex3f($origin->x, $origin->y + $axis_len, $ground_z);  #++
+#        glEnd();
+#        # draw line for Z axis
+#        # (re-enable depth test so that axis is correctly shown when objects are behind it)
+#        glEnable(GL_DEPTH_TEST);
+#        glBegin(GL_LINES);
+#        glColor3f(0, 0, 1);
+#        glVertex3f(@$origin, $ground_z);
+#        glVertex3f(@$origin, $ground_z+$axis_len);
+#        glEnd();
+#    }
 #==============================================================================================================================
-        my $axis_len = $self->use_plain_shader ? 0.3 * max(@{ $self->bed_bounding_box->size }) : 2 * max(@{ $volumes_bb->size });
-        glLineWidth(2);
-        glBegin(GL_LINES);
-        # draw line for x axis
-        glColor3f(1, 0, 0);
-        glVertex3f(@$origin, $ground_z);
-        glVertex3f($origin->x + $axis_len, $origin->y, $ground_z);  #,,
-        # draw line for y axis
-        glColor3f(0, 1, 0);
-        glVertex3f(@$origin, $ground_z);
-        glVertex3f($origin->x, $origin->y + $axis_len, $ground_z);  #++
-        glEnd();
-        # draw line for Z axis
-        # (re-enable depth test so that axis is correctly shown when objects are behind it)
-        glEnable(GL_DEPTH_TEST);
-        glBegin(GL_LINES);
-        glColor3f(0, 0, 1);
-        glVertex3f(@$origin, $ground_z);
-        glVertex3f(@$origin, $ground_z+$axis_len);
-        glEnd();
-    }
     
     glEnable(GL_LIGHTING);
         
diff --git a/lib/Slic3r/GUI/Plater/ObjectCutDialog.pm b/lib/Slic3r/GUI/Plater/ObjectCutDialog.pm
index 6d3234ff3..80ba4db50 100644
--- a/lib/Slic3r/GUI/Plater/ObjectCutDialog.pm
+++ b/lib/Slic3r/GUI/Plater/ObjectCutDialog.pm
@@ -9,6 +9,9 @@ use utf8;
 use Slic3r::Geometry qw(PI X);
 use Wx qw(wxTheApp :dialog :id :misc :sizer wxTAB_TRAVERSAL);
 use Wx::Event qw(EVT_CLOSE EVT_BUTTON);
+#==============================================================================================================================
+use List::Util qw(max);
+#==============================================================================================================================
 use base 'Wx::Dialog';
 
 sub new {
@@ -115,6 +118,7 @@ sub new {
         $canvas->load_object($self->{model_object}, undef, undef, [0]);
 #==============================================================================================================================
         Slic3r::GUI::_3DScene::set_auto_bed_shape($canvas);
+        Slic3r::GUI::_3DScene::set_axes_length($canvas, 2.0 * max(@{ $canvas->volumes_bounding_box->size }));
 #        $canvas->set_auto_bed_shape;
 #==============================================================================================================================
         $canvas->SetSize([500,500]);
diff --git a/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm b/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm
index ee1bf22d1..9320e6666 100644
--- a/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm
+++ b/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm
@@ -10,6 +10,9 @@ use File::Basename qw(basename);
 use Wx qw(:misc :sizer :treectrl :button :keycode wxTAB_TRAVERSAL wxSUNKEN_BORDER wxBITMAP_TYPE_PNG wxID_CANCEL wxMOD_CONTROL
     wxTheApp);
 use Wx::Event qw(EVT_BUTTON EVT_TREE_ITEM_COLLAPSING EVT_TREE_SEL_CHANGED EVT_TREE_KEY_DOWN EVT_KEY_DOWN);
+#==============================================================================================================================
+use List::Util qw(max);
+#==============================================================================================================================
 use base 'Wx::Panel';
 
 use constant ICON_OBJECT        => 0;
@@ -162,6 +165,7 @@ sub new {
         $canvas->load_object($self->{model_object}, undef, undef, [0]);
 #==============================================================================================================================
         Slic3r::GUI::_3DScene::set_auto_bed_shape($canvas);
+        Slic3r::GUI::_3DScene::set_axes_length($canvas, 2.0 * max(@{ $canvas->volumes_bounding_box->size }));
 #        $canvas->set_auto_bed_shape;
 #==============================================================================================================================
         $canvas->SetSize([500,700]);
diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp
index 9babd8bc6..02dfd18ae 100644
--- a/xs/src/slic3r/GUI/3DScene.cpp
+++ b/xs/src/slic3r/GUI/3DScene.cpp
@@ -1782,17 +1782,6 @@ 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);
-}
-
-void _3DScene::set_bed_origin(wxGLCanvas* canvas, const Pointf* origin)
-{
-    if (origin != nullptr)
-        s_canvas_mgr.set_bed_origin(canvas, *origin);
-}
-
 BoundingBoxf3 _3DScene::get_bed_bounding_box(wxGLCanvas* canvas)
 {
     return s_canvas_mgr.get_bed_bounding_box(canvas);
@@ -1808,6 +1797,27 @@ BoundingBoxf3 _3DScene::get_max_bounding_box(wxGLCanvas* canvas)
     return s_canvas_mgr.get_max_bounding_box(canvas);
 }
 
+Pointf3 _3DScene::get_axes_origin(wxGLCanvas* canvas)
+{
+    return s_canvas_mgr.get_axes_origin(canvas);
+}
+
+void _3DScene::set_axes_origin(wxGLCanvas* canvas, const Pointf3* origin)
+{
+    if (origin != nullptr)
+        s_canvas_mgr.set_axes_origin(canvas, *origin);
+}
+
+float _3DScene::get_axes_length(wxGLCanvas* canvas)
+{
+    return s_canvas_mgr.get_axes_length(canvas);
+}
+
+void _3DScene::set_axes_length(wxGLCanvas* canvas, float length)
+{
+    s_canvas_mgr.set_axes_length(canvas, length);
+}
+
 void _3DScene::set_cutting_plane(wxGLCanvas* canvas, float z, const ExPolygons& polygons)
 {
     return s_canvas_mgr.set_cutting_plane(canvas, z, polygons);
@@ -1898,6 +1908,11 @@ void _3DScene::render_bed(wxGLCanvas* canvas)
     s_canvas_mgr.render_bed(canvas);
 }
 
+void _3DScene::render_axes(wxGLCanvas* canvas)
+{
+    s_canvas_mgr.render_axes(canvas);
+}
+
 void _3DScene::render_cutting_plane(wxGLCanvas* canvas)
 {
     s_canvas_mgr.render_cutting_plane(canvas);
diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp
index eb03a5313..2ae07d858 100644
--- a/xs/src/slic3r/GUI/3DScene.hpp
+++ b/xs/src/slic3r/GUI/3DScene.hpp
@@ -555,13 +555,16 @@ public:
     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);
-
     static BoundingBoxf3 get_bed_bounding_box(wxGLCanvas* canvas);
     static BoundingBoxf3 get_volumes_bounding_box(wxGLCanvas* canvas);
     static BoundingBoxf3 get_max_bounding_box(wxGLCanvas* canvas);
 
+    static Pointf3 get_axes_origin(wxGLCanvas* canvas);
+    static void set_axes_origin(wxGLCanvas* canvas, const Pointf3* origin);
+
+    static float get_axes_length(wxGLCanvas* canvas);
+    static void set_axes_length(wxGLCanvas* canvas, float length);
+
     static void set_cutting_plane(wxGLCanvas* canvas, float z, const ExPolygons& polygons);
 
     static unsigned int get_camera_type(wxGLCanvas* canvas);
@@ -588,6 +591,7 @@ public:
     static void select_view(wxGLCanvas* canvas, const std::string& direction);
 
     static void render_bed(wxGLCanvas* canvas);
+    static void render_axes(wxGLCanvas* canvas);
     static void render_cutting_plane(wxGLCanvas* canvas);
 
     static void register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback);
diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp
index 9631f7996..de875841c 100644
--- a/xs/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp
@@ -196,8 +196,6 @@ void GLCanvas3D::Bed::set_shape(const Pointfs& shape)
     _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
@@ -205,16 +203,6 @@ const BoundingBoxf3& GLCanvas3D::Bed::get_bounding_box() const
     return m_bounding_box;
 }
 
-const Pointf& GLCanvas3D::Bed::get_origin() const
-{
-    return m_origin;
-}
-
-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;
@@ -297,6 +285,56 @@ void GLCanvas3D::Bed::_calc_gridlines(const ExPolygon& poly, const BoundingBox&
         printf("Unable to create bed grid lines\n");
 }
 
+GLCanvas3D::Axes::Axes()
+    : m_length(0.0f)
+{
+}
+
+const Pointf3& GLCanvas3D::Axes::get_origin() const
+{
+    return m_origin;
+}
+
+void GLCanvas3D::Axes::set_origin(const Pointf3& origin)
+{
+    m_origin = origin;
+}
+
+float GLCanvas3D::Axes::get_length() const
+{
+    return m_length;
+}
+
+void GLCanvas3D::Axes::set_length(float length)
+{
+    m_length = length;
+}
+
+void GLCanvas3D::Axes::render()
+{
+    // disable depth testing so that axes are not covered by ground
+    ::glDisable(GL_DEPTH_TEST);
+    ::glLineWidth(2.0f);
+    ::glBegin(GL_LINES);
+    // draw line for x axis
+    ::glColor3f(1.0f, 0.0f, 0.0f);
+    ::glVertex3f((float)m_origin.x, (float)m_origin.y, (float)m_origin.z);
+    ::glVertex3f((float)m_origin.x + m_length, (float)m_origin.y, (float)m_origin.z);
+     // draw line for y axis
+    ::glColor3f(0.0f, 1.0f, 0.0f);
+    ::glVertex3f((float)m_origin.x, (float)m_origin.y, (float)m_origin.z);
+    ::glVertex3f((float)m_origin.x, (float)m_origin.y + m_length, (float)m_origin.z);
+    ::glEnd();
+    // draw line for Z axis
+    // (re-enable depth test so that axis is correctly shown when objects are behind it)
+    ::glEnable(GL_DEPTH_TEST);
+    ::glBegin(GL_LINES);
+    ::glColor3f(0.0f, 0.0f, 1.0f);
+    ::glVertex3f((float)m_origin.x, (float)m_origin.y, (float)m_origin.z);
+    ::glVertex3f((float)m_origin.x, (float)m_origin.y, (float)m_origin.z + m_length);
+    ::glEnd();
+}
+
 GLCanvas3D::CuttingPlane::CuttingPlane()
     : m_z(-1.0f)
 {
@@ -472,6 +510,10 @@ void GLCanvas3D::set_volumes(GLVolumeCollection* volumes)
 void GLCanvas3D::set_bed_shape(const Pointfs& shape)
 {
     m_bed.set_shape(shape);
+
+    // Set the origin and size for painting of the coordinate system axes.
+    set_axes_origin(Pointf3(0.0, 0.0, (coordf_t)GROUND_Z));
+    set_axes_length(0.3f * (float)bed_bounding_box().max_size());
 }
 
 void GLCanvas3D::set_auto_bed_shape()
@@ -491,17 +533,27 @@ void GLCanvas3D::set_auto_bed_shape()
     set_bed_shape(bed_shape);
 
     // Set the origin for painting of the coordinate system axes.
-    set_bed_origin(Pointf(center.x, center.y));
+    set_axes_origin(Pointf3(center.x, center.y, (coordf_t)GROUND_Z));
 }
 
-const Pointf& GLCanvas3D::get_bed_origin() const
+const Pointf3& GLCanvas3D::get_axes_origin() const
 {
-    return m_bed.get_origin();
+    return m_axes.get_origin();
 }
 
-void GLCanvas3D::set_bed_origin(const Pointf& origin)
+void GLCanvas3D::set_axes_origin(const Pointf3& origin)
 {
-    m_bed.set_origin(origin);
+    m_axes.set_origin(origin);
+}
+
+float GLCanvas3D::get_axes_length() const
+{
+    return m_axes.get_length();
+}
+
+void GLCanvas3D::set_axes_length(float length)
+{
+    return m_axes.set_length(length);
 }
 
 void GLCanvas3D::set_cutting_plane(float z, const ExPolygons& polygons)
@@ -645,9 +697,16 @@ void GLCanvas3D::select_view(const std::string& direction)
 
 void GLCanvas3D::render_bed()
 {
+    ::glDisable(GL_LIGHTING);
     m_bed.render();
 }
 
+void GLCanvas3D::render_axes()
+{
+    ::glDisable(GL_LIGHTING);
+    m_axes.render();
+}
+
 void GLCanvas3D::render_cutting_plane()
 {
     m_cutting_plane.render_plane(volumes_bounding_box());
diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp
index a7e9dbfb0..201a840be 100644
--- a/xs/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp
@@ -79,7 +79,6 @@ public:
     {
         Pointfs m_shape;
         BoundingBoxf3 m_bounding_box;
-        Pointf m_origin;
         Polygon m_polygon;
         GeometryBuffer m_triangles;
         GeometryBuffer m_gridlines;
@@ -90,9 +89,6 @@ public:
 
         const BoundingBoxf3& get_bounding_box() const;
 
-        const Pointf& get_origin() const;
-        void set_origin(const Pointf& origin);
-
         void render();
 
     private:
@@ -101,6 +97,23 @@ public:
         void _calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox);
     };
 
+    class Axes
+    {
+        Pointf3 m_origin;
+        float m_length;
+
+    public:
+        Axes();
+
+        const Pointf3& get_origin() const;
+        void set_origin(const Pointf3& origin);
+
+        float get_length() const;
+        void set_length(float length);
+
+        void render();
+    };
+
     class CuttingPlane
     {
         float m_z;
@@ -120,6 +133,7 @@ private:
     wxGLContext* m_context;
     Camera m_camera;
     Bed m_bed;
+    Axes m_axes;
     CuttingPlane m_cutting_plane;
 
     GLVolumeCollection* m_volumes;
@@ -153,8 +167,11 @@ public:
     // 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);
+    const Pointf3& get_axes_origin() const;
+    void set_axes_origin(const Pointf3& origin);
+
+    float get_axes_length() const;
+    void set_axes_length(float length);
 
     void set_cutting_plane(float z, const ExPolygons& polygons);
 
@@ -186,6 +203,7 @@ public:
     void select_view(const std::string& direction);
 
     void render_bed();
+    void render_axes();
     void render_cutting_plane();
 
     void register_on_viewport_changed_callback(void* callback);
diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp
index 911fb2f0e..48241dafb 100644
--- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp
+++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp
@@ -201,19 +201,6 @@ void GLCanvas3DManager::set_auto_bed_shape(wxGLCanvas* canvas)
         it->second->set_auto_bed_shape();
 }
 
-Pointf GLCanvas3DManager::get_bed_origin(wxGLCanvas* canvas) const
-{
-    CanvasesMap::const_iterator it = _get_canvas(canvas);
-    return (it != m_canvases.end()) ? it->second->get_bed_origin() : Pointf();
-}
-
-void GLCanvas3DManager::set_bed_origin(wxGLCanvas* canvas, const Pointf& origin)
-{
-    CanvasesMap::iterator it = _get_canvas(canvas);
-    if (it != m_canvases.end())
-        it->second->set_bed_origin(origin);
-}
-
 BoundingBoxf3 GLCanvas3DManager::get_bed_bounding_box(wxGLCanvas* canvas)
 {
     CanvasesMap::const_iterator it = _get_canvas(canvas);
@@ -232,6 +219,32 @@ BoundingBoxf3 GLCanvas3DManager::get_max_bounding_box(wxGLCanvas* canvas)
     return (it != m_canvases.end()) ? it->second->max_bounding_box() : BoundingBoxf3();
 }
 
+Pointf3 GLCanvas3DManager::get_axes_origin(wxGLCanvas* canvas) const
+{
+    CanvasesMap::const_iterator it = _get_canvas(canvas);
+    return (it != m_canvases.end()) ? it->second->get_axes_origin() : Pointf3();
+}
+
+void GLCanvas3DManager::set_axes_origin(wxGLCanvas* canvas, const Pointf3& origin)
+{
+    CanvasesMap::iterator it = _get_canvas(canvas);
+    if (it != m_canvases.end())
+        it->second->set_axes_origin(origin);
+}
+
+float GLCanvas3DManager::get_axes_length(wxGLCanvas* canvas) const
+{
+    CanvasesMap::const_iterator it = _get_canvas(canvas);
+    return (it != m_canvases.end()) ? it->second->get_axes_length() : 0.0f;
+}
+
+void GLCanvas3DManager::set_axes_length(wxGLCanvas* canvas, float length)
+{
+    CanvasesMap::iterator it = _get_canvas(canvas);
+    if (it != m_canvases.end())
+        it->second->set_axes_length(length);
+}
+
 void GLCanvas3DManager::set_cutting_plane(wxGLCanvas* canvas, float z, const ExPolygons& polygons)
 {
     CanvasesMap::iterator it = _get_canvas(canvas);
@@ -357,6 +370,13 @@ void GLCanvas3DManager::render_bed(wxGLCanvas* canvas)
         it->second->render_bed();
 }
 
+void GLCanvas3DManager::render_axes(wxGLCanvas* canvas)
+{
+    CanvasesMap::iterator it = _get_canvas(canvas);
+    if (it != m_canvases.end())
+        it->second->render_axes();
+}
+
 void GLCanvas3DManager::render_cutting_plane(wxGLCanvas* canvas)
 {
     CanvasesMap::iterator it = _get_canvas(canvas);
diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp
index 4d8066597..4877618f0 100644
--- a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp
+++ b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp
@@ -65,13 +65,16 @@ public:
     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);
-
     BoundingBoxf3 get_bed_bounding_box(wxGLCanvas* canvas);
     BoundingBoxf3 get_volumes_bounding_box(wxGLCanvas* canvas);
     BoundingBoxf3 get_max_bounding_box(wxGLCanvas* canvas);
 
+    Pointf3 get_axes_origin(wxGLCanvas* canvas) const;
+    void set_axes_origin(wxGLCanvas* canvas, const Pointf3& origin);
+
+    float get_axes_length(wxGLCanvas* canvas) const;
+    void set_axes_length(wxGLCanvas* canvas, float length);
+
     void set_cutting_plane(wxGLCanvas* canvas, float z, const ExPolygons& polygons);
 
     unsigned int get_camera_type(wxGLCanvas* canvas) const;
@@ -98,6 +101,7 @@ public:
     void select_view(wxGLCanvas* canvas, const std::string& direction);
 
     void render_bed(wxGLCanvas* canvas);
+    void render_axes(wxGLCanvas* canvas);
     void render_cutting_plane(wxGLCanvas* canvas);
 
     void register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback);
diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp
index 2efe8f11b..55679ba16 100644
--- a/xs/xsp/GUI_3DScene.xsp
+++ b/xs/xsp/GUI_3DScene.xsp
@@ -221,21 +221,6 @@ set_auto_bed_shape(canvas)
     CODE:
         _3DScene::set_auto_bed_shape((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
 
-Clone<Pointf>
-get_bed_origin(canvas)
-        SV      *canvas;
-    CODE:
-        RETVAL = _3DScene::get_bed_origin((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
-    OUTPUT:
-        RETVAL
-
-void
-set_bed_origin(canvas, origin)
-        SV     *canvas;
-        Pointf *origin
-    CODE:
-        _3DScene::set_bed_origin((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), origin);
-
 Clone<BoundingBoxf3>
 get_bed_bounding_box(canvas)
         SV *canvas;
@@ -283,6 +268,36 @@ is_shown_on_screen(canvas)
     OUTPUT:
         RETVAL
 
+Clone<Pointf3>
+get_axes_origin(canvas)
+        SV *canvas;
+    CODE:
+        RETVAL = _3DScene::get_axes_origin((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
+    OUTPUT:
+        RETVAL
+
+void
+set_axes_origin(canvas, origin)
+        SV      *canvas;
+        Pointf3 *origin;
+    CODE:
+        _3DScene::set_axes_origin((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), origin);
+
+float
+get_axes_length(canvas)
+        SV *canvas;
+    CODE:
+        RETVAL = _3DScene::get_axes_length((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
+    OUTPUT:
+        RETVAL
+
+void
+set_axes_length(canvas, length)
+        SV    *canvas;
+        float length;
+    CODE:
+        _3DScene::set_axes_length((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), length);
+
 void
 set_cutting_plane(canvas, z, polygons)
         SV         *canvas;
@@ -414,6 +429,12 @@ render_bed(canvas)
     CODE:
         _3DScene::render_bed((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
     
+void
+render_axes(canvas)
+        SV *canvas;
+    CODE:
+        _3DScene::render_axes((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
+    
 void
 render_cutting_plane(canvas)
         SV *canvas;