From 50a38c0d90ca62316b5b5e0eb3640a0a027dc0ea Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 3 Jan 2022 13:17:34 +0100 Subject: [PATCH] Refactoring in Selection and Bed3D - OpenGL data initialization moved into render calls and removed all const_cast<> eveniences --- src/slic3r/GUI/3DBed.cpp | 84 ++++++++++++++++------------------- src/slic3r/GUI/3DBed.hpp | 14 +++--- src/slic3r/GUI/GLCanvas3D.cpp | 9 ++-- src/slic3r/GUI/GLCanvas3D.hpp | 6 +-- src/slic3r/GUI/Selection.cpp | 63 +++++++++++++------------- src/slic3r/GUI/Selection.hpp | 23 +++++----- 6 files changed, 92 insertions(+), 107 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index fe58901831..a7bed5619d 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -99,7 +99,7 @@ const float Bed3D::Axes::DefaultStemLength = 25.0f; const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius; const float Bed3D::Axes::DefaultTipLength = 5.0f; -void Bed3D::Axes::render() const +void Bed3D::Axes::render() { auto render_axis = [this](const Transform3f& transform) { glsafe(::glPushMatrix()); @@ -109,7 +109,7 @@ void Bed3D::Axes::render() const }; if (!m_arrow.is_initialized()) - const_cast(&m_arrow)->init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length)); + m_arrow.init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length)); GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader == nullptr) @@ -121,15 +121,15 @@ void Bed3D::Axes::render() const shader->set_uniform("emission_factor", 0.0f); // x axis - const_cast(&m_arrow)->set_color(-1, { 0.75f, 0.0f, 0.0f, 1.0f }); + m_arrow.set_color(-1, { 0.75f, 0.0f, 0.0f, 1.0f }); render_axis(Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0 }).cast()); // y axis - const_cast(&m_arrow)->set_color(-1, { 0.0f, 0.75f, 0.0f, 1.0f }); + m_arrow.set_color(-1, { 0.0f, 0.75f, 0.0f, 1.0f }); render_axis(Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0 }).cast()); // z axis - const_cast(&m_arrow)->set_color(-1, { 0.0f, 0.0f, 0.75f, 1.0f }); + m_arrow.set_color(-1, { 0.0f, 0.0f, 0.75f, 1.0f }); render_axis(Geometry::assemble_transform(m_origin).cast()); shader->stop_using(); @@ -228,8 +228,7 @@ void Bed3D::render_for_picking(GLCanvas3D& canvas, bool bottom, float scale_fact void Bed3D::render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes, bool show_texture, bool picking) { - float* factor = const_cast(&m_scale_factor); - *factor = scale_factor; + m_scale_factor = scale_factor; if (show_axes) render_axes(); @@ -328,13 +327,13 @@ std::tuple Bed3D::detect_type(const Point return { Type::Custom, {}, {} }; } -void Bed3D::render_axes() const +void Bed3D::render_axes() { if (m_build_volume.valid()) m_axes.render(); } -void Bed3D::render_system(GLCanvas3D& canvas, bool bottom, bool show_texture) const +void Bed3D::render_system(GLCanvas3D& canvas, bool bottom, bool show_texture) { if (!bottom) render_model(); @@ -343,26 +342,23 @@ void Bed3D::render_system(GLCanvas3D& canvas, bool bottom, bool show_texture) co render_texture(bottom, canvas); } -void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const +void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) { - GLTexture* texture = const_cast(&m_texture); - GLTexture* temp_texture = const_cast(&m_temp_texture); - if (m_texture_filename.empty()) { - texture->reset(); + m_texture.reset(); render_default(bottom, false); return; } - if (texture->get_id() == 0 || texture->get_source() != m_texture_filename) { - texture->reset(); + if (m_texture.get_id() == 0 || m_texture.get_source() != m_texture_filename) { + m_texture.reset(); if (boost::algorithm::iends_with(m_texture_filename, ".svg")) { // use higher resolution images if graphic card and opengl version allow GLint max_tex_size = OpenGLManager::get_gl_info().get_max_tex_size(); - if (temp_texture->get_id() == 0 || temp_texture->get_source() != m_texture_filename) { + if (m_temp_texture.get_id() == 0 || m_temp_texture.get_source() != m_texture_filename) { // generate a temporary lower resolution texture to show while no main texture levels have been compressed - if (!temp_texture->load_from_svg_file(m_texture_filename, false, false, false, max_tex_size / 8)) { + if (!m_temp_texture.load_from_svg_file(m_texture_filename, false, false, false, max_tex_size / 8)) { render_default(bottom, false); return; } @@ -370,15 +366,15 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const } // starts generating the main texture, compression will run asynchronously - if (!texture->load_from_svg_file(m_texture_filename, true, true, true, max_tex_size)) { + if (!m_texture.load_from_svg_file(m_texture_filename, true, true, true, max_tex_size)) { render_default(bottom, false); return; } } else if (boost::algorithm::iends_with(m_texture_filename, ".png")) { // generate a temporary lower resolution texture to show while no main texture levels have been compressed - if (temp_texture->get_id() == 0 || temp_texture->get_source() != m_texture_filename) { - if (!temp_texture->load_from_png_file(m_texture_filename, false, GLTexture::ECompressionType::None, false)) { + if (m_temp_texture.get_id() == 0 || m_temp_texture.get_source() != m_texture_filename) { + if (!m_temp_texture.load_from_png_file(m_texture_filename, false, GLTexture::ECompressionType::None, false)) { render_default(bottom, false); return; } @@ -386,7 +382,7 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const } // starts generating the main texture, compression will run asynchronously - if (!texture->load_from_png_file(m_texture_filename, true, GLTexture::ECompressionType::MultiThreaded, true)) { + if (!m_texture.load_from_png_file(m_texture_filename, true, GLTexture::ECompressionType::MultiThreaded, true)) { render_default(bottom, false); return; } @@ -396,13 +392,13 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const return; } } - else if (texture->unsent_compressed_data_available()) { + else if (m_texture.unsent_compressed_data_available()) { // sends to gpu the already available compressed levels of the main texture - texture->send_compressed_data_to_gpu(); + m_texture.send_compressed_data_to_gpu(); // the temporary texture is not needed anymore, reset it - if (temp_texture->get_id() != 0) - temp_texture->reset(); + if (m_temp_texture.get_id() != 0) + m_temp_texture.reset(); canvas.request_extra_frame(); } @@ -414,11 +410,9 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const shader->set_uniform("transparent_background", bottom); shader->set_uniform("svg_source", boost::algorithm::iends_with(m_texture.get_source(), ".svg")); - unsigned int* vbo_id = const_cast(&m_vbo_id); - - if (*vbo_id == 0) { - glsafe(::glGenBuffers(1, vbo_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, *vbo_id)); + if (m_vbo_id == 0) { + glsafe(::glGenBuffers(1, &m_vbo_id)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } @@ -439,12 +433,12 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const GLint tex_coords_id = shader->get_attrib_location("v_tex_coords"); // show the temporary texture while no compressed data is available - GLuint tex_id = (GLuint)temp_texture->get_id(); + GLuint tex_id = (GLuint)m_temp_texture.get_id(); if (tex_id == 0) - tex_id = (GLuint)texture->get_id(); + tex_id = (GLuint)m_texture.get_id(); glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, *vbo_id)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); if (position_id != -1) { glsafe(::glEnableVertexAttribArray(position_id)); @@ -478,38 +472,36 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const } } -void Bed3D::render_model() const +void Bed3D::render_model() { if (m_model_filename.empty()) return; - GLModel* model = const_cast(&m_model); - - if (model->get_filename() != m_model_filename && model->init_from_file(m_model_filename)) { - model->set_color(-1, DEFAULT_MODEL_COLOR); + if (m_model.get_filename() != m_model_filename && m_model.init_from_file(m_model_filename)) { + m_model.set_color(-1, DEFAULT_MODEL_COLOR); // move the model so that its origin (0.0, 0.0, 0.0) goes into the bed shape center and a bit down to avoid z-fighting with the texture quad - *const_cast(&m_model_offset) = to_3d(m_build_volume.bounding_volume2d().center(), -0.03); + m_model_offset = to_3d(m_build_volume.bounding_volume2d().center(), -0.03); // update extended bounding box - const_cast(m_extended_bounding_box) = this->calc_extended_bounding_box(); + m_extended_bounding_box = this->calc_extended_bounding_box(); } - if (!model->get_filename().empty()) { + if (!m_model.get_filename().empty()) { GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light"); if (shader != nullptr) { shader->start_using(); shader->set_uniform("emission_factor", 0.0f); glsafe(::glPushMatrix()); glsafe(::glTranslated(m_model_offset.x(), m_model_offset.y(), m_model_offset.z())); - model->render(); + m_model.render(); glsafe(::glPopMatrix()); shader->stop_using(); } } } -void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture, bool picking) const +void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture, bool picking) { if (m_texture_filename.empty() && m_model_filename.empty()) { render_default(bottom, picking); @@ -523,9 +515,9 @@ void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture, bo render_texture(bottom, canvas); } -void Bed3D::render_default(bool bottom, bool picking) const +void Bed3D::render_default(bool bottom, bool picking) { - const_cast(&m_texture)->reset(); + m_texture.reset(); unsigned int triangles_vcount = m_triangles.get_vertices_count(); if (triangles_vcount > 0) { diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index 639dc6c163..82c6b817be 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -60,7 +60,7 @@ class Bed3D m_arrow.reset(); } float get_total_length() const { return m_stem_length + DefaultTipLength; } - void render() const; + void render(); }; public: @@ -130,12 +130,12 @@ private: static std::tuple detect_type(const Pointfs& shape); void render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes, bool show_texture, bool picking); - void render_axes() const; - void render_system(GLCanvas3D& canvas, bool bottom, bool show_texture) const; - void render_texture(bool bottom, GLCanvas3D& canvas) const; - void render_model() const; - void render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture, bool picking) const; - void render_default(bool bottom, bool picking) const; + void render_axes(); + void render_system(GLCanvas3D& canvas, bool bottom, bool show_texture); + void render_texture(bool bottom, GLCanvas3D& canvas); + void render_model(); + void render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture, bool picking); + void render_default(bool bottom, bool picking); void release_VBOs(); }; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index bdb24b7892..4b37d6701c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1089,9 +1089,6 @@ bool GLCanvas3D::init() if (!_init_toolbars()) return false; - if (m_selection.is_enabled() && !m_selection.init()) - return false; - m_initialized = true; return true; @@ -5213,7 +5210,7 @@ void GLCanvas3D::_render_gcode() m_gcode_viewer.render(); } -void GLCanvas3D::_render_selection() const +void GLCanvas3D::_render_selection() { float scale_factor = 1.0; #if ENABLE_RETINA_GL @@ -5244,7 +5241,7 @@ void GLCanvas3D::_render_sequential_clearance() } #if ENABLE_RENDER_SELECTION_CENTER -void GLCanvas3D::_render_selection_center() const +void GLCanvas3D::_render_selection_center() { m_selection.render_center(m_gizmos.is_dragging()); } @@ -5637,7 +5634,7 @@ void GLCanvas3D::_render_sla_slices() } } -void GLCanvas3D::_render_selection_sidebar_hints() const +void GLCanvas3D::_render_selection_sidebar_hints() { m_selection.render_sidebar_hints(m_sidebar_field); } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 7942d9aff3..3512cf1940 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -911,10 +911,10 @@ private: void _render_bed_for_picking(bool bottom); void _render_objects(GLVolumeCollection::ERenderType type); void _render_gcode(); - void _render_selection() const; + void _render_selection(); void _render_sequential_clearance(); #if ENABLE_RENDER_SELECTION_CENTER - void _render_selection_center() const; + void _render_selection_center(); #endif // ENABLE_RENDER_SELECTION_CENTER void _check_and_update_toolbar_icon_scale(); void _render_overlays(); @@ -929,7 +929,7 @@ private: void _render_camera_target() const; #endif // ENABLE_SHOW_CAMERA_TARGET void _render_sla_slices(); - void _render_selection_sidebar_hints() const; + void _render_selection_sidebar_hints(); bool _render_undo_redo_stack(const bool is_undo, float pos_x); bool _render_search_list(float pos_x); bool _render_arrange_menu(float pos_x); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index aa222c50cb..e481bcc3e0 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -127,19 +127,6 @@ void Selection::set_volumes(GLVolumePtrs* volumes) update_valid(); } -// Init shall be called from the OpenGL render function, so that the OpenGL context is initialized! -bool Selection::init() -{ - m_arrow.init_from(straight_arrow(10.0f, 5.0f, 5.0f, 10.0f, 1.0f)); - m_curved_arrow.init_from(circular_arrow(16, 10.0f, 5.0f, 10.0f, 5.0f, 1.0f)); - -#if ENABLE_RENDER_SELECTION_CENTER - m_vbo_sphere.init_from(make_sphere(0.75, 2*PI/24)); -#endif // ENABLE_RENDER_SELECTION_CENTER - - return true; -} - void Selection::set_model(Model* model) { m_model = model; @@ -1296,12 +1283,17 @@ void Selection::erase() } } -void Selection::render(float scale_factor) const +void Selection::render(float scale_factor) { if (!m_valid || is_empty()) return; - *const_cast(&m_scale_factor) = scale_factor; + if (!m_arrow.is_initialized()) + m_arrow.init_from(straight_arrow(10.0f, 5.0f, 5.0f, 10.0f, 1.0f)); + if (!m_curved_arrow.is_initialized()) + m_curved_arrow.init_from(circular_arrow(16, 10.0f, 5.0f, 10.0f, 5.0f, 1.0f)); + + m_scale_factor = scale_factor; // render cumulative bounding box of selected volumes render_selected_volumes(); @@ -1309,24 +1301,29 @@ void Selection::render(float scale_factor) const } #if ENABLE_RENDER_SELECTION_CENTER -void Selection::render_center(bool gizmo_is_dragging) const +void Selection::render_center(bool gizmo_is_dragging) { if (!m_valid || is_empty()) return; +#if ENABLE_RENDER_SELECTION_CENTER + if (!m_sphere.is_initialized()) + m_sphere.init_from(its_make_sphere(0.75, 2 * PI / 24)); +#endif // ENABLE_RENDER_SELECTION_CENTER + const Vec3d center = gizmo_is_dragging ? m_cache.dragging_center : get_bounding_box().center(); glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glColor3f(1.0f, 1.0f, 1.0f)); glsafe(::glPushMatrix()); - glsafe(::glTranslated(center(0), center(1), center(2))); - m_vbo_sphere.render(); + glsafe(::glTranslated(center.x(), center.y(), center.z())); + m_sphere.render(); glsafe(::glPopMatrix()); } #endif // ENABLE_RENDER_SELECTION_CENTER -void Selection::render_sidebar_hints(const std::string& sidebar_field) const +void Selection::render_sidebar_hints(const std::string& sidebar_field) { if (sidebar_field.empty()) return; @@ -1837,13 +1834,13 @@ void Selection::do_remove_object(unsigned int object_idx) } } -void Selection::render_selected_volumes() const +void Selection::render_selected_volumes() { float color[3] = { 1.0f, 1.0f, 1.0f }; render_bounding_box(get_bounding_box(), color); } -void Selection::render_synchronized_volumes() const +void Selection::render_synchronized_volumes() { if (m_mode == Instance) return; @@ -1867,7 +1864,7 @@ void Selection::render_synchronized_volumes() const } } -void Selection::render_bounding_box(const BoundingBoxf3& box, float* color) const +void Selection::render_bounding_box(const BoundingBoxf3& box, float* color) { if (color == nullptr) return; @@ -1923,25 +1920,25 @@ static std::array get_color(Axis axis) return { AXES_COLOR[axis][0], AXES_COLOR[axis][1], AXES_COLOR[axis][2], AXES_COLOR[axis][3] }; }; -void Selection::render_sidebar_position_hints(const std::string& sidebar_field) const +void Selection::render_sidebar_position_hints(const std::string& sidebar_field) { if (boost::ends_with(sidebar_field, "x")) { glsafe(::glRotated(-90.0, 0.0, 0.0, 1.0)); - const_cast(&m_arrow)->set_color(-1, get_color(X)); + m_arrow.set_color(-1, get_color(X)); m_arrow.render(); } else if (boost::ends_with(sidebar_field, "y")) { - const_cast(&m_arrow)->set_color(-1, get_color(Y)); + m_arrow.set_color(-1, get_color(Y)); m_arrow.render(); } else if (boost::ends_with(sidebar_field, "z")) { glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); - const_cast(&m_arrow)->set_color(-1, get_color(Z)); + m_arrow.set_color(-1, get_color(Z)); m_arrow.render(); } } -void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field) const +void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field) { auto render_sidebar_rotation_hint = [this]() { m_curved_arrow.render(); @@ -1951,26 +1948,26 @@ void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field) if (boost::ends_with(sidebar_field, "x")) { glsafe(::glRotated(90.0, 0.0, 1.0, 0.0)); - const_cast(&m_curved_arrow)->set_color(-1, get_color(X)); + m_curved_arrow.set_color(-1, get_color(X)); render_sidebar_rotation_hint(); } else if (boost::ends_with(sidebar_field, "y")) { glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); - const_cast(&m_curved_arrow)->set_color(-1, get_color(Y)); + m_curved_arrow.set_color(-1, get_color(Y)); render_sidebar_rotation_hint(); } else if (boost::ends_with(sidebar_field, "z")) { - const_cast(&m_curved_arrow)->set_color(-1, get_color(Z)); + m_curved_arrow.set_color(-1, get_color(Z)); render_sidebar_rotation_hint(); } } -void Selection::render_sidebar_scale_hints(const std::string& sidebar_field) const +void Selection::render_sidebar_scale_hints(const std::string& sidebar_field) { bool uniform_scale = requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling(); auto render_sidebar_scale_hint = [this, uniform_scale](Axis axis) { - const_cast(&m_arrow)->set_color(-1, uniform_scale ? UNIFORM_SCALE_COLOR : get_color(axis)); + m_arrow.set_color(-1, uniform_scale ? UNIFORM_SCALE_COLOR : get_color(axis)); GLShaderProgram* shader = wxGetApp().get_current_shader(); if (shader != nullptr) shader->set_uniform("emission_factor", 0.0f); @@ -2004,7 +2001,7 @@ void Selection::render_sidebar_scale_hints(const std::string& sidebar_field) con } } -void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) const +void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) { static const double Margin = 10.0; diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index c18d24eab5..ecc7ed8478 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -215,7 +215,7 @@ private: std::optional m_scaled_instance_bounding_box; #if ENABLE_RENDER_SELECTION_CENTER - GLModel m_vbo_sphere; + GLModel m_sphere; #endif // ENABLE_RENDER_SELECTION_CENTER GLModel m_arrow; @@ -228,7 +228,6 @@ public: Selection(); void set_volumes(GLVolumePtrs* volumes); - bool init(); bool is_enabled() const { return m_enabled; } void set_enabled(bool enable) { m_enabled = enable; } @@ -335,11 +334,11 @@ public: void erase(); - void render(float scale_factor = 1.0) const; + void render(float scale_factor = 1.0); #if ENABLE_RENDER_SELECTION_CENTER - void render_center(bool gizmo_is_dragging) const; + void render_center(bool gizmo_is_dragging); #endif // ENABLE_RENDER_SELECTION_CENTER - void render_sidebar_hints(const std::string& sidebar_field) const; + void render_sidebar_hints(const std::string& sidebar_field); bool requires_local_axes() const; @@ -369,13 +368,13 @@ private: void do_remove_instance(unsigned int object_idx, unsigned int instance_idx); void do_remove_object(unsigned int object_idx); void set_bounding_boxes_dirty() { m_bounding_box.reset(); m_unscaled_instance_bounding_box.reset(); m_scaled_instance_bounding_box.reset(); } - void render_selected_volumes() const; - void render_synchronized_volumes() const; - void render_bounding_box(const BoundingBoxf3& box, float* color) const; - void render_sidebar_position_hints(const std::string& sidebar_field) const; - void render_sidebar_rotation_hints(const std::string& sidebar_field) const; - void render_sidebar_scale_hints(const std::string& sidebar_field) const; - void render_sidebar_layers_hints(const std::string& sidebar_field) const; + void render_selected_volumes(); + void render_synchronized_volumes(); + void render_bounding_box(const BoundingBoxf3& box, float* color); + void render_sidebar_position_hints(const std::string& sidebar_field); + void render_sidebar_rotation_hints(const std::string& sidebar_field); + void render_sidebar_scale_hints(const std::string& sidebar_field); + void render_sidebar_layers_hints(const std::string& sidebar_field); public: enum SyncRotationType {