diff --git a/xs/src/libslic3r/BoundingBox.hpp b/xs/src/libslic3r/BoundingBox.hpp index 1f71536ee..5324dbe3b 100644 --- a/xs/src/libslic3r/BoundingBox.hpp +++ b/xs/src/libslic3r/BoundingBox.hpp @@ -103,6 +103,10 @@ public: bool contains(const BoundingBox3Base& other) const { return contains(other.min) && contains(other.max); } + + bool intersects(const BoundingBox3Base& other) const { + return (this->min.x < other.max.x) && (this->max.x > other.min.x) && (this->min.y < other.max.y) && (this->max.y > other.min.y) && (this->min.z < other.max.z) && (this->max.z > other.min.z); + } }; class BoundingBox : public BoundingBoxBase diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index eb4146a67..8e0862cf2 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -785,9 +785,10 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // Order objects using a nearest neighbor search. std::vector object_indices; Points object_reference_points; - for (PrintObject *object : print.objects) + PrintObjectPtrs printable_objects = print.get_printable_objects(); + for (PrintObject *object : printable_objects) object_reference_points.push_back(object->_shifted_copies.front()); - Slic3r::Geometry::chained_path(object_reference_points, object_indices); + Slic3r::Geometry::chained_path(object_reference_points, object_indices); // Sort layers by Z. // All extrusion moves with the same top layer height are extruded uninterrupted. std::vector>> layers_to_print = collect_layers_to_print(print); @@ -799,7 +800,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // Verify, whether the print overaps the priming extrusions. BoundingBoxf bbox_print(get_print_extrusions_extents(print)); coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON; - for (const PrintObject *print_object : print.objects) + for (const PrintObject *print_object : printable_objects) bbox_print.merge(get_print_object_extrusions_extents(*print_object, twolayers_printz)); bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz)); BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print)); diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 3a28ec129..9b3f2694f 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -67,11 +67,13 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material) { m_print_config_ptr = &print.config; + + PrintObjectPtrs objects = print.get_printable_objects(); // Initialize the print layers for all objects and all layers. coordf_t object_bottom_z = 0.; { std::vector zs; - for (auto object : print.objects) { + for (auto object : objects) { zs.reserve(zs.size() + object->layers.size() + object->support_layers.size()); for (auto layer : object->layers) zs.emplace_back(layer->print_z); @@ -84,7 +86,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool } // Collect extruders reuqired to print the layers. - for (auto object : print.objects) + for (auto object : objects) this->collect_extruders(*object); // Reorder the extruders to minimize tool switches. diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index b2e439e5d..d6f1f05c9 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -1235,6 +1235,59 @@ void ModelObject::split(ModelObjectPtrs* new_objects) return; } +void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume) +{ + for (ModelVolume* vol : this->volumes) + { + if (!vol->modifier) + { + for (ModelInstance* inst : this->instances) + { + BoundingBoxf3 bb; + + double c = cos(inst->rotation); + double s = sin(inst->rotation); + + for (int f = 0; f < vol->mesh.stl.stats.number_of_facets; ++f) + { + const stl_facet& facet = vol->mesh.stl.facet_start[f]; + + for (int i = 0; i < 3; ++i) + { + // original point + const stl_vertex& v = facet.vertex[i]; + Pointf3 p((double)v.x, (double)v.y, (double)v.z); + + // scale + p.x *= inst->scaling_factor; + p.y *= inst->scaling_factor; + p.z *= inst->scaling_factor; + + // rotate Z + double x = p.x; + double y = p.y; + p.x = c * x - s * y; + p.y = s * x + c * y; + + // translate + p.x += inst->offset.x; + p.y += inst->offset.y; + + bb.merge(p); + } + } + + if (print_volume.contains(bb)) + inst->print_volume_state = ModelInstance::PVS_Inside; + else if (print_volume.intersects(bb)) + inst->print_volume_state = ModelInstance::PVS_Partly_Outside; + else + inst->print_volume_state = ModelInstance::PVS_Fully_Outside; + } + } + } +} + void ModelObject::print_info() const { using namespace std; diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp index 5003f8330..f5e97fb6a 100644 --- a/xs/src/libslic3r/Model.hpp +++ b/xs/src/libslic3r/Model.hpp @@ -132,6 +132,8 @@ public: void cut(coordf_t z, Model* model) const; void split(ModelObjectPtrs* new_objects); + void check_instances_print_volume_state(const BoundingBoxf3& print_volume); + // Print object statistics to console. void print_info() const; @@ -197,12 +199,24 @@ private: // Knows the affine transformation of an object. class ModelInstance { - friend class ModelObject; public: + enum EPrintVolumeState : unsigned char + { + PVS_Inside, + PVS_Partly_Outside, + PVS_Fully_Outside, + Num_BedStates + }; + + friend class ModelObject; + double rotation; // Rotation around the Z axis, in radians around mesh center point double scaling_factor; Pointf offset; // in unscaled coordinates + // flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state()) + EPrintVolumeState print_volume_state; + ModelObject* get_object() const { return this->object; } // To be called on an external mesh @@ -213,14 +227,16 @@ public: BoundingBoxf3 transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate = false) const; // To be called on an external polygon. It does not translate the polygon, only rotates and scales. void transform_polygon(Polygon* polygon) const; - + + bool is_printable() const { return print_volume_state == PVS_Inside; } + private: // Parent object, owning this instance. ModelObject* object; - ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), object(object) {} + ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), object(object), print_volume_state(PVS_Inside) {} ModelInstance(ModelObject *object, const ModelInstance &other) : - rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object) {} + rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object), print_volume_state(PVS_Inside) {} }; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 1abe02b84..e08ae1fc4 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -71,6 +71,13 @@ bool Print::reload_model_instances() return invalidated; } +PrintObjectPtrs Print::get_printable_objects() const +{ + PrintObjectPtrs printable_objects(this->objects); + printable_objects.erase(std::remove_if(printable_objects.begin(), printable_objects.end(), [](PrintObject* o) { return !o->is_printable(); }), printable_objects.end()); + return printable_objects; +} + PrintRegion* Print::add_region() { regions.push_back(new PrintRegion(this)); @@ -534,11 +541,17 @@ std::string Print::validate() const BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config.max_print_height)); // Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced. print_volume.min.z = -1e10; + unsigned int printable_count = 0; for (PrintObject *po : this->objects) { - if (!print_volume.contains(po->model_object()->tight_bounding_box(false))) - return L("Some objects are outside of the print volume."); + po->model_object()->check_instances_print_volume_state(print_volume); + po->reload_model_instances(); + if (po->is_printable()) + ++printable_count; } + if (printable_count == 0) + return L("All objects are outside of the print volume."); + if (this->config.complete_objects) { // Check horizontal clearance. { @@ -858,8 +871,9 @@ void Print::_make_skirt() // prepended to the first 'n' layers (with 'n' = skirt_height). // $skirt_height_z in this case is the highest possible skirt height for safety. coordf_t skirt_height_z = 0.; - for (const PrintObject *object : this->objects) { - size_t skirt_layers = this->has_infinite_skirt() ? + PrintObjectPtrs printable_objects = get_printable_objects(); + for (const PrintObject *object : printable_objects) { + size_t skirt_layers = this->has_infinite_skirt() ? object->layer_count() : std::min(size_t(this->config.skirt_height.value), object->layer_count()); skirt_height_z = std::max(skirt_height_z, object->layers[skirt_layers-1]->print_z); @@ -867,7 +881,7 @@ void Print::_make_skirt() // Collect points from all layers contained in skirt height. Points points; - for (const PrintObject *object : this->objects) { + for (const PrintObject *object : printable_objects) { Points object_points; // Get object layers up to skirt_height_z. for (const Layer *layer : object->layers) { @@ -980,7 +994,8 @@ void Print::_make_brim() // Brim is only printed on first layer and uses perimeter extruder. Flow flow = this->brim_flow(); Polygons islands; - for (PrintObject *object : this->objects) { + PrintObjectPtrs printable_objects = get_printable_objects(); + for (PrintObject *object : printable_objects) { Polygons object_islands; for (ExPolygon &expoly : object->layers.front()->slices.expolygons) object_islands.push_back(expoly.contour); diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 2217547ea..bcd61ea02 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -209,6 +209,8 @@ public: void combine_infill(); void _generate_support_material(); + bool is_printable() const { return !this->_shifted_copies.empty(); } + private: Print* _print; ModelObject* _model_object; @@ -257,6 +259,8 @@ public: void reload_object(size_t idx); bool reload_model_instances(); + PrintObjectPtrs get_printable_objects() const; + // methods for handling regions PrintRegion* get_region(size_t idx) { return regions.at(idx); } const PrintRegion* get_region(size_t idx) const { return regions.at(idx); } diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 7ac165864..8888da76d 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -102,7 +102,10 @@ bool PrintObject::reload_model_instances() Points copies; copies.reserve(this->_model_object->instances.size()); for (const ModelInstance *mi : this->_model_object->instances) - copies.emplace_back(Point::new_scale(mi->offset.x, mi->offset.y)); + { + if (mi->is_printable()) + copies.emplace_back(Point::new_scale(mi->offset.x, mi->offset.y)); + } return this->set_copies(copies); } @@ -291,6 +294,9 @@ bool PrintObject::has_support_material() const void PrintObject::_prepare_infill() { + if (!this->is_printable()) + return; + // This will assign a type (top/bottom/internal) to $layerm->slices. // Then the classifcation of $layerm->slices is transfered onto // the $layerm->fill_surfaces by clipping $layerm->fill_surfaces @@ -1442,6 +1448,9 @@ void PrintObject::_simplify_slices(double distance) void PrintObject::_make_perimeters() { + if (!this->is_printable()) + return; + if (this->state.is_done(posPerimeters)) return; this->state.set_started(posPerimeters); @@ -1550,6 +1559,9 @@ void PrintObject::_make_perimeters() void PrintObject::_infill() { + if (!this->is_printable()) + return; + if (this->state.is_done(posInfill)) return; this->state.set_started(posInfill); @@ -1954,6 +1966,9 @@ void PrintObject::combine_infill() void PrintObject::_generate_support_material() { + if (!this->is_printable()) + return; + PrintObjectSupportMaterial support_material(this, PrintObject::slicing_parameters()); support_material.generate(*this); } diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index d8fe592e8..2ffd788eb 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -22,11 +22,6 @@ #include #include -#include -#include -#include -#include - #include #include "GUI.hpp" @@ -540,8 +535,8 @@ double GLVolume::layer_height_texture_z_to_row_id() const void GLVolume::generate_layer_height_texture(PrintObject *print_object, bool force) { - GLTexture *tex = this->layer_height_texture.get(); - if (tex == nullptr) + LayersTexture *tex = this->layer_height_texture.get(); + if (tex == nullptr) // No layer_height_texture is assigned to this GLVolume, therefore the layer height texture cannot be filled. return; @@ -588,8 +583,8 @@ std::vector GLVolumeCollection::load_object( }; // Object will have a single common layer height texture for all volumes. - std::shared_ptr layer_height_texture = std::make_shared(); - + std::shared_ptr layer_height_texture = std::make_shared(); + std::vector volumes_idx; for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++ volume_idx) { const ModelVolume *model_volume = model_object->volumes[volume_idx]; @@ -743,7 +738,7 @@ void GLVolumeCollection::render_legacy() const glDisable(GL_BLEND); } -bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config) +bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstance::EPrintVolumeState* out_state) { if (config == nullptr) return false; @@ -757,18 +752,31 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config) // Allow the objects to protrude below the print bed print_volume.min.z = -1e10; - bool contained = true; + ModelInstance::EPrintVolumeState state = ModelInstance::PVS_Inside; + bool all_contained = true; + for (GLVolume* volume : this->volumes) { if ((volume != nullptr) && !volume->is_modifier) { - bool state = print_volume.contains(volume->transformed_bounding_box()); - contained &= state; - volume->is_outside = !state; + const BoundingBoxf3& bb = volume->transformed_bounding_box(); + bool contained = print_volume.contains(bb); + all_contained &= contained; + + volume->is_outside = !contained; + + if ((state == ModelInstance::PVS_Inside) && volume->is_outside) + state = ModelInstance::PVS_Fully_Outside; + + if ((state == ModelInstance::PVS_Fully_Outside) && volume->is_outside && print_volume.intersects(bb)) + state = ModelInstance::PVS_Partly_Outside; } } - return contained; + if (out_state != nullptr) + *out_state = state; + + return all_contained; } void GLVolumeCollection::reset_outside_state() @@ -1576,246 +1584,8 @@ void _3DScene::point3_to_verts(const Point3& point, double width, double height, thick_point_to_verts(point, width, height, volume); } -_3DScene::LegendTexture _3DScene::s_legend_texture; -_3DScene::WarningTexture _3DScene::s_warning_texture; GUI::GLCanvas3DManager _3DScene::s_canvas_mgr; -unsigned int _3DScene::TextureBase::finalize() -{ - if ((m_tex_id == 0) && !m_data.empty()) { - // sends buffer to gpu - ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - ::glGenTextures(1, &m_tex_id); - ::glBindTexture(GL_TEXTURE_2D, (GLuint)m_tex_id); - ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)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::TextureBase::_destroy_texture() -{ - if (m_tex_id > 0) - { - ::glDeleteTextures(1, &m_tex_id); - m_tex_id = 0; - m_tex_height = 0; - m_tex_width = 0; - } - m_data.clear(); -} - - -const unsigned char _3DScene::WarningTexture::Background_Color[3] = { 9, 91, 134 }; -const unsigned char _3DScene::WarningTexture::Opacity = 255; - -// Generate a texture data, but don't load it into the GPU yet, as the GPU context may not yet be valid. -bool _3DScene::WarningTexture::generate(const std::string& msg) -{ - // 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(); - - if (msg.empty()) - return false; - - wxMemoryDC memDC; - // select default font - memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - - // calculates texture size - wxCoord w, h; - memDC.GetTextExtent(msg, &w, &h); - m_tex_width = (unsigned int)w; - m_tex_height = (unsigned int)h; - - // generates bitmap - wxBitmap bitmap(m_tex_width, m_tex_height); - -#if defined(__APPLE__) || defined(_MSC_VER) - bitmap.UseAlpha(); -#endif - - memDC.SelectObject(bitmap); - memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2]))); - memDC.Clear(); - - memDC.SetTextForeground(*wxWHITE); - - // draw message - memDC.DrawText(msg, 0, 0); - - memDC.SelectObject(wxNullBitmap); - - // Convert the bitmap into a linear data ready to be loaded into the GPU. - { - 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 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; - } - } - } - return true; -} - -const unsigned char _3DScene::LegendTexture::Squares_Border_Color[3] = { 64, 64, 64 }; -const unsigned char _3DScene::LegendTexture::Background_Color[3] = { 9, 91, 134 }; -const unsigned char _3DScene::LegendTexture::Opacity = 255; - -// 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) -{ - // 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 - auto title = _(preview_data.get_legend_title()); - const GCodePreviewData::LegendItemsList& items = preview_data.get_legend_items(tool_colors); - - unsigned int items_count = (unsigned int)items.size(); - if (items_count == 0) - // nothing to render, return - return false; - - wxMemoryDC memDC; - // select default font - memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - - // calculates texture size - wxCoord w, h; - memDC.GetTextExtent(title, &w, &h); - unsigned int title_width = (unsigned int)w; - unsigned int title_height = (unsigned int)h; - - unsigned int max_text_width = 0; - unsigned int max_text_height = 0; - for (const GCodePreviewData::LegendItem& item : items) - { - memDC.GetTextExtent(GUI::from_u8(item.text), &w, &h); - max_text_width = std::max(max_text_width, (unsigned int)w); - max_text_height = std::max(max_text_height, (unsigned int)h); - } - - m_tex_width = std::max(2 * Px_Border + title_width, 2 * (Px_Border + Px_Square_Contour) + Px_Square + Px_Text_Offset + max_text_width); - m_tex_height = 2 * (Px_Border + Px_Square_Contour) + title_height + Px_Title_Offset + items_count * Px_Square; - if (items_count > 1) - m_tex_height += (items_count - 1) * Px_Square_Contour; - - // generates bitmap - wxBitmap bitmap(m_tex_width, m_tex_height); - -#if defined(__APPLE__) || defined(_MSC_VER) - bitmap.UseAlpha(); -#endif - - memDC.SelectObject(bitmap); - memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2]))); - memDC.Clear(); - - memDC.SetTextForeground(*wxWHITE); - - // draw title - unsigned int title_x = Px_Border; - unsigned int title_y = Px_Border; - memDC.DrawText(title, title_x, title_y); - - // draw icons contours as background - unsigned int squares_contour_x = Px_Border; - unsigned int squares_contour_y = Px_Border + title_height + Px_Title_Offset; - unsigned int squares_contour_width = Px_Square + 2 * Px_Square_Contour; - unsigned int squares_contour_height = items_count * Px_Square + 2 * Px_Square_Contour; - if (items_count > 1) - squares_contour_height += (items_count - 1) * Px_Square_Contour; - - wxColour color(Squares_Border_Color[0], Squares_Border_Color[1], Squares_Border_Color[2]); - wxPen pen(color); - wxBrush brush(color); - memDC.SetPen(pen); - memDC.SetBrush(brush); - memDC.DrawRectangle(wxRect(squares_contour_x, squares_contour_y, squares_contour_width, squares_contour_height)); - - // draw items (colored icon + text) - unsigned int icon_x = squares_contour_x + Px_Square_Contour; - unsigned int icon_x_inner = icon_x + 1; - unsigned int icon_y = squares_contour_y + Px_Square_Contour; - unsigned int icon_y_step = Px_Square + Px_Square_Contour; - - unsigned int text_x = icon_x + Px_Square + Px_Text_Offset; - unsigned int text_y_offset = (Px_Square - max_text_height) / 2; - - unsigned int px_inner_square = Px_Square - 2; - - for (const GCodePreviewData::LegendItem& item : items) - { - // draw darker icon perimeter - const std::vector& item_color_bytes = item.color.as_bytes(); - wxImage::HSVValue dark_hsv = wxImage::RGBtoHSV(wxImage::RGBValue(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2])); - dark_hsv.value *= 0.75; - wxImage::RGBValue dark_rgb = wxImage::HSVtoRGB(dark_hsv); - color.Set(dark_rgb.red, dark_rgb.green, dark_rgb.blue, item_color_bytes[3]); - pen.SetColour(color); - brush.SetColour(color); - memDC.SetPen(pen); - memDC.SetBrush(brush); - memDC.DrawRectangle(wxRect(icon_x, icon_y, Px_Square, Px_Square)); - - // draw icon interior - color.Set(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2], item_color_bytes[3]); - pen.SetColour(color); - brush.SetColour(color); - memDC.SetPen(pen); - memDC.SetBrush(brush); - memDC.DrawRectangle(wxRect(icon_x_inner, icon_y + 1, px_inner_square, px_inner_square)); - - // draw text - memDC.DrawText(GUI::from_u8(item.text), text_x, icon_y + text_y_offset); - - // update y - icon_y += icon_y_step; - } - - memDC.SelectObject(wxNullBitmap); - - // Convert the bitmap into a linear data ready to be loaded into the GPU. - { - 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 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; - } - } - } - return true; -} - void _3DScene::init_gl() { s_canvas_mgr.init_gl(); @@ -2218,54 +1988,9 @@ void _3DScene::load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* pr s_canvas_mgr.load_gcode_preview(canvas, preview_data, str_tool_colors); } -void _3DScene::generate_legend_texture(const GCodePreviewData& preview_data, const std::vector& tool_colors) -{ - s_legend_texture.generate(preview_data, tool_colors); -} - -unsigned int _3DScene::get_legend_texture_width() -{ - return s_legend_texture.get_texture_width(); -} - -unsigned int _3DScene::get_legend_texture_height() -{ - return s_legend_texture.get_texture_height(); -} - void _3DScene::reset_legend_texture() { - s_legend_texture.reset_texture(); -} - -unsigned int _3DScene::finalize_legend_texture() -{ - return s_legend_texture.finalize(); -} - -unsigned int _3DScene::get_warning_texture_width() -{ - return s_warning_texture.get_texture_width(); -} - -unsigned int _3DScene::get_warning_texture_height() -{ - return s_warning_texture.get_texture_height(); -} - -void _3DScene::generate_warning_texture(const std::string& msg) -{ - s_warning_texture.generate(msg); -} - -void _3DScene::reset_warning_texture() -{ - s_warning_texture.reset_texture(); -} - -unsigned int _3DScene::finalize_warning_texture() -{ - return s_warning_texture.finalize(); + s_canvas_mgr.reset_legend_texture(); } } // namespace Slic3r diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index f7fc75db5..a2ca1de7c 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -6,6 +6,7 @@ #include "../../libslic3r/Line.hpp" #include "../../libslic3r/TriangleMesh.hpp" #include "../../libslic3r/Utils.hpp" +#include "../../libslic3r/Model.hpp" #include "../../slic3r/GUI/GLCanvas3DManager.hpp" class wxBitmap; @@ -199,10 +200,10 @@ private: } }; -class GLTexture +class LayersTexture { public: - GLTexture() : width(0), height(0), levels(0), cells(0) {} + LayersTexture() : width(0), height(0), levels(0), cells(0) {} // Texture data std::vector data; @@ -341,7 +342,7 @@ public: void release_geometry() { this->indexed_vertex_array.release_geometry(); } /************************************************ Layer height texture ****************************************************/ - std::shared_ptr layer_height_texture; + std::shared_ptr layer_height_texture; // Data to render this volume using the layer height texture LayerHeightTextureData layer_height_texture_data; @@ -422,7 +423,9 @@ public: print_box_max[0] = max_x; print_box_max[1] = max_y; print_box_max[2] = max_z; } - bool check_outside_state(const DynamicPrintConfig* config); + // returns true if all the volumes are completely contained in the print volume + // returns the containment state in the given out_state, if non-null + bool check_outside_state(const DynamicPrintConfig* config, ModelInstance::EPrintVolumeState* out_state); void reset_outside_state(); void update_colors_by_extruder(const DynamicPrintConfig* config); @@ -437,65 +440,6 @@ private: class _3DScene { - class TextureBase - { - protected: - unsigned int m_tex_id; - unsigned int m_tex_width; - unsigned int m_tex_height; - - // generate() fills in m_data with the pixels, while finalize() moves the data to the GPU before rendering. - std::vector m_data; - - public: - TextureBase() : m_tex_id(0), m_tex_width(0), m_tex_height(0) {} - virtual ~TextureBase() { _destroy_texture(); } - - // 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 { 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() { _destroy_texture(); } - - private: - void _destroy_texture(); - }; - - class WarningTexture : public TextureBase - { - static const unsigned char Background_Color[3]; - static const unsigned char Opacity; - - public: - WarningTexture() : TextureBase() {} - - // Generate a texture data, but don't load it into the GPU yet, as the glcontext may not be valid yet. - bool generate(const std::string& msg); - }; - - class LegendTexture : public TextureBase - { - static const unsigned int Px_Title_Offset = 5; - static const unsigned int Px_Text_Offset = 5; - static const unsigned int Px_Square = 20; - static const unsigned int Px_Square_Contour = 1; - static const unsigned int Px_Border = Px_Square / 2; - static const unsigned char Squares_Border_Color[3]; - static const unsigned char Background_Color[3]; - static const unsigned char Opacity; - - public: - LegendTexture() : TextureBase() {} - - // 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); - }; - - static LegendTexture s_legend_texture; - static WarningTexture s_warning_texture; static GUI::GLCanvas3DManager s_canvas_mgr; public: @@ -597,21 +541,7 @@ public: static void load_wipe_tower_toolpaths(wxGLCanvas* canvas, const std::vector& str_tool_colors); static void load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector& str_tool_colors); - // generates the legend texture in dependence of the current shown view type - static void generate_legend_texture(const GCodePreviewData& preview_data, const std::vector& tool_colors); - static unsigned int get_legend_texture_width(); - static unsigned int get_legend_texture_height(); - static void reset_legend_texture(); - static unsigned int finalize_legend_texture(); - - static unsigned int get_warning_texture_width(); - static unsigned int get_warning_texture_height(); - - // generates a warning texture containing the given message - static void generate_warning_texture(const std::string& msg); - static void reset_warning_texture(); - static unsigned int finalize_warning_texture(); static void thick_lines_to_verts(const Lines& lines, const std::vector& widths, const std::vector& heights, bool closed, double top_z, GLVolume& volume); static void thick_lines_to_verts(const Lines3& lines, const std::vector& widths, const std::vector& heights, bool closed, GLVolume& volume); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 208125a15..064a9adce 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -15,6 +15,10 @@ #include #include +#include +#include +#include +#include #include #include @@ -1381,7 +1385,8 @@ void GLCanvas3D::Gizmos::render(const GLCanvas3D& canvas, const BoundingBoxf3& b ::glDisable(GL_DEPTH_TEST); - _render_current_gizmo(box); + if (box.radius() > 0.0) + _render_current_gizmo(box); ::glPushMatrix(); ::glLoadIdentity(); @@ -1456,6 +1461,224 @@ float GLCanvas3D::Gizmos::_get_total_overlay_height() const return height; } +const unsigned char GLCanvas3D::WarningTexture::Background_Color[3] = { 9, 91, 134 }; +const unsigned char GLCanvas3D::WarningTexture::Opacity = 255; + +bool GLCanvas3D::WarningTexture::generate(const std::string& msg) +{ + reset(); + + if (msg.empty()) + return false; + + wxMemoryDC memDC; + // select default font + memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + + // calculates texture size + wxCoord w, h; + memDC.GetTextExtent(msg, &w, &h); + m_width = (int)w; + m_height = (int)h; + + // generates bitmap + wxBitmap bitmap(m_width, m_height); + +#if defined(__APPLE__) || defined(_MSC_VER) + bitmap.UseAlpha(); +#endif + + memDC.SelectObject(bitmap); + memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2]))); + memDC.Clear(); + + memDC.SetTextForeground(*wxWHITE); + + // draw message + memDC.DrawText(msg, 0, 0); + + memDC.SelectObject(wxNullBitmap); + + // Convert the bitmap into a linear data ready to be loaded into the GPU. + wxImage image = bitmap.ConvertToImage(); + image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]); + + // prepare buffer + std::vector data(4 * m_width * m_height, 0); + for (int h = 0; h < m_height; ++h) + { + int hh = h * m_width; + unsigned char* px_ptr = data.data() + 4 * hh; + for (int w = 0; w < m_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 + ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + ::glGenTextures(1, &m_id); + ::glBindTexture(GL_TEXTURE_2D, (GLuint)m_id); + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)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); + + return true; +} + +const unsigned char GLCanvas3D::LegendTexture::Squares_Border_Color[3] = { 64, 64, 64 }; +const unsigned char GLCanvas3D::LegendTexture::Background_Color[3] = { 9, 91, 134 }; +const unsigned char GLCanvas3D::LegendTexture::Opacity = 255; + +bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, const std::vector& tool_colors) +{ + reset(); + + // collects items to render + auto title = _(preview_data.get_legend_title()); + const GCodePreviewData::LegendItemsList& items = preview_data.get_legend_items(tool_colors); + + unsigned int items_count = (unsigned int)items.size(); + if (items_count == 0) + // nothing to render, return + return false; + + wxMemoryDC memDC; + // select default font + memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + + // calculates texture size + wxCoord w, h; + memDC.GetTextExtent(title, &w, &h); + int title_width = (int)w; + int title_height = (int)h; + + int max_text_width = 0; + int max_text_height = 0; + for (const GCodePreviewData::LegendItem& item : items) + { + memDC.GetTextExtent(GUI::from_u8(item.text), &w, &h); + max_text_width = std::max(max_text_width, (int)w); + max_text_height = std::max(max_text_height, (int)h); + } + + m_width = std::max(2 * Px_Border + title_width, 2 * (Px_Border + Px_Square_Contour) + Px_Square + Px_Text_Offset + max_text_width); + m_height = 2 * (Px_Border + Px_Square_Contour) + title_height + Px_Title_Offset + items_count * Px_Square; + if (items_count > 1) + m_height += (items_count - 1) * Px_Square_Contour; + + // generates bitmap + wxBitmap bitmap(m_width, m_height); + +#if defined(__APPLE__) || defined(_MSC_VER) + bitmap.UseAlpha(); +#endif + + memDC.SelectObject(bitmap); + memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2]))); + memDC.Clear(); + + memDC.SetTextForeground(*wxWHITE); + + // draw title + int title_x = Px_Border; + int title_y = Px_Border; + memDC.DrawText(title, title_x, title_y); + + // draw icons contours as background + int squares_contour_x = Px_Border; + int squares_contour_y = Px_Border + title_height + Px_Title_Offset; + int squares_contour_width = Px_Square + 2 * Px_Square_Contour; + int squares_contour_height = items_count * Px_Square + 2 * Px_Square_Contour; + if (items_count > 1) + squares_contour_height += (items_count - 1) * Px_Square_Contour; + + wxColour color(Squares_Border_Color[0], Squares_Border_Color[1], Squares_Border_Color[2]); + wxPen pen(color); + wxBrush brush(color); + memDC.SetPen(pen); + memDC.SetBrush(brush); + memDC.DrawRectangle(wxRect(squares_contour_x, squares_contour_y, squares_contour_width, squares_contour_height)); + + // draw items (colored icon + text) + int icon_x = squares_contour_x + Px_Square_Contour; + int icon_x_inner = icon_x + 1; + int icon_y = squares_contour_y + Px_Square_Contour; + int icon_y_step = Px_Square + Px_Square_Contour; + + int text_x = icon_x + Px_Square + Px_Text_Offset; + int text_y_offset = (Px_Square - max_text_height) / 2; + + int px_inner_square = Px_Square - 2; + + for (const GCodePreviewData::LegendItem& item : items) + { + // draw darker icon perimeter + const std::vector& item_color_bytes = item.color.as_bytes(); + wxImage::HSVValue dark_hsv = wxImage::RGBtoHSV(wxImage::RGBValue(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2])); + dark_hsv.value *= 0.75; + wxImage::RGBValue dark_rgb = wxImage::HSVtoRGB(dark_hsv); + color.Set(dark_rgb.red, dark_rgb.green, dark_rgb.blue, item_color_bytes[3]); + pen.SetColour(color); + brush.SetColour(color); + memDC.SetPen(pen); + memDC.SetBrush(brush); + memDC.DrawRectangle(wxRect(icon_x, icon_y, Px_Square, Px_Square)); + + // draw icon interior + color.Set(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2], item_color_bytes[3]); + pen.SetColour(color); + brush.SetColour(color); + memDC.SetPen(pen); + memDC.SetBrush(brush); + memDC.DrawRectangle(wxRect(icon_x_inner, icon_y + 1, px_inner_square, px_inner_square)); + + // draw text + memDC.DrawText(GUI::from_u8(item.text), text_x, icon_y + text_y_offset); + + // update y + icon_y += icon_y_step; + } + + memDC.SelectObject(wxNullBitmap); + + // Convert the bitmap into a linear data ready to be loaded into the GPU. + wxImage image = bitmap.ConvertToImage(); + image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]); + + // prepare buffer + std::vector data(4 * m_width * m_height, 0); + for (int h = 0; h < m_height; ++h) + { + int hh = h * m_width; + unsigned char* px_ptr = data.data() + 4 * hh; + for (int w = 0; w < m_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 + ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + ::glGenTextures(1, &m_id); + ::glBindTexture(GL_TEXTURE_2D, (GLuint)m_id); + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)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); + + return true; +} + GLGizmoBase* GLCanvas3D::Gizmos::_get_current() const { GizmosMap::const_iterator it = m_gizmos.find(m_current); @@ -1657,7 +1880,7 @@ void GLCanvas3D::update_volumes_selection(const std::vector& selections) bool GLCanvas3D::check_volumes_outside_state(const DynamicPrintConfig* config) const { - return m_volumes.check_outside_state(config); + return m_volumes.check_outside_state(config, nullptr); } bool GLCanvas3D::move_volume_up(unsigned int id) @@ -1905,7 +2128,7 @@ void GLCanvas3D::update_volumes_colors_by_extruder() void GLCanvas3D::update_gizmos_data() { - if (!m_gizmos.is_running()) + if (!m_gizmos.is_enabled()) return; int id = _get_first_selected_object_id(); @@ -1917,26 +2140,16 @@ void GLCanvas3D::update_gizmos_data() ModelInstance* model_instance = model_object->instances[0]; if (model_instance != nullptr) { - switch (m_gizmos.get_current_type()) - { - case Gizmos::Scale: - { - m_gizmos.set_scale(model_instance->scaling_factor); - break; - } - case Gizmos::Rotate: - { - m_gizmos.set_angle_z(model_instance->rotation); - break; - } - default: - { - break; - } - } + m_gizmos.set_scale(model_instance->scaling_factor); + m_gizmos.set_angle_z(model_instance->rotation); } } } + else + { + m_gizmos.set_scale(1.0f); + m_gizmos.set_angle_z(0.0f); + } } void GLCanvas3D::render() @@ -2051,8 +2264,12 @@ void GLCanvas3D::reload_scene(bool force) m_objects_volumes_idxs.push_back(load_object(*m_model, obj_idx)); } + // 1st call to reset if no objects left update_gizmos_data(); update_volumes_selection(m_objects_selections); + // 2nd call to restore if something selected + if (!m_objects_selections.empty()) + update_gizmos_data(); if (m_config->has("nozzle_diameter")) { @@ -2082,25 +2299,28 @@ void GLCanvas3D::reload_scene(bool force) // checks for geometry outside the print volume to render it accordingly if (!m_volumes.empty()) { - bool contained = m_volumes.check_outside_state(m_config); + ModelInstance::EPrintVolumeState state; + bool contained = m_volumes.check_outside_state(m_config, &state); + if (!contained) { enable_warning_texture(true); - _3DScene::generate_warning_texture(L("Detected object outside print volume")); - m_on_enable_action_buttons_callback.call(false); + _generate_warning_texture(L("Detected object outside print volume")); + m_on_enable_action_buttons_callback.call(state == ModelInstance::PVS_Fully_Outside); } else { enable_warning_texture(false); m_volumes.reset_outside_state(); - _3DScene::reset_warning_texture(); + _reset_warning_texture(); m_on_enable_action_buttons_callback.call(!m_model->objects.empty()); } } else { enable_warning_texture(false); - _3DScene::reset_warning_texture(); + _reset_warning_texture(); + m_on_enable_action_buttons_callback.call(false); } } @@ -2490,11 +2710,11 @@ void GLCanvas3D::load_gcode_preview(const GCodePreviewData& preview_data, const _load_gcode_unretractions(preview_data); if (m_volumes.empty()) - _3DScene::reset_legend_texture(); + reset_legend_texture(); else { - _3DScene::generate_legend_texture(preview_data, tool_colors); - + _generate_legend_texture(preview_data, tool_colors); + // removes empty volumes m_volumes.volumes.erase(std::remove_if(m_volumes.volumes.begin(), m_volumes.volumes.end(), [](const GLVolume* volume) { return volume->print_zs.empty(); }), m_volumes.volumes.end()); @@ -3103,6 +3323,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { deselect_volumes(); _on_select(-1); + update_gizmos_data(); } } else if (evt.LeftUp() && m_gizmos.is_dragging()) @@ -3130,6 +3351,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.set_start_position_3D_as_invalid(); m_mouse.set_start_position_2D_as_invalid(); m_mouse.dragging = false; + m_dirty = true; } else if (evt.Moving()) { @@ -3181,6 +3403,14 @@ Point GLCanvas3D::get_local_mouse_position() const return Point(mouse_pos.x, mouse_pos.y); } +void GLCanvas3D::reset_legend_texture() +{ + if (!set_current()) + return; + + m_legend_texture.reset(); +} + bool GLCanvas3D::_is_shown_on_screen() const { return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false; @@ -3272,7 +3502,7 @@ BoundingBoxf3 GLCanvas3D::_selected_volumes_bounding_box() const BoundingBoxf3 bb; for (const GLVolume* volume : m_volumes.volumes) { - if ((volume != nullptr) && volume->selected) + if ((volume != nullptr) && !volume->is_wipe_tower && volume->selected) bb.merge(volume->transformed_bounding_box()); } return bb; @@ -3441,6 +3671,7 @@ void GLCanvas3D::_picking_pass() const ::glDisable(GL_MULTISAMPLE); ::glDisable(GL_BLEND); + ::glEnable(GL_DEPTH_TEST); ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -3549,7 +3780,7 @@ void GLCanvas3D::_render_objects() const { const BoundingBoxf3& bed_bb = m_bed.get_bounding_box(); m_volumes.set_print_box((float)bed_bb.min.x, (float)bed_bb.min.y, 0.0f, (float)bed_bb.max.x, (float)bed_bb.max.y, (float)m_config->opt_float("max_print_height")); - m_volumes.check_outside_state(m_config); + m_volumes.check_outside_state(m_config, nullptr); } // do not cull backfaces to show broken geometry, if any ::glDisable(GL_CULL_FACE); @@ -3588,11 +3819,11 @@ void GLCanvas3D::_render_warning_texture() const return; // If the warning texture has not been loaded into the GPU, do it now. - unsigned int tex_id = _3DScene::finalize_warning_texture(); + unsigned int tex_id = m_warning_texture.get_id(); if (tex_id > 0) { - unsigned int w = _3DScene::get_warning_texture_width(); - unsigned int h = _3DScene::get_warning_texture_height(); + int w = m_warning_texture.get_width(); + int h = m_warning_texture.get_height(); if ((w > 0) && (h > 0)) { ::glDisable(GL_DEPTH_TEST); @@ -3621,11 +3852,11 @@ void GLCanvas3D::_render_legend_texture() const return; // If the legend texture has not been loaded into the GPU, do it now. - unsigned int tex_id = _3DScene::finalize_legend_texture(); + unsigned int tex_id = m_legend_texture.get_id(); if (tex_id > 0) { - unsigned int w = _3DScene::get_legend_texture_width(); - unsigned int h = _3DScene::get_legend_texture_height(); + int w = m_legend_texture.get_width(); + int h = m_legend_texture.get_height(); if ((w > 0) && (h > 0)) { ::glDisable(GL_DEPTH_TEST); @@ -4539,5 +4770,29 @@ std::vector GLCanvas3D::_parse_colors(const std::vector& col return output; } +void GLCanvas3D::_generate_legend_texture(const GCodePreviewData& preview_data, const std::vector& tool_colors) +{ + if (!set_current()) + return; + + m_legend_texture.generate(preview_data, tool_colors); +} + +void GLCanvas3D::_generate_warning_texture(const std::string& msg) +{ + if (!set_current()) + return; + + m_warning_texture.generate(msg); +} + +void GLCanvas3D::_reset_warning_texture() +{ + if (!set_current()) + return; + + m_warning_texture.reset(); +} + } // namespace GUI } // namespace Slic3r diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index cc998226b..d18ca0cab 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -394,9 +394,35 @@ public: GLGizmoBase* _get_current() const; }; + class WarningTexture : public GUI::GLTexture + { + static const unsigned char Background_Color[3]; + static const unsigned char Opacity; + + public: + bool generate(const std::string& msg); + }; + + class LegendTexture : public GUI::GLTexture + { + static const int Px_Title_Offset = 5; + static const int Px_Text_Offset = 5; + static const int Px_Square = 20; + static const int Px_Square_Contour = 1; + static const int Px_Border = Px_Square / 2; + static const unsigned char Squares_Border_Color[3]; + static const unsigned char Background_Color[3]; + static const unsigned char Opacity; + + public: + bool generate(const GCodePreviewData& preview_data, const std::vector& tool_colors); + }; + private: wxGLCanvas* m_canvas; wxGLContext* m_context; + LegendTexture m_legend_texture; + WarningTexture m_warning_texture; wxTimer* m_timer; Camera m_camera; Bed m_bed; @@ -578,6 +604,8 @@ public: Size get_canvas_size() const; Point get_local_mouse_position() const; + void reset_legend_texture(); + private: bool _is_shown_on_screen() const; void _force_zoom_to_bed(); @@ -643,6 +671,13 @@ private: void _on_move(const std::vector& volume_idxs); void _on_select(int volume_idx); + // generates the legend texture in dependence of the current shown view type + void _generate_legend_texture(const GCodePreviewData& preview_data, const std::vector& tool_colors); + + // generates a warning texture containing the given message + void _generate_warning_texture(const std::string& msg); + void _reset_warning_texture(); + static std::vector _parse_colors(const std::vector& colors); }; diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp index 7a68cbc81..23a8f4c15 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -550,6 +550,15 @@ void GLCanvas3DManager::load_gcode_preview(wxGLCanvas* canvas, const GCodePrevie it->second->load_gcode_preview(*preview_data, str_tool_colors); } +void GLCanvas3DManager::reset_legend_texture() +{ + for (CanvasesMap::value_type& canvas : m_canvases) + { + if (canvas.second != nullptr) + canvas.second->reset_legend_texture(); + } +} + 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 c813fd477..98205982f 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -137,6 +137,8 @@ public: void load_wipe_tower_toolpaths(wxGLCanvas* canvas, const std::vector& str_tool_colors); void load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector& str_tool_colors); + void reset_legend_texture(); + void register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback); void register_on_double_click_callback(wxGLCanvas* canvas, void* callback); void register_on_right_click_callback(wxGLCanvas* canvas, void* callback); diff --git a/xs/src/slic3r/GUI/GLTexture.hpp b/xs/src/slic3r/GUI/GLTexture.hpp index 70480c605..2e936161e 100644 --- a/xs/src/slic3r/GUI/GLTexture.hpp +++ b/xs/src/slic3r/GUI/GLTexture.hpp @@ -10,7 +10,7 @@ namespace GUI { class GLTexture { - private: + protected: unsigned int m_id; int m_width; int m_height; @@ -18,7 +18,7 @@ namespace GUI { public: GLTexture(); - ~GLTexture(); + virtual ~GLTexture(); bool load_from_file(const std::string& filename, bool generate_mipmaps); void reset(); @@ -26,11 +26,12 @@ namespace GUI { unsigned int get_id() const; int get_width() const; int get_height() const; + const std::string& get_source() const; static void render_texture(unsigned int tex_id, float left, float right, float bottom, float top); - private: + protected: void _generate_mipmaps(wxImage& image); }; diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 65dfc8e8e..38c85c328 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -105,10 +105,6 @@ void release_geometry(); void set_print_box(float min_x, float min_y, float min_z, float max_x, float max_y, float max_z); - bool check_outside_state(DynamicPrintConfig* config) - %code%{ - RETVAL = THIS->check_outside_state(config); - %}; void reset_outside_state(); void update_colors_by_extruder(DynamicPrintConfig* config); @@ -627,64 +623,12 @@ register_on_update_geometry_info_callback(canvas, callback) SV *callback; CODE: _3DScene::register_on_update_geometry_info_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); - -unsigned int -finalize_legend_texture() - CODE: - RETVAL = _3DScene::finalize_legend_texture(); - OUTPUT: - RETVAL - -unsigned int -get_legend_texture_width() - CODE: - RETVAL = _3DScene::get_legend_texture_width(); - OUTPUT: - RETVAL - -unsigned int -get_legend_texture_height() - CODE: - RETVAL = _3DScene::get_legend_texture_height(); - OUTPUT: - RETVAL void reset_legend_texture() CODE: _3DScene::reset_legend_texture(); -void -generate_warning_texture(std::string msg) - CODE: - _3DScene::generate_warning_texture(msg); - -unsigned int -finalize_warning_texture() - CODE: - RETVAL = _3DScene::finalize_warning_texture(); - OUTPUT: - RETVAL - -unsigned int -get_warning_texture_width() - CODE: - RETVAL = _3DScene::get_warning_texture_width(); - OUTPUT: - RETVAL - -unsigned int -get_warning_texture_height() - CODE: - RETVAL = _3DScene::get_warning_texture_height(); - OUTPUT: - RETVAL - -void -reset_warning_texture() - CODE: - _3DScene::reset_warning_texture(); - std::vector load_model_object(canvas, model_object, obj_idx, instance_idxs) SV *canvas;