diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index 03055a582..4ca5b4188 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -1602,7 +1602,8 @@ sub draw_legend { if ($self->_legend_enabled) { - my $tex_id = Slic3r::GUI::_3DScene::get_legend_texture_id; + # If the legend texture has not been loaded into the GPU, do it now. + my $tex_id = Slic3r::GUI::_3DScene::finalize_legend_texture; if ($tex_id > 0) { my $tex_w = Slic3r::GUI::_3DScene::get_legend_texture_width; diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 17a39184d..6eaa231a6 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -786,7 +786,6 @@ sub remove { splice @{$self->{objects}}, $obj_idx, 1; $self->{model}->delete_object($obj_idx); $self->{print}->delete_object($obj_idx); - $self->{gcode_preview_data}->reset; $self->{list}->DeleteItem($obj_idx); $self->object_list_changed; @@ -807,7 +806,6 @@ sub reset { @{$self->{objects}} = (); $self->{model}->clear_objects; $self->{print}->clear_objects; - $self->{gcode_preview_data}->reset; $self->{list}->DeleteAllItems; $self->object_list_changed; @@ -1161,6 +1159,7 @@ sub async_apply_config { # Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared. # Otherwise they will be just refreshed. if ($invalidated) { + $self->{gcode_preview_data}->reset; $self->{toolpaths2D}->reload_print if $self->{toolpaths2D}; $self->{preview3D}->reload_print if $self->{preview3D}; } @@ -1267,8 +1266,6 @@ sub reslice { $self->stop_background_process; # Rather perform one additional unnecessary update of the print object instead of skipping a pending async update. $self->async_apply_config; - # Reset gcode data - $self->{gcode_preview_data}->reset; $self->statusbar->SetCancelCallback(sub { $self->stop_background_process; $self->statusbar->SetStatusText("Slicing cancelled"); diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 39f1a4102..538f9fefa 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -776,7 +776,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) _writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config.end_filament_gcode.get_at(m_writer.extruder()->id()), m_writer.extruder()->id())); } else { for (const std::string &end_gcode : print.config.end_filament_gcode.values) - _writeln(file, this->placeholder_parser_process("end_gcode", end_gcode, (unsigned int)(&end_gcode - &print.config.end_filament_gcode.values.front()))); + _writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, (unsigned int)(&end_gcode - &print.config.end_filament_gcode.values.front()))); } _writeln(file, this->placeholder_parser_process("end_gcode", print.config.end_gcode, m_writer.extruder()->id())); _write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100% diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 616d43496..3deadd105 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -1117,21 +1117,12 @@ const unsigned char _3DScene::LegendTexture::Squares_Border_Color[3] = { 64, 64, const unsigned char _3DScene::LegendTexture::Background_Color[3] = { 9, 91, 134 }; const unsigned char _3DScene::LegendTexture::Opacity = 255; -_3DScene::LegendTexture::LegendTexture() - : m_tex_id(0) - , m_tex_width(0) - , m_tex_height(0) +// Generate a texture data, but don't load it into the GPU yet, as the GPU context may not yet be valid. +bool _3DScene::LegendTexture::generate(const GCodePreviewData& preview_data, const std::vector& tool_colors) { -} - -_3DScene::LegendTexture::~LegendTexture() -{ - _destroy_texture(); -} - -bool _3DScene::LegendTexture::generate_texture(const GCodePreviewData& preview_data, const std::vector& tool_colors) -{ - _destroy_texture(); + // Mark the texture as released, but don't release the texture from the GPU yet. + m_tex_width = m_tex_height = 0; + m_data.clear(); // collects items to render const std::string& title = preview_data.get_legend_title(); @@ -1241,64 +1232,45 @@ bool _3DScene::LegendTexture::generate_texture(const GCodePreviewData& preview_d memDC.SelectObject(wxNullBitmap); - return _create_texture(preview_data, bitmap); -} - -unsigned int _3DScene::LegendTexture::get_texture_id() const -{ - return m_tex_id; -} - -unsigned int _3DScene::LegendTexture::get_texture_width() const -{ - return m_tex_width; -} - -unsigned int _3DScene::LegendTexture::get_texture_height() const -{ - return m_tex_height; -} - -void _3DScene::LegendTexture::reset_texture() -{ - _destroy_texture(); -} - -bool _3DScene::LegendTexture::_create_texture(const GCodePreviewData& preview_data, const wxBitmap& bitmap) -{ - if ((m_tex_width == 0) || (m_tex_height == 0)) - return false; - - wxImage image = bitmap.ConvertToImage(); - image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]); - - // prepare buffer - std::vector buffer(4 * m_tex_width * m_tex_height, 0); - for (unsigned int h = 0; h < m_tex_height; ++h) + // Convert the bitmap into a linear data ready to be loaded into the GPU. { - unsigned int hh = h * m_tex_width; - for (unsigned int w = 0; w < m_tex_width; ++w) + wxImage image = bitmap.ConvertToImage(); + image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]); + + // prepare buffer + m_data.assign(4 * m_tex_width * m_tex_height, 0); + for (unsigned int h = 0; h < m_tex_height; ++h) { - unsigned char* px_ptr = buffer.data() + 4 * (hh + w); - *px_ptr++ = image.GetRed(w, h); - *px_ptr++ = image.GetGreen(w, h); - *px_ptr++ = image.GetBlue(w, h); - *px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity; + unsigned int hh = h * m_tex_width; + unsigned char* px_ptr = m_data.data() + 4 * hh; + for (unsigned int w = 0; w < m_tex_width; ++w) + { + *px_ptr++ = image.GetRed(w, h); + *px_ptr++ = image.GetGreen(w, h); + *px_ptr++ = image.GetBlue(w, h); + *px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity; + } } } - - // sends buffer to gpu - ::glGenTextures(1, &m_tex_id); - ::glBindTexture(GL_TEXTURE_2D, m_tex_id); - ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)buffer.data()); - ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); - ::glBindTexture(GL_TEXTURE_2D, 0); - return true; } +unsigned int _3DScene::LegendTexture::finalize() +{ + if (! m_data.empty()) { + // sends buffer to gpu + ::glGenTextures(1, &m_tex_id); + ::glBindTexture(GL_TEXTURE_2D, m_tex_id); + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)m_data.data()); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); + ::glBindTexture(GL_TEXTURE_2D, 0); + m_data.clear(); + } + return (m_tex_width > 0 && m_tex_height > 0) ? m_tex_id : 0; +} + void _3DScene::LegendTexture::_destroy_texture() { if (m_tex_id > 0) @@ -1308,6 +1280,7 @@ void _3DScene::LegendTexture::_destroy_texture() m_tex_height = 0; m_tex_width = 0; } + m_data.clear(); } void _3DScene::_glew_init() @@ -2267,7 +2240,12 @@ void _3DScene::_update_gcode_volumes_visibility(const GCodePreviewData& preview_ void _3DScene::_generate_legend_texture(const GCodePreviewData& preview_data, const std::vector& tool_colors) { - s_legend_texture.generate_texture(preview_data, tool_colors); + s_legend_texture.generate(preview_data, tool_colors); +} + +unsigned int _3DScene::finalize_legend_texture() +{ + return s_legend_texture.finalize(); } void _3DScene::_load_shells(const Print& print, GLVolumeCollection& volumes, bool use_VBOs) diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index bf3515ac5..9cbcb6ebc 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -421,20 +421,25 @@ class _3DScene unsigned int m_tex_height; public: - LegendTexture(); - ~LegendTexture(); + LegendTexture() : m_tex_id(0), m_tex_width(0), m_tex_height(0) {} + ~LegendTexture() { _destroy_texture(); } - bool generate_texture(const GCodePreviewData& preview_data, const std::vector& tool_colors); + // Generate a texture data, but don't load it into the GPU yet, as the glcontext may not be valid yet. + bool generate(const GCodePreviewData& preview_data, const std::vector& tool_colors); + // If not loaded, load the texture data into the GPU. Return a texture ID or 0 if the texture has zero size. + unsigned int finalize(); - unsigned int get_texture_id() const; - unsigned int get_texture_width() const; - unsigned int get_texture_height() const; + unsigned int get_texture_id() const { return m_tex_id; } + unsigned int get_texture_width() const { return m_tex_width; } + unsigned int get_texture_height() const { return m_tex_height; } - void reset_texture(); + void reset_texture() { _destroy_texture(); } private: bool _create_texture(const GCodePreviewData& preview_data, const wxBitmap& bitmap); void _destroy_texture(); + // generate() fills in m_data with the pixels, while finalize() moves the data to the GPU before rendering. + std::vector m_data; }; static LegendTexture s_legend_texture; @@ -449,6 +454,7 @@ public: static unsigned int get_legend_texture_height(); static void reset_legend_texture(); + static unsigned int finalize_legend_texture(); static void _load_print_toolpaths( const Print *print, diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index c06c659b1..961c837d9 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -141,6 +141,13 @@ _glew_init() CODE: _3DScene::_glew_init(); +unsigned int +finalize_legend_texture() + CODE: + RETVAL = _3DScene::finalize_legend_texture(); + OUTPUT: + RETVAL + unsigned int get_legend_texture_id() CODE: