diff --git a/deps/Boost/Boost.cmake b/deps/Boost/Boost.cmake
index ae2bd96466..ec8bab799c 100644
--- a/deps/Boost/Boost.cmake
+++ b/deps/Boost/Boost.cmake
@@ -28,6 +28,9 @@ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
elseif (MSVC_VERSION LESS 1930)
# 1920-1929 = VS 16.0 (v142 toolset)
set(_boost_toolset "msvc-14.2")
+ elseif (MSVC_VERSION LESS 1940)
+ # 1930-1939 = VS 17.0 (v143 toolset)
+ set(_boost_toolset "msvc-14.3")
else ()
message(FATAL_ERROR "Unsupported MSVC version")
endif ()
diff --git a/deps/deps-windows.cmake b/deps/deps-windows.cmake
index 7288cfe6fa..aba6fcab49 100644
--- a/deps/deps-windows.cmake
+++ b/deps/deps-windows.cmake
@@ -15,6 +15,10 @@ elseif (MSVC_VERSION LESS 1930)
# 1920-1929 = VS 16.0 (v142 toolset)
set(DEP_VS_VER "16")
set(DEP_BOOST_TOOLSET "msvc-14.2")
+elseif (MSVC_VERSION LESS 1940)
+# 1930-1939 = VS 17.0 (v143 toolset)
+ set(DEP_VS_VER "17")
+ set(DEP_BOOST_TOOLSET "msvc-14.3")
else ()
message(FATAL_ERROR "Unsupported MSVC version")
endif ()
diff --git a/resources/data/hints.ini b/resources/data/hints.ini
index b90976c1a7..ccb248bc37 100644
--- a/resources/data/hints.ini
+++ b/resources/data/hints.ini
@@ -34,7 +34,7 @@
#
# Open preferences (might add item to highlight)
# hypertext_type = preferences
-# hypertext_preferences_page = 2 (values 0-2 according to prefernces tab to be opened)
+# hypertext_preferences_page = name of the prefernces tab
# hypertext_preferences_item = show_collapse_button (name of variable saved in prusaslicer.ini connected to the setting in preferences)
#
# Open gallery (no aditional var)
@@ -97,7 +97,7 @@ documentation_link = https://help.prusa3d.com/en/article/reload-from-disk_120427
[hint:Hiding sidebar]
text = Hiding sidebar\nDid you know that you can hide the right sidebar using the shortcut Shift+Tab? You can also enable the icon for this from thePreferences.
hypertext_type = preferences
-hypertext_preferences_page = 2
+hypertext_preferences_page = GUI
hypertext_preferences_item = show_collapse_button
[hint:Perspective camera]
@@ -214,7 +214,7 @@ disabled_tags = SLA
[hint:Settings in non-modal window]
text = Settings in non-modal window\nDid you know that you can open the Settings in a new non-modal window? This means you can have settings open on one screen and the G-code Preview on the other. Go to thePreferencesand select Settings in non-modal window.
hypertext_type = preferences
-hypertext_preferences_page = 2
+hypertext_preferences_page = GUI
hypertext_preferences_item = dlg_settings_layout_mode
[hint:Adaptive infills]
diff --git a/resources/icons/edit_button_pressed.svg b/resources/icons/edit_button_pressed.svg
new file mode 100644
index 0000000000..6e4058d10f
--- /dev/null
+++ b/resources/icons/edit_button_pressed.svg
@@ -0,0 +1,91 @@
+
+
+
+
diff --git a/resources/icons/legend_colorchanges.svg b/resources/icons/legend_colorchanges.svg
new file mode 100644
index 0000000000..cb95ef4676
--- /dev/null
+++ b/resources/icons/legend_colorchanges.svg
@@ -0,0 +1,157 @@
+
+
+
+
diff --git a/resources/icons/legend_customgcodes.svg b/resources/icons/legend_customgcodes.svg
new file mode 100644
index 0000000000..96e0be69e3
--- /dev/null
+++ b/resources/icons/legend_customgcodes.svg
@@ -0,0 +1,9 @@
+
diff --git a/resources/icons/legend_deretract.svg b/resources/icons/legend_deretract.svg
new file mode 100644
index 0000000000..4b636df9de
--- /dev/null
+++ b/resources/icons/legend_deretract.svg
@@ -0,0 +1,107 @@
+
+
+
+
diff --git a/resources/icons/legend_pauseprints.svg b/resources/icons/legend_pauseprints.svg
new file mode 100644
index 0000000000..954bc00e97
--- /dev/null
+++ b/resources/icons/legend_pauseprints.svg
@@ -0,0 +1,76 @@
+
+
diff --git a/resources/icons/legend_retract.svg b/resources/icons/legend_retract.svg
new file mode 100644
index 0000000000..494e2f7286
--- /dev/null
+++ b/resources/icons/legend_retract.svg
@@ -0,0 +1,110 @@
+
+
+
+
diff --git a/resources/icons/legend_seams.svg b/resources/icons/legend_seams.svg
new file mode 100644
index 0000000000..724414119d
--- /dev/null
+++ b/resources/icons/legend_seams.svg
@@ -0,0 +1,45 @@
+
+
diff --git a/resources/icons/legend_shells.svg b/resources/icons/legend_shells.svg
new file mode 100644
index 0000000000..b0a93effb2
--- /dev/null
+++ b/resources/icons/legend_shells.svg
@@ -0,0 +1,77 @@
+
+
diff --git a/resources/icons/legend_toolchanges.svg b/resources/icons/legend_toolchanges.svg
new file mode 100644
index 0000000000..85b6218a9b
--- /dev/null
+++ b/resources/icons/legend_toolchanges.svg
@@ -0,0 +1,10 @@
+
diff --git a/resources/icons/legend_toolmarker.svg b/resources/icons/legend_toolmarker.svg
new file mode 100644
index 0000000000..3cd5cf8d96
--- /dev/null
+++ b/resources/icons/legend_toolmarker.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/icons/legend_travel.svg b/resources/icons/legend_travel.svg
new file mode 100644
index 0000000000..553e90a743
--- /dev/null
+++ b/resources/icons/legend_travel.svg
@@ -0,0 +1,163 @@
+
+
+
+
diff --git a/resources/icons/legend_wipe.svg b/resources/icons/legend_wipe.svg
new file mode 100644
index 0000000000..decfcd6011
--- /dev/null
+++ b/resources/icons/legend_wipe.svg
@@ -0,0 +1,16 @@
+
+
+
diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h
index 09c80a9d9b..db0e54e60d 100644
--- a/src/imgui/imconfig.h
+++ b/src/imgui/imconfig.h
@@ -155,6 +155,18 @@ namespace ImGui
const wchar_t ClippyMarker = 0x2602;
const wchar_t InfoMarker = 0x2603;
const wchar_t SliderFloatEditBtnIcon = 0x2604;
+ const wchar_t SliderFloatEditBtnPressedIcon = 0x2605;
+ const wchar_t LegendTravel = 0x2606;
+ const wchar_t LegendWipe = 0x2607;
+ const wchar_t LegendRetract = 0x2608;
+ const wchar_t LegendDeretract = 0x2609;
+ const wchar_t LegendSeams = 0x2610;
+ const wchar_t LegendToolChanges = 0x2611;
+ const wchar_t LegendColorChanges = 0x2612;
+ const wchar_t LegendPausePrints = 0x2613;
+ const wchar_t LegendCustomGCodes = 0x2614;
+ const wchar_t LegendShells = 0x2615;
+ const wchar_t LegendToolMarker = 0x2616;
// void MyFunction(const char* name, const MyMatrix44& v);
}
diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index deaa0b9241..c79be847be 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -14,7 +14,7 @@ if (TARGET OpenVDB::openvdb)
set(OpenVDBUtils_SOURCES OpenVDBUtils.cpp OpenVDBUtils.hpp)
endif()
-add_library(libslic3r STATIC
+set(SLIC3R_SOURCES
pchheader.cpp
pchheader.hpp
BoundingBox.cpp
@@ -29,6 +29,8 @@ add_library(libslic3r STATIC
clipper.hpp
ClipperUtils.cpp
ClipperUtils.hpp
+ Color.cpp
+ Color.hpp
Config.cpp
Config.hpp
EdgeGrid.cpp
@@ -291,6 +293,14 @@ add_library(libslic3r STATIC
SLA/ReprojectPointsOnMesh.hpp
)
+add_library(libslic3r STATIC ${SLIC3R_SOURCES})
+
+foreach(_source IN ITEMS ${SLIC3R_SOURCES})
+ get_filename_component(_source_path "${_source}" PATH)
+ string(REPLACE "/" "\\" _group_path "${_source_path}")
+ source_group("${_group_path}" FILES "${_source}")
+endforeach()
+
if (SLIC3R_STATIC)
set(CGAL_Boost_USE_STATIC_LIBS ON CACHE BOOL "" FORCE)
endif ()
diff --git a/src/libslic3r/Color.cpp b/src/libslic3r/Color.cpp
new file mode 100644
index 0000000000..7b5a7f3ba7
--- /dev/null
+++ b/src/libslic3r/Color.cpp
@@ -0,0 +1,400 @@
+#include "libslic3r.h"
+#include "Color.hpp"
+
+#include
+
+static const float INV_255 = 1.0f / 255.0f;
+
+namespace Slic3r {
+
+// Conversion from RGB to HSV color space
+// The input RGB values are in the range [0, 1]
+// The output HSV values are in the ranges h = [0, 360], and s, v = [0, 1]
+static void RGBtoHSV(float r, float g, float b, float& h, float& s, float& v)
+{
+ assert(0.0f <= r && r <= 1.0f);
+ assert(0.0f <= g && g <= 1.0f);
+ assert(0.0f <= b && b <= 1.0f);
+
+ const float max_comp = std::max(std::max(r, g), b);
+ const float min_comp = std::min(std::min(r, g), b);
+ const float delta = max_comp - min_comp;
+
+ if (delta > 0.0f) {
+ if (max_comp == r)
+ h = 60.0f * (std::fmod(((g - b) / delta), 6.0f));
+ else if (max_comp == g)
+ h = 60.0f * (((b - r) / delta) + 2.0f);
+ else if (max_comp == b)
+ h = 60.0f * (((r - g) / delta) + 4.0f);
+
+ s = (max_comp > 0.0f) ? delta / max_comp : 0.0f;
+ }
+ else {
+ h = 0.0f;
+ s = 0.0f;
+ }
+ v = max_comp;
+
+ while (h < 0.0f) { h += 360.0f; }
+ while (h > 360.0f) { h -= 360.0f; }
+
+ assert(0.0f <= s && s <= 1.0f);
+ assert(0.0f <= v && v <= 1.0f);
+ assert(0.0f <= h && h <= 360.0f);
+}
+
+// Conversion from HSV to RGB color space
+// The input HSV values are in the ranges h = [0, 360], and s, v = [0, 1]
+// The output RGB values are in the range [0, 1]
+static void HSVtoRGB(float h, float s, float v, float& r, float& g, float& b)
+{
+ assert(0.0f <= s && s <= 1.0f);
+ assert(0.0f <= v && v <= 1.0f);
+ assert(0.0f <= h && h <= 360.0f);
+
+ const float chroma = v * s;
+ const float h_prime = std::fmod(h / 60.0f, 6.0f);
+ const float x = chroma * (1.0f - std::abs(std::fmod(h_prime, 2.0f) - 1.0f));
+ const float m = v - chroma;
+
+ if (0.0f <= h_prime && h_prime < 1.0f) {
+ r = chroma;
+ g = x;
+ b = 0.0f;
+ }
+ else if (1.0f <= h_prime && h_prime < 2.0f) {
+ r = x;
+ g = chroma;
+ b = 0.0f;
+ }
+ else if (2.0f <= h_prime && h_prime < 3.0f) {
+ r = 0.0f;
+ g = chroma;
+ b = x;
+ }
+ else if (3.0f <= h_prime && h_prime < 4.0f) {
+ r = 0.0f;
+ g = x;
+ b = chroma;
+ }
+ else if (4.0f <= h_prime && h_prime < 5.0f) {
+ r = x;
+ g = 0.0f;
+ b = chroma;
+ }
+ else if (5.0f <= h_prime && h_prime < 6.0f) {
+ r = chroma;
+ g = 0.0f;
+ b = x;
+ }
+ else {
+ r = 0.0f;
+ g = 0.0f;
+ b = 0.0f;
+ }
+
+ r += m;
+ g += m;
+ b += m;
+
+ assert(0.0f <= r && r <= 1.0f);
+ assert(0.0f <= g && g <= 1.0f);
+ assert(0.0f <= b && b <= 1.0f);
+}
+
+class Randomizer
+{
+ std::random_device m_rd;
+
+public:
+ float random_float(float min, float max) {
+ std::mt19937 rand_generator(m_rd());
+ std::uniform_real_distribution distrib(min, max);
+ return distrib(rand_generator);
+ }
+};
+
+ColorRGB::ColorRGB(float r, float g, float b)
+: m_data({ std::clamp(r, 0.0f, 1.0f), std::clamp(g, 0.0f, 1.0f), std::clamp(b, 0.0f, 1.0f) })
+{
+}
+
+ColorRGB::ColorRGB(unsigned char r, unsigned char g, unsigned char b)
+: m_data({ std::clamp(r * INV_255, 0.0f, 1.0f), std::clamp(g * INV_255, 0.0f, 1.0f), std::clamp(b * INV_255, 0.0f, 1.0f) })
+{
+}
+
+bool ColorRGB::operator < (const ColorRGB& other) const
+{
+ for (size_t i = 0; i < 3; ++i) {
+ if (m_data[i] < other.m_data[i])
+ return true;
+ }
+
+ return false;
+}
+
+bool ColorRGB::operator > (const ColorRGB& other) const
+{
+ for (size_t i = 0; i < 3; ++i) {
+ if (m_data[i] > other.m_data[i])
+ return true;
+ }
+
+ return false;
+}
+
+ColorRGB ColorRGB::operator + (const ColorRGB& other) const
+{
+ ColorRGB ret;
+ for (size_t i = 0; i < 3; ++i) {
+ ret.m_data[i] = std::clamp(m_data[i] + other.m_data[i], 0.0f, 1.0f);
+ }
+ return ret;
+}
+
+ColorRGB ColorRGB::operator * (float value) const
+{
+ assert(value >= 0.0f);
+ ColorRGB ret;
+ for (size_t i = 0; i < 3; ++i) {
+ ret.m_data[i] = std::clamp(value * m_data[i], 0.0f, 1.0f);
+ }
+ return ret;
+}
+
+ColorRGBA::ColorRGBA(float r, float g, float b, float a)
+: m_data({ std::clamp(r, 0.0f, 1.0f), std::clamp(g, 0.0f, 1.0f), std::clamp(b, 0.0f, 1.0f), std::clamp(a, 0.0f, 1.0f) })
+{
+}
+
+ColorRGBA::ColorRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+: m_data({ std::clamp(r * INV_255, 0.0f, 1.0f), std::clamp(g * INV_255, 0.0f, 1.0f), std::clamp(b * INV_255, 0.0f, 1.0f), std::clamp(a * INV_255, 0.0f, 1.0f) })
+{
+}
+
+bool ColorRGBA::operator < (const ColorRGBA& other) const
+{
+ for (size_t i = 0; i < 3; ++i) {
+ if (m_data[i] < other.m_data[i])
+ return true;
+ }
+
+ return false;
+}
+
+bool ColorRGBA::operator > (const ColorRGBA& other) const
+{
+ for (size_t i = 0; i < 3; ++i) {
+ if (m_data[i] > other.m_data[i])
+ return true;
+ }
+
+ return false;
+}
+
+ColorRGBA ColorRGBA::operator + (const ColorRGBA& other) const
+{
+ ColorRGBA ret;
+ for (size_t i = 0; i < 3; ++i) {
+ ret.m_data[i] = std::clamp(m_data[i] + other.m_data[i], 0.0f, 1.0f);
+ }
+ return ret;
+}
+
+ColorRGBA ColorRGBA::operator * (float value) const
+{
+ assert(value >= 0.0f);
+ ColorRGBA ret;
+ for (size_t i = 0; i < 3; ++i) {
+ ret.m_data[i] = std::clamp(value * m_data[i], 0.0f, 1.0f);
+ }
+ ret.m_data[3] = this->m_data[3];
+ return ret;
+}
+
+ColorRGB operator * (float value, const ColorRGB& other) { return other * value; }
+ColorRGBA operator * (float value, const ColorRGBA& other) { return other * value; }
+
+ColorRGB lerp(const ColorRGB& a, const ColorRGB& b, float t)
+{
+ assert(0.0f <= t && t <= 1.0f);
+ return (1.0f - t) * a + t * b;
+}
+
+ColorRGBA lerp(const ColorRGBA& a, const ColorRGBA& b, float t)
+{
+ assert(0.0f <= t && t <= 1.0f);
+ return (1.0f - t) * a + t * b;
+}
+
+ColorRGB complementary(const ColorRGB& color)
+{
+ return { 1.0f - color.r(), 1.0f - color.g(), 1.0f - color.b() };
+}
+
+ColorRGBA complementary(const ColorRGBA& color)
+{
+ return { 1.0f - color.r(), 1.0f - color.g(), 1.0f - color.b(), color.a() };
+}
+
+ColorRGB saturate(const ColorRGB& color, float factor)
+{
+ float h, s, v;
+ RGBtoHSV(color.r(), color.g(), color.b(), h, s, v);
+ s = std::clamp(s * factor, 0.0f, 1.0f);
+ float r, g, b;
+ HSVtoRGB(h, s, v, r, g, b);
+ return { r, g, b };
+}
+
+ColorRGBA saturate(const ColorRGBA& color, float factor)
+{
+ return to_rgba(saturate(to_rgb(color), factor), color.a());
+}
+
+ColorRGB opposite(const ColorRGB& color)
+{
+ float h, s, v;
+ RGBtoHSV(color.r(), color.g(), color.b(), h, s, v);
+
+ h += 65.0f; // 65 instead 60 to avoid circle values
+ if (h > 360.0f)
+ h -= 360.0f;
+
+ Randomizer rnd;
+ s = rnd.random_float(0.65f, 1.0f);
+ v = rnd.random_float(0.65f, 1.0f);
+
+ float r, g, b;
+ HSVtoRGB(h, s, v, r, g, b);
+ return { r, g, b };
+}
+
+ColorRGB opposite(const ColorRGB& a, const ColorRGB& b)
+{
+ float ha, sa, va;
+ RGBtoHSV(a.r(), a.g(), a.b(), ha, sa, va);
+ float hb, sb, vb;
+ RGBtoHSV(b.r(), b.g(), b.b(), hb, sb, vb);
+
+ float delta_h = std::abs(ha - hb);
+ float start_h = (delta_h > 180.0f) ? std::min(ha, hb) : std::max(ha, hb);
+
+ start_h += 5.0f; // to avoid circle change of colors for 120 deg
+ if (delta_h < 180.0f)
+ delta_h = 360.0f - delta_h;
+
+ Randomizer rnd;
+ float out_h = start_h + 0.5f * delta_h;
+ if (out_h > 360.0f)
+ out_h -= 360.0f;
+ float out_s = rnd.random_float(0.65f, 1.0f);
+ float out_v = rnd.random_float(0.65f, 1.0f);
+
+ float out_r, out_g, out_b;
+ HSVtoRGB(out_h, out_s, out_v, out_r, out_g, out_b);
+ return { out_r, out_g, out_b };
+}
+
+bool can_decode_color(const std::string& color) { return color.size() == 7 && color.front() == '#'; }
+
+bool decode_color(const std::string& color_in, ColorRGB& color_out)
+{
+ auto hex_digit_to_int = [](const char c) {
+ return
+ (c >= '0' && c <= '9') ? int(c - '0') :
+ (c >= 'A' && c <= 'F') ? int(c - 'A') + 10 :
+ (c >= 'a' && c <= 'f') ? int(c - 'a') + 10 : -1;
+ };
+
+ color_out = ColorRGB::BLACK();
+ if (can_decode_color(color_in)) {
+ const char* c = color_in.data() + 1;
+ for (unsigned int i = 0; i < 3; ++i) {
+ const int digit1 = hex_digit_to_int(*c++);
+ const int digit2 = hex_digit_to_int(*c++);
+ if (digit1 != -1 && digit2 != -1)
+ color_out.set(i, float(digit1 * 16 + digit2) * INV_255);
+ }
+ }
+ else
+ return false;
+
+ assert(0.0f <= color_out.r() && color_out.r() <= 1.0f);
+ assert(0.0f <= color_out.g() && color_out.g() <= 1.0f);
+ assert(0.0f <= color_out.b() && color_out.b() <= 1.0f);
+ return true;
+}
+
+bool decode_color(const std::string& color_in, ColorRGBA& color_out)
+{
+ ColorRGB rgb;
+ if (!decode_color(color_in, rgb))
+ return false;
+
+ color_out = to_rgba(rgb, color_out.a());
+ return true;
+}
+
+bool decode_colors(const std::vector& colors_in, std::vector& colors_out)
+{
+ colors_out = std::vector(colors_in.size(), ColorRGB::BLACK());
+ for (size_t i = 0; i < colors_in.size(); ++i) {
+ if (!decode_color(colors_in[i], colors_out[i]))
+ return false;
+ }
+ return true;
+}
+
+bool decode_colors(const std::vector& colors_in, std::vector& colors_out)
+{
+ colors_out = std::vector(colors_in.size(), ColorRGBA::BLACK());
+ for (size_t i = 0; i < colors_in.size(); ++i) {
+ if (!decode_color(colors_in[i], colors_out[i]))
+ return false;
+ }
+ return true;
+}
+
+std::string encode_color(const ColorRGB& color)
+{
+ char buffer[64];
+ ::sprintf(buffer, "#%02X%02X%02X", color.r_uchar(), color.g_uchar(), color.b_uchar());
+ return std::string(buffer);
+}
+
+std::string encode_color(const ColorRGBA& color) { return encode_color(to_rgb(color)); }
+
+ColorRGB to_rgb(const ColorRGBA& other_rgba) { return { other_rgba.r(), other_rgba.g(), other_rgba.b() }; }
+ColorRGBA to_rgba(const ColorRGB& other_rgb) { return { other_rgb.r(), other_rgb.g(), other_rgb.b(), 1.0f }; }
+ColorRGBA to_rgba(const ColorRGB& other_rgb, float alpha) { return { other_rgb.r(), other_rgb.g(), other_rgb.b(), alpha }; }
+
+ColorRGBA picking_decode(unsigned int id)
+{
+ return {
+ float((id >> 0) & 0xff) * INV_255, // red
+ float((id >> 8) & 0xff) * INV_255, // green
+ float((id >> 16) & 0xff) * INV_255, // blue
+ float(picking_checksum_alpha_channel(id & 0xff, (id >> 8) & 0xff, (id >> 16) & 0xff)) * INV_255 // checksum for validating against unwanted alpha blending and multi sampling
+ };
+}
+
+unsigned int picking_encode(unsigned char r, unsigned char g, unsigned char b) { return r + (g << 8) + (b << 16); }
+
+unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue)
+{
+ // 8 bit hash for the color
+ unsigned char b = ((((37 * red) + green) & 0x0ff) * 37 + blue) & 0x0ff;
+ // Increase enthropy by a bit reversal
+ b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
+ b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
+ b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
+ // Flip every second bit to increase the enthropy even more.
+ b ^= 0x55;
+ return b;
+}
+
+} // namespace Slic3r
+
diff --git a/src/libslic3r/Color.hpp b/src/libslic3r/Color.hpp
new file mode 100644
index 0000000000..fce0c67e00
--- /dev/null
+++ b/src/libslic3r/Color.hpp
@@ -0,0 +1,170 @@
+#ifndef slic3r_Color_hpp_
+#define slic3r_Color_hpp_
+
+#include
+#include
+
+namespace Slic3r {
+
+class ColorRGB
+{
+ std::array m_data{1.0f, 1.0f, 1.0f};
+
+public:
+ ColorRGB() = default;
+ ColorRGB(float r, float g, float b);
+ ColorRGB(unsigned char r, unsigned char g, unsigned char b);
+ ColorRGB(const ColorRGB& other) = default;
+
+ ColorRGB& operator = (const ColorRGB& other) { m_data = other.m_data; return *this; }
+
+ bool operator == (const ColorRGB& other) const { return m_data == other.m_data; }
+ bool operator != (const ColorRGB& other) const { return !operator==(other); }
+ bool operator < (const ColorRGB& other) const;
+ bool operator > (const ColorRGB& other) const;
+
+ ColorRGB operator + (const ColorRGB& other) const;
+ ColorRGB operator * (float value) const;
+
+ const float* const data() const { return m_data.data(); }
+
+ float r() const { return m_data[0]; }
+ float g() const { return m_data[1]; }
+ float b() const { return m_data[2]; }
+
+ void r(float r) { m_data[0] = std::clamp(r, 0.0f, 1.0f); }
+ void g(float g) { m_data[1] = std::clamp(g, 0.0f, 1.0f); }
+ void b(float b) { m_data[2] = std::clamp(b, 0.0f, 1.0f); }
+
+ void set(unsigned int comp, float value) {
+ assert(0 <= comp && comp <= 2);
+ m_data[comp] = std::clamp(value, 0.0f, 1.0f);
+ }
+
+ unsigned char r_uchar() const { return static_cast(m_data[0] * 255.0f); }
+ unsigned char g_uchar() const { return static_cast(m_data[1] * 255.0f); }
+ unsigned char b_uchar() const { return static_cast(m_data[2] * 255.0f); }
+
+ static const ColorRGB BLACK() { return { 0.0f, 0.0f, 0.0f }; }
+ static const ColorRGB BLUE() { return { 0.0f, 0.0f, 1.0f }; }
+ static const ColorRGB BLUEISH() { return { 0.5f, 0.5f, 1.0f }; }
+ static const ColorRGB DARK_GRAY() { return { 0.25f, 0.25f, 0.25f }; }
+ static const ColorRGB DARK_YELLOW() { return { 0.5f, 0.5f, 0.0f }; }
+ static const ColorRGB GRAY() { return { 0.5f, 0.5f, 0.5f }; }
+ static const ColorRGB GREEN() { return { 0.0f, 1.0f, 0.0f }; }
+ static const ColorRGB GREENISH() { return { 0.5f, 1.0f, 0.5f }; }
+ static const ColorRGB LIGHT_GRAY() { return { 0.75f, 0.75f, 0.75f }; }
+ static const ColorRGB ORANGE() { return { 0.92f, 0.50f, 0.26f }; }
+ static const ColorRGB RED() { return { 1.0f, 0.0f, 0.0f }; }
+ static const ColorRGB REDISH() { return { 1.0f, 0.5f, 0.5f }; }
+ static const ColorRGB YELLOW() { return { 1.0f, 1.0f, 0.0f }; }
+ static const ColorRGB WHITE() { return { 1.0f, 1.0f, 1.0f }; }
+
+ static const ColorRGB X() { return { 0.75f, 0.0f, 0.0f }; }
+ static const ColorRGB Y() { return { 0.0f, 0.75f, 0.0f }; }
+ static const ColorRGB Z() { return { 0.0f, 0.0f, 0.75f }; }
+};
+
+class ColorRGBA
+{
+ std::array m_data{ 1.0f, 1.0f, 1.0f, 1.0f };
+
+public:
+ ColorRGBA() = default;
+ ColorRGBA(float r, float g, float b, float a);
+ ColorRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+ ColorRGBA(const ColorRGBA& other) = default;
+
+ ColorRGBA& operator = (const ColorRGBA& other) { m_data = other.m_data; return *this; }
+
+ bool operator == (const ColorRGBA& other) const { return m_data == other.m_data; }
+ bool operator != (const ColorRGBA& other) const { return !operator==(other); }
+ bool operator < (const ColorRGBA& other) const;
+ bool operator > (const ColorRGBA& other) const;
+
+ ColorRGBA operator + (const ColorRGBA& other) const;
+ ColorRGBA operator * (float value) const;
+
+ const float* const data() const { return m_data.data(); }
+
+ float r() const { return m_data[0]; }
+ float g() const { return m_data[1]; }
+ float b() const { return m_data[2]; }
+ float a() const { return m_data[3]; }
+
+ void r(float r) { m_data[0] = std::clamp(r, 0.0f, 1.0f); }
+ void g(float g) { m_data[1] = std::clamp(g, 0.0f, 1.0f); }
+ void b(float b) { m_data[2] = std::clamp(b, 0.0f, 1.0f); }
+ void a(float a) { m_data[3] = std::clamp(a, 0.0f, 1.0f); }
+
+ void set(unsigned int comp, float value) {
+ assert(0 <= comp && comp <= 3);
+ m_data[comp] = std::clamp(value, 0.0f, 1.0f);
+ }
+
+ unsigned char r_uchar() const { return static_cast(m_data[0] * 255.0f); }
+ unsigned char g_uchar() const { return static_cast(m_data[1] * 255.0f); }
+ unsigned char b_uchar() const { return static_cast(m_data[2] * 255.0f); }
+ unsigned char a_uchar() const { return static_cast(m_data[3] * 255.0f); }
+
+ bool is_transparent() const { return m_data[3] < 1.0f; }
+
+ static const ColorRGBA BLACK() { return { 0.0f, 0.0f, 0.0f, 1.0f }; }
+ static const ColorRGBA BLUE() { return { 0.0f, 0.0f, 1.0f, 1.0f }; }
+ static const ColorRGBA BLUEISH() { return { 0.5f, 0.5f, 1.0f, 1.0f }; }
+ static const ColorRGBA DARK_GRAY() { return { 0.25f, 0.25f, 0.25f, 1.0f }; }
+ static const ColorRGBA DARK_YELLOW() { return { 0.5f, 0.5f, 0.0f, 1.0f }; }
+ static const ColorRGBA GRAY() { return { 0.5f, 0.5f, 0.5f, 1.0f }; }
+ static const ColorRGBA GREEN() { return { 0.0f, 1.0f, 0.0f, 1.0f }; }
+ static const ColorRGBA GREENISH() { return { 0.5f, 1.0f, 0.5f, 1.0f }; }
+ static const ColorRGBA LIGHT_GRAY() { return { 0.75f, 0.75f, 0.75f, 1.0f }; }
+ static const ColorRGBA ORANGE() { return { 0.923f, 0.504f, 0.264f, 1.0f }; }
+ static const ColorRGBA RED() { return { 1.0f, 0.0f, 0.0f, 1.0f }; }
+ static const ColorRGBA REDISH() { return { 1.0f, 0.5f, 0.5f, 1.0f }; }
+ static const ColorRGBA YELLOW() { return { 1.0f, 1.0f, 0.0f, 1.0f }; }
+ static const ColorRGBA WHITE() { return { 1.0f, 1.0f, 1.0f, 1.0f }; }
+
+ static const ColorRGBA X() { return { 0.75f, 0.0f, 0.0f, 1.0f }; }
+ static const ColorRGBA Y() { return { 0.0f, 0.75f, 0.0f, 1.0f }; }
+ static const ColorRGBA Z() { return { 0.0f, 0.0f, 0.75f, 1.0f }; }
+};
+
+extern ColorRGB operator * (float value, const ColorRGB& other);
+extern ColorRGBA operator * (float value, const ColorRGBA& other);
+
+extern ColorRGB lerp(const ColorRGB& a, const ColorRGB& b, float t);
+extern ColorRGBA lerp(const ColorRGBA& a, const ColorRGBA& b, float t);
+
+extern ColorRGB complementary(const ColorRGB& color);
+extern ColorRGBA complementary(const ColorRGBA& color);
+
+extern ColorRGB saturate(const ColorRGB& color, float factor);
+extern ColorRGBA saturate(const ColorRGBA& color, float factor);
+
+extern ColorRGB opposite(const ColorRGB& color);
+extern ColorRGB opposite(const ColorRGB& a, const ColorRGB& b);
+
+extern bool can_decode_color(const std::string& color);
+
+extern bool decode_color(const std::string& color_in, ColorRGB& color_out);
+extern bool decode_color(const std::string& color_in, ColorRGBA& color_out);
+
+extern bool decode_colors(const std::vector& colors_in, std::vector& colors_out);
+extern bool decode_colors(const std::vector& colors_in, std::vector& colors_out);
+
+extern std::string encode_color(const ColorRGB& color);
+extern std::string encode_color(const ColorRGBA& color);
+
+extern ColorRGB to_rgb(const ColorRGBA& other_rgba);
+extern ColorRGBA to_rgba(const ColorRGB& other_rgb);
+extern ColorRGBA to_rgba(const ColorRGB& other_rgb, float alpha);
+
+extern ColorRGBA picking_decode(unsigned int id);
+extern unsigned int picking_encode(unsigned char r, unsigned char g, unsigned char b);
+// Produce an alpha channel checksum for the red green blue components. The alpha channel may then be used to verify, whether the rgb components
+// were not interpolated by alpha blending or multi sampling.
+extern unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue);
+
+} // namespace Slic3r
+
+#endif /* slic3r_Color_hpp_ */
diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp
index f54e38eec8..1f19a548e7 100644
--- a/src/libslic3r/GCode/GCodeProcessor.cpp
+++ b/src/libslic3r/GCode/GCodeProcessor.cpp
@@ -189,6 +189,9 @@ void GCodeProcessor::TimeMachine::reset()
max_travel_acceleration = 0.0f;
extrude_factor_override_percentage = 1.0f;
time = 0.0f;
+#if ENABLE_TRAVEL_TIME
+ travel_time = 0.0f;
+#endif // ENABLE_TRAVEL_TIME
stop_times = std::vector();
curr.reset();
prev.reset();
@@ -304,9 +307,17 @@ void GCodeProcessor::TimeMachine::calculate_time(size_t keep_last_n_blocks, floa
block_time += additional_time;
time += block_time;
+#if ENABLE_TRAVEL_TIME
+ if (block.move_type == EMoveType::Travel)
+ travel_time += block_time;
+ else
+ roles_time[static_cast(block.role)] += block_time;
+#endif // ENABLE_TRAVEL_TIME
gcode_time.cache += block_time;
moves_time[static_cast(block.move_type)] += block_time;
+#if !ENABLE_TRAVEL_TIME
roles_time[static_cast(block.role)] += block_time;
+#endif // !ENABLE_TRAVEL_TIME
if (block.layer_id >= layers_time.size()) {
const size_t curr_size = layers_time.size();
layers_time.resize(block.layer_id);
@@ -1363,6 +1374,18 @@ std::string GCodeProcessor::get_time_dhm(PrintEstimatedStatistics::ETimeMode mod
return (mode < PrintEstimatedStatistics::ETimeMode::Count) ? short_time(get_time_dhms(m_time_processor.machines[static_cast(mode)].time)) : std::string("N/A");
}
+#if ENABLE_TRAVEL_TIME
+float GCodeProcessor::get_travel_time(PrintEstimatedStatistics::ETimeMode mode) const
+{
+ return (mode < PrintEstimatedStatistics::ETimeMode::Count) ? m_time_processor.machines[static_cast(mode)].travel_time : 0.0f;
+}
+
+std::string GCodeProcessor::get_travel_time_dhm(PrintEstimatedStatistics::ETimeMode mode) const
+{
+ return (mode < PrintEstimatedStatistics::ETimeMode::Count) ? short_time(get_time_dhms(m_time_processor.machines[static_cast(mode)].travel_time)) : std::string("N/A");
+}
+#endif // ENABLE_TRAVEL_TIME
+
std::vector>> GCodeProcessor::get_custom_gcode_times(PrintEstimatedStatistics::ETimeMode mode, bool include_remaining) const
{
std::vector>> ret;
@@ -3372,6 +3395,9 @@ void GCodeProcessor::update_estimated_times_stats()
auto update_mode = [this](PrintEstimatedStatistics::ETimeMode mode) {
PrintEstimatedStatistics::Mode& data = m_result.print_statistics.modes[static_cast(mode)];
data.time = get_time(mode);
+#if ENABLE_TRAVEL_TIME
+ data.travel_time = get_travel_time(mode);
+#endif // ENABLE_TRAVEL_TIME
data.custom_gcode_times = get_custom_gcode_times(mode, true);
data.moves_times = get_moves_time(mode);
data.roles_times = get_roles_time(mode);
diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp
index 2b6ee9cea9..33b9a23f38 100644
--- a/src/libslic3r/GCode/GCodeProcessor.hpp
+++ b/src/libslic3r/GCode/GCodeProcessor.hpp
@@ -44,6 +44,9 @@ namespace Slic3r {
struct Mode
{
float time;
+#if ENABLE_TRAVEL_TIME
+ float travel_time;
+#endif // ENABLE_TRAVEL_TIME
std::vector>> custom_gcode_times;
std::vector> moves_times;
std::vector> roles_times;
@@ -51,6 +54,9 @@ namespace Slic3r {
void reset() {
time = 0.0f;
+#if ENABLE_TRAVEL_TIME
+ travel_time = 0.0f;
+#endif // ENABLE_TRAVEL_TIME
custom_gcode_times.clear();
moves_times.clear();
roles_times.clear();
@@ -290,6 +296,9 @@ namespace Slic3r {
float max_travel_acceleration; // mm/s^2
float extrude_factor_override_percentage;
float time; // s
+#if ENABLE_TRAVEL_TIME
+ float travel_time; // s
+#endif // ENABLE_TRAVEL_TIME
struct StopTime
{
unsigned int g1_line_id;
@@ -596,6 +605,10 @@ namespace Slic3r {
float get_time(PrintEstimatedStatistics::ETimeMode mode) const;
std::string get_time_dhm(PrintEstimatedStatistics::ETimeMode mode) const;
+#if ENABLE_TRAVEL_TIME
+ float get_travel_time(PrintEstimatedStatistics::ETimeMode mode) const;
+ std::string get_travel_time_dhm(PrintEstimatedStatistics::ETimeMode mode) const;
+#endif // ENABLE_TRAVEL_TIME
std::vector>> get_custom_gcode_times(PrintEstimatedStatistics::ETimeMode mode, bool include_remaining) const;
std::vector> get_moves_time(PrintEstimatedStatistics::ETimeMode mode) const;
diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp
index 6764b197d1..dd6a2e03cc 100644
--- a/src/libslic3r/Preset.hpp
+++ b/src/libslic3r/Preset.hpp
@@ -116,6 +116,8 @@ public:
// This type is here to support PresetConfigSubstitutions for physical printers, however it does not belong to the Preset class,
// PhysicalPrinter class is used instead.
TYPE_PHYSICAL_PRINTER,
+ // This type is here to support search through the Preferences
+ TYPE_PREFERENCES,
};
Type type = TYPE_INVALID;
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index 2048dc66e9..34a06a18dc 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -2753,7 +2753,8 @@ void PrintConfigDef::init_fff_params()
def->label = L("Synchronize with object layers");
def->category = L("Support material");
def->tooltip = L("Synchronize support layers with the object print layers. This is useful "
- "with multi-material printers, where the extruder switch is expensive.");
+ "with multi-material printers, where the extruder switch is expensive. "
+ "This option is only available when top contact Z distance is set to zero.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false));
diff --git a/src/libslic3r/SLA/AGGRaster.hpp b/src/libslic3r/SLA/AGGRaster.hpp
index 2243a3c1b5..bc68cd3778 100644
--- a/src/libslic3r/SLA/AGGRaster.hpp
+++ b/src/libslic3r/SLA/AGGRaster.hpp
@@ -3,7 +3,6 @@
#include
#include "libslic3r/ExPolygon.hpp"
-#include "libslic3r/MTUtils.hpp"
// For rasterizing
#include
diff --git a/src/libslic3r/SLA/RasterBase.cpp b/src/libslic3r/SLA/RasterBase.cpp
index 581e84880b..cc9aca0274 100644
--- a/src/libslic3r/SLA/RasterBase.cpp
+++ b/src/libslic3r/SLA/RasterBase.cpp
@@ -77,6 +77,8 @@ std::unique_ptr create_raster_grayscale_aa(
if (gamma > 0)
rst = std::make_unique(res, pxdim, tr, gamma);
+ else if (std::abs(gamma - 1.) < 1e-6)
+ rst = std::make_unique(res, pxdim, tr, agg::gamma_none());
else
rst = std::make_unique(res, pxdim, tr, agg::gamma_threshold(.5));
diff --git a/src/libslic3r/SLA/RasterBase.hpp b/src/libslic3r/SLA/RasterBase.hpp
index 1eba360e31..6439830fe8 100644
--- a/src/libslic3r/SLA/RasterBase.hpp
+++ b/src/libslic3r/SLA/RasterBase.hpp
@@ -9,7 +9,7 @@
#include
#include
-#include
+//#include
namespace Slic3r {
diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp
index 833146985a..0622bec4e5 100644
--- a/src/libslic3r/SLAPrint.hpp
+++ b/src/libslic3r/SLAPrint.hpp
@@ -10,6 +10,8 @@
#include "MTUtils.hpp"
#include "Zipper.hpp"
+#include "libslic3r/Execution/ExecutionTBB.hpp"
+
namespace Slic3r {
enum SLAPrintStep : unsigned int {
diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp
index fff1d6b5d4..f267d4f55f 100644
--- a/src/libslic3r/Technologies.hpp
+++ b/src/libslic3r/Technologies.hpp
@@ -49,4 +49,19 @@
#define ENABLE_NEW_CAMERA_MOVEMENTS_SHIFT_SELECTION (1 && ENABLE_2_4_1_RC)
+//====================
+// 2.5.0.alpha1 techs
+//====================
+#define ENABLE_2_5_0_ALPHA1 1
+
+// Enable changes in preview layout
+#define ENABLE_PREVIEW_LAYOUT (1 && ENABLE_2_5_0_ALPHA1)
+// Enable drawing the items in legend toolbar using icons
+#define ENABLE_LEGEND_TOOLBAR_ICONS (1 && ENABLE_PREVIEW_LAYOUT)
+// Enable coloring of toolpaths in preview by layer time
+#define ENABLE_PREVIEW_LAYER_TIME (1 && ENABLE_2_5_0_ALPHA1)
+// Enable showing time estimate for travel moves in legend
+#define ENABLE_TRAVEL_TIME (1 && ENABLE_2_5_0_ALPHA1)
+
+
#endif // _prusaslicer_technologies_h_
diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp
index d9419495ee..2562d1913a 100644
--- a/src/libslic3r/Utils.hpp
+++ b/src/libslic3r/Utils.hpp
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
#include
@@ -360,7 +361,7 @@ inline std::string get_time_dhms(float time_in_secs)
else if (minutes > 0)
::sprintf(buffer, "%dm %ds", minutes, (int)time_in_secs);
else
- ::sprintf(buffer, "%ds", (int)time_in_secs);
+ ::sprintf(buffer, "%ds", (int)std::round(time_in_secs));
return buffer;
}
diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index 34cc980513..34c0efd014 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -169,9 +169,11 @@ set(SLIC3R_GUI_SOURCES
GUI/PrintHostDialogs.cpp
GUI/PrintHostDialogs.hpp
GUI/Jobs/Job.hpp
- GUI/Jobs/Job.cpp
- GUI/Jobs/PlaterJob.hpp
- GUI/Jobs/PlaterJob.cpp
+ GUI/Jobs/Worker.hpp
+ GUI/Jobs/BoostThreadWorker.hpp
+ GUI/Jobs/BoostThreadWorker.cpp
+ GUI/Jobs/BusyCursorJob.hpp
+ GUI/Jobs/PlaterWorker.hpp
GUI/Jobs/ArrangeJob.hpp
GUI/Jobs/ArrangeJob.cpp
GUI/Jobs/RotoptimizeJob.hpp
@@ -183,6 +185,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Jobs/ProgressIndicator.hpp
GUI/Jobs/NotificationProgressIndicator.hpp
GUI/Jobs/NotificationProgressIndicator.cpp
+ GUI/Jobs/ThreadSafeQueue.hpp
+ GUI/Jobs/SLAImportDialog.hpp
GUI/ProgressStatusBar.hpp
GUI/ProgressStatusBar.cpp
GUI/Mouse3DController.cpp
@@ -258,6 +262,12 @@ endif ()
add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES})
+foreach(_source IN ITEMS ${SLIC3R_GUI_SOURCES})
+ get_filename_component(_source_path "${_source}" PATH)
+ string(REPLACE "/" "\\" _group_path "${_source_path}")
+ source_group("${_group_path}" FILES "${_source}")
+endforeach()
+
encoding_check(libslic3r_gui)
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES})
diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp
index bd5ca9f521..21e23d402e 100644
--- a/src/slic3r/GUI/3DBed.cpp
+++ b/src/slic3r/GUI/3DBed.cpp
@@ -19,8 +19,10 @@
#include
static const float GROUND_Z = -0.02f;
-static const std::array DEFAULT_MODEL_COLOR = { 0.235f, 0.235f, 0.235f, 1.0f };
-static const std::array PICKING_MODEL_COLOR = { 0.0f, 0.0f, 0.0f, 1.0f };
+static const Slic3r::ColorRGBA DEFAULT_MODEL_COLOR = Slic3r::ColorRGBA::DARK_GRAY();
+static const Slic3r::ColorRGBA PICKING_MODEL_COLOR = Slic3r::ColorRGBA::BLACK();
+static const Slic3r::ColorRGBA DEFAULT_SOLID_GRID_COLOR = { 0.9f, 0.9f, 0.9f, 1.0f };
+static const Slic3r::ColorRGBA DEFAULT_TRANSPARENT_GRID_COLOR = { 0.9f, 0.9f, 0.9f, 0.6f };
namespace Slic3r {
namespace GUI {
@@ -121,15 +123,15 @@ void Bed3D::Axes::render() const
shader->set_uniform("emission_factor", 0.0f);
// x axis
- const_cast(&m_arrow)->set_color(-1, { 0.75f, 0.0f, 0.0f, 1.0f });
+ const_cast(&m_arrow)->set_color(-1, ColorRGBA::X());
render_axis(Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0 }).cast());
// y axis
- const_cast(&m_arrow)->set_color(-1, { 0.0f, 0.75f, 0.0f, 1.0f });
+ const_cast(&m_arrow)->set_color(-1, ColorRGBA::Y());
render_axis(Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0 }).cast());
// z axis
- const_cast(&m_arrow)->set_color(-1, { 0.0f, 0.0f, 0.75f, 1.0f });
+ const_cast(&m_arrow)->set_color(-1, ColorRGBA::Z());
render_axis(Geometry::assemble_transform(m_origin).cast());
shader->stop_using();
@@ -550,10 +552,7 @@ void Bed3D::render_default(bool bottom, bool picking) const
if (!picking) {
// draw grid
glsafe(::glLineWidth(1.5f * m_scale_factor));
- if (has_model && !bottom)
- glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 1.0f));
- else
- glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 0.6f));
+ glsafe(::glColor4fv(has_model && !bottom ? DEFAULT_SOLID_GRID_COLOR.data() : DEFAULT_TRANSPARENT_GRID_COLOR.data()));
glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_gridlines.get_vertices_data()));
glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)m_gridlines.get_vertices_count()));
}
diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp
index 263ba0e73a..93f0548bcb 100644
--- a/src/slic3r/GUI/3DScene.cpp
+++ b/src/slic3r/GUI/3DScene.cpp
@@ -344,20 +344,20 @@ void GLVolume::SinkingContours::update()
m_model.reset();
}
-const std::array GLVolume::SELECTED_COLOR = { 0.0f, 1.0f, 0.0f, 1.0f };
-const std::array GLVolume::HOVER_SELECT_COLOR = { 0.4f, 0.9f, 0.1f, 1.0f };
-const std::array GLVolume::HOVER_DESELECT_COLOR = { 1.0f, 0.75f, 0.75f, 1.0f };
-const std::array GLVolume::OUTSIDE_COLOR = { 0.0f, 0.38f, 0.8f, 1.0f };
-const std::array GLVolume::SELECTED_OUTSIDE_COLOR = { 0.19f, 0.58f, 1.0f, 1.0f };
-const std::array GLVolume::DISABLED_COLOR = { 0.25f, 0.25f, 0.25f, 1.0f };
-const std::array GLVolume::SLA_SUPPORT_COLOR = { 0.75f, 0.75f, 0.75f, 1.0f };
-const std::array GLVolume::SLA_PAD_COLOR = { 0.0f, 0.2f, 0.0f, 1.0f };
-const std::array GLVolume::NEUTRAL_COLOR = { 0.9f, 0.9f, 0.9f, 1.0f };
-const std::array, 4> GLVolume::MODEL_COLOR = { {
- { 1.0f, 1.0f, 0.0f, 1.f },
- { 1.0f, 0.5f, 0.5f, 1.f },
- { 0.5f, 1.0f, 0.5f, 1.f },
- { 0.5f, 0.5f, 1.0f, 1.f }
+const ColorRGBA GLVolume::SELECTED_COLOR = ColorRGBA::GREEN();
+const ColorRGBA GLVolume::HOVER_SELECT_COLOR = { 0.4f, 0.9f, 0.1f, 1.0f };
+const ColorRGBA GLVolume::HOVER_DESELECT_COLOR = { 1.0f, 0.75f, 0.75f, 1.0f };
+const ColorRGBA GLVolume::OUTSIDE_COLOR = { 0.0f, 0.38f, 0.8f, 1.0f };
+const ColorRGBA GLVolume::SELECTED_OUTSIDE_COLOR = { 0.19f, 0.58f, 1.0f, 1.0f };
+const ColorRGBA GLVolume::DISABLED_COLOR = ColorRGBA::DARK_GRAY();
+const ColorRGBA GLVolume::SLA_SUPPORT_COLOR = ColorRGBA::LIGHT_GRAY();
+const ColorRGBA GLVolume::SLA_PAD_COLOR = { 0.0f, 0.2f, 0.0f, 1.0f };
+const ColorRGBA GLVolume::NEUTRAL_COLOR = { 0.9f, 0.9f, 0.9f, 1.0f };
+const std::array GLVolume::MODEL_COLOR = { {
+ ColorRGBA::YELLOW(),
+ { 1.0f, 0.5f, 0.5f, 1.0f },
+ { 0.5f, 1.0f, 0.5f, 1.0f },
+ { 0.5f, 0.5f, 1.0f, 1.0f }
} };
GLVolume::GLVolume(float r, float g, float b, float a)
@@ -388,21 +388,6 @@ GLVolume::GLVolume(float r, float g, float b, float a)
set_render_color(color);
}
-void GLVolume::set_color(const std::array& rgba)
-{
- color = rgba;
-}
-
-void GLVolume::set_render_color(float r, float g, float b, float a)
-{
- render_color = { r, g, b, a };
-}
-
-void GLVolume::set_render_color(const std::array& rgba)
-{
- render_color = rgba;
-}
-
void GLVolume::set_render_color()
{
bool outside = is_outside || is_below_printbed();
@@ -432,40 +417,28 @@ void GLVolume::set_render_color()
set_render_color(color);
}
- if (!printable) {
- render_color[0] /= 4;
- render_color[1] /= 4;
- render_color[2] /= 4;
- }
+ if (!printable)
+ render_color = saturate(render_color, 0.25f);
if (force_transparent)
- render_color[3] = color[3];
+ render_color.a(color.a());
}
-std::array color_from_model_volume(const ModelVolume& model_volume)
+ColorRGBA color_from_model_volume(const ModelVolume& model_volume)
{
- std::array color;
- if (model_volume.is_negative_volume()) {
- color[0] = 0.2f;
- color[1] = 0.2f;
- color[2] = 0.2f;
- }
- else if (model_volume.is_modifier()) {
- color[0] = 1.0f;
- color[1] = 1.0f;
- color[2] = 0.2f;
- }
- else if (model_volume.is_support_blocker()) {
- color[0] = 1.0f;
- color[1] = 0.2f;
- color[2] = 0.2f;
- }
- else if (model_volume.is_support_enforcer()) {
- color[0] = 0.2f;
- color[1] = 0.2f;
- color[2] = 1.0f;
- }
- color[3] = model_volume.is_model_part() ? 1.f : 0.5f;
+ ColorRGBA color;
+ if (model_volume.is_negative_volume())
+ color = { 0.2f, 0.2f, 0.2f, 1.0f };
+ else if (model_volume.is_modifier())
+ color = { 1.0, 1.0f, 0.2f, 1.0f };
+ else if (model_volume.is_support_blocker())
+ color = { 1.0f, 0.2f, 0.2f, 1.0f };
+ else if (model_volume.is_support_enforcer())
+ color = { 0.2f, 0.2f, 1.0f, 1.0f };
+
+ if (!model_volume.is_model_part())
+ color.a(0.5f);
+
return color;
}
@@ -625,8 +598,8 @@ int GLVolumeCollection::load_object_volume(
const int extruder_id = model_volume->extruder_id();
const ModelInstance *instance = model_object->instances[instance_idx];
const TriangleMesh &mesh = model_volume->mesh();
- std::array color = GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4];
- color[3] = model_volume->is_model_part() ? 1.f : 0.5f;
+ ColorRGBA color = GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4];
+ color.a(model_volume->is_model_part() ? 1.0f : 0.5f);
this->volumes.emplace_back(new GLVolume(color));
GLVolume& v = *this->volumes.back();
v.set_color(color_from_model_volume(*model_volume));
@@ -707,13 +680,13 @@ int GLVolumeCollection::load_wipe_tower_preview(
height = 0.1f;
TriangleMesh mesh;
- std::array color = { 0.5f, 0.5f, 0.0f, 1.0f };
+ ColorRGBA color = ColorRGBA::DARK_YELLOW();
// In case we don't know precise dimensions of the wipe tower yet, we'll draw
// the box with different color with one side jagged:
if (size_unknown) {
- color[0] = 0.9f;
- color[1] = 0.6f;
+ color.r(0.9f);
+ color.g(0.6f);
// Too narrow tower would interfere with the teeth. The estimate is not precise anyway.
depth = std::max(depth, 10.f);
@@ -769,14 +742,14 @@ int GLVolumeCollection::load_wipe_tower_preview(
return int(volumes.size() - 1);
}
-GLVolume* GLVolumeCollection::new_toolpath_volume(const std::array& rgba, size_t reserve_vbo_floats)
+GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats)
{
GLVolume *out = new_nontoolpath_volume(rgba, reserve_vbo_floats);
out->is_extrusion_path = true;
return out;
}
-GLVolume* GLVolumeCollection::new_nontoolpath_volume(const std::array& rgba, size_t reserve_vbo_floats)
+GLVolume* GLVolumeCollection::new_nontoolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats)
{
GLVolume *out = new GLVolume(rgba);
out->is_extrusion_path = false;
@@ -793,7 +766,7 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo
for (unsigned int i = 0; i < (unsigned int)volumes.size(); ++i) {
GLVolume* volume = volumes[i];
- bool is_transparent = (volume->render_color[3] < 1.0f);
+ bool is_transparent = volume->render_color.is_transparent();
if (((type == GLVolumeCollection::ERenderType::Opaque && !is_transparent) ||
(type == GLVolumeCollection::ERenderType::Transparent && is_transparent) ||
type == GLVolumeCollection::ERenderType::All) &&
@@ -972,8 +945,7 @@ bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, Mo
void GLVolumeCollection::reset_outside_state()
{
- for (GLVolume* volume : this->volumes)
- {
+ for (GLVolume* volume : this->volumes) {
if (volume != nullptr)
volume->is_outside = false;
}
@@ -981,46 +953,18 @@ void GLVolumeCollection::reset_outside_state()
void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* config)
{
- static const float inv_255 = 1.0f / 255.0f;
+ using ColorItem = std::pair;
+ std::vector colors;
- struct Color
- {
- std::string text;
- unsigned char rgb[3];
-
- Color()
- : text("")
- {
- rgb[0] = 255;
- rgb[1] = 255;
- rgb[2] = 255;
- }
-
- void set(const std::string& text, unsigned char* rgb)
- {
- this->text = text;
- ::memcpy((void*)this->rgb, (const void*)rgb, 3 * sizeof(unsigned char));
- }
- };
-
- if (config == nullptr)
- return;
-
- unsigned char rgb[3];
- std::vector colors;
-
- if (static_cast(config->opt_int("printer_technology")) == ptSLA)
- {
+ if (static_cast(config->opt_int("printer_technology")) == ptSLA) {
const std::string& txt_color = config->opt_string("material_colour").empty() ?
print_config_def.get("material_colour")->get_default_value()->value :
config->opt_string("material_colour");
- if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb)) {
- colors.resize(1);
- colors[0].set(txt_color, rgb);
- }
- }
- else
- {
+ ColorRGBA rgba;
+ if (decode_color(txt_color, rgba))
+ colors.push_back({ txt_color, rgba });
+}
+ else {
const ConfigOptionStrings* extruders_opt = dynamic_cast(config->option("extruder_colour"));
if (extruders_opt == nullptr)
return;
@@ -1029,37 +973,35 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* con
if (filamemts_opt == nullptr)
return;
- unsigned int colors_count = std::max((unsigned int)extruders_opt->values.size(), (unsigned int)filamemts_opt->values.size());
+ size_t colors_count = std::max(extruders_opt->values.size(), filamemts_opt->values.size());
if (colors_count == 0)
return;
colors.resize(colors_count);
for (unsigned int i = 0; i < colors_count; ++i) {
- const std::string& txt_color = config->opt_string("extruder_colour", i);
- if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
- colors[i].set(txt_color, rgb);
+ const std::string& ext_color = config->opt_string("extruder_colour", i);
+ ColorRGBA rgba;
+ if (decode_color(ext_color, rgba))
+ colors[i] = { ext_color, rgba };
else {
- const std::string& txt_color = config->opt_string("filament_colour", i);
- if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
- colors[i].set(txt_color, rgb);
+ const std::string& fil_color = config->opt_string("filament_colour", i);
+ if (decode_color(fil_color, rgba))
+ colors[i] = { fil_color, rgba };
}
}
}
for (GLVolume* volume : volumes) {
- if (volume == nullptr || volume->is_modifier || volume->is_wipe_tower || (volume->volume_idx() < 0))
+ if (volume == nullptr || volume->is_modifier || volume->is_wipe_tower || volume->volume_idx() < 0)
continue;
int extruder_id = volume->extruder_id - 1;
if (extruder_id < 0 || (int)colors.size() <= extruder_id)
extruder_id = 0;
- const Color& color = colors[extruder_id];
- if (!color.text.empty()) {
- for (int i = 0; i < 3; ++i) {
- volume->color[i] = (float)color.rgb[i] * inv_255;
- }
- }
+ const ColorItem& color = colors[extruder_id];
+ if (!color.first.empty())
+ volume->color = color.second;
}
}
diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp
index 6d82e3bb7c..7ad12c3542 100644
--- a/src/slic3r/GUI/3DScene.hpp
+++ b/src/slic3r/GUI/3DScene.hpp
@@ -7,6 +7,7 @@
#include "libslic3r/TriangleMesh.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/Geometry.hpp"
+#include "libslic3r/Color.hpp"
#include "GLModel.hpp"
@@ -43,7 +44,7 @@ class ModelVolume;
enum ModelInstanceEPrintVolumeState : unsigned char;
// Return appropriate color based on the ModelVolume.
-std::array color_from_model_volume(const ModelVolume& model_volume);
+extern ColorRGBA color_from_model_volume(const ModelVolume& model_volume);
// A container for interleaved arrays of 3D vertices and normals,
// possibly indexed by triangles and / or quads.
@@ -248,16 +249,16 @@ private:
class GLVolume {
public:
- static const std::array SELECTED_COLOR;
- static const std::array HOVER_SELECT_COLOR;
- static const std::array HOVER_DESELECT_COLOR;
- static const std::array OUTSIDE_COLOR;
- static const std::array SELECTED_OUTSIDE_COLOR;
- static const std::array DISABLED_COLOR;
- static const std::array SLA_SUPPORT_COLOR;
- static const std::array SLA_PAD_COLOR;
- static const std::array NEUTRAL_COLOR;
- static const std::array, 4> MODEL_COLOR;
+ static const ColorRGBA SELECTED_COLOR;
+ static const ColorRGBA HOVER_SELECT_COLOR;
+ static const ColorRGBA HOVER_DESELECT_COLOR;
+ static const ColorRGBA OUTSIDE_COLOR;
+ static const ColorRGBA SELECTED_OUTSIDE_COLOR;
+ static const ColorRGBA DISABLED_COLOR;
+ static const ColorRGBA SLA_SUPPORT_COLOR;
+ static const ColorRGBA SLA_PAD_COLOR;
+ static const ColorRGBA NEUTRAL_COLOR;
+ static const std::array MODEL_COLOR;
enum EHoverState : unsigned char
{
@@ -267,8 +268,8 @@ public:
HS_Deselect
};
- GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f);
- GLVolume(const std::array& rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {}
+ GLVolume(float r = 1.0f, float g = 1.0f, float b = 1.0f, float a = 1.0f);
+ GLVolume(const ColorRGBA& color) : GLVolume(color.r(), color.g(), color.b(), color.a()) {}
private:
Geometry::Transformation m_instance_transformation;
@@ -305,9 +306,9 @@ private:
public:
// Color of the triangles / quads held by this volume.
- std::array color;
+ ColorRGBA color;
// Color used to render this volume.
- std::array render_color;
+ ColorRGBA render_color;
struct CompositeID {
CompositeID(int object_id, int volume_id, int instance_id) : object_id(object_id), volume_id(volume_id), instance_id(instance_id) {}
@@ -393,9 +394,8 @@ public:
return out;
}
- void set_color(const std::array& rgba);
- void set_render_color(float r, float g, float b, float a);
- void set_render_color(const std::array& rgba);
+ void set_color(const ColorRGBA& rgba) { color = rgba; }
+ void set_render_color(const ColorRGBA& rgba) { render_color = rgba; }
// Sets render color in dependence of current state
void set_render_color();
// set color according to model volume
@@ -595,8 +595,8 @@ public:
int load_wipe_tower_preview(
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized);
- GLVolume* new_toolpath_volume(const std::array& rgba, size_t reserve_vbo_floats = 0);
- GLVolume* new_nontoolpath_volume(const std::array& rgba, size_t reserve_vbo_floats = 0);
+ GLVolume* new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0);
+ GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0);
// Render the volumes by OpenGL.
void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function filter_func = std::function()) const;
diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp
index 2b21b9ee01..e444fb03c4 100644
--- a/src/slic3r/GUI/AboutDialog.cpp
+++ b/src/slic3r/GUI/AboutDialog.cpp
@@ -2,6 +2,7 @@
#include "I18N.hpp"
#include "libslic3r/Utils.hpp"
+#include "libslic3r/Color.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "MainFrame.hpp"
@@ -133,12 +134,12 @@ wxString CopyrightsDialog::get_html_text()
wxColour bgr_clr = wxGetApp().get_window_default_clr();//wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
const auto text_clr = wxGetApp().get_label_clr_default();
- const auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue());
- const auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue());
+ const auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue()));
+ const auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()));
- const wxString copyright_str = _(L("Copyright")) + "© ";
+ const wxString copyright_str = _L("Copyright") + "© ";
// TRN "Slic3r _is licensed under the_ License"
- const wxString header_str = _(L("License agreements of all following programs (libraries) are part of application license agreement"));
+ const wxString header_str = _L("License agreements of all following programs (libraries) are part of application license agreement");
wxString text = wxString::Format(
""
@@ -257,8 +258,8 @@ AboutDialog::AboutDialog()
m_html->SetMinSize(wxSize(-1, 16 * wxGetApp().em_unit()));
wxFont font = get_default_font(this);
const auto text_clr = wxGetApp().get_label_clr_default();
- auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue());
- auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue());
+ const auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue()));
+ const auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()));
const int fs = font.GetPointSize()-1;
int size[] = {fs,fs,fs,fs,fs,fs,fs};
diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp
index 39ba849d33..e23591fb62 100644
--- a/src/slic3r/GUI/BitmapCache.cpp
+++ b/src/slic3r/GUI/BitmapCache.cpp
@@ -395,21 +395,5 @@ wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsi
return wxImage_to_wxBitmap_with_alpha(std::move(image), scale);
}
-bool BitmapCache::parse_color(const std::string& scolor, unsigned char* rgb_out)
-{
- rgb_out[0] = rgb_out[1] = rgb_out[2] = 0;
- if (scolor.size() != 7 || scolor.front() != '#')
- return false;
- const char* c = scolor.data() + 1;
- for (size_t i = 0; i < 3; ++i) {
- int digit1 = hex_digit_to_int(*c++);
- int digit2 = hex_digit_to_int(*c++);
- if (digit1 == -1 || digit2 == -1)
- return false;
- rgb_out[i] = (unsigned char)(digit1 * 16 + digit2);
- }
- return true;
-}
-
} // namespace GUI
} // namespace Slic3r
diff --git a/src/slic3r/GUI/BitmapCache.hpp b/src/slic3r/GUI/BitmapCache.hpp
index 4d1d383c41..5af90c5f7b 100644
--- a/src/slic3r/GUI/BitmapCache.hpp
+++ b/src/slic3r/GUI/BitmapCache.hpp
@@ -9,9 +9,12 @@
#include
#endif
+#include "libslic3r/Color.hpp"
+
struct NSVGimage;
-namespace Slic3r { namespace GUI {
+namespace Slic3r {
+namespace GUI {
class BitmapCache
{
@@ -43,11 +46,9 @@ public:
wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false, const bool dark_mode = false, const std::string& new_color = "");
wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency, bool suppress_scaling = false, size_t border_width = 0, bool dark_mode = false);
- wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3], bool suppress_scaling = false, size_t border_width = 0, bool dark_mode = false) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE, suppress_scaling, border_width, dark_mode); }
+ wxBitmap mksolid(size_t width, size_t height, const ColorRGB& rgb, bool suppress_scaling = false, size_t border_width = 0, bool dark_mode = false) { return mksolid(width, height, rgb.r_uchar(), rgb.g_uchar(), rgb.b_uchar(), wxALPHA_OPAQUE, suppress_scaling, border_width, dark_mode); }
wxBitmap mkclear(size_t width, size_t height) { return mksolid(width, height, 0, 0, 0, wxALPHA_TRANSPARENT); }
- static bool parse_color(const std::string& scolor, unsigned char* rgb_out);
-
private:
std::map m_map;
double m_gs = 0.2; // value, used for image.ConvertToGreyscale(m_gs, m_gs, m_gs)
diff --git a/src/slic3r/GUI/ConfigSnapshotDialog.cpp b/src/slic3r/GUI/ConfigSnapshotDialog.cpp
index afa495d0c2..e2bea55d13 100644
--- a/src/slic3r/GUI/ConfigSnapshotDialog.cpp
+++ b/src/slic3r/GUI/ConfigSnapshotDialog.cpp
@@ -5,6 +5,7 @@
#include "libslic3r/Utils.hpp"
#include "libslic3r/Time.hpp"
+#include "libslic3r/Color.hpp"
#include "GUI_App.hpp"
#include "MainFrame.hpp"
#include "wxExtensions.hpp"
@@ -31,11 +32,9 @@ static wxString format_reason(const Config::Snapshot::Reason reason)
static std::string get_color(wxColour colour)
{
- wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), colour.Red(), colour.Green(), colour.Blue());
- return clr_str.ToStdString();
+ return encode_color(ColorRGB(colour.Red(), colour.Green(), colour.Blue()));
};
-
static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_even, bool snapshot_active, bool dark_mode)
{
// Start by declaring a row with an alternating background color.
diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp
index dadf5d8ca3..4ff0898820 100644
--- a/src/slic3r/GUI/ConfigWizard.cpp
+++ b/src/slic3r/GUI/ConfigWizard.cpp
@@ -36,6 +36,7 @@
#include "libslic3r/Config.hpp"
#include "libslic3r/libslic3r.h"
#include "libslic3r/Model.hpp"
+#include "libslic3r/Color.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "GUI_Utils.hpp"
@@ -746,9 +747,9 @@ void PageMaterials::set_compatible_printers_html_window(const std::vector* are not compatible with some installed printers."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials"));
wxString text;
if (all_printers) {
@@ -2522,23 +2523,33 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
{
wxString header, caption = _L("Configuration is edited in ConfigWizard");
const auto enabled_vendors = appconfig_new.vendors();
+ const auto enabled_vendors_old = app_config->vendors();
bool suppress_sla_printer = model_has_multi_part_objects(wxGetApp().model());
PrinterTechnology preferred_pt = ptAny;
- auto get_preferred_printer_technology = [enabled_vendors, suppress_sla_printer](const std::string& bundle_name, const Bundle& bundle) {
+ auto get_preferred_printer_technology = [enabled_vendors, enabled_vendors_old, suppress_sla_printer](const std::string& bundle_name, const Bundle& bundle) {
const auto config = enabled_vendors.find(bundle_name);
PrinterTechnology pt = ptAny;
if (config != enabled_vendors.end()) {
for (const auto& model : bundle.vendor_profile->models) {
if (const auto model_it = config->second.find(model.id);
model_it != config->second.end() && model_it->second.size() > 0) {
- if (pt == ptAny)
- pt = model.technology;
- // if preferred printer model has SLA printer technology it's important to check the model for multypart state
- if (pt == ptSLA && suppress_sla_printer)
- continue;
- else
+ pt = model.technology;
+ const auto config_old = enabled_vendors_old.find(bundle_name);
+ if (config_old == enabled_vendors_old.end() || config_old->second.find(model.id) == config_old->second.end()) {
+ // if preferred printer model has SLA printer technology it's important to check the model for multi-part state
+ if (pt == ptSLA && suppress_sla_printer)
+ continue;
return pt;
+ }
+
+ if (const auto model_it_old = config_old->second.find(model.id);
+ model_it_old == config_old->second.end() || model_it_old->second != model_it->second) {
+ // if preferred printer model has SLA printer technology it's important to check the model for multi-part state
+ if (pt == ptSLA && suppress_sla_printer)
+ continue;
+ return pt;
+ }
}
}
}
@@ -2645,7 +2656,6 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
std::string preferred_model;
std::string preferred_variant;
- const auto enabled_vendors_old = app_config->vendors();
auto get_preferred_printer_model = [enabled_vendors, enabled_vendors_old, preferred_pt](const std::string& bundle_name, const Bundle& bundle, std::string& variant) {
const auto config = enabled_vendors.find(bundle_name);
if (config == enabled_vendors.end())
diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp
index 3d914d5b66..ee5aacb191 100644
--- a/src/slic3r/GUI/DoubleSlider.cpp
+++ b/src/slic3r/GUI/DoubleSlider.cpp
@@ -2557,36 +2557,46 @@ bool Control::check_ticks_changed_event(Type type)
std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int extruder)
{
+ auto opposite_one_color = [](const std::string& color) {
+ ColorRGB rgb;
+ decode_color(color, rgb);
+ return encode_color(opposite(rgb));
+ };
+ auto opposite_two_colors = [](const std::string& a, const std::string& b) {
+ ColorRGB rgb1; decode_color(a, rgb1);
+ ColorRGB rgb2; decode_color(b, rgb2);
+ return encode_color(opposite(rgb1, rgb2));
+ };
+
if (mode == SingleExtruder && type == ColorChange && m_use_default_colors) {
#if 1
if (ticks.empty())
- return color_generator.get_opposite_color((*m_colors)[0]);
-
+ return opposite_one_color((*m_colors)[0]);
+
auto before_tick_it = std::lower_bound(ticks.begin(), ticks.end(), tick);
- if (before_tick_it == ticks.end())
- {
+ if (before_tick_it == ticks.end()) {
while (before_tick_it != ticks.begin())
if (--before_tick_it; before_tick_it->type == ColorChange)
break;
if (before_tick_it->type == ColorChange)
- return color_generator.get_opposite_color(before_tick_it->color);
- return color_generator.get_opposite_color((*m_colors)[0]);
+ return opposite_one_color(before_tick_it->color);
+
+ return opposite_one_color((*m_colors)[0]);
}
- if (before_tick_it == ticks.begin())
- {
+ if (before_tick_it == ticks.begin()) {
const std::string& frst_color = (*m_colors)[0];
if (before_tick_it->type == ColorChange)
- return color_generator.get_opposite_color(frst_color, before_tick_it->color);
+ return opposite_two_colors(frst_color, before_tick_it->color);
auto next_tick_it = before_tick_it;
while (next_tick_it != ticks.end())
if (++next_tick_it; next_tick_it->type == ColorChange)
break;
if (next_tick_it->type == ColorChange)
- return color_generator.get_opposite_color(frst_color, next_tick_it->color);
+ return opposite_two_colors(frst_color, next_tick_it->color);
- return color_generator.get_opposite_color(frst_color);
+ return opposite_one_color(frst_color);
}
std::string frst_color = "";
@@ -2607,13 +2617,15 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int
if (before_tick_it->type == ColorChange) {
if (frst_color.empty())
- return color_generator.get_opposite_color(before_tick_it->color);
- return color_generator.get_opposite_color(before_tick_it->color, frst_color);
+ return opposite_one_color(before_tick_it->color);
+
+ return opposite_two_colors(before_tick_it->color, frst_color);
}
if (frst_color.empty())
- return color_generator.get_opposite_color((*m_colors)[0]);
- return color_generator.get_opposite_color((*m_colors)[0], frst_color);
+ return opposite_one_color((*m_colors)[0]);
+
+ return opposite_two_colors((*m_colors)[0], frst_color);
#else
const std::vector& colors = ColorPrintColors::get();
if (ticks.empty())
diff --git a/src/slic3r/GUI/DoubleSlider.hpp b/src/slic3r/GUI/DoubleSlider.hpp
index 23275cf2ad..e0f713d879 100644
--- a/src/slic3r/GUI/DoubleSlider.hpp
+++ b/src/slic3r/GUI/DoubleSlider.hpp
@@ -3,7 +3,6 @@
#include "libslic3r/CustomGCode.hpp"
#include "wxExtensions.hpp"
-#include "DoubleSlider_Utils.hpp"
#include
#include
@@ -119,7 +118,6 @@ class TickCodeInfo
// int m_default_color_idx = 0;
std::vector* m_colors {nullptr};
- ColorGenerator color_generator;
std::string get_color_for_tick(TickCode tick, Type type, const int extruder);
diff --git a/src/slic3r/GUI/DoubleSlider_Utils.hpp b/src/slic3r/GUI/DoubleSlider_Utils.hpp
index b5955f2fc4..283d527fa4 100644
--- a/src/slic3r/GUI/DoubleSlider_Utils.hpp
+++ b/src/slic3r/GUI/DoubleSlider_Utils.hpp
@@ -1,191 +1,8 @@
+#ifndef slic3r_GUI_DoubleSlider_Utils_hpp_
+#define slic3r_GUI_DoubleSlider_Utils_hpp_
+
#include
#include
-#include "wx/colour.h"
-class ColorGenerator
-{
- // Some of next code is borrowed from https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both
- typedef struct {
- double r; // a fraction between 0 and 1
- double g; // a fraction between 0 and 1
- double b; // a fraction between 0 and 1
- } rgb;
-
- typedef struct {
- double h; // angle in degrees
- double s; // a fraction between 0 and 1
- double v; // a fraction between 0 and 1
- } hsv;
-
- //static hsv rgb2hsv(rgb in);
- //static rgb hsv2rgb(hsv in);
-
- hsv rgb2hsv(rgb in)
- {
- hsv out;
- double min, max, delta;
-
- min = in.r < in.g ? in.r : in.g;
- min = min < in.b ? min : in.b;
-
- max = in.r > in.g ? in.r : in.g;
- max = max > in.b ? max : in.b;
-
- out.v = max; // v
- delta = max - min;
- if (delta < 0.00001)
- {
- out.s = 0;
- out.h = 0; // undefined, maybe nan?
- return out;
- }
- if (max > 0.0) { // NOTE: if Max is == 0, this divide would cause a crash
- out.s = (delta / max); // s
- }
- else {
- // if max is 0, then r = g = b = 0
- // s = 0, h is undefined
- out.s = 0.0;
- out.h = NAN; // its now undefined
- return out;
- }
- if (in.r >= max) // > is bogus, just keeps compilor happy
- out.h = (in.g - in.b) / delta; // between yellow & magenta
- else
- if (in.g >= max)
- out.h = 2.0 + (in.b - in.r) / delta; // between cyan & yellow
- else
- out.h = 4.0 + (in.r - in.g) / delta; // between magenta & cyan
-
- out.h *= 60.0; // degrees
-
- if (out.h < 0.0)
- out.h += 360.0;
-
- return out;
- }
-
- hsv rgb2hsv(const std::string& str_clr_in)
- {
- wxColour clr(str_clr_in);
- rgb in = { clr.Red() / 255.0, clr.Green() / 255.0, clr.Blue() / 255.0 };
- return rgb2hsv(in);
- }
-
-
- rgb hsv2rgb(hsv in)
- {
- double hh, p, q, t, ff;
- long i;
- rgb out;
-
- if (in.s <= 0.0) { // < is bogus, just shuts up warnings
- out.r = in.v;
- out.g = in.v;
- out.b = in.v;
- return out;
- }
- hh = in.h;
- if (hh >= 360.0) hh -= 360.0;//hh = 0.0;
- hh /= 60.0;
- i = (long)hh;
- ff = hh - i;
- p = in.v * (1.0 - in.s);
- q = in.v * (1.0 - (in.s * ff));
- t = in.v * (1.0 - (in.s * (1.0 - ff)));
-
- switch (i) {
- case 0:
- out.r = in.v;
- out.g = t;
- out.b = p;
- break;
- case 1:
- out.r = q;
- out.g = in.v;
- out.b = p;
- break;
- case 2:
- out.r = p;
- out.g = in.v;
- out.b = t;
- break;
-
- case 3:
- out.r = p;
- out.g = q;
- out.b = in.v;
- break;
- case 4:
- out.r = t;
- out.g = p;
- out.b = in.v;
- break;
- case 5:
- default:
- out.r = in.v;
- out.g = p;
- out.b = q;
- break;
- }
- return out;
- }
-
- std::random_device rd;
-
-public:
-
- ColorGenerator() {}
- ~ColorGenerator() {}
-
- double rand_val()
- {
- std::mt19937 rand_generator(rd());
-
- // this value will be used for Saturation and Value
- // to avoid extremely light/dark colors, take this value from range [0.65; 1.0]
- std::uniform_real_distribution distrib(0.65, 1.0);
- return distrib(rand_generator);
- }
-
-
- std::string get_opposite_color(const std::string& color)
- {
- std::string opp_color = "";
-
- hsv hsv_clr = rgb2hsv(color);
- hsv_clr.h += 65; // 65 instead 60 to avoid circle values
- hsv_clr.s = rand_val();
- hsv_clr.v = rand_val();
-
- rgb rgb_opp_color = hsv2rgb(hsv_clr);
-
- wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), (unsigned char)(rgb_opp_color.r * 255), (unsigned char)(rgb_opp_color.g * 255), (unsigned char)(rgb_opp_color.b * 255));
- opp_color = clr_str.ToStdString();
-
- return opp_color;
- }
-
- std::string get_opposite_color(const std::string& color_frst, const std::string& color_scnd)
- {
- std::string opp_color = "";
-
- hsv hsv_frst = rgb2hsv(color_frst);
- hsv hsv_scnd = rgb2hsv(color_scnd);
-
- double delta_h = fabs(hsv_frst.h - hsv_scnd.h);
- double start_h = delta_h > 180 ? std::min(hsv_scnd.h, hsv_frst.h) : std::max(hsv_scnd.h, hsv_frst.h);
- start_h += 5; // to avoid circle change of colors for 120 deg
- if (delta_h < 180)
- delta_h = 360 - delta_h;
-
- hsv hsv_opp = hsv{ start_h + 0.5 * delta_h, rand_val(), rand_val() };
- rgb rgb_opp_color = hsv2rgb(hsv_opp);
-
- wxString clr_str = wxString::Format(wxT("#%02X%02X%02X"), (unsigned char)(rgb_opp_color.r * 255), (unsigned char)(rgb_opp_color.g * 255), (unsigned char)(rgb_opp_color.b * 255));
- opp_color = clr_str.ToStdString();
-
- return opp_color;
- }
-};
\ No newline at end of file
+#endif // slic3r_GUI_DoubleSlider_Utils_hpp_
diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index 5ec622b872..c54e3e80b1 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -1387,13 +1387,8 @@ void ColourPicker::set_value(const boost::any& value, bool change_event)
boost::any& ColourPicker::get_value()
{
auto colour = static_cast(window)->GetColour();
- if (colour == wxTransparentColour)
- m_value = std::string("");
- else {
- auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), colour.Red(), colour.Green(), colour.Blue());
- m_value = clr_str.ToStdString();
- }
- return m_value;
+ m_value = (colour == wxTransparentColour) ? std::string("") : encode_color(ColorRGB(colour.Red(), colour.Green(), colour.Blue()));
+ return m_value;
}
void ColourPicker::msw_rescale()
diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp
index 151e66d4d1..5edc321f7b 100644
--- a/src/slic3r/GUI/GCodeViewer.cpp
+++ b/src/slic3r/GUI/GCodeViewer.cpp
@@ -47,32 +47,6 @@ static EMoveType buffer_type(unsigned char id) {
return static_cast(static_cast(EMoveType::Retract) + id);
}
-static std::array decode_color(const std::string& color) {
- static const float INV_255 = 1.0f / 255.0f;
-
- std::array ret = { 0.0f, 0.0f, 0.0f, 1.0f };
- const char* c = color.data() + 1;
- if (color.size() == 7 && color.front() == '#') {
- for (size_t j = 0; j < 3; ++j) {
- int digit1 = hex_digit_to_int(*c++);
- int digit2 = hex_digit_to_int(*c++);
- if (digit1 == -1 || digit2 == -1)
- break;
-
- ret[j] = float(digit1 * 16 + digit2) * INV_255;
- }
- }
- return ret;
-}
-
-static std::vector> decode_colors(const std::vector& colors) {
- std::vector> output(colors.size(), { 0.0f, 0.0f, 0.0f, 1.0f });
- for (size_t i = 0; i < colors.size(); ++i) {
- output[i] = decode_color(colors[i]);
- }
- return output;
-}
-
// Round to a bin with minimum two digits resolution.
// Equivalent to conversion to string with sprintf(buf, "%.2g", value) and conversion back to float, but faster.
static float round_to_bin(const float value)
@@ -186,27 +160,47 @@ void GCodeViewer::TBuffer::add_path(const GCodeProcessorResult::MoveVertex& move
move.volumetric_rate(), move.extruder_id, move.cp_color_id, { { endpoint, endpoint } } });
}
-GCodeViewer::Color GCodeViewer::Extrusions::Range::get_color_at(float value) const
+#if ENABLE_PREVIEW_LAYER_TIME
+float GCodeViewer::Extrusions::Range::step_size(EType type) const
+{
+ switch (type)
+ {
+ default:
+ case EType::Linear: { return (max > min) ? (max - min) / (static_cast(Range_Colors.size()) - 1.0f) : 0.0f; }
+ case EType::Logarithmic: { return (max > min && min > 0.0f) ? ::log(max / min) / (static_cast(Range_Colors.size()) - 1.0f) : 0.0f; }
+ }
+}
+
+ColorRGBA GCodeViewer::Extrusions::Range::get_color_at(float value, EType type) const
+#else
+ColorRGBA GCodeViewer::Extrusions::Range::get_color_at(float value) const
+#endif // ENABLE_PREVIEW_LAYER_TIME
{
// Input value scaled to the colors range
+#if ENABLE_PREVIEW_LAYER_TIME
+ float global_t = 0.0f;
+ const float step = step_size(type);
+ if (step > 0.0f) {
+ switch (type)
+ {
+ default:
+ case EType::Linear: { global_t = (value > min) ? (value - min) / step : 0.0f; break; }
+ case EType::Logarithmic: { global_t = (value > min && min > 0.0f) ? ::log(value / min) / step : 0.0f; break; }
+ }
+ }
+#else
const float step = step_size();
const float global_t = (step != 0.0f) ? std::max(0.0f, value - min) / step : 0.0f; // lower limit of 0.0f
+#endif // ENABLE_PREVIEW_LAYER_TIME
const size_t color_max_idx = Range_Colors.size() - 1;
// Compute the two colors just below (low) and above (high) the input value
- const size_t color_low_idx = std::clamp(static_cast(global_t), 0, color_max_idx);
+ const size_t color_low_idx = std::clamp(static_cast(global_t), 0, color_max_idx);
const size_t color_high_idx = std::clamp(color_low_idx + 1, 0, color_max_idx);
- // Compute how far the value is between the low and high colors so that they can be interpolated
- const float local_t = std::clamp(global_t - static_cast(color_low_idx), 0.0f, 1.0f);
-
// Interpolate between the low and high colors to find exactly which color the input value should get
- Color ret = { 0.0f, 0.0f, 0.0f, 1.0f };
- for (unsigned int i = 0; i < 3; ++i) {
- ret[i] = lerp(Range_Colors[color_low_idx][i], Range_Colors[color_high_idx][i], local_t);
- }
- return ret;
+ return lerp(Range_Colors[color_low_idx], Range_Colors[color_high_idx], global_t - static_cast(color_low_idx));
}
GCodeViewer::SequentialRangeCap::~SequentialRangeCap() {
@@ -351,11 +345,11 @@ void GCodeViewer::SequentialView::GCodeWindow::render(float top, float bottom, u
return ret;
};
- static const ImVec4 LINE_NUMBER_COLOR = ImGuiWrapper::COL_ORANGE_LIGHT;
+ static const ImVec4 LINE_NUMBER_COLOR = ImGuiWrapper::COL_ORANGE_LIGHT;
static const ImVec4 SELECTION_RECT_COLOR = ImGuiWrapper::COL_ORANGE_DARK;
- static const ImVec4 COMMAND_COLOR = { 0.8f, 0.8f, 0.0f, 1.0f };
- static const ImVec4 PARAMETERS_COLOR = { 1.0f, 1.0f, 1.0f, 1.0f };
- static const ImVec4 COMMENT_COLOR = { 0.7f, 0.7f, 0.7f, 1.0f };
+ static const ImVec4 COMMAND_COLOR = { 0.8f, 0.8f, 0.0f, 1.0f };
+ static const ImVec4 PARAMETERS_COLOR = { 1.0f, 1.0f, 1.0f, 1.0f };
+ static const ImVec4 COMMENT_COLOR = { 0.7f, 0.7f, 0.7f, 1.0f };
if (!m_visible || m_filename.empty() || m_lines_ends.empty() || curr_line_id == 0)
return;
@@ -480,7 +474,7 @@ void GCodeViewer::SequentialView::render(float legend_height) const
gcode_window.render(legend_height, bottom, static_cast(gcode_ids[current.last]));
}
-const std::vector GCodeViewer::Extrusion_Role_Colors {{
+const std::vector GCodeViewer::Extrusion_Role_Colors{ {
{ 0.90f, 0.70f, 0.70f, 1.0f }, // erNone
{ 1.00f, 0.90f, 0.30f, 1.0f }, // erPerimeter
{ 1.00f, 0.49f, 0.22f, 1.0f }, // erExternalPerimeter
@@ -499,7 +493,7 @@ const std::vector GCodeViewer::Extrusion_Role_Colors {{
{ 0.00f, 0.00f, 0.00f, 1.0f } // erMixed
}};
-const std::vector GCodeViewer::Options_Colors {{
+const std::vector GCodeViewer::Options_Colors{ {
{ 0.803f, 0.135f, 0.839f, 1.0f }, // Retractions
{ 0.287f, 0.679f, 0.810f, 1.0f }, // Unretractions
{ 0.900f, 0.900f, 0.900f, 1.0f }, // Seams
@@ -509,7 +503,7 @@ const std::vector GCodeViewer::Options_Colors {{
{ 0.886f, 0.825f, 0.262f, 1.0f } // CustomGCodes
}};
-const std::vector GCodeViewer::Travel_Colors {{
+const std::vector GCodeViewer::Travel_Colors{ {
{ 0.219f, 0.282f, 0.609f, 1.0f }, // Move
{ 0.112f, 0.422f, 0.103f, 1.0f }, // Extrude
{ 0.505f, 0.064f, 0.028f, 1.0f } // Retract
@@ -517,7 +511,7 @@ const std::vector GCodeViewer::Travel_Colors {{
#if 1
// Normal ranges
-const std::vector GCodeViewer::Range_Colors {{
+const std::vector GCodeViewer::Range_Colors{ {
{ 0.043f, 0.173f, 0.478f, 1.0f }, // bluish
{ 0.075f, 0.349f, 0.522f, 1.0f },
{ 0.110f, 0.533f, 0.569f, 1.0f },
@@ -532,7 +526,7 @@ const std::vector GCodeViewer::Range_Colors {{
}};
#else
// Detailed ranges
-const std::vector GCodeViewer::Range_Colors{ {
+const std::vector GCodeViewer::Range_Colors{ {
{ 0.043f, 0.173f, 0.478f, 1.0f }, // bluish
{ 0.5f * (0.043f + 0.075f), 0.5f * (0.173f + 0.349f), 0.5f * (0.478f + 0.522f), 1.0f },
{ 0.075f, 0.349f, 0.522f, 1.0f },
@@ -557,8 +551,8 @@ const std::vector GCodeViewer::Range_Colors{ {
} };
#endif
-const GCodeViewer::Color GCodeViewer::Wipe_Color = { 1.0f, 1.0f, 0.0f, 1.0f };
-const GCodeViewer::Color GCodeViewer::Neutral_Color = { 0.25f, 0.25f, 0.25f, 1.0f };
+const ColorRGBA GCodeViewer::Wipe_Color = ColorRGBA::YELLOW();
+const ColorRGBA GCodeViewer::Neutral_Color = ColorRGBA::DARK_GRAY();
GCodeViewer::GCodeViewer()
{
@@ -729,14 +723,17 @@ void GCodeViewer::refresh(const GCodeProcessorResult& gcode_result, const std::v
if (m_view_type == EViewType::Tool && !gcode_result.extruder_colors.empty())
// update tool colors from config stored in the gcode
- m_tool_colors = decode_colors(gcode_result.extruder_colors);
+ decode_colors(gcode_result.extruder_colors, m_tool_colors);
else
// update tool colors
- m_tool_colors = decode_colors(str_tool_colors);
+ decode_colors(str_tool_colors, m_tool_colors);
+
+ ColorRGBA default_color;
+ decode_color("#FF8000", default_color);
// ensure there are enough colors defined
while (m_tool_colors.size() < std::max(size_t(1), gcode_result.extruders_count))
- m_tool_colors.push_back(decode_color("#FF8000"));
+ m_tool_colors.push_back(default_color);
// update ranges for coloring / legend
m_extrusions.reset_ranges();
@@ -770,19 +767,37 @@ void GCodeViewer::refresh(const GCodeProcessorResult& gcode_result, const std::v
}
}
+#if ENABLE_PREVIEW_LAYER_TIME
+ for (size_t i = 0; i < gcode_result.print_statistics.modes.size(); ++i) {
+ m_layers_times[i] = gcode_result.print_statistics.modes[i].layers_times;
+ }
+
+ for (size_t i = 0; i < m_layers_times.size(); ++i) {
+ for (float time : m_layers_times[i]) {
+ m_extrusions.ranges.layer_time[i].update_from(time);
+ }
+ }
+#endif // ENABLE_PREVIEW_LAYER_TIME
+
#if ENABLE_GCODE_VIEWER_STATISTICS
m_statistics.refresh_time = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start_time).count();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
// update buffers' render paths
+#if ENABLE_PREVIEW_LAYOUT
+ refresh_render_paths(false, false);
+#else
refresh_render_paths();
+#endif // ENABLE_PREVIEW_LAYOUT
log_memory_used("Refreshed G-code extrusion paths, ");
}
+#if !ENABLE_PREVIEW_LAYOUT
void GCodeViewer::refresh_render_paths()
{
refresh_render_paths(false, false);
}
+#endif // !ENABLE_PREVIEW_LAYOUT
void GCodeViewer::update_shells_color_by_extruder(const DynamicPrintConfig* config)
{
@@ -800,7 +815,7 @@ void GCodeViewer::reset()
m_paths_bounding_box = BoundingBoxf3();
m_max_bounding_box = BoundingBoxf3();
m_max_print_height = 0.0f;
- m_tool_colors = std::vector();
+ m_tool_colors = std::vector();
m_extruders_count = 0;
m_extruder_ids = std::vector();
m_filament_diameters = std::vector();
@@ -811,12 +826,20 @@ void GCodeViewer::reset()
m_layers_z_range = { 0, 0 };
m_roles = std::vector();
m_print_statistics.reset();
+#if ENABLE_PREVIEW_LAYER_TIME
+ for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
+ m_layers_times[i] = std::vector();
+ }
+#endif // ENABLE_PREVIEW_LAYER_TIME
m_custom_gcode_per_print_z = std::vector();
m_sequential_view.gcode_window.reset();
#if ENABLE_GCODE_VIEWER_STATISTICS
m_statistics.reset_all();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
m_contained_in_bed = true;
+#if ENABLE_PREVIEW_LAYOUT
+ m_legend_resizer.reset();
+#endif // ENABLE_PREVIEW_LAYOUT
}
void GCodeViewer::render()
@@ -926,7 +949,9 @@ unsigned int GCodeViewer::get_options_visibility_flags() const
flags = set_flag(flags, static_cast(Preview::OptionType::CustomGCodes), is_toolpath_move_type_visible(EMoveType::Custom_GCode));
flags = set_flag(flags, static_cast(Preview::OptionType::Shells), m_shells.visible);
flags = set_flag(flags, static_cast(Preview::OptionType::ToolMarker), m_sequential_view.marker.is_visible());
+#if !ENABLE_PREVIEW_LAYOUT
flags = set_flag(flags, static_cast(Preview::OptionType::Legend), is_legend_enabled());
+#endif // !ENABLE_PREVIEW_LAYOUT
return flags;
}
@@ -947,7 +972,9 @@ void GCodeViewer::set_options_visibility_from_flags(unsigned int flags)
set_toolpath_move_type_visible(EMoveType::Custom_GCode, is_flag_set(static_cast(Preview::OptionType::CustomGCodes)));
m_shells.visible = is_flag_set(static_cast(Preview::OptionType::Shells));
m_sequential_view.marker.set_visible(is_flag_set(static_cast(Preview::OptionType::ToolMarker)));
+#if !ENABLE_PREVIEW_LAYOUT
enable_legend(is_flag_set(static_cast(Preview::OptionType::Legend)));
+#endif // !ENABLE_PREVIEW_LAYOUT
}
void GCodeViewer::set_layers_z_range(const std::array& layers_z_range)
@@ -978,7 +1005,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
return;
// collect color information to generate materials
- std::vector colors;
+ std::vector colors;
for (const RenderPath& path : t_buffer.render_paths) {
colors.push_back(path.color);
}
@@ -1000,10 +1027,10 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
fprintf(fp, "# Generated by %s-%s based on Slic3r\n", SLIC3R_APP_NAME, SLIC3R_VERSION);
unsigned int colors_count = 1;
- for (const Color& color : colors) {
+ for (const ColorRGBA& color : colors) {
fprintf(fp, "\nnewmtl material_%d\n", colors_count++);
fprintf(fp, "Ka 1 1 1\n");
- fprintf(fp, "Kd %g %g %g\n", color[0], color[1], color[2]);
+ fprintf(fp, "Kd %g %g %g\n", color.r(), color.g(), color.b());
fprintf(fp, "Ks 0 0 0\n");
}
@@ -1064,7 +1091,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
}
size_t i = 0;
- for (const Color& color : colors) {
+ for (const ColorRGBA& color : colors) {
// save material triangles to file
fprintf(fp, "\nusemtl material_%zu\n", i + 1);
fprintf(fp, "# triangles material %zu\n", i + 1);
@@ -2012,7 +2039,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
if (last_z == nullptr || z < *last_z - EPSILON || *last_z + EPSILON < z)
m_layers.append(z, { last_travel_s_id, move_id });
else
- m_layers.get_endpoints().back().last = move_id;
+ m_layers.get_ranges().back().last = move_id;
// extruder ids
m_extruder_ids.emplace_back(move.extruder_id);
// roles
@@ -2021,7 +2048,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
}
else if (move.type == EMoveType::Travel) {
if (move_id - last_travel_s_id > 1 && !m_layers.empty())
- m_layers.get_endpoints().back().last = move_id;
+ m_layers.get_ranges().back().last = move_id;
last_travel_s_id = move_id;
}
@@ -2126,7 +2153,7 @@ void GCodeViewer::load_shells(const Print& print, bool initialized)
for (GLVolume* volume : m_shells.volumes.volumes) {
volume->zoom_to_volumes = false;
- volume->color[3] = 0.25f;
+ volume->color.a(0.25f);
volume->force_native_color = true;
volume->set_render_color();
}
@@ -2139,7 +2166,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
#endif // ENABLE_GCODE_VIEWER_STATISTICS
auto extrusion_color = [this](const Path& path) {
- Color color;
+ ColorRGBA color;
switch (m_view_type)
{
case EViewType::FeatureType: { color = Extrusion_Role_Colors[static_cast(path.role)]; break; }
@@ -2148,17 +2175,37 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
case EViewType::Feedrate: { color = m_extrusions.ranges.feedrate.get_color_at(path.feedrate); break; }
case EViewType::FanSpeed: { color = m_extrusions.ranges.fan_speed.get_color_at(path.fan_speed); break; }
case EViewType::Temperature: { color = m_extrusions.ranges.temperature.get_color_at(path.temperature); break; }
+#if ENABLE_PREVIEW_LAYER_TIME
+ case EViewType::LayerTimeLinear:
+ case EViewType::LayerTimeLogarithmic: {
+ const Path::Sub_Path& sub_path = path.sub_paths.front();
+ double z = static_cast(sub_path.first.position.z());
+ const std::vector& zs = m_layers.get_zs();
+ const std::vector& ranges = m_layers.get_ranges();
+ size_t time_mode_id = static_cast(m_time_estimate_mode);
+ for (size_t i = 0; i < zs.size(); ++i) {
+ if (std::abs(zs[i] - z) < EPSILON) {
+ if (ranges[i].contains(sub_path.first.s_id)) {
+ color = m_extrusions.ranges.layer_time[time_mode_id].get_color_at(m_layers_times[time_mode_id][i],
+ (m_view_type == EViewType::LayerTimeLinear) ? Extrusions::Range::EType::Linear : Extrusions::Range::EType::Logarithmic);
+ break;
+ }
+ }
+ }
+ break;
+ }
+#endif // ENABLE_PREVIEW_LAYER_TIME
case EViewType::VolumetricRate: { color = m_extrusions.ranges.volumetric_rate.get_color_at(path.volumetric_rate); break; }
case EViewType::Tool: { color = m_tool_colors[path.extruder_id]; break; }
case EViewType::ColorPrint: {
if (path.cp_color_id >= static_cast(m_tool_colors.size()))
- color = { 0.5f, 0.5f, 0.5f, 1.0f };
+ color = ColorRGBA::GRAY();
else
color = m_tool_colors[path.cp_color_id];
break;
}
- default: { color = { 1.0f, 1.0f, 1.0f, 1.0f }; break; }
+ default: { color = ColorRGBA::WHITE(); break; }
}
return color;
@@ -2172,7 +2219,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
auto is_in_layers_range = [this](const Path& path, size_t min_id, size_t max_id) {
auto in_layers_range = [this, min_id, max_id](size_t id) {
- return m_layers.get_endpoints_at(min_id).first <= id && id <= m_layers.get_endpoints_at(max_id).last;
+ return m_layers.get_range_at(min_id).first <= id && id <= m_layers.get_range_at(max_id).last;
};
return in_layers_range(path.sub_paths.front().first.s_id) && in_layers_range(path.sub_paths.back().last.s_id);
@@ -2197,8 +2244,8 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
path.sub_paths.back().last = buffer.paths[last].sub_paths.back().last;
}
- const size_t min_s_id = m_layers.get_endpoints_at(min_id).first;
- const size_t max_s_id = m_layers.get_endpoints_at(max_id).last;
+ const size_t min_s_id = m_layers.get_range_at(min_id).first;
+ const size_t max_s_id = m_layers.get_range_at(max_id).last;
return (min_s_id <= path.sub_paths.front().first.s_id && path.sub_paths.front().first.s_id <= max_s_id) ||
(min_s_id <= path.sub_paths.back().last.s_id && path.sub_paths.back().last.s_id <= max_s_id);
@@ -2231,14 +2278,14 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::InstancedModel ||
buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::BatchedModel) {
for (size_t id : buffer.model.instances.s_ids) {
- if (id < m_layers.get_endpoints_at(m_layers_z_range[0]).first || m_layers.get_endpoints_at(m_layers_z_range[1]).last < id)
+ if (id < m_layers.get_range_at(m_layers_z_range[0]).first || m_layers.get_range_at(m_layers_z_range[1]).last < id)
continue;
global_endpoints.first = std::min(global_endpoints.first, id);
global_endpoints.last = std::max(global_endpoints.last, id);
if (top_layer_only) {
- if (id < m_layers.get_endpoints_at(m_layers_z_range[1]).first || m_layers.get_endpoints_at(m_layers_z_range[1]).last < id)
+ if (id < m_layers.get_range_at(m_layers_z_range[1]).first || m_layers.get_range_at(m_layers_z_range[1]).last < id)
continue;
top_layer_endpoints.first = std::min(top_layer_endpoints.first, id);
@@ -2357,7 +2404,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
if (m_sequential_view.current.last < sub_path.first.s_id || sub_path.last.s_id < m_sequential_view.current.first)
continue;
- Color color;
+ ColorRGBA color;
switch (path.type)
{
case EMoveType::Tool_change:
@@ -2676,7 +2723,7 @@ void GCodeViewer::render_toolpaths()
// Some OpenGL drivers crash on empty glMultiDrawElements, see GH #7415.
assert(! path.sizes.empty());
assert(! path.offsets.empty());
- glsafe(::glUniform4fv(uniform_color, 1, static_cast(path.color.data())));
+ shader.set_uniform(uniform_color, path.color);
glsafe(::glMultiDrawElements(GL_POINTS, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.gl_multi_points_calls_count;
@@ -2700,7 +2747,7 @@ void GCodeViewer::render_toolpaths()
// Some OpenGL drivers crash on empty glMultiDrawElements, see GH #7415.
assert(! path.sizes.empty());
assert(! path.offsets.empty());
- glsafe(::glUniform4fv(uniform_color, 1, static_cast(path.color.data())));
+ shader.set_uniform(uniform_color, path.color);
glsafe(::glMultiDrawElements(GL_LINES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.gl_multi_lines_calls_count;
@@ -2718,7 +2765,7 @@ void GCodeViewer::render_toolpaths()
// Some OpenGL drivers crash on empty glMultiDrawElements, see GH #7415.
assert(! path.sizes.empty());
assert(! path.offsets.empty());
- glsafe(::glUniform4fv(uniform_color, 1, static_cast(path.color.data())));
+ shader.set_uniform(uniform_color, path.color);
glsafe(::glMultiDrawElements(GL_TRIANGLES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size()));
#if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.gl_multi_triangles_calls_count;
@@ -2980,7 +3027,11 @@ void GCodeViewer::render_legend(float& legend_height)
const float max_height = 0.75f * static_cast(cnv_size.get_height());
const float child_height = 0.3333f * max_height;
ImGui::SetNextWindowSizeConstraints({ 0.0f, 0.0f }, { -1.0f, max_height });
+#if ENABLE_PREVIEW_LAYOUT
+ imgui.begin(std::string("Legend"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove);
+#else
imgui.begin(std::string("Legend"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove);
+#endif // ENABLE_PREVIEW_LAYOUT
enum class EItemType : unsigned char
{
@@ -2991,15 +3042,21 @@ void GCodeViewer::render_legend(float& legend_height)
};
const PrintEstimatedStatistics::Mode& time_mode = m_print_statistics.modes[static_cast(m_time_estimate_mode)];
+#if ENABLE_PREVIEW_LAYER_TIME
+ bool show_estimated_time = time_mode.time > 0.0f && (m_view_type == EViewType::FeatureType ||
+ m_view_type == EViewType::LayerTimeLinear || m_view_type == EViewType::LayerTimeLogarithmic ||
+ (m_view_type == EViewType::ColorPrint && !time_mode.custom_gcode_times.empty()));
+#else
bool show_estimated_time = time_mode.time > 0.0f && (m_view_type == EViewType::FeatureType ||
(m_view_type == EViewType::ColorPrint && !time_mode.custom_gcode_times.empty()));
+#endif // ENABLE_PREVIEW_LAYER_TIME
const float icon_size = ImGui::GetTextLineHeight();
const float percent_bar_size = 2.0f * ImGui::GetTextLineHeight();
bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
- auto append_item = [icon_size, percent_bar_size, &imgui, imperial_units](EItemType type, const Color& color, const std::string& label,
+ auto append_item = [icon_size, percent_bar_size, &imgui, imperial_units](EItemType type, const ColorRGBA& color, const std::string& label,
bool visible = true, const std::string& time = "", float percent = 0.0f, float max_percent = 0.0f, const std::array& offsets = { 0.0f, 0.0f, 0.0f, 0.0f },
double used_filament_m = 0.0, double used_filament_g = 0.0,
std::function callback = nullptr) {
@@ -3012,21 +3069,21 @@ void GCodeViewer::render_legend(float& legend_height)
default:
case EItemType::Rect: {
draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f },
- ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }));
+ ImGuiWrapper::to_ImU32(color));
break;
}
case EItemType::Circle: {
ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size));
- draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
+ draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGuiWrapper::to_ImU32(color), 16);
break;
}
case EItemType::Hexagon: {
ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size));
- draw_list->AddNgonFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 6);
+ draw_list->AddNgonFilled(center, 0.5f * icon_size, ImGuiWrapper::to_ImU32(color), 6);
break;
}
case EItemType::Line: {
- draw_list->AddLine({ pos.x + 1, pos.y + icon_size - 1 }, { pos.x + icon_size - 1, pos.y + 1 }, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 3.0f);
+ draw_list->AddLine({ pos.x + 1, pos.y + icon_size - 1 }, { pos.x + icon_size - 1, pos.y + 1 }, ImGuiWrapper::to_ImU32(color), 3.0f);
break;
}
}
@@ -3078,7 +3135,25 @@ void GCodeViewer::render_legend(float& legend_height)
}
else {
imgui.text(label);
+#if ENABLE_TRAVEL_TIME
+ if (!time.empty()) {
+ ImGui::SameLine(offsets[0]);
+ imgui.text(time);
+ ImGui::SameLine(offsets[1]);
+ pos = ImGui::GetCursorScreenPos();
+ const float width = std::max(1.0f, percent_bar_size * percent / max_percent);
+ draw_list->AddRectFilled({ pos.x, pos.y + 2.0f }, { pos.x + width, pos.y + icon_size - 2.0f },
+ ImGui::GetColorU32(ImGuiWrapper::COL_ORANGE_LIGHT));
+ ImGui::Dummy({ percent_bar_size, icon_size });
+ ImGui::SameLine();
+ char buf[64];
+ ::sprintf(buf, "%.1f%%", 100.0f * percent);
+ ImGui::TextUnformatted((percent > 0.0f) ? buf : "");
+ }
+ else if (used_filament_m > 0.0) {
+#else
if (used_filament_m > 0.0) {
+#endif // ENABLE_TRAVEL_TIME
char buf[64];
ImGui::SameLine(offsets[0]);
::sprintf(buf, imperial_units ? "%.2f in" : "%.2f m", used_filament_m);
@@ -3104,6 +3179,7 @@ void GCodeViewer::render_legend(float& legend_height)
// single item use case
append_range_item(0, range.min, decimals);
else if (range.count == 2) {
+ // two items use case
append_range_item(static_cast(Range_Colors.size()) - 1, range.max, decimals);
append_range_item(0, range.min, decimals);
}
@@ -3115,6 +3191,39 @@ void GCodeViewer::render_legend(float& legend_height)
}
};
+#if ENABLE_PREVIEW_LAYER_TIME
+ auto append_time_range = [append_item](const Extrusions::Range& range, Extrusions::Range::EType type) {
+ auto append_range_item = [append_item](int i, float value) {
+ std::string str_value = get_time_dhms(value);
+ if (str_value == "0s")
+ str_value = "< 1s";
+ append_item(EItemType::Rect, Range_Colors[i], str_value);
+ };
+
+ if (range.count == 1)
+ // single item use case
+ append_range_item(0, range.min);
+ else if (range.count == 2) {
+ // two items use case
+ append_range_item(static_cast(Range_Colors.size()) - 1, range.max);
+ append_range_item(0, range.min);
+ }
+ else {
+ float step_size = range.step_size(type);
+ for (int i = static_cast(Range_Colors.size()) - 1; i >= 0; --i) {
+ float value = 0.0f;
+ switch (type)
+ {
+ default:
+ case Extrusions::Range::EType::Linear: { value = range.min + static_cast(i) * step_size; break; }
+ case Extrusions::Range::EType::Logarithmic: { value = ::exp(::log(range.min) + static_cast(i) * step_size); break; }
+ }
+ append_range_item(i, value);
+ }
+ }
+ };
+#endif // ENABLE_PREVIEW_LAYER_TIME
+
auto append_headers = [&imgui](const std::array& texts, const std::array& offsets) {
size_t i = 0;
for (; i < offsets.size(); i++) {
@@ -3144,7 +3253,7 @@ void GCodeViewer::render_legend(float& legend_height)
};
auto color_print_ranges = [this](unsigned char extruder_id, const std::vector& custom_gcode_per_print_z) {
- std::vector>> ret;
+ std::vector>> ret;
ret.reserve(custom_gcode_per_print_z.size());
for (const auto& item : custom_gcode_per_print_z) {
@@ -3163,8 +3272,11 @@ void GCodeViewer::render_legend(float& legend_height)
const double previous_z = (lower_b == zs.begin()) ? 0.0 : *(--lower_b);
// to avoid duplicate values, check adding values
- if (ret.empty() || !(ret.back().second.first == previous_z && ret.back().second.second == current_z))
- ret.push_back({ decode_color(item.color), { previous_z, current_z } });
+ if (ret.empty() || !(ret.back().second.first == previous_z && ret.back().second.second == current_z)) {
+ ColorRGBA color;
+ decode_color(item.color, color);
+ ret.push_back({ color, { previous_z, current_z } });
+ }
}
return ret;
@@ -3211,7 +3323,7 @@ void GCodeViewer::render_legend(float& legend_height)
std::vector percents;
std::vector used_filaments_m;
std::vector used_filaments_g;
- float max_percent = 0.0f;
+ float max_time_percent = 0.0f;
if (m_view_type == EViewType::FeatureType) {
// calculate offsets to align time/percentage data
@@ -3222,7 +3334,7 @@ void GCodeViewer::render_legend(float& legend_height)
auto [time, percent] = role_time_and_percent(role);
times.push_back((time > 0.0f) ? short_time(get_time_dhms(time)) : "");
percents.push_back(percent);
- max_percent = std::max(max_percent, percent);
+ max_time_percent = std::max(max_time_percent, percent);
auto [used_filament_m, used_filament_g] = used_filament_per_role(role);
used_filaments_m.push_back(used_filament_m);
used_filaments_g.push_back(used_filament_g);
@@ -3282,6 +3394,47 @@ void GCodeViewer::render_legend(float& legend_height)
offsets = calculate_offsets(labels, times, { "Extruder NNN", longest_used_filament_string }, icon_size);
}
+#if ENABLE_PREVIEW_LAYOUT
+ // selection section
+ bool view_type_changed = false;
+ int old_view_type = static_cast(get_view_type());
+ int view_type = old_view_type;
+
+ if (!m_legend_resizer.dirty)
+ ImGui::SetNextItemWidth(-1.0f);
+
+ ImGui::PushStyleColor(ImGuiCol_FrameBg, { 0.1f, 0.1f, 0.1f, 0.8f });
+ ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, { 0.2f, 0.2f, 0.2f, 0.8f });
+ imgui.combo("", { _u8L("Feature type"),
+ _u8L("Height (mm)"),
+ _u8L("Width (mm)"),
+ _u8L("Speed (mm/s)"),
+ _u8L("Fan speed (%)"),
+ _u8L("Temperature (°C)"),
+ _u8L("Volumetric flow rate (mm³/s)"),
+#if ENABLE_PREVIEW_LAYER_TIME
+ _u8L("Layer time (linear)"),
+ _u8L("Layer time (logarithmic)"),
+#endif // ENABLE_PREVIEW_LAYER_TIME
+ _u8L("Tool"),
+ _u8L("Color Print") }, view_type, ImGuiComboFlags_HeightLargest);
+ ImGui::PopStyleColor(2);
+
+ if (old_view_type != view_type) {
+ set_view_type(static_cast(view_type));
+ wxGetApp().plater()->set_keep_current_preview_type(true);
+ wxGetApp().plater()->refresh_print();
+ view_type_changed = true;
+ }
+
+ // extrusion paths section -> title
+ if (m_view_type == EViewType::FeatureType)
+ append_headers({ _u8L(""), _u8L("Time"), _u8L("Percentage"), _u8L("Used filament") }, offsets);
+ else if (m_view_type == EViewType::Tool)
+ append_headers({ _u8L(""), _u8L("Used filament"), _u8L(""), _u8L("") }, offsets);
+ else
+ ImGui::Separator();
+#else
// extrusion paths section -> title
switch (m_view_type)
{
@@ -3290,58 +3443,81 @@ void GCodeViewer::render_legend(float& legend_height)
append_headers({ _u8L("Feature type"), _u8L("Time"), _u8L("Percentage"), _u8L("Used filament") }, offsets);
break;
}
- case EViewType::Height: { imgui.title(_u8L("Height (mm)")); break; }
- case EViewType::Width: { imgui.title(_u8L("Width (mm)")); break; }
- case EViewType::Feedrate: { imgui.title(_u8L("Speed (mm/s)")); break; }
- case EViewType::FanSpeed: { imgui.title(_u8L("Fan Speed (%)")); break; }
- case EViewType::Temperature: { imgui.title(_u8L("Temperature (°C)")); break; }
- case EViewType::VolumetricRate: { imgui.title(_u8L("Volumetric flow rate (mm³/s)")); break; }
- case EViewType::Tool:
- {
+ case EViewType::Height: { imgui.title(_u8L("Height (mm)")); break; }
+ case EViewType::Width: { imgui.title(_u8L("Width (mm)")); break; }
+ case EViewType::Feedrate: { imgui.title(_u8L("Speed (mm/s)")); break; }
+ case EViewType::FanSpeed: { imgui.title(_u8L("Fan Speed (%)")); break; }
+ case EViewType::Temperature: { imgui.title(_u8L("Temperature (°C)")); break; }
+ case EViewType::VolumetricRate: { imgui.title(_u8L("Volumetric flow rate (mm³/s)")); break; }
+#if ENABLE_PREVIEW_LAYER_TIME
+ case EViewType::LayerTimeLinear: { imgui.title(_u8L("Layer time (linear)")); break; }
+ case EViewType::LayerTimeLogarithmic: { imgui.title(_u8L("Layer time (logarithmic)")); break; }
+#endif // ENABLE_PREVIEW_LAYER_TIME
+ case EViewType::Tool: {
append_headers({ _u8L("Tool"), _u8L("Used filament") }, offsets);
break;
}
- case EViewType::ColorPrint: { imgui.title(_u8L("Color Print")); break; }
+ case EViewType::ColorPrint: { imgui.title(_u8L("Color Print")); break; }
default: { break; }
}
+#endif // ENABLE_PREVIEW_LAYOUT
+#if ENABLE_PREVIEW_LAYOUT
+ if (!view_type_changed) {
+#endif // ENABLE_PREVIEW_LAYOUT
// extrusion paths section -> items
switch (m_view_type)
{
case EViewType::FeatureType:
{
+#if ENABLE_TRAVEL_TIME
+ max_time_percent = std::max(max_time_percent, time_mode.travel_time / time_mode.time);
+#endif // ENABLE_TRAVEL_TIME
+
for (size_t i = 0; i < m_roles.size(); ++i) {
ExtrusionRole role = m_roles[i];
if (role >= erCount)
continue;
const bool visible = is_visible(role);
append_item(EItemType::Rect, Extrusion_Role_Colors[static_cast(role)], labels[i],
- visible, times[i], percents[i], max_percent, offsets, used_filaments_m[i], used_filaments_g[i], [this, role, visible]() {
+ visible, times[i], percents[i], max_time_percent, offsets, used_filaments_m[i], used_filaments_g[i], [this, role, visible]() {
m_extrusions.role_visibility_flags = visible ? m_extrusions.role_visibility_flags & ~(1 << role) : m_extrusions.role_visibility_flags | (1 << role);
// update buffers' render paths
refresh_render_paths(false, false);
wxGetApp().plater()->update_preview_moves_slider();
wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
+#if !ENABLE_PREVIEW_LAYOUT
wxGetApp().plater()->update_preview_bottom_toolbar();
+#endif // !ENABLE_PREVIEW_LAYOUT
}
);
}
+
+#if ENABLE_TRAVEL_TIME
+ if (m_buffers[buffer_id(EMoveType::Travel)].visible)
+ append_item(EItemType::Line, Travel_Colors[0], _u8L("Travel"), true, short_time(get_time_dhms(time_mode.travel_time)),
+ time_mode.travel_time / time_mode.time, max_time_percent, offsets, 0.0f, 0.0f);
+#endif // ENABLE_TRAVEL_TIME
+
break;
}
- case EViewType::Height: { append_range(m_extrusions.ranges.height, 3); break; }
- case EViewType::Width: { append_range(m_extrusions.ranges.width, 3); break; }
- case EViewType::Feedrate: { append_range(m_extrusions.ranges.feedrate, 1); break; }
- case EViewType::FanSpeed: { append_range(m_extrusions.ranges.fan_speed, 0); break; }
- case EViewType::Temperature: { append_range(m_extrusions.ranges.temperature, 0); break; }
- case EViewType::VolumetricRate: { append_range(m_extrusions.ranges.volumetric_rate, 3); break; }
- case EViewType::Tool:
- {
+ case EViewType::Height: { append_range(m_extrusions.ranges.height, 3); break; }
+ case EViewType::Width: { append_range(m_extrusions.ranges.width, 3); break; }
+ case EViewType::Feedrate: { append_range(m_extrusions.ranges.feedrate, 1); break; }
+ case EViewType::FanSpeed: { append_range(m_extrusions.ranges.fan_speed, 0); break; }
+ case EViewType::Temperature: { append_range(m_extrusions.ranges.temperature, 0); break; }
+ case EViewType::VolumetricRate: { append_range(m_extrusions.ranges.volumetric_rate, 3); break; }
+#if ENABLE_PREVIEW_LAYER_TIME
+ case EViewType::LayerTimeLinear: { append_time_range(m_extrusions.ranges.layer_time[static_cast(m_time_estimate_mode)], Extrusions::Range::EType::Linear); break; }
+ case EViewType::LayerTimeLogarithmic: { append_time_range(m_extrusions.ranges.layer_time[static_cast(m_time_estimate_mode)], Extrusions::Range::EType::Logarithmic); break; }
+#endif // ENABLE_PREVIEW_LAYER_TIME
+ case EViewType::Tool: {
// shows only extruders actually used
size_t i = 0;
for (unsigned char extruder_id : m_extruder_ids) {
append_item(EItemType::Rect, m_tool_colors[extruder_id], _u8L("Extruder") + " " + std::to_string(extruder_id + 1),
true, "", 0.0f, 0.0f, offsets, used_filaments_m[i], used_filaments_g[i]);
- i++;
+ ++i;
}
break;
}
@@ -3353,17 +3529,16 @@ void GCodeViewer::render_legend(float& legend_height)
total_items += color_print_ranges(i, custom_gcode_per_print_z).size();
}
- const bool need_scrollable = static_cast(total_items) * (icon_size + ImGui::GetStyle().ItemSpacing.y) > child_height;
+ const bool need_scrollable = static_cast(total_items) * icon_size + (static_cast(total_items) - 1.0f) * ImGui::GetStyle().ItemSpacing.y > child_height;
// add scrollable region, if needed
if (need_scrollable)
ImGui::BeginChild("color_prints", { -1.0f, child_height }, false);
if (m_extruders_count == 1) { // single extruder use case
- const std::vector>> cp_values = color_print_ranges(0, custom_gcode_per_print_z);
+ const std::vector>> cp_values = color_print_ranges(0, custom_gcode_per_print_z);
const int items_cnt = static_cast(cp_values.size());
- if (items_cnt == 0) { // There are no color changes, but there are some pause print or custom Gcode
+ if (items_cnt == 0) // There are no color changes, but there are some pause print or custom Gcode
append_item(EItemType::Rect, m_tool_colors.front(), _u8L("Default color"));
- }
else {
for (int i = items_cnt; i >= 0; --i) {
// create label for color change item
@@ -3382,11 +3557,11 @@ void GCodeViewer::render_legend(float& legend_height)
else { // multi extruder use case
// shows only extruders actually used
for (unsigned char i : m_extruder_ids) {
- const std::vector>> cp_values = color_print_ranges(i, custom_gcode_per_print_z);
+ const std::vector>> cp_values = color_print_ranges(i, custom_gcode_per_print_z);
const int items_cnt = static_cast(cp_values.size());
- if (items_cnt == 0) { // There are no color changes, but there are some pause print or custom Gcode
+ if (items_cnt == 0)
+ // There are no color changes, but there are some pause print or custom Gcode
append_item(EItemType::Rect, m_tool_colors[i], _u8L("Extruder") + " " + std::to_string(i + 1) + " " + _u8L("default color"));
- }
else {
for (int j = items_cnt; j >= 0; --j) {
// create label for color change item
@@ -3415,6 +3590,9 @@ void GCodeViewer::render_legend(float& legend_height)
}
default: { break; }
}
+#if ENABLE_PREVIEW_LAYOUT
+ }
+#endif // ENABLE_PREVIEW_LAYOUT
// partial estimated printing time section
if (m_view_type == EViewType::ColorPrint) {
@@ -3432,10 +3610,10 @@ void GCodeViewer::render_legend(float& legend_height)
};
EType type;
int extruder_id;
- Color color1;
- Color color2;
+ ColorRGBA color1;
+ ColorRGBA color2;
Times times;
- std::pair used_filament {0.0f, 0.0f};
+ std::pair used_filament{ 0.0f, 0.0f };
};
using PartialTimes = std::vector;
@@ -3444,7 +3622,7 @@ void GCodeViewer::render_legend(float& legend_height)
std::vector custom_gcode_per_print_z = wxGetApp().is_editor() ? wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes : m_custom_gcode_per_print_z;
int extruders_count = wxGetApp().extruders_edited_cnt();
- std::vector last_color(extruders_count);
+ std::vector last_color(extruders_count);
for (int i = 0; i < extruders_count; ++i) {
last_color[i] = m_tool_colors[i];
}
@@ -3456,8 +3634,8 @@ void GCodeViewer::render_legend(float& legend_height)
case CustomGCode::PausePrint: {
auto it = std::find_if(custom_gcode_per_print_z.begin(), custom_gcode_per_print_z.end(), [time_rec](const CustomGCode::Item& item) { return item.type == time_rec.first; });
if (it != custom_gcode_per_print_z.end()) {
- items.push_back({ PartialTime::EType::Print, it->extruder, last_color[it->extruder - 1], Color(), time_rec.second });
- items.push_back({ PartialTime::EType::Pause, it->extruder, Color(), Color(), time_rec.second });
+ items.push_back({ PartialTime::EType::Print, it->extruder, last_color[it->extruder - 1], ColorRGBA::BLACK(), time_rec.second });
+ items.push_back({ PartialTime::EType::Pause, it->extruder, ColorRGBA::BLACK(), ColorRGBA::BLACK(), time_rec.second });
custom_gcode_per_print_z.erase(it);
}
break;
@@ -3465,14 +3643,16 @@ void GCodeViewer::render_legend(float& legend_height)
case CustomGCode::ColorChange: {
auto it = std::find_if(custom_gcode_per_print_z.begin(), custom_gcode_per_print_z.end(), [time_rec](const CustomGCode::Item& item) { return item.type == time_rec.first; });
if (it != custom_gcode_per_print_z.end()) {
- items.push_back({ PartialTime::EType::Print, it->extruder, last_color[it->extruder - 1], Color(), time_rec.second, get_used_filament_from_volume(used_filaments[color_change_idx++], it->extruder-1) });
- items.push_back({ PartialTime::EType::ColorChange, it->extruder, last_color[it->extruder - 1], decode_color(it->color), time_rec.second });
- last_color[it->extruder - 1] = decode_color(it->color);
+ items.push_back({ PartialTime::EType::Print, it->extruder, last_color[it->extruder - 1], ColorRGBA::BLACK(), time_rec.second, get_used_filament_from_volume(used_filaments[color_change_idx++], it->extruder - 1) });
+ ColorRGBA color;
+ decode_color(it->color, color);
+ items.push_back({ PartialTime::EType::ColorChange, it->extruder, last_color[it->extruder - 1], color, time_rec.second });
+ last_color[it->extruder - 1] = color;
last_extruder_id = it->extruder;
custom_gcode_per_print_z.erase(it);
}
else
- items.push_back({ PartialTime::EType::Print, last_extruder_id, last_color[last_extruder_id - 1], Color(), time_rec.second, get_used_filament_from_volume(used_filaments[color_change_idx++], last_extruder_id -1) });
+ items.push_back({ PartialTime::EType::Print, last_extruder_id, last_color[last_extruder_id - 1], ColorRGBA::BLACK(), time_rec.second, get_used_filament_from_volume(used_filaments[color_change_idx++], last_extruder_id - 1) });
break;
}
@@ -3483,7 +3663,7 @@ void GCodeViewer::render_legend(float& legend_height)
return items;
};
- auto append_color_change = [&imgui](const Color& color1, const Color& color2, const std::array& offsets, const Times& times) {
+ auto append_color_change = [&imgui](const ColorRGBA& color1, const ColorRGBA& color2, const std::array& offsets, const Times& times) {
imgui.text(_u8L("Color change"));
ImGui::SameLine();
@@ -3493,16 +3673,16 @@ void GCodeViewer::render_legend(float& legend_height)
pos.x -= 0.5f * ImGui::GetStyle().ItemSpacing.x;
draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f },
- ImGui::GetColorU32({ color1[0], color1[1], color1[2], 1.0f }));
+ ImGuiWrapper::to_ImU32(color1));
pos.x += icon_size;
draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f },
- ImGui::GetColorU32({ color2[0], color2[1], color2[2], 1.0f }));
+ ImGuiWrapper::to_ImU32(color2));
ImGui::SameLine(offsets[0]);
imgui.text(short_time(get_time_dhms(times.second - times.first)));
};
- auto append_print = [&imgui, imperial_units](const Color& color, const std::array& offsets, const Times& times, std::pair used_filament) {
+ auto append_print = [&imgui, imperial_units](const ColorRGBA& color, const std::array& offsets, const Times& times, std::pair used_filament) {
imgui.text(_u8L("Print"));
ImGui::SameLine();
@@ -3512,7 +3692,7 @@ void GCodeViewer::render_legend(float& legend_height)
pos.x -= 0.5f * ImGui::GetStyle().ItemSpacing.x;
draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f },
- ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }));
+ ImGuiWrapper::to_ImU32(color));
ImGui::SameLine(offsets[0]);
imgui.text(short_time(get_time_dhms(times.second)));
@@ -3560,7 +3740,7 @@ void GCodeViewer::render_legend(float& legend_height)
ImGui::Spacing();
append_headers({ _u8L("Event"), _u8L("Remaining time"), _u8L("Duration"), _u8L("Used filament") }, offsets);
- const bool need_scrollable = static_cast(partial_times.size()) * (icon_size + ImGui::GetStyle().ItemSpacing.y) > child_height;
+ const bool need_scrollable = static_cast(partial_times.size()) * icon_size + (static_cast(partial_times.size()) - 1.0f) * ImGui::GetStyle().ItemSpacing.y > child_height;
if (need_scrollable)
// add scrollable region
ImGui::BeginChild("events", { -1.0f, child_height }, false);
@@ -3590,6 +3770,7 @@ void GCodeViewer::render_legend(float& legend_height)
}
}
+#if !ENABLE_PREVIEW_LAYOUT
// travel paths section
if (m_buffers[buffer_id(EMoveType::Travel)].visible) {
switch (m_view_type)
@@ -3670,6 +3851,7 @@ void GCodeViewer::render_legend(float& legend_height)
add_option(EMoveType::Pause_Print, EOptionsColors::PausePrints, _u8L("Print pauses"));
add_option(EMoveType::Custom_GCode, EOptionsColors::CustomGCodes, _u8L("Custom G-codes"));
}
+#endif // !ENABLE_PREVIEW_LAYOUT
// settings section
bool has_settings = false;
@@ -3751,7 +3933,7 @@ void GCodeViewer::render_legend(float& legend_height)
if (can_show_mode_button(m_time_estimate_mode)) {
switch (m_time_estimate_mode)
{
- case PrintEstimatedStatistics::ETimeMode::Normal: { time_title += " [" + _u8L("Normal mode") + "]"; break; }
+ case PrintEstimatedStatistics::ETimeMode::Normal: { time_title += " [" + _u8L("Normal mode") + "]"; break; }
case PrintEstimatedStatistics::ETimeMode::Stealth: { time_title += " [" + _u8L("Stealth mode") + "]"; break; }
default: { assert(false); break; }
}
@@ -3782,6 +3964,10 @@ void GCodeViewer::render_legend(float& legend_height)
if (can_show_mode_button(mode)) {
if (imgui.button(label)) {
m_time_estimate_mode = mode;
+#if ENABLE_PREVIEW_LAYER_TIME
+ if (m_view_type == EViewType::LayerTimeLinear || m_view_type == EViewType::LayerTimeLogarithmic)
+ refresh_render_paths(false, false);
+#endif // ENABLE_PREVIEW_LAYER_TIME
imgui.set_requires_extra_frame();
}
}
@@ -3789,18 +3975,216 @@ void GCodeViewer::render_legend(float& legend_height)
switch (m_time_estimate_mode) {
case PrintEstimatedStatistics::ETimeMode::Normal: {
- show_mode_button(_L("Show stealth mode"), PrintEstimatedStatistics::ETimeMode::Stealth);
+ show_mode_button(_u8L("Show stealth mode"), PrintEstimatedStatistics::ETimeMode::Stealth);
break;
}
case PrintEstimatedStatistics::ETimeMode::Stealth: {
- show_mode_button(_L("Show normal mode"), PrintEstimatedStatistics::ETimeMode::Normal);
+ show_mode_button(_u8L("Show normal mode"), PrintEstimatedStatistics::ETimeMode::Normal);
break;
}
default : { assert(false); break; }
}
}
- legend_height = ImGui::GetCurrentWindow()->Size.y;
+#if ENABLE_PREVIEW_LAYOUT
+ // toolbar section
+ auto toggle_button = [this, &imgui, icon_size](Preview::OptionType type, const std::string& name,
+ std::function draw_callback) {
+ auto is_flag_set = [](unsigned int flags, unsigned int flag) {
+ return (flags & (1 << flag)) != 0;
+ };
+
+ auto set_flag = [](unsigned int flags, unsigned int flag, bool active) {
+ return active ? (flags | (1 << flag)) : (flags & ~(1 << flag));
+ };
+
+ unsigned int flags = get_options_visibility_flags();
+ unsigned int flag = static_cast(type);
+ bool active = is_flag_set(flags, flag);
+
+ if (imgui.draw_radio_button(name, 1.5f * icon_size, active, draw_callback)) {
+ unsigned int new_flags = set_flag(flags, flag, !active);
+ set_options_visibility_from_flags(new_flags);
+
+ const unsigned int diff_flags = flags ^ new_flags;
+ if (m_view_type == GCodeViewer::EViewType::Feedrate && is_flag_set(diff_flags, static_cast(Preview::OptionType::Travel)))
+ wxGetApp().plater()->refresh_print();
+ else {
+ bool keep_first = m_sequential_view.current.first != m_sequential_view.global.first;
+ bool keep_last = m_sequential_view.current.last != m_sequential_view.global.last;
+ wxGetApp().plater()->get_current_canvas3D()->refresh_gcode_preview_render_paths(keep_first, keep_last);
+ }
+ wxGetApp().plater()->update_preview_moves_slider();
+ }
+
+ if (ImGui::IsItemHovered()) {
+ ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND);
+ ImGui::BeginTooltip();
+ imgui.text(name);
+ ImGui::EndTooltip();
+ ImGui::PopStyleColor();
+ }
+ };
+
+#if ENABLE_LEGEND_TOOLBAR_ICONS
+// auto circle_icon = [](ImGuiWindow& window, const ImVec2& pos, float size, const Color& color) {
+// const float margin = 3.0f;
+// const ImVec2 center(0.5f * (pos.x + pos.x + size), 0.5f * (pos.y + pos.y + size));
+// window.DrawList->AddCircleFilled(center, 0.5f * (size - 2.0f * margin), ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
+// };
+// auto line_icon = [](ImGuiWindow& window, const ImVec2& pos, float size, const Color& color) {
+// const float margin = 3.0f;
+// window.DrawList->AddLine({ pos.x + margin, pos.y + size - margin }, { pos.x + size - margin, pos.y + margin }, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 3.0f);
+// };
+ auto image_icon = [&imgui](ImGuiWindow& window, const ImVec2& pos, float size, const wchar_t& icon_id) {
+ ImGuiIO& io = ImGui::GetIO();
+ const ImTextureID tex_id = io.Fonts->TexID;
+ const float tex_w = static_cast(io.Fonts->TexWidth);
+ const float tex_h = static_cast(io.Fonts->TexHeight);
+ const ImFontAtlas::CustomRect* const rect = imgui.GetTextureCustomRect(icon_id);
+ const ImVec2 uv0 = { static_cast(rect->X) / tex_w, static_cast(rect->Y) / tex_h };
+ const ImVec2 uv1 = { static_cast(rect->X + rect->Width) / tex_w, static_cast(rect->Y + rect->Height) / tex_h };
+ window.DrawList->AddImage(tex_id, pos, { pos.x + size, pos.y + size }, uv0, uv1, ImGui::GetColorU32({ 1.0f, 1.0f, 1.0f, 1.0f }));
+ };
+#else
+ auto circle_icon = [](ImGuiWindow& window, const ImVec2& pos, float size, const Color& color) {
+ const float margin = 3.0f;
+ const ImVec2 center(0.5f * (pos.x + pos.x + size), 0.5f * (pos.y + pos.y + size));
+ window.DrawList->AddCircleFilled(center, 0.5f * (size - 2.0f * margin), ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
+ };
+ auto line_icon = [](ImGuiWindow& window, const ImVec2& pos, float size, const Color& color) {
+ const float margin = 3.0f;
+ window.DrawList->AddLine({ pos.x + margin, pos.y + size - margin }, { pos.x + size - margin, pos.y + margin }, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 3.0f);
+ };
+#endif // ENABLE_LEGEND_TOOLBAR_ICONS
+
+ ImGui::Spacing();
+ ImGui::Separator();
+ ImGui::Spacing();
+ ImGui::Spacing();
+#if ENABLE_LEGEND_TOOLBAR_ICONS
+ toggle_button(Preview::OptionType::Travel, _u8L("Travel"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ image_icon(window, pos, size, ImGui::LegendTravel);
+#else
+ toggle_button(Preview::OptionType::Travel, _u8L("Travel"), [line_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ line_icon(window, pos, size, Travel_Colors[0]);
+#endif // ENABLE_LEGEND_TOOLBAR_ICONS
+ });
+ ImGui::SameLine();
+#if ENABLE_LEGEND_TOOLBAR_ICONS
+ toggle_button(Preview::OptionType::Wipe, _u8L("Wipe"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ image_icon(window, pos, size, ImGui::LegendWipe);
+#else
+ toggle_button(Preview::OptionType::Wipe, _u8L("Wipe"), [line_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ line_icon(window, pos, size, Wipe_Color);
+#endif // ENABLE_LEGEND_TOOLBAR_ICONS
+ });
+ ImGui::SameLine();
+#if ENABLE_LEGEND_TOOLBAR_ICONS
+ toggle_button(Preview::OptionType::Retractions, _u8L("Retractions"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ image_icon(window, pos, size, ImGui::LegendRetract);
+#else
+ toggle_button(Preview::OptionType::Retractions, _u8L("Retractions"), [circle_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ circle_icon(window, pos, size, Options_Colors[static_cast(EOptionsColors::Retractions)]);
+#endif // ENABLE_LEGEND_TOOLBAR_ICONS
+ });
+ ImGui::SameLine();
+#if ENABLE_LEGEND_TOOLBAR_ICONS
+ toggle_button(Preview::OptionType::Unretractions, _u8L("Deretractions"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ image_icon(window, pos, size, ImGui::LegendDeretract);
+#else
+ toggle_button(Preview::OptionType::Unretractions, _u8L("Deretractions"), [circle_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ circle_icon(window, pos, size, Options_Colors[static_cast(EOptionsColors::Unretractions)]);
+#endif // ENABLE_LEGEND_TOOLBAR_ICONS
+ });
+ ImGui::SameLine();
+#if ENABLE_LEGEND_TOOLBAR_ICONS
+ toggle_button(Preview::OptionType::Seams, _u8L("Seams"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ image_icon(window, pos, size, ImGui::LegendSeams);
+#else
+ toggle_button(Preview::OptionType::Seams, _u8L("Seams"), [circle_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ circle_icon(window, pos, size, Options_Colors[static_cast(EOptionsColors::Seams)]);
+#endif // ENABLE_LEGEND_TOOLBAR_ICONS
+ });
+ ImGui::SameLine();
+#if ENABLE_LEGEND_TOOLBAR_ICONS
+ toggle_button(Preview::OptionType::ToolChanges, _u8L("Tool changes"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ image_icon(window, pos, size, ImGui::LegendToolChanges);
+#else
+ toggle_button(Preview::OptionType::ToolChanges, _u8L("Tool changes"), [circle_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ circle_icon(window, pos, size, Options_Colors[static_cast(EOptionsColors::ToolChanges)]);
+#endif // ENABLE_LEGEND_TOOLBAR_ICONS
+ });
+ ImGui::SameLine();
+#if ENABLE_LEGEND_TOOLBAR_ICONS
+ toggle_button(Preview::OptionType::ColorChanges, _u8L("Color changes"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ image_icon(window, pos, size, ImGui::LegendColorChanges);
+#else
+ toggle_button(Preview::OptionType::ColorChanges, _u8L("Color changes"), [circle_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ circle_icon(window, pos, size, Options_Colors[static_cast(EOptionsColors::ColorChanges)]);
+#endif // ENABLE_LEGEND_TOOLBAR_ICONS
+ });
+ ImGui::SameLine();
+#if ENABLE_LEGEND_TOOLBAR_ICONS
+ toggle_button(Preview::OptionType::PausePrints, _u8L("Print pauses"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ image_icon(window, pos, size, ImGui::LegendPausePrints);
+#else
+ toggle_button(Preview::OptionType::PausePrints, _u8L("Print pauses"), [circle_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ circle_icon(window, pos, size, Options_Colors[static_cast(EOptionsColors::PausePrints)]);
+#endif // ENABLE_LEGEND_TOOLBAR_ICONS
+ });
+ ImGui::SameLine();
+#if ENABLE_LEGEND_TOOLBAR_ICONS
+ toggle_button(Preview::OptionType::CustomGCodes, _u8L("Custom G-codes"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ image_icon(window, pos, size, ImGui::LegendCustomGCodes);
+#else
+ toggle_button(Preview::OptionType::CustomGCodes, _u8L("Custom G-codes"), [circle_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ circle_icon(window, pos, size, Options_Colors[static_cast(EOptionsColors::CustomGCodes)]);
+#endif // ENABLE_LEGEND_TOOLBAR_ICONS
+ });
+ ImGui::SameLine();
+#if ENABLE_LEGEND_TOOLBAR_ICONS
+ toggle_button(Preview::OptionType::Shells, _u8L("Shells"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ image_icon(window, pos, size, ImGui::LegendShells);
+#else
+ toggle_button(Preview::OptionType::Shells, _u8L("Shells"), [](ImGuiWindow& window, const ImVec2& pos, float size) {
+ const ImU32 color = ImGui::GetColorU32({ 1.0f, 1.0f, 1.0f, 1.0f });
+ const float margin = 3.0f;
+ const float proj = 0.25f * size;
+ window.DrawList->AddRect({ pos.x + margin, pos.y + size - margin }, { pos.x + size - margin - proj, pos.y + margin + proj }, color);
+ window.DrawList->AddLine({ pos.x + margin, pos.y + margin + proj }, { pos.x + margin + proj, pos.y + margin }, color);
+ window.DrawList->AddLine({ pos.x + size - margin - proj, pos.y + margin + proj }, { pos.x + size - margin, pos.y + margin }, color);
+ window.DrawList->AddLine({ pos.x + size - margin - proj, pos.y + size - margin }, { pos.x + size - margin, pos.y + size - margin - proj }, color);
+ window.DrawList->AddLine({ pos.x + margin + proj, pos.y + margin }, { pos.x + size - margin, pos.y + margin }, color);
+ window.DrawList->AddLine({ pos.x + size - margin, pos.y + margin }, { pos.x + size - margin, pos.y + size - margin - proj }, color);
+#endif // ENABLE_LEGEND_TOOLBAR_ICONS
+ });
+ ImGui::SameLine();
+#if ENABLE_LEGEND_TOOLBAR_ICONS
+ toggle_button(Preview::OptionType::ToolMarker, _u8L("Tool marker"), [image_icon](ImGuiWindow& window, const ImVec2& pos, float size) {
+ image_icon(window, pos, size, ImGui::LegendToolMarker);
+#else
+ toggle_button(Preview::OptionType::ToolMarker, _u8L("Tool marker"), [](ImGuiWindow& window, const ImVec2& pos, float size) {
+ const ImU32 color = ImGui::GetColorU32({ 1.0f, 1.0f, 1.0f, 0.8f });
+ const float margin = 3.0f;
+ const ImVec2 p1(0.5f * (pos.x + pos.x + size), pos.y + size - margin);
+ const ImVec2 p2 = ImVec2(p1.x + 0.25f * size, p1.y - 0.25f * size);
+ const ImVec2 p3 = ImVec2(p1.x - 0.25f * size, p1.y - 0.25f * size);
+ window.DrawList->AddTriangleFilled(p1, p2, p3, color);
+ const float mid_x = 0.5f * (pos.x + pos.x + size);
+ window.DrawList->AddRectFilled({ mid_x - 0.09375f * size, p1.y - 0.25f * size }, { mid_x + 0.09375f * size, pos.y + margin }, color);
+#endif // ENABLE_LEGEND_TOOLBAR_ICONS
+ });
+
+ bool size_dirty = !ImGui::GetCurrentWindow()->ScrollbarY && ImGui::CalcWindowNextAutoFitSize(ImGui::GetCurrentWindow()).x != ImGui::GetWindowWidth();
+ if (m_legend_resizer.dirty || size_dirty != m_legend_resizer.dirty) {
+ wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
+ wxGetApp().plater()->get_current_canvas3D()->request_extra_frame();
+ }
+ m_legend_resizer.dirty = size_dirty;
+#endif // ENABLE_PREVIEW_LAYOUT
+
+ legend_height = ImGui::GetWindowHeight();
imgui.end();
ImGui::PopStyleVar();
@@ -3922,14 +4306,14 @@ void GCodeViewer::log_memory_used(const std::string& label, int64_t additional)
}
}
int64_t layers_size = SLIC3R_STDVEC_MEMSIZE(m_layers.get_zs(), double);
- layers_size += SLIC3R_STDVEC_MEMSIZE(m_layers.get_endpoints(), Layers::Endpoints);
+ layers_size += SLIC3R_STDVEC_MEMSIZE(m_layers.get_ranges(), Layers::Range);
BOOST_LOG_TRIVIAL(trace) << label
<< "(" << format_memsize_MB(additional + paths_size + render_paths_size + layers_size) << ");"
<< log_memory_info();
}
}
-GCodeViewer::Color GCodeViewer::option_color(EMoveType move_type) const
+ColorRGBA GCodeViewer::option_color(EMoveType move_type) const
{
switch (move_type)
{
diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp
index a67208f10b..f7adcc9eb3 100644
--- a/src/slic3r/GUI/GCodeViewer.hpp
+++ b/src/slic3r/GUI/GCodeViewer.hpp
@@ -22,7 +22,6 @@ namespace GUI {
class GCodeViewer
{
using IBufferType = unsigned short;
- using Color = std::array;
using VertexBuffer = std::vector;
using MultiVertexBuffer = std::vector;
using IndexBuffer = std::vector;
@@ -31,12 +30,12 @@ class GCodeViewer
using InstanceIdBuffer = std::vector;
using InstancesOffsets = std::vector;
- static const std::vector