Merge remote-tracking branch 'upstream/main' into feedback

This commit is contained in:
Clifford Garwood
2026-04-21 14:56:08 -04:00
10271 changed files with 1877977 additions and 1865978 deletions
+13 -3
View File
@@ -301,6 +301,8 @@ set(SLIC3R_GUI_SOURCES
GUI/KBShortcutsDialog.hpp
GUI/LibVGCode/LibVGCodeWrapper.hpp
GUI/LibVGCode/LibVGCodeWrapper.cpp
GUI/LinuxDisplayBackend.cpp
GUI/LinuxDisplayBackend.hpp
GUI/MainFrame.cpp
GUI/MainFrame.hpp
GUI/MarkdownTip.cpp
@@ -736,7 +738,7 @@ else()
set(_opengl_link_lib OpenGL::GL)
endif()
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo libvgcode md4c-html GLEW::GLEW OpenGL::GL hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto noise::noise)
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo libvgcode md4c-html glad ${_opengl_link_lib} hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto noise::noise)
if (MSVC)
@@ -787,16 +789,24 @@ if (UNIX AND NOT APPLE)
find_package(PkgConfig REQUIRED)
find_package(GTK${SLIC3R_GTK} REQUIRED)
pkg_check_modules(LIBSECRET REQUIRED libsecret-1)
pkg_check_modules(webkit2gtk REQUIRED webkit2gtk-4.1)
if (FLATPAK)
# I don't know why this is needed, but for whatever reason slic3r isn't
# linking to X11 and webkit2gtk. force it.
find_package(X11 REQUIRED)
pkg_check_modules(webkit2gtk REQUIRED webkit2gtk-4.1)
target_link_libraries(libslic3r_gui ${X11_LIBRARIES} ${webkit2gtk_LIBRARIES})
endif()
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${GTK${SLIC3R_GTK}_INCLUDE_DIRS} ${LIBSECRET_INCLUDE_DIRS})
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${GTK${SLIC3R_GTK}_INCLUDE_DIRS} ${LIBSECRET_INCLUDE_DIRS} ${webkit2gtk_INCLUDE_DIRS})
target_link_libraries(libslic3r_gui ${GTK${SLIC3R_GTK}_LIBRARIES} fontconfig ${LIBSECRET_LIBRARIES})
# Propagate GDK backend detection results as compile definitions so that
# LinuxDisplayBackend.cpp can include the right GDK headers.
if (wxHAVE_GDK_X11)
target_compile_definitions(libslic3r_gui PRIVATE wxHAVE_GDK_X11)
endif ()
if (wxHAVE_GDK_WAYLAND)
target_compile_definitions(libslic3r_gui PRIVATE wxHAVE_GDK_WAYLAND)
endif ()
# We add GStreamer for bambu:/// support.
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
+1 -1
View File
@@ -15,7 +15,7 @@
#include "Plater.hpp"
#include "Camera.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem/operations.hpp>
+1 -1
View File
@@ -1,4 +1,4 @@
#include <GL/glew.h>
#include <glad/gl.h>
#include "3DScene.hpp"
#include "GLShader.hpp"
+1 -1
View File
@@ -94,7 +94,7 @@ void CopyrightsDialog::fill_entries()
{ "Eigen3", "", "http://eigen.tuxfamily.org" },
{ "Expat", "", "http://www.libexpat.org" },
{ "fast_float", "", "https://github.com/fastfloat/fast_float" },
{ "GLEW (The OpenGL Extension Wrangler Library)", "", "http://glew.sourceforge.net" },
{ "GLAD (Multi-Language GL Loader-Generator)", "", "https://github.com/Dav1dde/glad" },
{ "GLFW", "", "https://www.glfw.org" },
{ "GNU gettext", "", "https://www.gnu.org/software/gettext" },
{ "ImGUI", "", "https://github.com/ocornut/imgui" },
+36 -12
View File
@@ -6,6 +6,9 @@
#include "I18N.hpp"
#include "GUI_App.hpp"
#include "GUI.hpp"
#ifdef __WXGTK__
#include "LinuxDisplayBackend.hpp"
#endif
#include "wxExtensions.hpp"
#include "Plater.hpp"
#include "MainFrame.hpp"
@@ -56,9 +59,9 @@ CenteredTitle::CenteredTitle(wxWindow* parent)
wxString ellipsized = wxControl::Ellipsize(m_title, dc, wxELLIPSIZE_END, wxMax(0, rect.GetWidth() - FromDIP(8)));
int y = rect.y + (rect.height - textHeight) / 2;
int x = rect.x + (ellipsized != m_title) // is ellipsized
int x = rect.x + ((ellipsized != m_title) // is ellipsized
? FromDIP(4) // align to left when clipped
: (rect.width - dc.GetTextExtent(m_title).GetWidth()) / 2; // centered when has available space
: (rect.width - dc.GetTextExtent(m_title).GetWidth()) / 2); // centered when has available space
dc.DrawText(ellipsized, x, y);
});
@@ -126,9 +129,10 @@ void BBLTopbarArt::DrawButton(wxDC& dc, wxWindow* wnd, const wxAuiToolBarItem& i
int bmpX = 0, bmpY = 0;
int textX = 0, textY = 0;
const wxBitmap& bmp = item.GetState() & wxAUI_BUTTON_STATE_DISABLED
? item.GetDisabledBitmap()
: item.GetBitmap();
// ORCA resolves the toolbar item bitmap using the actual window DPI context used for painting.
// GetBitmap() / GetDisabledBitmap() was using internal window pointer (m_window), not the paint-time wnd
// m_window was created before final DPI context was known so items not scales properly
const wxBitmap bmp = item.GetCurrentBitmapFor(wnd);
const wxSize bmpSize = bmp.IsOk() ? bmp.GetScaledSize() : wxSize(0, 0);
@@ -346,6 +350,10 @@ void BBLTopbar::Init(wxFrame* parent)
this->Bind(wxEVT_LEFT_DCLICK, &BBLTopbar::OnMouseLeftDClock, this);
this->Bind(wxEVT_LEFT_DOWN, &BBLTopbar::OnMouseLeftDown, this);
this->Bind(wxEVT_LEFT_UP, &BBLTopbar::OnMouseLeftUp, this);
this->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& event) {
m_last_mouse_position = wxDefaultPosition;
event.Skip();
});
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnOpenProject, this, wxID_OPEN);
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnSaveProject, this, wxID_SAVE);
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnRedo, this, wxID_REDO);
@@ -589,8 +597,9 @@ void BBLTopbar::OnCloseFrame(wxAuiToolBarEvent& event)
void BBLTopbar::OnMouseLeftDClock(wxMouseEvent& mouse)
{
wxPoint mouse_pos = ::wxGetMousePosition();
wxAuiToolBarItem* item = this->FindToolByCurrentPosition();
m_last_mouse_position = mouse.GetPosition();
wxPoint mouse_pos = this->ClientToScreen(mouse.GetPosition());
wxAuiToolBarItem* item = this->FindToolByPosition(mouse.GetX(), mouse.GetY());
// check whether mouse is not on any tool item
if (item != NULL && item->GetWindow() != m_title_ctrl) {
mouse.Skip();
@@ -658,9 +667,12 @@ void BBLTopbar::OnCalibToolItem(wxAuiToolBarEvent &evt)
void BBLTopbar::OnMouseLeftDown(wxMouseEvent& event)
{
wxPoint mouse_pos = ::wxGetMousePosition();
m_last_mouse_position = event.GetPosition();
// Use event-relative coords converted to screen, instead of wxGetMousePosition()
// which returns (0,0) on Wayland for global screen coordinates.
wxPoint mouse_pos = this->ClientToScreen(event.GetPosition());
wxPoint frame_pos = m_frame->GetScreenPosition();
wxAuiToolBarItem* item = this->FindToolByCurrentPosition();
wxAuiToolBarItem* item = this->FindToolByPosition(event.GetX(), event.GetY());
m_delta = mouse_pos - frame_pos;
if (item == NULL || item->GetWindow() == m_title_ctrl)
@@ -688,7 +700,8 @@ void BBLTopbar::OnMouseLeftDown(wxMouseEvent& event)
void BBLTopbar::OnMouseLeftUp(wxMouseEvent& event)
{
wxPoint mouse_pos = ::wxGetMousePosition();
m_last_mouse_position = event.GetPosition();
wxPoint mouse_pos = this->ClientToScreen(event.GetPosition());
if (HasCapture())
{
ReleaseMouse();
@@ -699,7 +712,10 @@ void BBLTopbar::OnMouseLeftUp(wxMouseEvent& event)
void BBLTopbar::OnMouseMotion(wxMouseEvent& event)
{
wxPoint mouse_pos = ::wxGetMousePosition();
m_last_mouse_position = event.GetPosition();
// Use event-relative coords converted to screen, instead of wxGetMousePosition()
// which returns (0,0) on Wayland for global screen coordinates.
wxPoint mouse_pos = this->ClientToScreen(event.GetPosition());
if (!HasCapture()) {
//m_frame->OnMouseMotion(event);
@@ -743,12 +759,20 @@ void BBLTopbar::OnMenuClose(wxMenuEvent& event)
wxAuiToolBarItem* BBLTopbar::FindToolByCurrentPosition()
{
if (m_last_mouse_position != wxDefaultPosition && GetClientRect().Contains(m_last_mouse_position))
return this->FindToolByPosition(m_last_mouse_position.x, m_last_mouse_position.y);
#ifdef __WXGTK__
if (Slic3r::GUI::is_running_on_wayland())
return nullptr;
#endif
wxPoint mouse_pos = ::wxGetMousePosition();
wxPoint client_pos = this->ScreenToClient(mouse_pos);
return this->FindToolByPosition(client_pos.x, client_pos.y);
}
#ifdef __WIN32__
#ifdef __WXMSW__
WXLRESULT CenteredTitle::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{
switch (nMsg) {
+3 -2
View File
@@ -19,7 +19,7 @@ public:
wxSize DoGetBestSize() const override;
protected:
#ifdef __WIN32__
#ifdef __WXMSW__
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override;
#endif
@@ -75,7 +75,7 @@ public:
void ShowCalibrationButton(bool show = true);
protected:
#ifdef __WIN32__
#ifdef __WXMSW__
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override;
#endif
@@ -85,6 +85,7 @@ private:
wxAuiToolBarItem* m_dropdown_menu_item;
wxRect m_normalRect;
wxPoint m_delta;
wxPoint m_last_mouse_position{wxDefaultPosition};
wxMenu m_top_menu;
wxMenu* m_file_menu;
wxMenu m_calib_menu;
+3 -3
View File
@@ -50,7 +50,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para
def.min = 0;
def.max = 214700;
def.width = 10; // increase width for large scale printers with 4 digit values
def.sidetext = L("mm"); // milimeters, CIS languages need translation
def.sidetext = L("mm"); // millimeters, CIS languages need translation
def.label = get_option_label(param);
def.tooltip = L("Size in X and Y of the rectangular plate.");
key = "rect_size";
@@ -61,7 +61,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para
def.min = -107350;
def.max = 107350;
def.width = 10; // increase width for large scale printers with 4 digit values
def.sidetext = L("mm"); // milimeters, CIS languages need translation
def.sidetext = L("mm"); // millimeters, CIS languages need translation
def.label = get_option_label(param);
def.tooltip = L("Distance of the 0,0 G-code coordinate from the front left corner of the rectangle.");
key = "rect_origin";
@@ -70,7 +70,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para
def.type = coFloat;
def.set_default_value(new ConfigOptionFloat(200));
def.width = 10; // match size
def.sidetext = L("mm"); // milimeters, CIS languages need translation
def.sidetext = L("mm"); // millimeters, CIS languages need translation
def.label = get_option_label(param);
def.tooltip = L("Diameter of the print bed. It is assumed that origin (0,0) is located in the center.");
key = "diameter";
+1 -1
View File
@@ -13,7 +13,7 @@
#include <wx/mstream.h>
#include <wx/rawbmp.h>
#endif /* __WXGTK2__ */
#include <GL/glew.h>
#include <glad/gl.h>
#define NANOSVG_IMPLEMENTATION
#include "nanosvg/nanosvg.h"
#define NANOSVGRAST_IMPLEMENTATION
+1 -1
View File
@@ -8,7 +8,7 @@
#include "Plater.hpp"
#endif // ENABLE_CAMERA_STATISTICS
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r {
namespace GUI {
+10 -6
View File
@@ -209,7 +209,7 @@ bool DesktopIntegrationDialog::is_integrated()
if (path.empty())
return false;
// confirmation that OrcaSlicer.desktop exists
// confirmation that com.orcaslicer.OrcaSlicer.desktop exists
struct stat buffer;
return (stat (path.c_str(), &buffer) == 0);
}
@@ -336,19 +336,21 @@ void DesktopIntegrationDialog::perform_desktop_integration()
"Exec=\"%3%\" %%F\n"
"Terminal=false\n"
"Type=Application\n"
"PrefersNonDefaultGPU=true\n"
"X-KDE-RunOnDiscreteGpu=true\n"
"MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;\n"
"Categories=Graphics;3DGraphics;Engineering;\n"
"Keywords=3D;Printing;Slicer;slice;3D;printer;convert;gcode;stl;obj;amf;SLA\n"
"StartupNotify=false\n"
"StartupWMClass=orca-slicer\n", name_suffix, version_suffix, excutable_path);
std::string path = GUI::format("%1%/applications/OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix);
std::string path = GUI::format("%1%/applications/com.orcaslicer.OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix);
if (create_desktop_file(path, desktop_file)){
BOOST_LOG_TRIVIAL(debug) << "OrcaSlicer.desktop file installation success.";
BOOST_LOG_TRIVIAL(debug) << "com.orcaslicer.OrcaSlicer.desktop file installation success.";
break;
} else {
// write failed - try another path
BOOST_LOG_TRIVIAL(debug) << "Attempt to OrcaSlicer.desktop file installation failed. failed path: " << target_candidates[i];
BOOST_LOG_TRIVIAL(debug) << "Attempt to com.orcaslicer.OrcaSlicer.desktop file installation failed. failed path: " << target_candidates[i];
target_dir_desktop.clear();
}
// if all failed - try creating default home folder
@@ -357,7 +359,7 @@ void DesktopIntegrationDialog::perform_desktop_integration()
create_path(into_u8(wxFileName::GetHomeDir()), ".local/share/applications");
// create desktop file
target_dir_desktop = GUI::format("%1%/.local/share",wxFileName::GetHomeDir());
std::string path = GUI::format("%1%/applications/OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix);
std::string path = GUI::format("%1%/applications/com.orcaslicer.OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix);
if (contains_path_dir(target_dir_desktop, "applications")) {
if (!create_desktop_file(path, desktop_file)) {
// Desktop file not written - end desktop integration
@@ -379,7 +381,7 @@ void DesktopIntegrationDialog::perform_desktop_integration()
return;
}
// save path to desktop file
app_config->set("desktop_integration_app_path", GUI::format("%1%/applications/OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix));
app_config->set("desktop_integration_app_path", GUI::format("%1%/applications/com.orcaslicer.OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix));
// Repeat for Gcode viewer - use same paths as for slicer files
// Do NOT add gcode viewer desktop file on ChromeOS
@@ -405,6 +407,8 @@ void DesktopIntegrationDialog::perform_desktop_integration()
"Exec=\"%3%\" --gcodeviewer %%F\n"
"Terminal=false\n"
"Type=Application\n"
"PrefersNonDefaultGPU=true\n"
"X-KDE-RunOnDiscreteGpu=true\n"
"MimeType=text/x.gcode;\n"
"Categories=Graphics;3DGraphics;\n"
"Keywords=3D;Printing;Slicer;\n"
+1 -1
View File
@@ -18,7 +18,7 @@ public:
// methods that actually do / undo desktop integration. Static to be accesible from anywhere.
// returns true if path to OrcaSlicer.desktop is stored in App Config and existence of desktop file.
// returns true if path to com.orcaslicer.OrcaSlicer.desktop is stored in App Config and existence of desktop file.
// Does not check if desktop file leads to this binary or existence of icons and viewer desktop file.
static bool is_integrated();
// true if appimage
+44 -10
View File
@@ -4,16 +4,15 @@
#include "wx/dcgraph.h"
#include "I18N.hpp"
#include "PartPlate.hpp"
#include "Widgets/HyperLink.hpp"
namespace Slic3r { namespace GUI {
static const wxColour LabelEnableColor = wxColour("#262E30");
static const wxColour LabelDisableColor = wxColour("#ACACAC");
static const wxColour GreyColor = wxColour("#6B6B6B");
static const wxColour GreenColor = wxColour("#009688");
static const wxColour BackGroundColor = wxColour("#FFFFFF");
static bool should_pop_up()
{
const auto &preset_bundle = wxGetApp().preset_bundle;
@@ -47,6 +46,37 @@ static void set_prefered_map_mode(FilamentMapMode mode)
app_config->set("prefered_filament_map_mode", mode_str);
}
bool play_dual_extruder_slice_video()
{
if (wxLaunchDefaultBrowser("https://e.bambulab.com/t?c=HDB24RlwSmt77YFH")) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("Video is being played using the system's default browser.");
return true;
}
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format("launch system's default browser failed");
return false;
}
bool play_dual_extruder_print_tpu_video()
{
const wxString video_url = "https://e.bambulab.com/t?c=fwWqpBg37Liel92N";
if (wxLaunchDefaultBrowser(video_url)){
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("Print Tpu Video is being played using the system's default browser.");
return true;
}
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format("launch system's default browser failed");
return false;
}
bool open_filament_group_wiki()
{
if (wxLaunchDefaultBrowser("https://e.bambulab.com/t?c=mOkvsXkJ9pldGYp9")) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("Wiki is being displayed using the system's default browser.");
return true;
}
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format("launch system's default browser failed");
return false;
}
void FilamentGroupPopup::CreateBmps()
{
checked_bmp = create_scaled_bitmap("radio_on", nullptr, 16);; // ORCA match icons
@@ -146,16 +176,20 @@ FilamentGroupPopup::FilamentGroupPopup(wxWindow *parent) : PopupWindow(parent, w
{
wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL);
const std::string wiki_path = Slic3r::resources_dir() + "/wiki/filament_group_wiki_zh.html"; // NEEDFIX this link is broken
auto* wiki_sizer = new wxBoxSizer(wxHORIZONTAL);
wiki_link = new HyperLink(this, _L("Wiki Guide"), wxString(wiki_path.c_str())); // ORCA
wiki_sizer->Add(wiki_link, 0, wxALIGN_CENTER | wxALL, FromDIP(3));
button_sizer->Add(wiki_sizer, 0, wxLEFT, horizontal_margin);
// ORCA Unified hyperlinks
video_link = new HyperLink(this, _L("Video tutorial"));
video_link->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent& e)
{
play_dual_extruder_slice_video();
wxGetApp().app_config->set("play_slicing_video", "false");
});
button_sizer->Add(video_link, 0, wxLEFT, horizontal_margin + FromDIP(3));
button_sizer->AddStretchSpacer();
wiki_link = new HyperLink(this, _L("Wiki Guide"));
wiki_link->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent&) { open_filament_group_wiki(); });
button_sizer->Add(wiki_link, 0, wxLEFT, horizontal_margin);
top_sizer->Add(button_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, horizontal_margin);
}
+5
View File
@@ -14,6 +14,10 @@ class PartPlate;
class Plater;
bool play_dual_extruder_slice_video();
bool play_dual_extruder_print_tpu_video();
bool open_filament_group_wiki();
class FilamentGroupPopup : public PopupWindow
{
public:
@@ -69,6 +73,7 @@ private:
wxStaticText *wiki_link;
wxStaticText *video_link;
PartPlate* partplate_ref{ nullptr };
Plater* plater_ref{ nullptr };
+8 -8
View File
@@ -21,6 +21,7 @@
#include "GUI_Utils.hpp"
#include "GUI.hpp"
#include "GLCanvas3D.hpp"
#include "FilamentGroupPopup.hpp"
#include "GLToolbar.hpp"
#include "GUI_Preview.hpp"
#include "libslic3r/Print.hpp"
@@ -33,7 +34,7 @@
#endif // ENABLE_ACTUAL_SPEED_DEBUG
#include <imgui/imgui_internal.h>
#include <GL/glew.h>
#include <glad/gl.h>
#include <boost/log/trivial.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/nowide/cstdio.hpp>
@@ -3081,13 +3082,12 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding)
auto link_filament_group_wiki = [&](const std::string& label) {
ImVec2 wiki_part_size = ImGui::CalcTextSize(label.c_str());
ImColor HyperColor = ImColor(0, 150, 136, 255).Value;
ImColor HyperColor = ImColor(0, 150, 136, 255); // ORCA match color
ImGui::PushStyleColor(ImGuiCol_Text, HyperColor.Value);
imgui.text(label.c_str());
ImGui::PopStyleColor();
// underline
// ORCA use underline to match hyperlink style
ImVec2 lineEnd = ImGui::GetItemRectMax();
lineEnd.y -= 2.0f;
ImVec2 lineStart = lineEnd;
@@ -3096,8 +3096,7 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding)
// click behavior
if (ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), true)) {
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
std::string wiki_path = Slic3r::resources_dir() + "/wiki/filament_group_wiki_zh.html";
wxLaunchDefaultBrowser(wxString(wiki_path.c_str()));
open_filament_group_wiki();
}
}
};
@@ -3304,8 +3303,9 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding)
link_text(_u8L("Regroup filament"));
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetWindowContentRegionWidth() - window_padding - ImGui::CalcTextSize("Tips").x);
link_filament_group_wiki(_u8L("Tips"));
std::string wiki_str = _u8L("Wiki Guide"); // ORCA
ImGui::SetCursorPosX(ImGui::GetWindowContentRegionWidth() - window_padding - ImGui::CalcTextSize(wiki_str.c_str()).x);
link_filament_group_wiki(wiki_str);
ImGui::EndChild();
}
+168 -130
View File
@@ -44,7 +44,7 @@
#include "slic3r/Utils/RetinaHelper.hpp"
#endif
#include <GL/glew.h>
#include <glad/gl.h>
#include <wx/glcanvas.h>
#include <wx/bitmap.h>
@@ -2194,8 +2194,12 @@ void GLCanvas3D::render(bool only_init)
wxGetApp().imgui()->render();
m_canvas->SwapBuffers();
m_render_stats.increment_fps_counter();
// On Wayland, eglSwapBuffers blocks when the canvas is hidden or
// occluded. Skip the swap to avoid stalling the render loop.
if (m_canvas->IsShownOnScreen()) {
m_canvas->SwapBuffers();
m_render_stats.increment_fps_counter();
}
}
void GLCanvas3D::render_thumbnail(ThumbnailData & thumbnail_data,
@@ -2354,6 +2358,13 @@ void GLCanvas3D::ensure_on_bed(unsigned int object_idx, bool allow_negative_z)
InstancesToZMap instances_min_z;
for (GLVolume* volume : m_volumes.volumes) {
ModelObject* mo = m_model->objects[volume->object_idx()];
ModelInstance* mi = mo->instances[volume->instance_idx()];
if (!mi->auto_drop) {
continue;
}
if (volume->object_idx() == (int)object_idx && !volume->is_modifier) {
double min_z = volume->transformed_convex_hull_bounding_box().min.z();
std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
@@ -4817,14 +4828,13 @@ Vec2d GLCanvas3D::get_local_mouse_position() const
if (m_canvas == nullptr)
return Vec2d::Zero();
wxPoint mouse_pos = m_canvas->ScreenToClient(wxGetMousePosition());
const double factor =
#if ENABLE_RETINA_GL
m_retina_helper->get_scale_factor();
#else
1.0;
#endif
return Vec2d(factor * mouse_pos.x, factor * mouse_pos.y);
// Use the cached mouse position from event handlers (m_mouse.position)
// instead of wxGetMousePosition() + ScreenToClient(), because
// wxGetMousePosition() returns (0,0) on Wayland for global coords.
// m_mouse.position already stores local canvas coordinates (set from
// event.GetX(), event.GetY()) and is already scaled by the retina factor
// in on_mouse(), so we can return it directly.
return m_mouse.position;
}
void GLCanvas3D::set_tooltip(const std::string& tooltip)
@@ -4865,28 +4875,30 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
// Move instances/volumes
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance) {
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
if ((model_object->instances[instance_idx]->get_assemble_offset() - v->get_instance_offset()).norm() > 1e-2) {
model_object->instances[instance_idx]->set_assemble_transformation(v->get_instance_transformation());
}
} else {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
}
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
if (model_object == nullptr)
continue;
object_moved = true;
model_object->invalidate_bounding_box();
if (selection_mode == Selection::Instance) {
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
if ((model_object->instances[instance_idx]->get_assemble_offset() - v->get_instance_offset()).norm() > 1e-2) {
model_object->instances[instance_idx]->set_assemble_transformation(v->get_instance_transformation());
}
} else {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
}
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
object_moved = true;
model_object->invalidate_bounding_box();
}
else if (object_idx >= 1000 && object_idx < 1000 + n_plates) {
// Move a wipe tower proxy.
@@ -4897,20 +4909,27 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(-1, 0);
// Fixes flying instances
// Fixes sinking/flying instances (snaps object to buildplate)
for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first];
const double shift_z = m->get_instance_min_z(i.second);
ModelObject* mo = m_model->objects[i.first];
ModelInstance* mi = mo->instances[i.second];
if (!mi->auto_drop) {
continue;
}
const double shift_z = mo->get_instance_min_z(i.second);
//BBS: don't call translate if the z is zero
if ((current_printer_technology() == ptSLA || shift_z > SINKING_Z_THRESHOLD) && (shift_z != 0.0f)) {
const Vec3d shift(0.0, 0.0, -shift_z);
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
mo->translate_instance(i.second, shift);
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(i.first, i.second);
}
wxGetApp().obj_list()->update_info_items(static_cast<size_t>(i.first));
}
//BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
@@ -4984,40 +5003,47 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
// Rotate instances/volumes.
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance) {
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
model_object->instances[instance_idx]->set_assemble_from_transform(v->get_instance_transformation().get_matrix());
} else {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
if (model_object == nullptr)
continue;
if (selection_mode == Selection::Instance) {
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
model_object->instances[instance_idx]->set_assemble_from_transform(v->get_instance_transformation().get_matrix());
} else {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
model_object->invalidate_bounding_box();
}
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
model_object->invalidate_bounding_box();
}
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(-1, -1);
if (m_canvas_type != CanvasAssembleView) {
// Fixes sinking/flying instances
// Fixes sinking/flying instances (snaps object to buildplate)
for (const std::pair<int, int> &i : done) {
ModelObject *m = m_model->objects[i.first];
ModelObject *mo = m_model->objects[i.first];
ModelInstance* mi = mo->instances[i.second];
if (!mi->auto_drop) {
continue;
}
// BBS: don't call translate if the z is zero
const double shift_z = m->get_instance_min_z(i.second);
const double shift_z = mo->get_instance_min_z(i.second);
// leave sinking instances as sinking
if ((min_zs.find({i.first, i.second})->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) && (shift_z != 0.0f)) {
const Vec3d shift(0.0, 0.0, -shift_z);
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
mo->translate_instance(i.second, shift);
// BBS: notify instance updates to part plater list
m_selection.notify_instance_update(i.first, i.second);
}
@@ -5025,6 +5051,7 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
wxGetApp().obj_list()->update_info_items(static_cast<size_t>(i.first));
}
}
//BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
@@ -5072,42 +5099,49 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
// Rotate instances/volumes
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
model_object->invalidate_bounding_box();
if (model_object == nullptr)
continue;
if (selection_mode == Selection::Instance) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
model_object->invalidate_bounding_box();
}
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(-1, -1);
// Fixes sinking/flying instances
// Fixes sinking/flying instances (snaps object to buildplate)
for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first];
ModelObject* mo = m_model->objects[i.first];
ModelInstance* mi = mo->instances[i.second];
if (!mi->auto_drop) {
continue;
}
//BBS: don't call translate if the z is zero
double shift_z = m->get_instance_min_z(i.second);
double shift_z = mo->get_instance_min_z(i.second);
// leave sinking instances as sinking
if ((min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) && (shift_z != 0.0f)) {
Vec3d shift(0.0, 0.0, -shift_z);
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
mo->translate_instance(i.second, shift);
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(i.first, i.second);
}
wxGetApp().obj_list()->update_info_items(static_cast<size_t>(i.first));
}
//BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
//BBS: notify object info update
@@ -5177,35 +5211,41 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
// Mirror instances/volumes
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance)
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
else if (selection_mode == Selection::Volume) {
if (model_object->volumes[volume_idx]->get_transformation() != v->get_volume_transformation()) {
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
if (model_object == nullptr)
continue;
model_object->invalidate_bounding_box();
if (selection_mode == Selection::Instance)
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
else if (selection_mode == Selection::Volume) {
if (model_object->volumes[volume_idx]->get_transformation() != v->get_volume_transformation()) {
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
model_object->invalidate_bounding_box();
}
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(-1, -1);
// Fixes sinking/flying instances
// Fixes sinking/flying instances (snaps object to buildplate)
for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first];
ModelObject* mo = m_model->objects[i.first];
ModelInstance* mi = mo->instances[i.second];
if (!mi->auto_drop) {
continue;
}
//BBS: don't call translate if the z is zero
double shift_z = m->get_instance_min_z(i.second);
double shift_z = mo->get_instance_min_z(i.second);
// leave sinking instances as sinking
if ((min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD)&&(shift_z != 0.0f)) {
Vec3d shift(0.0, 0.0, -shift_z);
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
mo->translate_instance(i.second, shift);
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(i.first, i.second);
}
@@ -5214,10 +5254,8 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
//BBS: notify instance updates to part plater list
PartPlateList &plate_list = wxGetApp().plater()->get_partplate_list();
plate_list.notify_instance_update(i.first, i.second);
//BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
}
}
//BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
@@ -6388,21 +6426,21 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data,
// glsafe(::glEnable(GL_MULTISAMPLE));
GLint max_samples;
glsafe(::glGetIntegerv(GL_MAX_SAMPLES_EXT, &max_samples));
glsafe(::glGetIntegerv(GL_MAX_SAMPLES, &max_samples));
GLsizei num_samples = max_samples / 2;
GLuint render_fbo;
glsafe(::glGenFramebuffersEXT(1, &render_fbo));
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, render_fbo));
glsafe(::glGenFramebuffers(1, &render_fbo));
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, render_fbo));
GLuint render_tex = 0;
GLuint render_tex_buffer = 0;
if (multisample) {
// use renderbuffer instead of texture to avoid the need to use glTexImage2DMultisample which is available only since OpenGL 3.2
glsafe(::glGenRenderbuffersEXT(1, &render_tex_buffer));
glsafe(::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_tex_buffer));
glsafe(::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, num_samples, GL_RGBA8, w, h));
glsafe(::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, render_tex_buffer));
glsafe(::glGenRenderbuffers(1, &render_tex_buffer));
glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, render_tex_buffer));
glsafe(::glRenderbufferStorageMultisample(GL_RENDERBUFFER, num_samples, GL_RGBA8, w, h));
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, render_tex_buffer));
}
else {
glsafe(::glGenTextures(1, &render_tex));
@@ -6410,31 +6448,31 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data,
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, render_tex, 0));
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render_tex, 0));
}
GLuint render_depth;
glsafe(::glGenRenderbuffersEXT(1, &render_depth));
glsafe(::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_depth));
glsafe(::glGenRenderbuffers(1, &render_depth));
glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, render_depth));
if (multisample)
glsafe(::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, num_samples, GL_DEPTH_COMPONENT24, w, h));
glsafe(::glRenderbufferStorageMultisample(GL_RENDERBUFFER, num_samples, GL_DEPTH_COMPONENT24, w, h));
else
glsafe(::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, w, h));
glsafe(::glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h));
glsafe(::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, render_depth));
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_depth));
GLenum drawBufs[] = { GL_COLOR_ATTACHMENT0 };
glsafe(::glDrawBuffers(1, drawBufs));
if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT) {
if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
render_thumbnail_internal(thumbnail_data, thumbnail_params, partplate_list, model_objects, volumes, extruder_colors, shader, camera_type, camera_view_angle_type,
for_picking,
ban_light);
if (multisample) {
GLuint resolve_fbo;
glsafe(::glGenFramebuffersEXT(1, &resolve_fbo));
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, resolve_fbo));
glsafe(::glGenFramebuffers(1, &resolve_fbo));
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, resolve_fbo));
GLuint resolve_tex;
glsafe(::glGenTextures(1, &resolve_tex));
@@ -6442,21 +6480,21 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data,
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glsafe(::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, resolve_tex, 0));
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolve_tex, 0));
glsafe(::glDrawBuffers(1, drawBufs));
if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT) {
glsafe(::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, render_fbo));
glsafe(::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, resolve_fbo));
glsafe(::glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR));
if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
glsafe(::glBindFramebuffer(GL_READ_FRAMEBUFFER, render_fbo));
glsafe(::glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo));
glsafe(::glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR));
glsafe(::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, resolve_fbo));
glsafe(::glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo));
glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
}
glsafe(::glDeleteTextures(1, &resolve_tex));
glsafe(::glDeleteFramebuffersEXT(1, &resolve_fbo));
glsafe(::glDeleteFramebuffers(1, &resolve_fbo));
}
else
glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
@@ -6466,13 +6504,13 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data,
#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
}
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
glsafe(::glDeleteRenderbuffersEXT(1, &render_depth));
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0));
glsafe(::glDeleteRenderbuffers(1, &render_depth));
if (render_tex_buffer != 0)
glsafe(::glDeleteRenderbuffersEXT(1, &render_tex_buffer));
glsafe(::glDeleteRenderbuffers(1, &render_tex_buffer));
if (render_tex != 0)
glsafe(::glDeleteTextures(1, &render_tex));
glsafe(::glDeleteFramebuffersEXT(1, &render_fbo));
glsafe(::glDeleteFramebuffers(1, &render_fbo));
//if (!multisample)
// glsafe(::glDisable(GL_MULTISAMPLE));
@@ -7249,8 +7287,8 @@ void GLCanvas3D::_rectangular_selection_picking_pass()
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, render_fbo));
}
else {
glsafe(::glGenFramebuffersEXT(1, &render_fbo));
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, render_fbo));
glsafe(::glGenFramebuffers(1, &render_fbo));
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, render_fbo));
}
glsafe(::glGenTextures(1, &render_tex));
glsafe(::glBindTexture(GL_TEXTURE_2D, render_tex));
@@ -7265,11 +7303,11 @@ void GLCanvas3D::_rectangular_selection_picking_pass()
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_depth));
}
else {
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, render_tex, 0));
glsafe(::glGenRenderbuffersEXT(1, &render_depth));
glsafe(::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_depth));
glsafe(::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height));
glsafe(::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, render_depth));
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render_tex, 0));
glsafe(::glGenRenderbuffers(1, &render_depth));
glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, render_depth));
glsafe(::glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height));
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_depth));
}
const GLenum drawBufs[] = { GL_COLOR_ATTACHMENT0 };
glsafe(::glDrawBuffers(1, drawBufs));
@@ -7278,7 +7316,7 @@ void GLCanvas3D::_rectangular_selection_picking_pass()
use_framebuffer = false;
}
else {
if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
use_framebuffer = false;
}
}
@@ -7389,11 +7427,11 @@ void GLCanvas3D::_rectangular_selection_picking_pass()
glsafe(::glDeleteFramebuffers(1, &render_fbo));
}
else if (framebuffers_type == OpenGLManager::EFramebufferType::Ext) {
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0));
if (render_depth != 0)
glsafe(::glDeleteRenderbuffersEXT(1, &render_depth));
glsafe(::glDeleteRenderbuffers(1, &render_depth));
if (render_fbo != 0)
glsafe(::glDeleteFramebuffersEXT(1, &render_fbo));
glsafe(::glDeleteFramebuffers(1, &render_fbo));
}
if (render_tex != 0)
+1 -1
View File
@@ -954,7 +954,7 @@ public:
Camera::ViewAngleType camera_view_angle_type = Camera::ViewAngleType::Iso,
bool for_picking = false,
bool ban_light = false);
// render thumbnail using an off-screen framebuffer when GLEW_EXT_framebuffer_object is supported
// render thumbnail using an off-screen framebuffer when GL_EXT_framebuffer_object is supported
static void render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector<ColorRGBA>& extruder_colors,
GLShaderProgram * shader,
+1 -1
View File
@@ -20,7 +20,7 @@
#include <igl/per_vertex_normals.h>
#endif // ENABLE_SMOOTH_NORMALS
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r {
namespace GUI {
+1 -1
View File
@@ -7,7 +7,7 @@
#include "Plater.hpp"
#include <igl/project.h>
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r {
namespace GUI {
+1 -1
View File
@@ -7,7 +7,7 @@
#include "libslic3r/Color.hpp"
#include <boost/nowide/fstream.hpp>
#include <GL/glew.h>
#include <glad/gl.h>
#include <cassert>
#include <boost/log/trivial.hpp>
+1 -1
View File
@@ -9,7 +9,7 @@
#include <string_view>
using namespace std::literals;
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r {
+1 -1
View File
@@ -11,7 +11,7 @@
#include "GUI_App.hpp"
#include "GLModel.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <wx/image.h>
#include <boost/filesystem.hpp>
+28 -2
View File
@@ -161,6 +161,10 @@ typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS2)(
#include <boost/nowide/fstream.hpp>
#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG
#ifdef __WXGTK__
#include "LinuxDisplayBackend.hpp"
#endif
// Needed for forcing menu icons back under gtk2 and gtk3
#if defined(__WXGTK20__) || defined(__WXGTK3__)
#include <gtk/gtk.h>
@@ -909,6 +913,8 @@ void GUI_App::post_init()
}
else {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << "Found glcontext not ready, postpone the init";
plater_->canvas3D()->enable_render(true);
plater_->canvas3D()->set_as_dirty();
}
//#endif
if (is_editor())
@@ -2303,7 +2309,8 @@ bool GUI_App::init_opengl()
{
#ifdef __linux__
bool status = m_opengl_mgr.init_gl();
m_opengl_initialized = true;
if (status)
m_opengl_initialized = true;
return status;
#else
return m_opengl_mgr.init_gl();
@@ -3091,6 +3098,20 @@ bool GUI_App::on_init_inner()
// Let the libslic3r know the callback, which will translate messages on demand.
Slic3r::I18N::set_translate_callback(libslic3r_translate_callback);
#if defined(__WXGTK__) && wxHAS_EGL
// Configure GL backend before any wxGLCanvas is created.
// On X11, prefer GLX for maximum driver compatibility.
// On Wayland, EGL is used by default (only option).
if (Slic3r::GUI::is_running_on_x11()) {
wxGLCanvas::PreferGLX();
BOOST_LOG_TRIVIAL(info) << "X11 detected, using GLX for OpenGL context";
} else if (Slic3r::GUI::is_running_on_wayland()) {
BOOST_LOG_TRIVIAL(info) << "Wayland detected, using EGL for OpenGL context";
} else {
BOOST_LOG_TRIVIAL(warning) << "Unknown display backend, defaulting to EGL";
}
#endif
BOOST_LOG_TRIVIAL(info) << "create the main window";
mainframe = new MainFrame();
// hide settings tabs after first Layout
@@ -7708,7 +7729,12 @@ bool GUI_App::window_pos_restore(wxTopLevelWindow* window, const std::string &na
}
const wxRect& rect = metrics->get_rect();
window->SetPosition(rect.GetPosition());
#if defined(__WXGTK__)
// On Wayland, SetPosition() is a no-op for top-level windows.
// Only restore size and maximize state.
if (!Slic3r::GUI::is_running_on_wayland())
#endif
window->SetPosition(rect.GetPosition());
window->SetSize(rect.GetSize());
window->Maximize(metrics->get_maximized());
return true;
+52 -2
View File
@@ -855,6 +855,23 @@ wxMenuItem* MenuFactory::append_menu_item_printable(wxMenu* menu)
return menu_item_printable;
}
wxMenuItem* MenuFactory::append_menu_item_auto_drop(wxMenu* menu)
{
wxString menu_text = _L("Auto Drop");
wxString menu_tooltip = _L("Automatically drops the selected object to the build plate");
wxMenuItem* menu_item_auto_drop = append_menu_check_item(
menu, wxID_ANY, menu_text, menu_tooltip,
[](wxCommandEvent&) { obj_list()->toggle_auto_drop(); }, menu);
m_parent->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) {
bool check = wxGetApp().plater()->get_selection().get_auto_drop();
evt.Check(check);
},
menu_item_auto_drop->GetId());
return menu_item_auto_drop;
}
void MenuFactory::append_menu_item_rename(wxMenu* menu)
{
append_menu_item(menu, wxID_ANY, _L("Rename"), "",
@@ -1416,6 +1433,10 @@ void MenuFactory::create_extra_object_menu()
// Set filament insert menu item here
// Set Printable
wxMenuItem* menu_item_printable = append_menu_item_printable(&m_object_menu);
m_object_menu.AppendSeparator();
wxMenuItem* menu_item_auto_drop = append_menu_item_auto_drop(&m_object_menu);
m_object_menu.AppendSeparator();
append_menu_item_per_object_process(&m_object_menu);
// Enter per object parameters
append_menu_item_per_object_settings(&m_object_menu);
@@ -1845,8 +1866,14 @@ wxMenu* MenuFactory::multi_selection_menu()
menu->AppendSeparator();
append_menu_item_set_printable(menu);
menu->AppendSeparator();
append_menu_item_set_auto_drop(menu);
menu->AppendSeparator();
append_menu_item_per_object_process(menu);
menu->AppendSeparator();
append_menu_items_convert_unit(menu);
append_menu_item_replace_all_with_stl(menu);
//BBS
@@ -2032,7 +2059,7 @@ void MenuFactory::append_menu_item_drop(wxMenu* menu)
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
else {
return (plater()->get_view3D_canvas3D()->get_selection().get_bounding_box().min.z() != 0);
return (plater()->get_view3D_canvas3D()->get_selection().get_bounding_box().min.z() > SINKING_Z_THRESHOLD);
} //disable if model is on the bed / not in View3D
}, m_parent);
}
@@ -2184,7 +2211,7 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu)
void MenuFactory::append_menu_item_set_printable(wxMenu* menu)
{
const Selection& selection = plater()->canvas3D()->get_selection();
bool all_printable = true;
bool all_printable = true;
ObjectList* list = obj_list();
wxDataViewItemArray sels;
list->GetSelections(sels);
@@ -2212,6 +2239,29 @@ void MenuFactory::append_menu_item_set_printable(wxMenu* menu)
}, menu_item_set_printable->GetId());
}
void MenuFactory::append_menu_item_set_auto_drop(wxMenu* menu)
{
const Selection& selection = plater()->canvas3D()->get_selection();
const bool current_auto_drop = selection.get_auto_drop();
wxString menu_text = _L("Auto Drop");
wxString menu_tooltip = _L("Automatically snaps the selected object to the build plate");
wxMenuItem* menu_item_set_auto_drop = append_menu_check_item(
menu, wxID_ANY, menu_text, menu_tooltip,
[this, current_auto_drop](wxCommandEvent&) {
Selection& selection = plater()->canvas3D()->get_selection();
selection.set_auto_drop(!current_auto_drop);
},
menu);
m_parent->Bind(
wxEVT_UPDATE_UI,
[current_auto_drop](wxUpdateUIEvent& evt) {
evt.Check(current_auto_drop);
plater()->set_current_canvas_as_dirty();
},
menu_item_set_auto_drop->GetId());
}
void MenuFactory::append_menu_item_locked(wxMenu* menu)
{
const std::vector<wxString> names = { _L("Unlock"), _L("Lock") };
+2
View File
@@ -137,6 +137,7 @@ private:
wxMenuItem* append_menu_item_change_type(wxMenu* menu);
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu);
wxMenuItem* append_menu_item_printable(wxMenu* menu);
wxMenuItem* append_menu_item_auto_drop(wxMenu* menu);
void append_menu_item_rename(wxMenu* menu);
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
//wxMenuItem* append_menu_item_simplify(wxMenu* menu);
@@ -171,6 +172,7 @@ private:
void append_menu_item_per_object_settings(wxMenu* menu);
void append_menu_item_change_filament(wxMenu* menu);
void append_menu_item_set_printable(wxMenu* menu);
void append_menu_item_set_auto_drop(wxMenu* menu);
void append_menu_item_locked(wxMenu* menu);
void append_menu_item_fill_bed(wxMenu *menu);
void append_menu_item_plate_name(wxMenu *menu);
+87 -5
View File
@@ -914,15 +914,15 @@ void ObjectList::object_config_options_changed(const ObjectVolumeID& ov_id)
}
}
void ObjectList::printable_state_changed(const std::vector<ObjectVolumeID>& ov_ids)
void ObjectList::printable_state_changed(const std::vector<ModelObject*> model_objects)
{
std::vector<size_t> obj_idxs;
for (const ObjectVolumeID ov_id : ov_ids) {
if (ov_id.object == nullptr)
for (const ModelObject* mo : model_objects) {
if (mo == nullptr)
continue;
ModelInstance* mi = ov_id.object->instances[0];
wxDataViewItem obj_item = m_objects_model->GetObjectItem(ov_id.object);
ModelInstance* mi = mo->instances[0];
wxDataViewItem obj_item = m_objects_model->GetObjectItem(mo);
m_objects_model->SetObjectPrintableState(mi->printable ? piPrintable : piUnprintable, obj_item);
int obj_idx = m_objects_model->GetObjectIdByItem(obj_item);
@@ -939,6 +939,19 @@ void ObjectList::printable_state_changed(const std::vector<ObjectVolumeID>& ov_i
wxGetApp().plater()->update();
}
void ObjectList::printable_state_changed(const std::vector<ObjectVolumeID>& ov_ids)
{
std::vector<ModelObject*> model_objects;
model_objects.reserve(ov_ids.size());
for (const ObjectVolumeID& ov_id : ov_ids) {
if (ov_id.object != nullptr)
model_objects.emplace_back(ov_id.object);
}
printable_state_changed(model_objects);
}
void ObjectList::assembly_plate_object_name()
{
m_objects_model->assembly_name();
@@ -1153,6 +1166,7 @@ void ObjectList::update_name_in_list(int obj_idx, int vol_idx) const
void ObjectList::selection_changed()
{
if (wxGetApp().is_closing()) return;
if (m_prevent_list_events) return;
fix_multiselection_conflicts();
@@ -1747,6 +1761,8 @@ void ObjectList::key_event(wxKeyEvent& event)
decrease_instances();
else if (event.GetUnicodeKey() == 'p')
toggle_printable_state();
else if (event.GetUnicodeKey() == 'd')
toggle_auto_drop();
else if (filaments_count() > 1) {
std::vector<wxChar> numbers = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
wxChar key_char = event.GetUnicodeKey();
@@ -3043,6 +3059,17 @@ void ObjectList::merge(bool to_multipart_object)
volume->config.set_key_value("extruder", option->clone());
}
// merge printable and auto_drop values
// non-default have priority -> if one object has printable == false,
// then merged object will also have printable == false
if (object->instances[0]->printable == false) {
new_object->printable = false;
new_object->instances[0]->printable = false;
}
if (object->instances[0]->auto_drop == false) {
new_object->instances[0]->auto_drop = false;
}
// merge layers
for (const auto& range : object->layer_config_ranges)
new_object->layer_config_ranges.emplace(range);
@@ -3076,6 +3103,9 @@ void ObjectList::merge(bool to_multipart_object)
// Add new object(merged) to the object_list
add_object_to_list(m_objects->size() - 1);
if (new_object->printable == false) {
wxGetApp().obj_list()->printable_state_changed({new_object});
}
select_item(m_objects_model->GetItemById(m_objects->size() - 1));
update_selections_on_canvas();
}
@@ -3456,6 +3486,9 @@ void ObjectList::changed_object(const int obj_idx/* = -1*/) const
void ObjectList::part_selection_changed()
{
if (wxGetApp().is_closing())
return;
if (m_extruder_editor) m_extruder_editor->Hide();
int obj_idx = -1;
int volume_id = -1;
@@ -4656,6 +4689,9 @@ int ObjectList::get_selected_layers_range_idx() const
void ObjectList::update_selections()
{
if (wxGetApp().is_closing())
return;
const Selection& selection = scene_selection();
wxDataViewItemArray sels;
@@ -6593,6 +6629,52 @@ void ObjectList::toggle_printable_state()
wxGetApp().plater()->reload_paint_after_background_process_apply();
}
void ObjectList::toggle_auto_drop()
{
wxDataViewItemArray sels;
GetSelections(sels);
if (sels.IsEmpty())
return;
for (auto item : sels) {
ItemType type = m_objects_model->GetItemType(item);
if (!(type & (itObject | itInstance)))
return;
}
const bool current_auto_drop = wxGetApp().plater()->get_selection().get_auto_drop();
take_snapshot("");
std::vector<size_t> obj_idxs;
for (auto item : sels) {
int obj_idx = m_objects_model->GetObjectIdByItem(item);
ModelObject* obj = object(obj_idx);
obj_idxs.emplace_back(static_cast<size_t>(obj_idx));
ItemType type = m_objects_model->GetItemType(item);
// set auto_drop value for selected instance/instances in object
if (type == itInstance) {
int inst_idx = m_objects_model->GetInstanceIdByItem(item);
obj->instances[inst_idx]->auto_drop = !current_auto_drop;
} else {
for (auto inst : obj->instances)
inst->auto_drop = !current_auto_drop;
if (current_auto_drop == false)
obj->ensure_on_bed();
}
}
sort(obj_idxs.begin(), obj_idxs.end());
obj_idxs.erase(unique(obj_idxs.begin(), obj_idxs.end()), obj_idxs.end());
// update scene
wxGetApp().plater()->update();
wxGetApp().plater()->reload_paint_after_background_process_apply();
}
void ObjectList::enable_layers_editing()
{
wxDataViewItemArray sels;
+2
View File
@@ -449,6 +449,7 @@ public:
//update printable state for item from objects model
void update_printable_state(int obj_idx, int instance_idx);
void toggle_printable_state();
void toggle_auto_drop();
void enable_layers_editing();
//BBS: remove const qualifier
@@ -463,6 +464,7 @@ public:
void on_plate_selected(int plate_index);
void notify_instance_updated(int obj_idx);
void object_config_options_changed(const ObjectVolumeID& ov_id);
void printable_state_changed(const std::vector<ModelObject*> model_objects);
void printable_state_changed(const std::vector<ObjectVolumeID>& ov_ids);
// search objectlist
+3
View File
@@ -86,6 +86,9 @@ bool ObjectSettings::update_settings_list()
m_settings_list_sizer->Clear(true);
m_og_settings.resize(0);
if (wxGetApp().is_closing())
return false;
auto objects_ctrl = wxGetApp().obj_list();
auto objects_model = wxGetApp().obj_list()->GetModel();
auto config = wxGetApp().obj_list()->config();
+1 -6
View File
@@ -1520,12 +1520,7 @@ void ObjectGridTable::update_value_to_object(Model* model, ObjectGridRow* grid_r
object->printable = grid_row->printable.value;
object->instances[0]->printable = object->printable;
std::vector<ObjectVolumeID> object_volume_ids;
ObjectVolumeID object_volume_id;
object_volume_id.object = object;
object_volume_id.volume = nullptr;
object_volume_ids.push_back(object_volume_id);
wxGetApp().obj_list()->printable_state_changed(object_volume_ids);
wxGetApp().obj_list()->printable_state_changed({object});
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", change object %1%'s printable to %2%")%object->module_name %object->printable;
}
}
+1 -1
View File
@@ -2,7 +2,7 @@
#include "GLGizmoAdvancedCut.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <wx/button.h>
#include <wx/checkbox.h>
+1 -1
View File
@@ -12,7 +12,7 @@
#include <numeric>
#include <GL/glew.h>
#include <glad/gl.h>
#include <tbb/parallel_for.h>
#include <future>
+1 -1
View File
@@ -1,7 +1,7 @@
#include "GLGizmoBase.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Plater.hpp"
+1 -1
View File
@@ -1,5 +1,5 @@
#include "GLGizmoBrimEars.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/Camera.hpp"
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
+1 -1
View File
@@ -1,7 +1,7 @@
#include "GLGizmoCut.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <algorithm>
+1 -1
View File
@@ -50,7 +50,7 @@
#include <cereal/types/string.hpp>
#include <cereal/archives/binary.hpp>
#include <GL/glew.h>
#include <glad/gl.h>
#include <chrono> // measure enumeration of fonts
// uncomment for easier debug
+1 -1
View File
@@ -19,7 +19,7 @@
#include "libslic3r/TextConfiguration.hpp"
#include <imgui/imgui.h>
#include <GL/glew.h>
#include <glad/gl.h>
class wxFont;
namespace Slic3r{
@@ -9,7 +9,7 @@
#include "slic3r/GUI/ImGuiWrapper.hpp"
#include "slic3r/GUI/Plater.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#ifdef __WINDOWS__
#include <windows.h>
+1 -1
View File
@@ -15,7 +15,7 @@
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/Utils/UndoRedo.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <boost/log/trivial.hpp>
+1 -1
View File
@@ -9,7 +9,7 @@
#include <numeric>
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r {
namespace GUI {
+1 -1
View File
@@ -11,7 +11,7 @@
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/Utils/UndoRedo.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <algorithm>
namespace Slic3r::GUI {
+1 -1
View File
@@ -3,7 +3,7 @@
#include "slic3r/GUI/Camera.hpp"
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/GUI_ObjectSettings.hpp"
+1 -1
View File
@@ -12,7 +12,7 @@
#include <numeric>
#include <GL/glew.h>
#include <glad/gl.h>
#include <tbb/parallel_for.h>
@@ -15,7 +15,7 @@
#include "slic3r/Utils/UndoRedo.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r::GUI {
+1 -1
View File
@@ -6,7 +6,7 @@
#include "libslic3r/AppConfig.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <wx/utils.h>
+1 -1
View File
@@ -2,7 +2,7 @@
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Camera.hpp"
+1 -1
View File
@@ -10,7 +10,7 @@
#include "libslic3r/Model.hpp"
#include <cereal/types/vector.hpp>
#include <GL/glew.h>
#include <glad/gl.h>
#include <memory>
+1 -1
View File
@@ -9,7 +9,7 @@
#include "libslic3r/PresetBundle.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r {
namespace GUI {
+1 -1
View File
@@ -32,7 +32,7 @@
#include <wx/display.h> // detection of change DPI
#include <boost/log/trivial.hpp>
#include <GL/glew.h>
#include <glad/gl.h>
#include <chrono> // measure enumeration of fonts
#include <sstream> // save for svg
#include <array>
+1 -1
View File
@@ -19,7 +19,7 @@
#include "libslic3r/Model.hpp"
#include <imgui/imgui.h>
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r{
class ModelVolume;
+1 -1
View File
@@ -3,7 +3,7 @@
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Plater.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <wx/utils.h>
+1 -1
View File
@@ -11,7 +11,7 @@
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/Utils/UndoRedo.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r::GUI {
+1 -1
View File
@@ -11,7 +11,7 @@
#include "libslic3r/Model.hpp"
#include "libslic3r/QuadricEdgeCollapse.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <thread>
+1 -1
View File
@@ -6,7 +6,7 @@
#include "slic3r/GUI/MainFrame.hpp"
#include "slic3r/Utils/UndoRedo.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <wx/msgdlg.h>
#include <wx/settings.h>
+1 -1
View File
@@ -16,7 +16,7 @@
#include <boost/log/trivial.hpp>
#include <GL/glew.h>
#include <glad/gl.h>
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
+1 -1
View File
@@ -10,7 +10,7 @@
#include "libslic3r/PresetBundle.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r {
namespace GUI {
+1 -1
View File
@@ -242,7 +242,7 @@ int HMSQuery::save_to_local(std::string lang, std::string hms_type, std::string
std::string dir_str = (hms_folder / filename).make_preferred().string();
std::ofstream json_file(encode_path(dir_str.c_str()));
if (json_file.is_open()) {
json_file << std::setw(4) << save_json << std::endl;
json_file << save_json.dump(1, '\t') << std::endl;
json_file.close();
return 0;
}
+2 -2
View File
@@ -1,7 +1,7 @@
#include "IMToolbar.hpp"
#include "3DScene.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <imgui/imgui_internal.h>
#include <imgui/imgui.h>
@@ -87,7 +87,7 @@ bool IMReturnToolbar::init()
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glsafe(::glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
if (compress && GLEW_EXT_texture_compression_s3tc)
if (compress && GLAD_GL_EXT_texture_compression_s3tc)
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, data.width, data.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
else
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data.width, data.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
+1 -1
View File
@@ -9,7 +9,7 @@
#include "libslic3r/Utils.hpp" // ScopeGuard
#include "3DScene.hpp" // glsafe
#include "GL/glew.h"
#include <glad/gl.h>
#define STB_RECT_PACK_IMPLEMENTATION
#include "imgui/imstb_rectpack.h" // distribute rectangles
+2 -2
View File
@@ -18,7 +18,7 @@
#include <wx/clipbrd.h>
#include <wx/debug.h>
#include <GL/glew.h>
#include <glad/gl.h>
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
@@ -2839,7 +2839,7 @@ void ImGuiWrapper::init_font(bool compress)
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glsafe(::glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
if (compress && GLEW_EXT_texture_compression_s3tc)
if (compress && GLAD_GL_EXT_texture_compression_s3tc)
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
else
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
@@ -3,7 +3,7 @@
#include <vector>
#include <string>
#include <GL/glew.h>
#include <glad/gl.h>
#include <wx/string.h>
#include <wx/fontenc.h>
#include "Job.hpp"
+1 -1
View File
@@ -219,7 +219,7 @@ void create_volume(TriangleMesh &&mesh, const ObjectID& object_id, const ModelVo
/// Create projection for cut surface from mesh
/// </summary>
/// <param name="tr">Volume transformation in object</param>
/// <param name="shape_scale">Convert shape to milimeters</param>
/// <param name="shape_scale">Convert shape to millimeters</param>
/// <param name="z_range">Bounding box 3d of model volume for projection ranges</param>
/// <returns>Orthogonal cut_projection</returns>
OrthoProject create_projection_for_cut(Transform3d tr, double shape_scale, const std::pair<float, float> &z_range);
+53
View File
@@ -0,0 +1,53 @@
#include "LinuxDisplayBackend.hpp"
#if defined(__WXGTK__)
#include <gdk/gdk.h>
#ifdef wxHAVE_GDK_X11
#include <gdk/gdkx.h>
#endif
#ifdef wxHAVE_GDK_WAYLAND
#include <gdk/gdkwayland.h>
#endif
namespace Slic3r {
namespace GUI {
LinuxDisplayBackend get_linux_display_backend()
{
static const LinuxDisplayBackend backend = []() -> LinuxDisplayBackend {
GdkDisplay *display = gdk_display_get_default();
if (!display)
return LinuxDisplayBackend::Unknown;
#ifdef wxHAVE_GDK_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY(display))
return LinuxDisplayBackend::Wayland;
#endif
#ifdef wxHAVE_GDK_X11
if (GDK_IS_X11_DISPLAY(display))
return LinuxDisplayBackend::X11;
#endif
return LinuxDisplayBackend::Unknown;
}();
return backend;
}
bool is_running_on_wayland()
{
return get_linux_display_backend() == LinuxDisplayBackend::Wayland;
}
bool is_running_on_x11()
{
return get_linux_display_backend() == LinuxDisplayBackend::X11;
}
} // namespace GUI
} // namespace Slic3r
#endif // defined(__WXGTK__)
+19
View File
@@ -0,0 +1,19 @@
#pragma once
namespace Slic3r {
namespace GUI {
#if defined(__WXGTK__)
enum class LinuxDisplayBackend { X11, Wayland, Unknown };
// Detect which display backend is in use at runtime.
// Must be called after gtk_init() / wxWidgets initialization.
LinuxDisplayBackend get_linux_display_backend();
// Convenience predicates.
bool is_running_on_wayland();
bool is_running_on_x11();
#endif // defined(__WXGTK__)
} // namespace GUI
} // namespace Slic3r
+36 -1
View File
@@ -310,6 +310,17 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
m_edge_right = new ResizeEdgePanel(this, ResizeEdgePanel::Right);
#endif
#ifdef __WXMSW__
if (HWND hWnd = GetHandle(); hWnd != nullptr) {
LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE);
if ((style & WS_CAPTION) != 0) {
SetWindowLongPtr(hWnd, GWL_STYLE, style & ~WS_CAPTION);
SetWindowPos(hWnd, nullptr, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
}
#endif
if (!wxGetApp().app_config->has("user_mode")) {
wxGetApp().app_config->set("user_mode", "simple");
wxGetApp().app_config->set_bool("developer_mode", false);
@@ -524,6 +535,28 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
update_layout();
sizer->SetSizeHints(this);
#ifdef __WXMSW__
// SetMaximize causes the window to overlap the taskbar, due to the fact this window has wxMAXIMIZE_BOX off
// https://forums.wxwidgets.org/viewtopic.php?t=50634
// Fix it here
this->Bind(wxEVT_MAXIMIZE, [this](auto &e) {
wxDisplay display(this);
auto size = display.GetClientArea().GetSize();
auto pos = display.GetClientArea().GetPosition();
HWND hWnd = GetHandle();
RECT borderThickness;
SetRectEmpty(&borderThickness);
AdjustWindowRectEx(&borderThickness, GetWindowLongPtr(hWnd, GWL_STYLE), FALSE, 0);
const auto max_size = size + wxSize{-borderThickness.left + borderThickness.right, -borderThickness.top + borderThickness.bottom};
const auto current_size = GetSize();
SetSize({std::min(max_size.x, current_size.x), std::min(max_size.y, current_size.y)});
Move(pos + wxPoint{borderThickness.left, borderThickness.top});
e.Skip();
});
#endif // __WXMSW__
// BBS
Fit();
@@ -586,6 +619,8 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
#endif
MarkdownTip::ExitTip();
// Prevent queued selection/UI refresh work from running as normal during reset.
wxGetApp().set_closing(true);
m_plater->reset();
this->shutdown();
@@ -758,7 +793,7 @@ void MainFrame::bind_diff_dialog()
}
#ifdef __WIN32__
#ifdef __WXMSW__
// Orca: Fix maximized window overlaps taskbar when taskbar auto hide is enabled (#8085)
// Adopted from https://gist.github.com/MortenChristiansen/6463580
+1 -1
View File
@@ -204,7 +204,7 @@ protected:
virtual void on_dpi_changed(const wxRect &suggested_rect) override;
virtual void on_sys_color_changed() override;
#ifdef __WIN32__
#ifdef __WXMSW__
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override;
#endif
+1 -1
View File
@@ -14,7 +14,7 @@
#include "slic3r/GUI/CameraUtils.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <igl/unproject.h>
+2 -2
View File
@@ -205,8 +205,8 @@ void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable)
if (m_printable == printable)
return;
m_printable = printable;
m_printable_icon = m_printable == piUndef ? m_empty_bmp :
create_scaled_bitmap(m_printable == piPrintable ? "check_on" : "check_off_focused");
m_printable_icon = m_printable == piUndef ?
m_empty_bmp : create_scaled_bitmap(m_printable == piPrintable ? "check_on" : "check_off_focused");
}
void ObjectDataViewModelNode::set_variable_height_icon(VaryHeightIndicator vari_height) {
+5 -5
View File
@@ -241,7 +241,7 @@ public:
void SetExtruder(const wxString &extruder) { m_extruder = extruder; }
void SetWarningIconName(const std::string& warning_icon_name) { m_warning_icon_name = warning_icon_name; }
void SetLock(bool has_lock) { m_has_lock = has_lock; }
const wxBitmap& GetBitmap() const { return m_bmp; }
const wxBitmap& GetBitmap() const { return m_bmp; }
const wxString& GetName() const { return m_name; }
ItemType GetType() const { return m_type; }
InfoItemType GetInfoItemType() const { return m_info_item_type; }
@@ -249,16 +249,16 @@ public:
int GetIdx() const { return m_idx; }
//BBS: add part plate related logic
void SetPlateIdx(const int& idx);
int GetPlateIdx() const { return m_plate_idx; }
int GetPlateIdx() const { return m_plate_idx; }
ModelVolumeType GetVolumeType() { return m_volume_type; }
t_layer_height_range GetLayerRange() const { return m_layer_range; }
wxString GetExtruder() { return m_extruder; }
PrintIndicator IsPrintable() const { return m_printable; }
VaryHeightIndicator IsVaribaleHeight() const { return m_variable_height; }
VaryHeightIndicator IsVaribaleHeight() const { return m_variable_height; }
// BBS
bool HasColorPainting() const { return m_color_enable; }
bool HasSupportPainting() const { return m_support_enable; }
bool HasSinking() const { return m_sink_enable; }
bool HasSupportPainting() const { return m_support_enable; }
bool HasSinking() const { return m_sink_enable; }
bool IsActionEnabled() const { return m_action_enable; }
void UpdateExtruderAndColorIcon(wxString extruder = "");
+42 -21
View File
@@ -7,7 +7,7 @@
#include "libslic3r/Platform.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
@@ -22,16 +22,11 @@
#include "../Utils/MacDarkMode.hpp"
#endif // __APPLE__
// Verify GLEW and wxWidgets use the same OpenGL backend (EGL vs GLX).
// A mismatch causes rendering failures: GLEW's function loading must match
// the context type created by wxWidgets.
#if defined(__linux__)
#if defined(GLEW_EGL) && (!defined(wxUSE_GLCANVAS_EGL) || !wxUSE_GLCANVAS_EGL)
#error "OpenGL backend mismatch: GLEW has EGL support enabled but wxWidgets does not. Ensure GLEW_USE_EGL and wxUSE_GLCANVAS_EGL are both ON or both OFF."
#endif
#if !defined(GLEW_EGL) && defined(wxUSE_GLCANVAS_EGL) && wxUSE_GLCANVAS_EGL
#error "OpenGL backend mismatch: wxWidgets has EGL support enabled but GLEW does not. Ensure GLEW_USE_EGL and wxUSE_GLCANVAS_EGL are both ON or both OFF."
#endif
#ifdef __WXGTK__
#include "LinuxDisplayBackend.hpp"
#ifdef wxHAS_EGL
#include <EGL/egl.h>
#endif
#endif
namespace Slic3r {
@@ -121,12 +116,12 @@ void OpenGLManager::GLInfo::detect() const
if (Slic3r::total_physical_memory() / (1024 * 1024 * 1024) < 6)
*max_tex_size /= 2;
if (GLEW_EXT_texture_filter_anisotropic) {
if (GLAD_GL_EXT_texture_filter_anisotropic) {
float* max_anisotropy = const_cast<float*>(&m_max_anisotropy);
glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy));
}
if (!GLEW_ARB_compatibility)
if (!GLAD_GL_ARB_compatibility)
*const_cast<bool*>(&m_core_profile) = true;
*const_cast<bool*>(&m_detected) = true;
@@ -245,24 +240,36 @@ OpenGLManager::~OpenGLManager()
bool OpenGLManager::init_gl(bool popup_error)
{
if (!m_gl_initialized) {
glewExperimental = true;
GLenum result = glewInit();
if (result != GLEW_OK) {
BOOST_LOG_TRIVIAL(error) << "Unable to init glew library, Error: " << glewGetErrorString(result);
int version = 0;
#if defined(__WXGTK__) && defined(wxHAS_EGL)
if (is_running_on_wayland()) {
// On EGL/Wayland, gladLoaderLoadGL() dlopen's libGL.so then
// immediately dlclose's it. Since nothing else holds libGL.so
// open (unlike GLX where the context keeps it loaded), the
// library gets unmapped and all function pointers become invalid.
// Use eglGetProcAddress directly to avoid this.
version = gladLoadGL((GLADloadfunc)eglGetProcAddress);
} else
#endif
{
version = gladLoaderLoadGL();
}
if (version == 0) {
BOOST_LOG_TRIVIAL(error) << "Unable to init GLAD OpenGL loader";
return false;
}
//BOOST_LOG_TRIVIAL(info) << "glewInit Success."<< std::endl;
BOOST_LOG_TRIVIAL(info) << "GLAD loaded OpenGL " << GLAD_VERSION_MAJOR(version) << "." << GLAD_VERSION_MINOR(version);
m_gl_initialized = true;
if (GLEW_EXT_texture_compression_s3tc)
if (GLAD_GL_EXT_texture_compression_s3tc)
s_compressed_textures_supported = true;
else
s_compressed_textures_supported = false;
if (GLEW_ARB_framebuffer_object) {
if (GLAD_GL_ARB_framebuffer_object) {
s_framebuffers_type = EFramebufferType::Arb;
BOOST_LOG_TRIVIAL(info) << "Found Framebuffer Type ARB."<< std::endl;
}
else if (GLEW_EXT_framebuffer_object) {
else if (GLAD_GL_EXT_framebuffer_object) {
BOOST_LOG_TRIVIAL(info) << "Found Framebuffer Type Ext."<< std::endl;
s_framebuffers_type = EFramebufferType::Ext;
}
@@ -438,6 +445,20 @@ void OpenGLManager::detect_multisample(int* attribList)
{
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER;
bool enable_multisample = wxVersion >= 30003;
#if defined(__WXGTK__)
// On Wayland, wxGLCanvas::IsDisplaySupported() requires the EGL backend.
// If wxWidgets was built without EGL, the GLX backend will crash trying
// to access a non-existent X11 display. Disable multisample in that case.
if (is_running_on_wayland()) {
#if !defined(wxHAS_EGL) || !wxHAS_EGL
BOOST_LOG_TRIVIAL(warning) << "Wayland without EGL: disabling multisample detection";
s_multisample = EMultisampleState::Disabled;
return;
#endif
}
#endif
s_multisample =
enable_multisample &&
// Disable multi-sampling on ChromeOS, as the OpenGL virtualization swaps Red/Blue channels with multi-sampling enabled,
+34 -8
View File
@@ -7,7 +7,7 @@
#include <set>
#include <regex>
#include <future>
#include <GL/glew.h>
#include <glad/gl.h>
#include <boost/algorithm/string.hpp>
#include <boost/optional.hpp>
#include <boost/filesystem/path.hpp>
@@ -1678,9 +1678,12 @@ void PartPlate::render_icon_texture(GLModel &buffer, GLTexture &texture)
void PartPlate::render_plate_name_texture()
{
if (m_name_texture.get_id() == 0)
if (m_plate_name_edit_icon.mesh_raycaster == nullptr)
generate_plate_name_texture();
if (m_name_texture.get_id() == 0)
return;
GLuint tex_id = (GLuint)m_name_texture.get_id();
glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id));
m_plate_name_icon.render();
@@ -2091,6 +2094,9 @@ void PartPlate::render_right_arrow(const ColorRGBA render_color, bool use_lighti
static void register_model_for_picking(GLCanvas3D &canvas, PickingModel &model, int id)
{
if (model.mesh_raycaster == nullptr)
return;
canvas.add_raycaster_for_picking(SceneRaycaster::EType::Bed, id, *model.mesh_raycaster, Transform3d::Identity());
}
@@ -2105,7 +2111,10 @@ void PartPlate::register_raycasters_for_picking(GLCanvas3D &canvas)
register_model_for_picking(canvas, m_plate_settings_icon, picking_id_component(5));
canvas.remove_raycasters_for_picking(SceneRaycaster::EType::Bed, picking_id_component(6));
register_model_for_picking(canvas, m_plate_name_edit_icon, picking_id_component(6));
// Plate-name edit picking is built lazily together with the plate-name texture.
// During reset / reload_scene the icon may not have a raycaster yet, which is valid.
if (m_plate_name_edit_icon.mesh_raycaster != nullptr)
register_model_for_picking(canvas, m_plate_name_edit_icon, picking_id_component(6));
register_model_for_picking(canvas, m_move_front_icon, picking_id_component(7));
// Only register filament map button for H2D (dual-extruder Bambu Lab) printers
@@ -2862,7 +2871,7 @@ void PartPlate::clear(bool clear_sliced_result)
m_ready_for_slice = true;
update_slice_result_valid_state(false);
}
m_name_texture.reset();
invalidate_plate_name_texture();
return;
}
@@ -2952,6 +2961,10 @@ Vec3d PartPlate::get_center_origin()
void PartPlate::generate_plate_name_texture()
{
auto canvas = this->m_partplate_list->m_plater->get_view3D_canvas3D();
if (canvas == nullptr)
return;
m_plate_name_icon.reset();
// generate m_name_texture texture from m_name with generate_from_text_string
@@ -2964,8 +2977,10 @@ void PartPlate::generate_plate_name_texture()
wxFont* font = &l;
wxColour foreground(0xf2, 0x75, 0x4e, 0xff);
if (!m_name_texture.generate_from_text_string(text.ToUTF8().data(), *font, *wxBLACK, foreground))
if (!m_name_texture.generate_from_text_string(text.ToUTF8().data(), *font, *wxBLACK, foreground)) {
BOOST_LOG_TRIVIAL(error) << "PartPlate::generate_plate_name_texture(): generate_from_text_string() failed";
return;
}
ExPolygon poly;
auto bed_ext = get_extents(m_shape);
@@ -2989,11 +3004,22 @@ void PartPlate::generate_plate_name_texture()
if (!init_model_from_poly(m_plate_name_icon, poly, GROUND_Z))
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n";
auto canvas = this->m_partplate_list->m_plater->get_view3D_canvas3D();
canvas->remove_raycasters_for_picking(SceneRaycaster::EType::Bed, picking_id_component(6));
calc_vertex_for_plate_name_edit_icon(&m_name_texture, 0, m_plate_name_edit_icon);
register_model_for_picking(*canvas, m_plate_name_edit_icon, picking_id_component(6));
}
void PartPlate::invalidate_plate_name_texture()
{
m_plate_name_edit_icon.mesh_raycaster.reset();
auto canvas = (m_plater != nullptr) ? m_plater->get_view3D_canvas3D() : nullptr;
if (canvas != nullptr) {
canvas->remove_raycasters_for_picking(SceneRaycaster::EType::Bed, picking_id_component(6));
canvas->set_as_dirty();
}
}
void PartPlate::set_plate_name(const std::string& name)
{
// compare if name equal to m_name, case sensitive
@@ -3004,7 +3030,7 @@ void PartPlate::set_plate_name(const std::string& name)
if (m_print != nullptr)
m_print->set_plate_name(name);
generate_plate_name_texture();
invalidate_plate_name_texture();
}
//get the print's object, result and index
@@ -3816,7 +3842,7 @@ bool PartPlate::set_shape(const Pointfs& shape, const Pointfs& exclude_areas, co
calc_vertex_for_number(0, false, m_plate_idx_icon);
// calc vertex for plate name
generate_plate_name_texture();
invalidate_plate_name_texture();
}
}
+1
View File
@@ -217,6 +217,7 @@ private:
void render_icons(bool bottom, bool only_name = false, int hover_id = -1);
void render_only_numbers(bool bottom);
void render_plate_name_texture();
void invalidate_plate_name_texture();
void register_raycasters_for_picking(GLCanvas3D& canvas);
int picking_id_component(int idx) const;
+178 -30
View File
@@ -76,6 +76,9 @@
#include "GUI_App.hpp"
#include "GuiColor.hpp"
#include "GUI_ObjectList.hpp"
#ifdef __WXGTK__
#include "LinuxDisplayBackend.hpp"
#endif
#include "GUI_Utils.hpp"
#include "GUI_Factories.hpp"
#include "wxExtensions.hpp"
@@ -349,6 +352,57 @@ void SlicedInfo::SetTextAndShow(SlicedInfoIdx idx, const wxString& text, const w
static wxString temp_dir;
namespace {
#ifdef __WXGTK__
wxString sanitize_window_layout_for_wayland(const wxString& layout, bool* removed_floating_state = nullptr)
{
if (!Slic3r::GUI::is_running_on_wayland() || layout.empty()) {
if (removed_floating_state != nullptr)
*removed_floating_state = false;
return layout;
}
static const std::regex state_pattern(R"(state=(\d+);)");
constexpr unsigned int disabled_wayland_flags =
static_cast<unsigned int>(wxAuiPaneInfo::optionFloating) |
static_cast<unsigned int>(wxAuiPaneInfo::optionFloatable);
const std::string input = layout.utf8_string();
std::string output;
output.reserve(input.size());
bool modified = false;
std::smatch match;
auto search_start = input.cbegin();
while (std::regex_search(search_start, input.cend(), match, state_pattern)) {
output.append(search_start, match[0].first);
try {
const unsigned long state = std::stoul(match[1].str());
const unsigned long sanitized_state = state & ~static_cast<unsigned long>(disabled_wayland_flags);
modified = modified || sanitized_state != state;
output += "state=" + std::to_string(sanitized_state) + ";";
} catch (const std::exception&) {
output += match[0].str();
}
search_start = match[0].second;
}
output.append(search_start, input.cend());
if (removed_floating_state != nullptr)
*removed_floating_state = modified;
return modified ? wxString::FromUTF8(output) : layout;
}
#endif
} // namespace
// Sidebar / private
enum class ActionButtonType : int {
@@ -1782,7 +1836,11 @@ Sidebar::Sidebar(Plater *parent)
e.Skip();
});
w->Bind(wxEVT_LEAVE_WINDOW, [this, panel_color](wxMouseEvent &e) {
wxWindow* next_w = wxFindWindowAtPoint(wxGetMousePosition());
// Use event-relative coords instead of wxGetMousePosition() which
// returns (0,0) on Wayland for global screen coordinates.
wxWindow* evtObj = dynamic_cast<wxWindow*>(e.GetEventObject());
wxPoint screenPos = evtObj ? evtObj->ClientToScreen(e.GetPosition()) : wxGetMousePosition();
wxWindow* next_w = wxFindWindowAtPoint(screenPos);
if (!next_w || !p->panel_printer_preset->IsDescendant(next_w)){
if(!p->combo_printer->HasFocus())
p->panel_printer_preset->SetBorderColor(panel_color.bd_normal);
@@ -1844,7 +1902,11 @@ Sidebar::Sidebar(Plater *parent)
e.Skip();
});
w->Bind(wxEVT_LEAVE_WINDOW, [this, panel_color](wxMouseEvent &e) {
wxWindow* next_w = wxFindWindowAtPoint(wxGetMousePosition());
// Use event-relative coords instead of wxGetMousePosition() which
// returns (0,0) on Wayland for global screen coordinates.
wxWindow* evtObj = dynamic_cast<wxWindow*>(e.GetEventObject());
wxPoint screenPos = evtObj ? evtObj->ClientToScreen(e.GetPosition()) : wxGetMousePosition();
wxWindow* next_w = wxFindWindowAtPoint(screenPos);
if (!p->combo_nozzle_dia->HasFocus() && (!next_w || !p->panel_nozzle_dia->IsDescendant(next_w)))
p->panel_nozzle_dia->SetBorderColor(panel_color.bd_normal);
e.Skip();
@@ -1914,7 +1976,11 @@ Sidebar::Sidebar(Plater *parent)
e.Skip();
});
w->Bind(wxEVT_LEAVE_WINDOW, [this, w, panel_color](wxMouseEvent &e) {
wxWindow* next_w = wxFindWindowAtPoint(wxGetMousePosition());
// Use event-relative coords instead of wxGetMousePosition() which
// returns (0,0) on Wayland for global screen coordinates.
wxWindow* evtObj = dynamic_cast<wxWindow*>(e.GetEventObject());
wxPoint screenPos = evtObj ? evtObj->ClientToScreen(e.GetPosition()) : wxGetMousePosition();
wxWindow* next_w = wxFindWindowAtPoint(screenPos);
if (!p->combo_printer_bed->HasFocus() && (!next_w || !p->panel_printer_bed->IsDescendant(next_w)))
p->panel_printer_bed->SetBorderColor(panel_color.bd_normal);
if(w == p->image_printer_bed)
@@ -4442,7 +4508,7 @@ struct Plater::priv
// BBS: backup & restore
std::vector<size_t> load_files(const std::vector<fs::path>& input_files, LoadStrategy strategy, bool ask_multi = false);
std::vector<size_t> load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false, bool split_object = false);
std::vector<size_t> load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false, bool split_object = false, bool auto_drop = true);
fs::path get_export_file_path(GUI::FileType file_type);
wxString get_export_file(GUI::FileType file_type);
@@ -4473,7 +4539,8 @@ struct Plater::priv
void center_selection();
void drop_selection();
void mirror(Axis axis);
void split_object();
void split_object(bool auto_drop = true);
void split_object(int obj_idx, bool auto_drop = true);
void split_volume();
void scale_selection_to_fit_print_volume();
@@ -4837,8 +4904,16 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
{
m_is_dark = wxGetApp().app_config->get("dark_color_mode") == "1";
#ifdef __WXGTK__
const bool disable_wayland_floating = Slic3r::GUI::is_running_on_wayland();
#endif
m_aui_mgr.SetManagedWindow(q);
m_aui_mgr.SetDockSizeConstraint(1, 1);
#ifdef __WXGTK__
if (disable_wayland_floating)
m_aui_mgr.SetFlags(m_aui_mgr.GetFlags() & ~wxAUI_MGR_ALLOW_FLOATING);
#endif
//m_aui_mgr.GetArtProvider()->SetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE, 0);
//m_aui_mgr.GetArtProvider()->SetMetric(wxAUI_DOCKART_SASH_SIZE, 2);
m_aui_mgr.GetArtProvider()->SetMetric(wxAUI_DOCKART_CAPTION_SIZE, 18);
@@ -4930,7 +5005,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
.CloseButton(false)
.TopDockable(false)
.BottomDockable(false)
.Floatable(true)
.BestSize(wxSize(39 * wxGetApp().em_unit(), 90 * wxGetApp().em_unit())));
auto* panel_sizer = new wxBoxSizer(wxHORIZONTAL);
@@ -4949,7 +5023,19 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
const auto cfg = wxGetApp().app_config;
wxString layout = wxString::FromUTF8(cfg->get("window_layout"));
if (!layout.empty()) {
m_aui_mgr.LoadPerspective(layout, false);
bool removed_floating_state = false;
#ifdef __WXGTK__
if (disable_wayland_floating)
layout = sanitize_window_layout_for_wayland(layout, &removed_floating_state);
#endif
if (!m_aui_mgr.LoadPerspective(layout, false)) {
BOOST_LOG_TRIVIAL(warning) << "Failed to restore saved window layout";
m_aui_mgr.LoadPerspective(m_default_window_layout, false);
} else if (removed_floating_state) {
BOOST_LOG_TRIVIAL(info) << "Removed floating AUI state from saved window layout for Wayland";
}
sidebar_layout.is_collapsed = !sidebar.IsShown();
}
@@ -6632,14 +6718,37 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
if (new_model != nullptr && new_model->objects.size() > 1) {
//BBS do not popup this dialog
bool new_model_auto_drop = true;
int single_object_answer = false;
if (ask_multi) {
MessageDialog msg_dlg(q, _L("Load these files as a single object with multiple parts?\n"), _L("Object with multiple parts was detected"),
wxICON_WARNING | wxYES | wxNO);
if (msg_dlg.ShowModal() == wxID_YES) { new_model->convert_multipart_object(filaments_cnt); }
RichMessageDialog dlg(q, _L("Load these files as a single object with multiple parts?\n"),
_L("Object with multiple parts was detected"), wxICON_QUESTION | wxYES_NO);
dlg.ShowCheckBox(_L("Auto-Drop"), true);
single_object_answer = dlg.ShowModal();
if (dlg.IsCheckBoxChecked() == false)
new_model_auto_drop = false;
// convert to multipart and split after load_model_objects
// to keep relative positioning if auto_drop == false
if (single_object_answer == wxID_YES || new_model_auto_drop == false)
new_model->convert_multipart_object(filaments_cnt);
}
auto loaded_idxs = load_model_objects(new_model->objects);
// TODO
// DONE always convert to multipart, split afterwards to retain relative position
// DONE if !auto_drop move all objects over the z-position 0, so that none are clipped by the bed.
// DONE retain auto_drop (and printable) state when assembling or splitting objects.
// DONE when manually split to object ask users if looks_like_multipart and none have auto_drob disabled if they want to disable auto_drop for all resulting objects.
// - add icon in object list, similar to fuzzy painting, etc.
auto loaded_idxs = load_model_objects(new_model->objects, false, false, new_model_auto_drop);
obj_idxs.insert(obj_idxs.end(), loaded_idxs.begin(), loaded_idxs.end());
if (single_object_answer == wxID_NO && new_model_auto_drop == false) {
split_object(loaded_idxs[0], new_model_auto_drop);
}
}
if (load_config) {
@@ -6806,7 +6915,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
#define AUTOPLACEMENT_ON_LOAD
std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z, bool split_object)
std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z, bool split_object, bool auto_drop)
{
const Vec3d bed_size = Slic3r::to_3d(this->bed.build_volume().bounding_volume2d().size(), 1.0) - 2.0 * Vec3d::Ones();
@@ -6833,7 +6942,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
#else /* AUTOPLACEMENT_ON_LOAD */
// if object has no defined position(s) we need to rearrange everything after loading
// need_arrange = true;
// add a default instance and center object around origin
// add a default instance and center object around origin
object->center_around_origin(); // also aligns object to Z = 0
ModelInstance* instance = object->add_instance();
@@ -6842,7 +6951,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
instance->set_offset(Slic3r::to_3d(this->bed.build_volume().bed_center(), -object->origin_translation(2)));
#endif /* AUTOPLACEMENT_ON_LOAD */
}
//BBS: when the object is too large, let the user choose whether to scale it down
for (size_t i = 0; i < object->instances.size(); ++i) {
ModelInstance* instance = object->instances[i];
@@ -6872,7 +6981,20 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
}
}
object->ensure_on_bed(allow_negative_z);
if (!auto_drop) {
for (size_t i = 0; i < object->instances.size(); ++i) {
ModelInstance* instance = object->instances[i];
instance->auto_drop = auto_drop;
}
// if under the bed, move over the bed
double dist_to_bed = std::min(object->min_z(), double(0));
object->translate_instances(Vec3d(0, 0, -dist_to_bed));
}
else {
object->ensure_on_bed(allow_negative_z);
}
if (!split_object) {
//BBS initial assemble transformation
for (ModelObject* model_object : model.objects) {
@@ -6882,7 +7004,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
model_object->instances[i]->set_assemble_transformation(model_object->instances[i]->get_transformation());
}
}
}
}
}
}
@@ -6949,7 +7071,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
// which is updated after a view3D->reload_scene(false, flags & (unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH) call
for (const size_t idx : obj_idxs)
wxGetApp().obj_list()->update_info_items(idx);
object_list_changed();
this->schedule_background_process();
@@ -7401,9 +7523,16 @@ void Plater::find_new_position(const ModelInstancePtrs &instances)
m.apply();
}
void Plater::priv::split_object()
{
// split selected object into multiple objects by its volumes
void Plater::priv::split_object(bool auto_drop /* = true */)
{
int obj_idx = get_selected_object_idx();
priv::split_object(obj_idx, auto_drop);
}
// split provided object into multiple objects by its volumes
void Plater::priv::split_object(int obj_idx, bool auto_drop /* = true */)
{
if (obj_idx == -1)
return;
@@ -7429,12 +7558,30 @@ void Plater::priv::split_object()
Plater::TakeSnapshot snapshot(q, "Split to Objects");
auto is_atleast_one_floating = [new_objects]() {
for (ModelObject* new_object : new_objects) {
if (new_object->get_instance_min_z(0) >= SINKING_MIN_Z_THRESHOLD)
return true;
}
return false;
};
bool split_auto_drop = auto_drop;
if (current_model_object->instances[0]->auto_drop && is_atleast_one_floating()) {
MessageDialog dlg(q, _L("Disable Auto-Drop to preserve z positioning?\n"),
_L("Object with floating parts was detected"), wxICON_QUESTION | wxYES_NO);
if (dlg.ShowModal() == wxID_YES)
split_auto_drop = false;
}
remove(obj_idx);
// load all model objects at once, otherwise the plate would be rearranged after each one
// causing original positions not to be kept
//BBS: set split_object to true to avoid re-compute assemble matrix
std::vector<size_t> idxs = load_model_objects(new_objects, false, true);
std::vector<size_t> idxs = load_model_objects(new_objects, false, true, split_auto_drop);
wxGetApp().plater()->get_view3D_canvas3D()->update_instance_printable_state_for_objects(idxs);
// select newly added objects
for (size_t idx : idxs)
@@ -8897,11 +9044,9 @@ void Plater::priv::set_current_panel(wxPanel* panel, bool no_slice)
wxPanel* old_panel = current_panel;
//#if BBL_HAS_FIRST_PAGE
if (!old_panel) {
//BBS: only switch to the first panel when visible
// Wayland may report the first canvas as not yet shown while the frame is still mapping.
// Keep the panel switch anyway so handlers are bound and the first paint can initialize GL later.
panel->Show();
//dynamic_cast<View3D *>(panel)->get_canvas3d()->render();
if (!panel->IsShownOnScreen())
return;
}
//#endif
current_panel = panel;
@@ -10221,6 +10366,9 @@ void Plater::priv::on_action_split_volumes(SimpleEvent&)
void Plater::priv::on_object_select(SimpleEvent& evt)
{
if (wxGetApp().is_closing())
return;
wxGetApp().obj_list()->update_selections();
selection_changed();
}
@@ -16752,7 +16900,7 @@ const GLCanvas3D* Plater::canvas3D() const
GLCanvas3D* Plater::get_view3D_canvas3D()
{
return p->view3D->get_canvas3d();
return p ? p->view3D->get_canvas3d() : nullptr;
}
GLCanvas3D* Plater::get_preview_canvas3D()
@@ -16943,11 +17091,11 @@ void Plater::suppress_background_process(const bool stop_background_process)
this->p->suppressed_backround_processing_update = true;
}
void Plater::center_selection() { p->center_selection(); }
void Plater::drop_selection() { p->drop_selection(); }
void Plater::mirror(Axis axis) { p->mirror(axis); }
void Plater::split_object() { p->split_object(); }
void Plater::split_volume() { p->split_volume(); }
void Plater::center_selection() { p->center_selection(); }
void Plater::drop_selection() { p->drop_selection(); }
void Plater::mirror(Axis axis) { p->mirror(axis); }
void Plater::split_object(bool auto_drop) { p->split_object(auto_drop); }
void Plater::split_volume() { p->split_volume(); }
void Plater::optimize_rotation()
{
auto &w = get_ui_job_worker();
+2 -1
View File
@@ -643,7 +643,8 @@ public:
void drop_selection();
void search(bool plater_is_active, Preset::Type type, wxWindow *tag, TextInput *etag, wxWindow *stag);
void mirror(Axis axis);
void split_object();
void split_object(bool auto_drop = true);
void split_object(int obj_idx, bool auto_drop = true);
void split_volume();
void optimize_rotation();
// find all empty cells on the plate and won't overlap with exclusion areas
+12
View File
@@ -15,6 +15,10 @@
#include <slic3r/GUI/Widgets/WebView.hpp>
#include <wx/webview.h>
#ifdef __linux__
#include <webkit2/webkit2.h>
#endif
namespace pt = boost::property_tree;
namespace Slic3r {
@@ -33,6 +37,14 @@ PrinterWebView::PrinterWebView(wxWindow *parent)
return;
}
#ifdef __linux__
auto cookiesPath = boost::filesystem::path(data_dir() + "/cache/cookies.db");
auto wv = static_cast<WebKitWebView*>(m_browser->GetNativeBackend());
auto wv_ctx = webkit_web_view_get_context(wv);
auto cookieManager = webkit_web_context_get_cookie_manager(wv_ctx);
webkit_cookie_manager_set_persistent_storage(cookieManager, cookiesPath.c_str(), WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE);
#endif
m_browser->Bind(wxEVT_WEBVIEW_ERROR, &PrinterWebView::OnError, this);
m_browser->Bind(wxEVT_WEBVIEW_LOADED, &PrinterWebView::OnLoaded, this);
+47 -6
View File
@@ -22,6 +22,10 @@
#include "imgui/imconfig.h"
#if defined(__WXGTK__)
#include "LinuxDisplayBackend.hpp"
#endif
using boost::optional;
namespace Slic3r {
@@ -33,6 +37,17 @@ wxDEFINE_EVENT(wxCUSTOMEVT_JUMP_TO_OBJECT, wxCommandEvent);
using GUI::from_u8;
using GUI::into_u8;
namespace {
bool focus_left_popup(wxWindow* popup, wxWindow* focus_window, wxWindow* related_window_1 = nullptr,
wxWindow* related_window_2 = nullptr, wxWindow* related_window_3 = nullptr)
{
return focus_window != popup && !popup->IsDescendant(focus_window) && focus_window != related_window_1 &&
focus_window != related_window_2 && focus_window != related_window_3;
}
} // namespace
namespace Search {
static char marker_by_type(Preset::Type type, PrinterTechnology pt)
@@ -674,11 +689,24 @@ void SearchDialog::OnDismiss() { }
void SearchDialog::Dismiss()
{
auto pos = wxGetMousePosition();
auto focus_window = wxWindow::FindFocus();
if (!focus_window)
if (!focus_window) {
Die();
else if (!m_event_tag->GetScreenRect().Contains(pos) && !this->GetScreenRect().Contains(pos) && !m_search_item_tag->GetScreenRect().Contains(pos)) {
return;
}
#if defined(__WXGTK__)
// On Wayland, wxGetMousePosition() returns unreliable global coords.
// Rely on focus tracking instead: if focus moved to a window outside
// this dialog and its related controls, dismiss.
if (Slic3r::GUI::is_running_on_wayland()) {
if (focus_left_popup(this, focus_window, m_event_tag, m_search_item_tag, search_line)) {
Die();
}
return;
}
#endif
auto pos = wxGetMousePosition();
if (!m_event_tag->GetScreenRect().Contains(pos) && !this->GetScreenRect().Contains(pos) && !m_search_item_tag->GetScreenRect().Contains(pos)) {
Die();
}
}
@@ -904,11 +932,24 @@ void SearchObjectDialog::OnDismiss() {}
void SearchObjectDialog::Dismiss()
{
auto pos = wxGetMousePosition();
auto focus_window = wxWindow::FindFocus();
if (!focus_window)
if (!focus_window) {
Die();
else if (!search_line->GetScreenRect().Contains(pos) && !this->GetScreenRect().Contains(pos)) {
return;
}
#if defined(__WXGTK__)
// On Wayland, wxGetMousePosition() returns unreliable global coords.
// Rely on focus tracking instead: if focus moved to a window outside
// this dialog and its related controls, dismiss.
if (Slic3r::GUI::is_running_on_wayland()) {
if (focus_left_popup(this, focus_window, search_line)) {
Die();
}
return;
}
#endif
auto pos = wxGetMousePosition();
if (!search_line->GetScreenRect().Contains(pos) && !this->GetScreenRect().Contains(pos)) {
Die();
}
}
+206 -79
View File
@@ -18,7 +18,7 @@
#include "libslic3r/BuildVolume.hpp"
#endif // ENABLE_ENHANCED_PRINT_VOLUME_FIT
#include <GL/glew.h>
#include <glad/gl.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/log/trivial.hpp>
@@ -525,8 +525,32 @@ void Selection::center()
void Selection::drop()
{
if (this->get_bounding_box().min.z() < SINKING_Z_THRESHOLD) {
return; // shouldnt happen, but better check anyways, already checked in append_menu_item_drop()
}
wxGetApp().plater()->take_snapshot(L("Move Object"));
this->move_to_center(Vec3d(0, 0, -this->get_bounding_box().min.z()));
wxGetApp().plater()->get_view3D_canvas3D()->do_move(L("Move Object"));
for (unsigned int i : m_list) {
GLVolume& volume = *(*m_volumes)[i];
ModelObject* model_object = m_model->objects[volume.object_idx()];
if (model_object != nullptr) {
if (m_mode == Volume) {
ModelVolume* cur_mv = model_object->volumes[volume.volume_idx()];
cur_mv->set_transformation(volume.get_volume_transformation());
} else if (m_mode == Instance) {
model_object->instances[volume.instance_idx()]->set_transformation(volume.get_instance_transformation());
}
model_object->invalidate_bounding_box();
this->notify_instance_update(volume.object_idx(), volume.instance_idx());
}
}
wxGetApp().plater()->get_view3D_canvas3D()->post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MOVED));
}
void Selection::center_plate(const int plate_idx) {
@@ -550,11 +574,9 @@ void Selection::set_printable(bool printable)
return;
std::set<std::pair<int, int>> instances_idxs;
for (ObjectIdxsToInstanceIdxsMap::iterator obj_it = m_cache.content.begin(); obj_it != m_cache.content.end(); ++obj_it)
{
for (InstanceIdxsList::reverse_iterator inst_it = obj_it->second.rbegin(); inst_it != obj_it->second.rend(); ++inst_it)
{
instances_idxs.insert(std::make_pair(obj_it->first, *inst_it));
for (const auto& [obj_idx, inst_list] : m_cache.content) {
for (int inst_idx : inst_list) {
instances_idxs.insert({obj_idx, inst_idx});
}
}
@@ -562,15 +584,68 @@ void Selection::set_printable(bool printable)
wxGetApp().plater()->take_snapshot(snapshot_text);
// set printable value for all instances in object
for (const std::pair<int, int>& i : instances_idxs)
for (const auto& [obj_idx, inst_idx] : instances_idxs)
{
ModelObject* object = m_model->objects[i.first];
ModelObject* object = m_model->objects[obj_idx];
for (auto inst : object->instances)
inst->printable = printable;
wxGetApp().obj_list()->update_printable_state(i.first, i.second);
wxGetApp().obj_list()->update_printable_state(obj_idx, inst_idx);
//update printable state on canvas
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object((size_t)i.first);
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object((size_t) obj_idx);
}
// update scene
wxGetApp().plater()->update();
}
bool Selection::get_auto_drop() const {
// The wipe tower is not a ModelObject and has no per-instance auto_drop;
// return the default to avoid indexing m_model->objects with its synthetic id.
if (!m_valid || is_wipe_tower())
return true;
std::set<std::pair<int, int>> instances_idxs;
for (const auto& [obj_idx, inst_list] : m_cache.content) {
for (int inst_idx : inst_list) {
instances_idxs.insert({obj_idx, inst_idx});
}
}
// return false, if one of the instances in the selection has auto_drop disabled, otherwise return true
for (const auto& [obj_idx, inst_idx] : instances_idxs) {
ModelObject* object = m_model->objects[obj_idx];
for (const auto* inst : object->instances) {
if (!inst->auto_drop) {
return false;
}
}
}
return true;
}
void Selection::set_auto_drop(bool enabled)
{
if (!m_valid)
return;
std::set<std::pair<int, int>> instances_idxs;
for (const auto& [obj_idx, inst_list] : m_cache.content) {
for (int inst_idx : inst_list) {
instances_idxs.insert({obj_idx, inst_idx});
}
}
std::string snapshot_text = (boost::format("%1%") % (enabled ? "Set Selection Auto-Drop Enabled" : "Set Selection Auto-Drop Disabled")).str();
wxGetApp().plater()->take_snapshot(snapshot_text);
// set auto_drop value for all instances in object
for (const auto& [obj_idx, inst_idx] : instances_idxs) {
ModelObject* object = m_model->objects[obj_idx];
for (auto* inst : object->instances) {
inst->auto_drop = enabled;
}
}
// update scene
@@ -1601,7 +1676,6 @@ void Selection::scale_and_translate(const Vec3d &scale, const Vec3d &world_trans
synchronize_unselected_volumes();
#endif // !DISABLE_INSTANCES_SYNCH
ensure_on_bed();
set_bounding_boxes_dirty();
if (wxGetApp().plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasAssembleView) {
wxGetApp().plater()->canvas3D()->requires_check_outside_state();
@@ -1612,7 +1686,6 @@ void Selection::mirror(Axis axis, TransformationType transformation_type)
{
const Vec3d mirror((axis == X) ? -1.0 : 1.0, (axis == Y) ? -1.0 : 1.0, (axis == Z) ? -1.0 : 1.0);
scale_and_translate(mirror, Vec3d::Zero(), transformation_type);
}
void Selection::translate(unsigned int object_idx, const Vec3d& displacement)
@@ -1927,7 +2000,8 @@ void Selection::render(float scale_factor)
m_scale_factor = scale_factor;
// render cumulative bounding box of selected volumes
const auto& [box, trafo] = get_bounding_box_in_current_reference_system();
render_bounding_box(box, trafo,
const bool auto_drop = get_auto_drop();
render_bounding_box(box, trafo, auto_drop,
wxGetApp().plater()->canvas3D()->get_canvas_type() == GLCanvas3D::ECanvasType::CanvasAssembleView ? ColorRGB::YELLOW(): ColorRGB::WHITE());
render_synchronized_volumes();
}
@@ -2530,86 +2604,128 @@ void Selection::render_synchronized_volumes()
box = v.transformed_convex_hull_bounding_box(v.get_volume_transformation().get_matrix());
trafo = v.get_instance_transformation().get_matrix();
}
render_bounding_box(box, trafo, ColorRGB::YELLOW());
const bool auto_drop = get_auto_drop();
render_bounding_box(box, trafo, auto_drop, ColorRGB::YELLOW());
}
}
}
void Selection::render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const ColorRGB& color)
void Selection::render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const bool auto_drop, const ColorRGB& color)
{
const BoundingBoxf3& curr_box = m_box.get_bounding_box();
const bool curr_auto_drop = m_auto_drop;
if (!m_box.is_initialized() || !is_approx(box.min, curr_box.min) || !is_approx(box.max, curr_box.max)) {
if (!m_box.is_initialized() || !is_approx(box.min, curr_box.min) || !is_approx(box.max, curr_box.max) || curr_auto_drop != auto_drop) {
m_box.reset();
m_auto_drop = auto_drop;
const Vec3f b_min = box.min.cast<float>();
const Vec3f b_max = box.max.cast<float>();
const Vec3f size = 0.2f * box.size().cast<float>();
// 48 brackets + (24 if auto_drop == false)
int total_vertices = 48 + (auto_drop ? 0 : 24);
GLModel::Geometry init_data;
init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P3 };
init_data.reserve_vertices(48);
init_data.reserve_indices(48);
init_data.reserve_vertices(total_vertices);
init_data.reserve_indices(total_vertices);
// vertices
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y() + size.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z() + size.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y() + size.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_min.z() + size.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y() + size.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z() + size.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y() - size.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z() + size.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y() - size.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z() + size.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y() + size.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z() - size.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y() + size.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z() - size.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y() - size.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z() - size.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y() - size.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z() - size.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y() + size.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_min.z() + size.z()));
// Indicate that auto_drop == false, by drawing an arrow on bottom corners
if (!auto_drop) {
float visual_scale = m_scale_factor;
float head_s = 2.0f * visual_scale; // Width of the arrowhead wings
float z_gap = 1.0f * visual_scale; // Gap between box and arrow tip
float arrow_h = 5.0f * visual_scale; // Total height of the arrow stem
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y() - size.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_min.z() + size.z()));
// 4 bottom corners
std::vector<Vec3f> corners = {{b_min.x(), b_min.y(), b_min.z()},
{b_max.x(), b_min.y(), b_min.z()},
{b_max.x(), b_max.y(), b_min.z()},
{b_min.x(), b_max.y(), b_min.z()}};
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y() - size.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_min.z() + size.z()));
for (const auto& pt : corners) {
Vec3f tip = {pt.x(), pt.y(), pt.z() - z_gap};
Vec3f base = {pt.x(), pt.y(), tip.z() - arrow_h};
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y() + size.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_min.y(), b_max.z() - size.z()));
// Stem
init_data.add_vertex(base);
init_data.add_vertex(tip);
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y() + size.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_min.y(), b_max.z() - size.z()));
// Wings
// Determine direction to the center of the footprint
float dirX = (pt.x() == b_min.x()) ? head_s : -head_s;
float dirY = (pt.y() == b_min.y()) ? head_s : -head_s;
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x() - size.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y() - size.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_max.x(), b_max.y(), b_max.z() - size.z()));
// Wing 1 (X-Inward)
init_data.add_vertex(tip);
init_data.add_vertex(Vec3f(tip.x() + dirX, tip.y(), tip.z() - head_s));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x() + size.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y() - size.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z()));
init_data.add_vertex(Vec3f(b_min.x(), b_max.y(), b_max.z() - size.z()));
// Wing 2 (Y-Inward)
init_data.add_vertex(tip);
init_data.add_vertex(Vec3f(tip.x(), tip.y() + dirY, tip.z() - head_s));
}
}
// indices
for (unsigned int i = 0; i < 48; ++i) {
// Finalize indices
for (unsigned int i = 0; i < init_data.vertices_count(); ++i) {
init_data.add_index(i);
}
@@ -2941,8 +3057,11 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_
}
else if (sync_rotation_type != SyncRotationType::NONE || mirrored)
new_inst_trafo_j.linear() = (old_inst_trafo_j.linear() * old_inst_trafo_i.linear().inverse()) * curr_inst_trafo_i.linear();
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
bool should_synchronize_z = m_model->objects[volume_j->object_idx()]->instances[volume_j->instance_idx()]->auto_drop == false;
if (should_synchronize_z && wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
new_inst_trafo_j.translation().z() = curr_inst_trafo_i.translation().z();
assert(is_rotation_xy_synchronized(curr_inst_trafo_i, new_inst_trafo_j));
volume_j->set_instance_transformation(new_inst_trafo_j);
done.insert(j);
@@ -2985,17 +3104,25 @@ void Selection::ensure_on_bed()
InstancesToZMap instances_min_z;
for (size_t i = 0; i < m_volumes->size(); ++i) {
GLVolume* volume = (*m_volumes)[i];
if (!volume->is_wipe_tower && !volume->is_modifier &&
std::find(m_cache.sinking_volumes.begin(), m_cache.sinking_volumes.end(), i) == m_cache.sinking_volumes.end()) {
const double min_z = volume->transformed_convex_hull_bounding_box().min.z();
std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
InstancesToZMap::iterator it = instances_min_z.find(instance);
if (it == instances_min_z.end())
it = instances_min_z.insert(InstancesToZMap::value_type(instance, DBL_MAX)).first;
GLVolume* volume = (*m_volumes)[i];
ModelObject* mo = m_model->objects[volume->object_idx()];
ModelInstance* mi = mo->instances[volume->instance_idx()];
it->second = std::min(it->second, min_z);
if (mi->auto_drop == false
|| volume->is_wipe_tower
|| volume->is_modifier
|| std::find(m_cache.sinking_volumes.begin(), m_cache.sinking_volumes.end(), i) != m_cache.sinking_volumes.end())
{
continue;
}
const double min_z = volume->transformed_convex_hull_bounding_box().min.z();
std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
InstancesToZMap::iterator it = instances_min_z.find(instance);
if (it == instances_min_z.end())
it = instances_min_z.insert(InstancesToZMap::value_type(instance, DBL_MAX)).first;
it->second = std::min(it->second, min_z);
}
for (GLVolume* volume : *m_volumes) {
+5 -2
View File
@@ -181,6 +181,7 @@ private:
GLModel m_arrow;
GLModel m_curved_arrow;
GLModel m_box;
bool m_auto_drop = true;
struct Planes
{
std::array<Vec3f, 2> check_points{ Vec3f::Zero(), Vec3f::Zero() };
@@ -237,6 +238,8 @@ public:
void drop();
void center_plate(const int plate_idx);
void set_printable(bool printable);
bool get_auto_drop() const;
void set_auto_drop(bool enabled);
void add_all();
void remove_all();
@@ -370,7 +373,7 @@ public:
void render_bounding_box(const BoundingBoxf3& box, const ColorRGB& color, float scale) {
m_scale_factor = scale;
render_bounding_box(box, Transform3d::Identity(), color);
render_bounding_box(box, Transform3d::Identity(), get_auto_drop(), color);
}
//BBS
@@ -414,7 +417,7 @@ private:
m_bounding_sphere.reset();
}
void render_synchronized_volumes();
void render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const ColorRGB& color);
void render_bounding_box(const BoundingBoxf3& box, const Transform3d& trafo, const bool auto_drop, const ColorRGB& color);
void render_sidebar_position_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix);
void render_sidebar_rotation_hints(const std::string& sidebar_field, GLShaderProgram& shader, const Transform3d& matrix);
//BBS: GUI refactor: add uniform_scale from gizmo
+26 -1
View File
@@ -17,6 +17,9 @@
#include "GUI_App.hpp"
#include "GUI_Utils.hpp"
#include "I18N.hpp"
#ifdef __WXGTK__
#include "LinuxDisplayBackend.hpp"
#endif
#include "MainFrame.hpp"
#include "MsgDialog.hpp"
#include "OpenGLManager.hpp"
@@ -28,7 +31,7 @@
#include <boost/property_tree/json_parser.hpp>
#include <boost/uuid/detail/md5.hpp>
#include "GL/glew.h"
#include <glad/gl.h>
#include <wx/display.h>
#include <wx/htmllbox.h>
@@ -420,6 +423,28 @@ static std::string generate_system_info_json()
data_node.put("Linux_DistroID", distro_id);
data_node.put("Linux_DistroVer", distro_ver);
data_node.put("Linux_Wayland", wxGetEnv("WAYLAND_DISPLAY", nullptr));
#ifdef __WXGTK__
const LinuxDisplayBackend display_backend = get_linux_display_backend();
const char* display_backend_name = "unknown";
const char* gl_backend_hint = "Unknown";
switch (display_backend) {
case LinuxDisplayBackend::Wayland:
display_backend_name = "wayland";
gl_backend_hint = "EGL";
break;
case LinuxDisplayBackend::X11:
display_backend_name = "x11";
gl_backend_hint = "GLX";
break;
default:
break;
}
data_node.put("Linux_DisplayBackend", display_backend_name);
data_node.put("Linux_GLBackendHint", gl_backend_hint);
#else
data_node.put("Linux_DisplayBackend", "unknown");
data_node.put("Linux_GLBackendHint", "Unknown");
#endif
#endif
data_node.put("wxWidgets", wxVERSION_NUM_DOT_STRING);
#ifdef __WXGTK__
+1 -1
View File
@@ -1,4 +1,4 @@
#include <GL/glew.h>
#include <glad/gl.h>
#include "SkipPartCanvas.hpp"
#include <opencv2/opencv.hpp>
+1 -1
View File
@@ -1,6 +1,6 @@
#include "TextLines.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include "libslic3r/Model.hpp"
+3 -1
View File
@@ -516,7 +516,9 @@ void Button::OnParentMotion(wxMouseEvent& event)
tipWindow->SetLabel(tip);
}
tipWindow->Position(wxGetMousePosition(), wxSize(0, 0));
// Position tooltip relative to the button widget itself rather than
// using wxGetMousePosition() which returns (0,0) on Wayland.
tipWindow->Position(this->ClientToScreen(wxPoint(0, 0)), this->GetSize());
tipWindow->Popup();
}
else
+6
View File
@@ -138,6 +138,10 @@ void SwitchButton::Rescale()
memdc.SelectObject(bmp);
#endif
memdc.SetFont(dc.GetFont());
#ifdef __WXMSW__
const double scale = GetDPIScaleFactor();
fontScale = scale;
#endif
if (fontScale) {
memdc.SetFont(dc.GetFont().Scaled(fontScale));
textSize[0] = memdc.GetTextExtent(labels[0]);
@@ -176,6 +180,8 @@ void SwitchButton::Rescale()
memdc.SelectObject(wxNullBitmap);
#ifdef __WXOSX__
bmp = wxBitmap(bmp.ConvertToImage(), -1, scale);
#elif defined(__WXMSW__)
bmp.SetScaleFactor(scale); // ORCA
#endif
(i == 0 ? m_off : m_on).bmp() = bmp;
}
+2 -2
View File
@@ -1407,8 +1407,8 @@ void Cornering_Test_Dlg::on_start(wxCommandEvent& event) {
!preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("machine_max_junction_deviation")->values.empty() &&
preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("machine_max_junction_deviation")->values[0] > 0) {
// Using Junction Deviation (mm)
max_end_value = 1.0;
warning_threshold = 0.3;
max_end_value = 0.3;
warning_threshold = 0.25;
}
if (!read_double || m_params.start < 0 || m_params.end > max_end_value || m_params.start >= m_params.end) {
+37 -3
View File
@@ -468,6 +468,10 @@ wxBitmap create_scaled_bitmap( const std::string& bmp_name_in,
throw Slic3r::RuntimeError("Could not load bitmap: " + bmp_name);
}
#ifdef __WXMSW__
// ORCA MSW needs to set scale factor for bitmaps loaded from cache because they arent auto scaled by wxBitmapBundle like bitmaps
bmp->SetScaleFactor(win ? win->GetDPIScaleFactor() : (wxWindow::FromDIP(100, nullptr) / 100.0));
#endif
return *bmp;
}
@@ -487,6 +491,10 @@ wxBitmap create_scaled_bitmap2(const std::string& bmp_name_in, Slic3r::GUI::Bitm
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Could not load bitmap: " << bmp_name;
throw Slic3r::RuntimeError("Could not load bitmap: " + bmp_name);
}
#ifdef __WXMSW__
// ORCA MSW needs to set scale factor for bitmaps loaded from cache because they arent auto scaled by wxBitmapBundle like bitmaps
bmp->SetScaleFactor(win ? win->GetDPIScaleFactor() : (wxWindow::FromDIP(100, nullptr) / 100.0));
#endif
return *bmp;
}
@@ -500,7 +508,8 @@ wxBitmap* get_default_extruder_color_icon(bool thin_icon/* = false*/)
const int icon_height = lround(2 * em);
bool dark_mode = Slic3r::GUI::wxGetApp().dark_mode();
wxClientDC cdc((wxWindow*)Slic3r::GUI::wxGetApp().mainframe);
auto win = (wxWindow*)Slic3r::GUI::wxGetApp().mainframe;
wxClientDC cdc(win);
wxMemoryDC dc(&cdc);
dc.SetFont(::Label::Body_12);
@@ -526,6 +535,12 @@ wxBitmap* get_default_extruder_color_icon(bool thin_icon/* = false*/)
dc.SelectObject(wxNullBitmap);
}
#ifdef __WXMSW__
// ORCA MSW needs to set scale factor for bitmaps loaded from cache because they arent auto scaled by wxBitmapBundle like bitmaps
double scale = win ? win->GetDPIScaleFactor() : (wxWindow::FromDIP(100, nullptr) / 100.0);
bitmap->SetScaleFactor(scale);
#endif
return bitmap;
}
@@ -633,6 +648,9 @@ wxBitmap *get_extruder_color_icon(std::vector<std::string> colors, bool is_gradi
bitmap_key += "h" + std::to_string(icon_height) + "-w" + std::to_string(icon_width) + "-i" + label;
wxBitmap *bitmap = bmp_cache.find(bitmap_key);
#ifdef __WXMSW__
auto win = (wxWindow *) Slic3r::GUI::wxGetApp().mainframe;
#endif
if (bitmap == nullptr) {
std::vector<wxColour> wx_colors;
@@ -656,8 +674,11 @@ wxBitmap *get_extruder_color_icon(std::vector<std::string> colors, bool is_gradi
#ifndef __WXMSW__
wxMemoryDC dc(base_bitmap);
#else
wxClientDC cdc((wxWindow *) Slic3r::GUI::wxGetApp().mainframe);
wxClientDC cdc(win);
wxMemoryDC dc(&cdc);
// ORCA MSW needs to set scale factor for bitmaps loaded from cache because they arent auto scaled by wxBitmapBundle like bitmaps
double scale = win ? win->GetDPIScaleFactor() : (wxWindow::FromDIP(100, nullptr) / 100.0);
base_bitmap.SetScaleFactor(scale);
dc.SelectObject(base_bitmap);
#endif
@@ -694,6 +715,11 @@ wxBitmap *get_extruder_color_icon(std::vector<std::string> colors, bool is_gradi
// cache result
bitmap = bmp_cache.insert(bitmap_key, base_bitmap);
}
#ifdef __WXMSW__
// ORCA MSW needs to set scale factor for bitmaps loaded from cache because they arent auto scaled by wxBitmapBundle like bitmaps
double scale = win ? win->GetDPIScaleFactor() : (wxWindow::FromDIP(100, nullptr) / 100.0);
bitmap->SetScaleFactor(scale);
#endif
return bitmap;
}
@@ -704,6 +730,9 @@ wxBitmap *get_extruder_color_icon(std::string color, std::string label, int icon
std::string bitmap_key = color + "-h" + std::to_string(icon_height) + "-w" + std::to_string(icon_width) + "-i" + label;
wxBitmap *bitmap = bmp_cache.find(bitmap_key);
#ifdef __WXMSW__
auto win = (wxWindow *) Slic3r::GUI::wxGetApp().mainframe;
#endif
if (bitmap == nullptr) {
// Paint the color icon.
// Slic3r::GUI::BitmapCache::parse_color(color, rgb);
@@ -714,7 +743,7 @@ wxBitmap *get_extruder_color_icon(std::string color, std::string label, int icon
bitmap->UseAlpha();
wxMemoryDC dc(*bitmap);
#elif defined(__WXMSW__)
wxClientDC cdc((wxWindow *) Slic3r::GUI::wxGetApp().mainframe);
wxClientDC cdc(win);
wxMemoryDC dc(&cdc);
dc.SelectObject(*bitmap);
#else
@@ -748,6 +777,11 @@ wxBitmap *get_extruder_color_icon(std::string color, std::string label, int icon
dc.DrawText(label, (icon_width - size.x) / 2, (icon_height - size.y) / 2);
dc.SelectObject(wxNullBitmap);
}
#ifdef __WXMSW__
// ORCA MSW needs to set scale factor for bitmaps loaded from cache because they arent auto scaled by wxBitmapBundle like bitmaps
double scale = win ? win->GetDPIScaleFactor() : (wxWindow::FromDIP(100, nullptr) / 100.0);
bitmap->SetScaleFactor(scale);
#endif
return bitmap;
}
void apply_extruder_selector(Slic3r::GUI::BitmapComboBox** ctrl,
+8 -2
View File
@@ -458,8 +458,14 @@ static void read_model_from_file(const std::string& input_file, Model& model)
&is_bbl_3mf, &file_version, nullptr, nullptr, nullptr, plate_to_slice);
model.add_default_instances();
for (auto object : model.objects)
object->ensure_on_bed();
const std::string extension = fs::path(input_file).extension().string();
const bool is_project_file = extension == ".3mf" || extension == ".3MF" || extension == ".amf" || extension == ".AMF";
for (auto object : model.objects) {
if (!is_project_file)
object->center_around_origin(false);
object->ensure_on_bed(is_project_file);
}
}
std::array<Vec3d, 4> get_cut_plane_points(const BoundingBoxf3 &bbox, const double &cut_height)
+1 -1
View File
@@ -1,6 +1,6 @@
#include "EmbossStyleManager.hpp"
#include <optional>
#include <GL/glew.h> // Imgui texture
#include <glad/gl.h> // Imgui texture
#include <imgui/imgui_internal.h> // ImTextCharFromUtf8
#include <libslic3r/AppConfig.hpp>
#include <libslic3r/Utils.hpp> // ScopeGuard
+1 -1
View File
@@ -7,7 +7,7 @@
#include <functional>
#include <imgui/imgui.h>
#include <wx/font.h>
#include <GL/glew.h>
#include <glad/gl.h>
#include <libslic3r/BoundingBox.hpp>
#include <libslic3r/Emboss.hpp>
#include <libslic3r/TextConfiguration.hpp>
+1 -1
View File
@@ -627,7 +627,7 @@ void PresetUpdater::priv::sync_resources(std::string http_url, std::map<std::str
boost::nowide::ofstream c;
c.open(changelog_file, std::ios::out | std::ios::trunc);
c << std::setw(4) << j << std::endl;
c << j.dump(1, '\t') << std::endl;
c.close();
}
catch(std::exception &err) {
+1 -1
View File
@@ -166,7 +166,7 @@ void SimplyPrint::save_oauth_credential(const GUI::OAuthResult& cred) const
boost::nowide::ofstream c;
c.open(cred_file, std::ios::out | std::ios::trunc);
c << std::setw(4) << j << std::endl;
c << j.dump(1, '\t') << std::endl;
c.close();
}